URL Rewrite in IIS: an ISAPI example written in VS2005
05 Mar 2011
Want to rewrite URL [/a.html] as [/?page=a]? In IIS, there is no mod_rewrite module like Apache. However, it supports ISAPI. And here is an example. The environment is VS2005 express version.
As my VS2005 is a Chinese version. If my translation is not correct, please guess the correct one by yourself :)
文件(F)(File) > 新建(N)(New) > 项目(P)(Project) > Visual C++ > 空项目(Empty Project)
Create a new source file with extension .DEF with the following content:
LIBRARY ISAPIsample
EXPORTS
GetFilterVersion
HttpFilterProc
In the previous code, the [ISAPIsample] should be the same as project name which will be used as the generated DLL name, so there would be no warning.
Create a new source file with extension .CPP with empty content.
Right click project name > 属性(R)(Properties)
配置属性(Configuration Properties)
常规(General)
配置类型(Configuration Type): 动态库(.dll)(Dynamic Linked Library)
字符集(Charset): 未设置(Not Configurated)
C/C++
常规(General)
调试信息格式(Debug Information Format): 程序数据库(/Zi)(Application Database)
代码生成(Code Generation)
运行时库(Runtime Library): 多线程(/MT)(Multi-thread) for Release & 多线程调试(/MTd)(Multi-thread debug) for Debug
链接器(Linker)
输入(Input)
模块定义文件(Module Definition File): The .DEF file we created just now.
调试(Debug)
生成调试信息(Generate Debug Information): 否(No) for Release & 是(/DEBUG)(Yes) for Debug
Fill the .CPP file with the following content:
#include <stdio.h>
#include <stdlib.h>
#include <afx.h>
#include <afxisapi.h>
BOOL WINAPI __stdcall GetFilterVersion(HTTP_FILTER_VERSION *pVer) {
pVer->dwFilterVersion = HTTP_FILTER_REVISION;
strcpy_s<SF_MAX_FILTER_DESC_LEN>(pVer->lpszFilterDesc, "URL Rewrite");
pVer->dwFlags = SF_NOTIFY_PREPROC_HEADERS;
return TRUE;
}
// Initial dstRemainChar should be sizeof(dst)-1. And manually pending '\0' is needed.
size_t str_copy(char* dst, size_t& dstRemainChar, char* src) {
char c = *src;
size_t copied = 0;
while (c != '\0') {
if (!dstRemainChar) {
break;
}
*dst = c;
dst++;
src++;
dstRemainChar--;
copied++;
c = *src;
}
return copied;
}
DWORD WINAPI __stdcall HttpFilterProc(HTTP_FILTER_CONTEXT *pfc, DWORD NotificationType, VOID *pvData) {
CHttpFilterContext *chc = (CHttpFilterContext *)pfc;
switch (NotificationType) {
case SF_NOTIFY_PREPROC_HEADERS:
HTTP_FILTER_PREPROC_HEADERS *p = (HTTP_FILTER_PREPROC_HEADERS *)pvData;
#define BUFFER_SIZE 8192
// 8192 is chosen here because as this program is written,
// apache supports 8192 and IIS supports 16384,
// IE supports 2038 and Chrome supports 8182.
char buffer[BUFFER_SIZE], buffer2[BUFFER_SIZE];
DWORD urlActuralLen = sizeof(buffer);
p->GetHeader(pfc, "url", buffer, &urlActuralLen);
if (strlen(buffer)) {
// Input URL can be filled into buffer.
// Convert
// /a.html /?page=a
// Keep
// /a.php
// /a/b.html
// /a/b.html?c=d
char* posSlashLast = strrchr(buffer, '/');
if (NULL == posSlashLast) {
// No slash. Might be an error
} else if (posSlashLast != buffer) {
// /a/b.html
// /a/b.html?c=d
} else {
size_t bufferLen = strlen(buffer);
char* posHTML = strstr(buffer, ".html");
if (NULL == posHTML) {
// /a.php
} else {
posHTML[0] = 0;
posHTML += 5; // Expresses codes after .html
char* buffer1Copy = buffer, *buffer2Copy = buffer2;
size_t lenRemain = BUFFER_SIZE - 1;
// Convertion code here!
buffer1Copy++;
buffer2Copy += str_copy(buffer2Copy, lenRemain, "/?page=");
buffer2Copy += str_copy(buffer2Copy, lenRemain, buffer1Copy);
// Ending of convertion.
buffer2Copy[0] = 0;
p->SetHeader(pfc, "url", buffer2);
return SF_STATUS_REQ_HANDLED_NOTIFICATION;
}
}
}
#undef BUFFER_SIZE
break;
}
return SF_STATUS_REQ_NEXT_NOTIFICATION;
}
And the project should be compilable. For the generated files, if the type is release, the .exp and .lib files can be deleted, leaving only the .dll file
The next step is config the IIS to use the ISAPI. (In the previous actions, if there is no DEF file, the project can still compile, but the generated DLL will cause IIS 500 error.) Here I'm using IIS7:
Open IIS Manager.
On the left, choose Computer name > Sites > Site Name. In the middle, choose "ISAPI Filters", enter it. On the right, choose Actions > Add..., and fill the "executable" field with our generated DLL file.
Restart the site, and the URL rewrite should work.
The attachment is the VS2005 solution folder and the DLL file to convert /a.html into /?page=a