Sheen Space

Posts Tagged ‘IIS

Web Development Study: Writing IIS native module

leave a comment »

This post comes from my IIS study. It includes basic information about writing own IIS 7 module, and also try to demonstrate difference between global module and HTTP request module, by using the two types of modules in a classic scenario, which is redirecting HTTP requests to HTTPS.

Definitions of request module and global module can be found everywhere. Simply speaking, request module is attached to individual request. In run time, there is a new module instance created everytime a new request comes in. Of course you don’t neccessarily have to create new instance, you can also use singleton, or object pool pattern. But request module’s behaviour is only meaningful to individual request. Request module can only register for request-related events, like BeginRequest, AuthenticateRequest, and EndRequest.

In contrast, global module has its life as long as the application it is enabled for. It can have state information visible to all requests. And it can register for global events, like GlobalFileChange, GlobalConfigurationChange, and PreBeginRequest.

Interface & Base Class

Microsoft provides a selection of interfaces and base classes for developers to write their own modules. A module is typically a DLL file, with one single export function:

HRESULT __stdcall RegisterModule(DWORD aServerVersion, IHttpModuleRegistrationInfo* aRegInfo, IHttpServer* aServer)

To implement global module, you need to derive from CGlobalModule base class, which provides a group of event handler member functions, and Terminate(). You only need to override handler virtual functions of interested events. But remember you have to register for those interested events, and not register for event that you don’t have overrided handler, otherwise IIS will call event handler of base class, and it triggers Debug Break by definition.

To implement Http module, you need to derive from CHttpModule, which also provides a group of event handler member functions and Dispose(). Different from global module implementation, you also need to write your module factory class, derived from IHttpModuleFactory, which declares two pure virtual functions:

HRESULT GetHttpModule(OUT CHttpModule** ppModule, IN IModuleAllocator* pAllocator);
VOID Terminate();

IIS Module Life Management

Both global module and Http module factory have application-level life. They are created in RegisterModule(), and are passed to IIS via aRegInfo->SetGlobalNotifications() and aRegInfo->SetRequestNotifications(). RegisterModule() is called when IIS worker process (w3wp.exe) loads the module DLL. This can happen in two situations:

  • when first request comes in, and first worker process of the application hasn’t loaded the module DLL;
  • when worker process is recycled.

Terminate() is called for both class objects in two situations:

  • when worker process is stopping;
  • when worker process is recycled.

Http module object, in contrast, has request-level life. It is typically created in IHttpModuleFactory::GetHttpModule() function. This function is called whenever new request is ready for processing. Module’s Dispose() function is called when request processing ends.

Now we can write empty modules which do nothing:

Http Module

class TestHttpModuleFactory : public IHttpModuleFactory
	HRESULT GetHttpModule(OUT CHttpModule** ppModule, IN IModuleAllocator* pAllocator)
		*ppModule = new TestHttpModule();
		return S_OK;

	VOID Terminate()
		delete this;

class TestHttpModule : public CHttpModule
    REQUEST_NOTIFICATION_STATUS OnBeginRequest(IN IHttpContext* pHttpContext, IN IHttpEventProvider* pProvider)

	REQUEST_NOTIFICATION_STATUS OnEndRequest(IN IHttpContext* pHttpContext, IN IHttpEventProvider* pProvider)

Global Module

class TestGlobalModule : public CGlobalModule
	GLOBAL_NOTIFICATION_STATUS OnGlobalPreBeginRequest(IN IPreBeginRequestProvider* pProvider)

	VOID Terminate()
		delete this;

Module Deployment

There are many good posts about installing and enabling module in IIS, like this one: IIS 7 Modules Overview. You can put your module DLL file anywhere, but the only thing to remember is to grant file access permission to ApplicationPoolIdentity, or you will get vague error.

Redirecting HTTP to HTTPS

Now we want to use module to handle a classic scenario – automatically redirect non-secure client request (http://) to secure url (https://).

I use default web site provided by IIS 7 to demonstrate. In SSL settings of application “Default Web Site”, we enable “Require SSL”. Now when we type “http://localhost/iisstart.htm” in browser, we will get error message:

HTTP Error 403.4 – Forbidden
The page you are trying to access is secured with Secure Sockets Layer (SSL).

Error 403.4

We can try to use http module to tackle the problem. Naturally, we want to register for BeginRequest event, and redirect request url there. After implementation, we re-type “http://localhost/iisstart.htm”, but still get same error message. Redirection doesn’t work. Why is it? First good thing to do is to enable Failed Request Logging for our application, error code 403.4. In generated log file, we can see that BeginRequest event is not triggered for our module, only EndRequest event triggered. It looks like SSL request check is done in IIS Web Core component, and if check fails, no normal events will be triggered for http modules, only error logging and response sending continue.

We notice that global PreBeginRequest event is triggered for those global modules. We can turn to global module for help. In the global module code below, we register for GL_PRE_BEGIN_REQUEST event, and redirect request there.

    GLOBAL_NOTIFICATION_STATUS OnGlobalPreBeginRequest(IN IPreBeginRequestProvider* pProvider)
		IHttpContext* pHttpContext = pProvider->GetHttpContext();
		IHttpRequest* pRequest = pHttpContext->GetRequest();

		PCWSTR url = pRequest->GetRawHttpRequest()->CookedUrl.pFullUrl;

		PCWSTR http = L"http://";
		PCWSTR https = L"https://";
		PHTTP_SSL_INFO ssl = pRequest->GetRawHttpRequest()->pSslInfo;

		if (wcsncmp(url, https, 8) != 0 && ssl == NULL && wcsncmp(url, http, 7) == 0)
			HRESULT hr = pHttpContext->GetResponse()->Redirect("https://localhost/iisstart.htm");
			if (FAILED(hr))
				// Log error


This time, redirection works well. It proves that if we want to implement complete HTTP-to-HTTPS redirection functionality, using Http module is not enough. Global module is the only candidate for comprehensive solution.

Written by Ying

21/10/2010 at 13:30

Posted in ASP.Net, Programming, Technology

Tagged with ,

Links: 2010-October

leave a comment »

How to Use the restrict Qualifier in C

Douglas Walls

Objects referenced through a restrict-qualified pointer have a special association with that pointer. All references to that object must directly or indirectly use the value of this pointer. In the absence of this qualifier, other pointers can alias this object.

Extending web.config in ASP.NET

Aaron Johnson

   <sectionGroup name=”myapplication”>
      <section name=”types” type=”System.Configuration.NameValueSectionHandler”/>
      <section name=”security” type=”System.Configuration.NameValueSectionHandler”/>

and then you add the actual settings:

      <add key=”section” value=”com.ignitionlabs.Section” />
      <add key=”template” value=”com.ignitionlabs.Template” />
      <add key=”/controlpanel/” value=”Systems Administrators,Project Managers” />
      <add key=”/members/” value=”members” />

Switching Between HTTP and HTTPS Automatically: Version 2

Matt Sollars

SecureWebPageModule is a class that implements the IHttpModule interface. HTTP modules give programmers a means of “attaching” to a Web application to process its events. It’s like descending from the System.Web.HttpApplication class and overriding the application and session events in a Global.asax file. The main difference is you don’t have to worry about copying and pasting the same code into the file for every application that is to use it. HTTP modules are simply “linked in” to a Web application and become part of the pipeline.

The goal of this security solution is to allow a developer to easily secure a website without the need to hard-code absolute URLs. This is accomplished by listing the files and/or directories that should be secured by SSL. It only seems natural to have a custom configuration section for this.

Licensed Memory in 32-Bit Windows Vista

Geoff Chappell

That 32-bit editions of Windows Vista are limited to 4GB is not because of any technical constraint on 32-bit operating systems. The 32-bit editions of Windows Vista all contain code for using physical memory above 4GB. Microsoft just doesn’t license you to use that code.

IIS7. Why Global Managed Modules are Disallowed

David Wong

This is a very good thread, not only discussing about IIS 7, but also about design consideration behind, and software development philosophy.

Using advanced logging to log custom module data


Post-Mortem Debugging Revisited

Stefan Worthmuller

Distributed Caching On The Path To Scalability

Iqbal Khan

A distributed cache as a concept and as a best practice is gaining more popularity. Only a few years ago, very few people in the .NET space knew about it, although the Java community has been ahead of .NET in this area. With the explosive growth in application transactions, databases are stressed beyond their limits, and distributed caching is now accepted as a vital part of any scalable application architecture.

SQL Server: Understanding and Controlling Connection-Pooling Fragmentation

Mohammed Mawla

Written by Ying

12/10/2010 at 07:30

Posted in Links

Tagged with , , ,

Web Development Study: ASP.Net 4 & IIS 7 hate each other?

leave a comment »

“PageHandlerFactory-Integrated” Issue

After environment set up, I started learning IIS 7 configuration. The first thing I want to do is to use ASP.Net 4 as default ASP.Net environment, replacing default ASP.Net 2. It appeared to be straightforward. I deployed example website from VS2010 to server; I changed the application pool’s .NET version to 4.0. When I tried to browse my website, it gave me this horrible error:

HTTP Error 500.21 – Internal Server Error

Handler “PageHandlerFactory-Integrated” has a bad module “ManagedPipelineHandler” in its module list

By googling internet, I find it is classic IIS and ASP.Net 4 configuration problem, and many forum threads are about it, like this one:

How to Fix “PageHandlerFactory-Integrated” bad module “ManagedPipelineHandler in IIS7

and this one:

Bad module “ManagedPipelineHandler” in its module list

However, after I tried all suggestions, website still gave same error message. Now I turn my notice to one line of settings in C:WindowsSystem32inetsrvconfigapplicationHost.config:

<add name="ManagedEngine" image="%windir%Microsoft.NETFrameworkv2.0.50727webengine.dll" preCondition="integratedMode,runtimeVersionv2.0,bitness32" />

If root managed engine is version 2.0, how can it handle later version of component? So I changed it to:

<add name="ManagedEngine" image="%windir%Microsoft.NETFrameworkv4.0.30319webengine4.dll" preCondition="integratedMode,runtimeVersionv4.0,bitness32" />

After I saved change, restart server and application pool, website is alive!

You must have noticed that there are 2 webengine DLLs under %windir%Microsoft.NETFrameworkv4.0.30319, webengine.dll and webengine4.dll. I am not sure what the difference is, and can’t get much information from Internet, but I guess webengine.dll becomes a wrapper or delegate to the new webengine4.dll. Because webengine.dll is 14K in size, but webengine4.dll is 481K, that is similar to webengine.dll (426K) in %windir%Microsoft.NETFrameworkv2.0.50727.

Question regarding basic authentication & authorization in IIS and ASP.Net

In addition, I asked a question on StackOverflow regarding IIS authentication and ASP.Net authorization:

Authentication settings in IIS 7.5 and ASP.Net, what is difference?

Issue with SQL Server Express provider services

Another issue regarding SQL Server user instance creation I met, is described here:

Problems with SQL Server Express user instancing and Web Application Projects

In article below, author tells alternative workaround instead of using NETWORK SERVICE system account: Auto-generated SQLEXPRESS database: Failed to generate a user instance of SQL Server ( troubleshooting 1 )

However, I notice that, not like what is shown in the article, in my Windows 7 system with IIS 7.5, DefaultAppPool user account doesn’t have user profile by default. Creating a user profile for it may not be such a good idea for whatever reason.

Written by Ying

07/10/2010 at 13:05