Specifying exact path for my ASP.NET Http Handler - asp.net

I generate an XML/Google sitemap on the fly using an Http Handler, so that I don't need to maintain an XML file manually.
I have mapped my Http Handler to "sitemap.xml" in my web.config like this:
<httpHandlers>
<add verb="*" path="sitemap.xml" type="My.Name.Space, MyAssembly" />
</httpHandlers>
It works nicely. Now, www.mywebsite.com/sitemap.xml sets my Http Handler into action and does exactly what I want. However, this url will do the same: www.mywebsite.com/some/folder/sitemap.xml and I don't really want that i.e. I just want to map my handler to the root of my application.
I have tried changing the "path" of my handler in my web.config to "/sitemap.xml" and "~/sitemap.xml" but neither works.
Am I missing something here?

Try adding the following to your web.config
<urlMappings enabled="true">
<add url="~/SiteMap.xml" mappedUrl="~/MyHandler.ashx"/>
</urlMappings>
This uses a little known feature of ASP.NET 2.0 called 'Url Mapping'

Following on from Kirtan suggested solution #1 you can do a workaround like follows:
public void ProcessRequest(HttpContext context) {
//Ensure that the sitemap.xml request is to the root of the application
if (!context.Request.PhysicalPath.Equals(Server.MapPath("~/sitemap.xml"))) {
//Invoke the Default Handler for this Request
context.RemapHandler(null);
}
//Generate the Sitemap
}
You might need to play with this a bit, not sure if invoking the default handler will just cause IIS to re-invoke your Handler again. Probably worth testing in Debug mode from VS. If it does just re-invoke then you'll need to try invoking some static file Handler instead or you could just issue a HTTP 404 yourself eg
//Issue a HTTP 404
context.Response.Clear();
context.Response.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return;
See the MSDN documentation on HttpContext.RemapHandler for more info -
http://msdn.microsoft.com/en-us/library/system.web.httpcontext.remaphandler.aspx

2 solutions to this:
Soln #1:
You can check the request path using the Request.Url property, if the request is from the root path, you can generate the XML, else don't do anything.
Soln #2:
Put a web.config file with the following setting in every folder in which you don't want to handle the request for the sitemap.xml file.

You can, alternately, run a check in the global.asax, verify the request, and finaly re-assigning a new handler throughtout context.RemapHandler method.
The only thing is that you would´ve to implement a factory for that matter.
I would suggest you inherit the HttpApplication, and implement there the factory, but that's your call.

Related

Creating HttpHandler in IIS subdirectory that accepts POST requests from other hosts

I have access to a sub directory on server like http://root/_pp. My job is to create a generic http handler in .NET and drop it in _pp directory. The said handler should accept POST and OPTIONS request from external sources like custom code in .NET and java would be calling the handler using OPTIONS and POST requests.
I have uploaded quite a simple handler in the sub directory. The code looks like the following
public void ProcessRequest(HttpContext context){
context.Response.ClearHeaders();
//string origin = context.Request.Headers["Origin"];
context.Response.AppendHeader("Access-Control-Allow-Origin","*");
//string requestHeaders = context.Request.Headers["Access-Control-Request-Headers"];
context.Response.AppendHeader("Access-Control-Allow-Headers","*");
context.Response.AppendHeader("Access-Control-Allow-Methods", "POST, OPTIONS");
context.Response.ContentType = "text/plain";
context.Response.Write("Hello World again again");
}
When I upload this handler to the _pp sub directory and send a POST or OPTIONS request from fiddler, it returns 500 Internal Server Error.
Please Note: I have no control over configuring the IIS on server, nor can I access anything in root directory of the server.
Is it possible to achieve what I want with given constraints? Please help
EDIT 1 handler registration in web.config of _pp
<system.webserver>
<handlers>
<add name="IPN" verb="*" path="IPN.ashx" type="System.Web.UI.SimpleHandlerFactory" />
</handlers>
</system.webServer>

Letsencrypt acme-challenge on wordpress or asp.net mvc

I have been trying without success to generate security certificates for my company using Let's Encrypt. My company uses WordPress 3.9.7 for its main website and I am not allow to upgrade to a newer version since that is handled by a third party company.
The website is running on top of Internet Information Services 7.5 on Windows Server 2008 R2.
My question is: How can I make wordpress handle http://www.company.com/.well-known/acme-challenge/mftvrU2brecAXB76BsLEqW_SL_srdG3oqTQTzR5KHeA
?
I have already created a new empty page and a new template that returns exactly what let's encrypt is expecting but wordpress keeps returning a 404 for that page. My guess is that the problem arise with the dot(.) at the beginning of the route (".well-known") but I don't know how to solve that on wordpress.
I am also able to use an asp.net mvc website and make IIS point to that website for a while. Not a good idea though since clients may not be able to reach our website for a few minutes, but still an option. Then the question is: How can I create a controller or a route with a dot(".") at the beginning of the name?
Help will be really appreciated.
For ASP.Net MVC or Web Forms, with certain Routing configs, you'll end up treating this URL as something for the Routing Engine to hand off to the MVC/Forms Handler, not a static file return. The result will be a 404 or a 503. The solution is surprisingly very simple:
If you haven't already, place the Challenge file:
Create the necessary dirs - .well-known is tricky mostly because Microsoft is lazy, but you can either do it from cmdline or create the folder as .well-known. and Windows Explorer will notice the workaround and remove the trailing period for you.
Inside \.well-known\acme-challenge place the challenge file with the proper name and contents. You can go about this part any way you like; I happen to use Git Bash like echo "oo0acontents" > abcdefilename
Then make a Web.Config file in the acme-challenge dir with these contents:
<?xml version = "1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<staticContent>
<clear />
<mimeMap fileExtension = ".*" mimeType="text/json" />
</staticContent>
<handlers>
<clear />
<add name="StaticFile" path="*" verb="*" modules="StaticFileModule,DefaultDocumentModule"
resourceType="Either" requireAccess="Read" />
</handlers>
</system.webServer>
</configuration>
Source: https://github.com/Lone-Coder/letsencrypt-win-simple/issues/37
Done. The file will start returning instead of 404/503 allowing the Challenge to complete - you can now Submit and get your domain validated.
Aside: The above code snippet sets the content-type to json, a historical requirement that is no longer relevant to letsencrypt. The current requirement is there is no requirement - you can send a content-type of pantsless/elephants and it'll still work.
More for Asp.Net
I like to redirect all HTTP requests back to HTTPS to ensure users end up on a secure connection even if they didn't know to ask. There are a lot of easy ways to do that, until you're using LetsEncrypt - because you're going to break requests for .well-known. You can setup a static method in a class, like this:
public static class HttpsHelper
{
public static bool AppLevelUseHttps =
#if DEBUG
false;
#else
true;
#endif
public static bool Application_BeginRequest(HttpRequest Request, HttpResponse Response)
{
if (!AppLevelUseHttps)
return false;
switch (Request.Url.Scheme)
{
case "https":
return false;
#if !DEBUG
case "http":
var reqUrl = Request.Url;
var pathAndQuery = reqUrl.PathAndQuery;
// Let's Encrypt exception
if (pathAndQuery.StartsWith("/.well-known"))
return false;
// http://stackoverflow.com/a/21226409/176877
var url = "https://" + reqUrl.Host + pathAndQuery;
Response.Redirect(url, true);
return true;
#endif
}
return false;
}
}
Now that can do a great job of redirecting to HTTPS except when LetsEncrypt comes knocking. Tie it in, in Global.asax.cs:
protected void Application_BeginRequest(object sender, EventArgs ev)
{
HttpsHelper.Application_BeginRequest(Request, Response);
}
Notice that the bool returned is discarded here. You can use it if you like to decide whether to end the request/response immediately, true meaning, end it.
Finally, if you like, you can use the AppLevelUseHttps variable to turn off this behavior if need-be, for example to test if things are working without HTTPS. For example, you can have it set to the value of a Web.Config variable.

How to validate Request.RawUrl in Application_BeginRequest event in Global.asax.cs file?

Some bots are requesting URLs like www.example.com/test-</p><p>they-are-angry... which is creating A potentially dangerous exception in my asp.net application.
I need to validate the HttpContext.Current.Request.RawUrl in Application_BeginRequest event of Global.asax.cs file and if it is invalid I will redirect to another error page.
I do NOT want to set validateRequest="false" or requestValidationMode="2.0" but want to redirect to a particular error page if Request.RawUrl is invalid.
How to achieve this? Is there any Asp.Net predefined method to validated this URL?
Any help is highly appreciated!
If you want to just redirect to an error page, you can simply configure customErrors or implement global error handlers as detailed in existing post and on MSDN.
However, if you want to delay validation until later, such as Application_BeginRequest, you can disable request validation and invoke it explicitly, as mentioned in Imran's blog:
1. set requestValidationMode="2.0"
2. invoke Request.ValidateInput()
protected void Application_BeginRequest()
{
Request.ValidateInput();
var q = Request.QueryString;
}

How can I set up IIS to run server code for an HTML form?

If I have a simple html page with a small form whose data I'd like to store in a DB on the server, what do I need on my server to be able to accept the form input?
I'd rather not use any ASP.NET code in the HTML page.
As I mentioned in the comments, the closest thing to a Java Servlet in ASP.NET is a raw implementation of IHttpHandler. You'll note it has the following contract:
bool IsReusable { get; };
void ProcessRequest(HttpContext context);
This is very similar to a Java servlet which exposes the method:
service(ServletRequest req, ServletResponse res);
The difference being that in ProcessRequest you'll grab context.Request and context.Response.
Finally, you need to register your handler in the web.config:
<configuration>
<system.web>
<httpHandlers>
<add verb="*" path="/Url/Path/To/Your/Handler" type="SampleHandler, SampleHandlerAssembly" />
</httpHandlers>
</system.web>
</configuration>
Your HTML form submits data to the server. You will need something on the server that accepts this data and writes it to your database. This could be an ASP.NET app, PHP, Perl or Python scripts, or just about anything else that you can get to run on your server.
Your HTML page doesn't necessarily have to have any ASP.NET code, even if your server-side application is built with it.

Weird "The file '/DefaultWsdlHelpGenerator.aspx' does not exist" error when remapping WebService HttpHandler

I have dynamic CMS-driven (custom rolled, I know, wheels, etc. but not my decision!) site, which uses an HttpModule to direct content. I have found that .asmx resources were not working. After investigation, I figured out that this was because I had essentially overridden the handler by taking the request out of the overall pipeline.
So I am now detecting if the resource exists and is an .asmx file, and handling accordingly. Which I think is to create a WebServiceHandler using WebServiceHandlerFactory and then remapping it.
This works fine with a ?wsdl querystring, but ask for the URI itself and you get (at point indicated by asterisks):
System.InvalidOperationException was unhandled by user code
Message=Failed to handle request.
[snip]
InnerException:
System.InvalidOperationException
Message=Unable to handle request.
Source=System.Web.Services
InnerException: System.Web.HttpException
Message=The file '/DefaultWsdlHelpGenerator.aspx' does not
exist.
Note the final InnerException. This thread appears to suggest a corrupt .NET Framework install, but the file is present in the 4.0 Config folder. I suspect a mistake on my part. Am I remapping incorrectly?
public class xxxVirtualContentHttpModule : xxxHttpModule
{
protected override void OnBeginRequest(IxxxContextProvider cmsContext, HttpContext httpContext)
{
string resolvePath = httpContext.Request.Url.AbsolutePath;
// is path a physical file?
IRootPathResolver rootPathResolver=new HttpServerRootPathResolver(httpContext.Server);
string serverPath = rootPathResolver.ResolveRoot("~" + resolvePath);
if (File.Exists(serverPath))
{
if (Path.GetExtension(serverPath).Equals(".asmx", StringComparison.CurrentCultureIgnoreCase))
{
WebServiceHandlerFactory webServiceHandlerFactory = new WebServiceHandlerFactory();
IHttpHandler webServiceHttpHandler = webServiceHandlerFactory.GetHandler(httpContext, "Get", resolvePath, serverPath); // *****
httpContext.RemapHandler(webServiceHttpHandler);
}
}
}
Update
I have removed all references to the HttpModules and this issue still occurs, meaning it has nothing to do with the CMS portion of the system.
Solved it.
There seems to be a new configuration added to web.config:
<system.web>
<webServices>
<wsdlHelpGenerator href="DefaultWsdlHelpGenerator.aspx" />
</webServices>
</system.web>
Removed this, and it all works.

Resources