<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.iis.net/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:cs="http://blogs.iis.net/"><channel><title>Yaminij&amp;#39;s blog</title><link>http://blogs.iis.net/yaminij/default.aspx</link><description /><dc:language>en</dc:language><generator>CommunityServer 2007 SP1 (Build: 20510.895)</generator><item><title>Session Tracker Native Module for IIS 7.0</title><link>http://blogs.iis.net/yaminij/archive/2009/01/28/session-tracker-native-module-for-iis-7-0.aspx</link><pubDate>Wed, 28 Jan 2009 18:47:37 GMT</pubDate><guid isPermaLink="false">50bcf3b4-f6fe-4638-adff-0c150e922e99:2898763</guid><dc:creator>yaminij</dc:creator><slash:comments>5</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.iis.net/yaminij/rsscomments.aspx?PostID=2898763</wfw:commentRss><comments>http://blogs.iis.net/yaminij/archive/2009/01/28/session-tracker-native-module-for-iis-7-0.aspx#comments</comments><description>&lt;blockquote&gt;&lt;/blockquote&gt;  &lt;h2&gt;Overview&lt;/h2&gt;  &lt;blockquote&gt;   &lt;p&gt;The Session Tracker is a native&amp;#160; C++ module for IIS 7.0 that can be used to obtain information about user-activity on a site using cookies. &lt;/p&gt; &lt;/blockquote&gt;  &lt;h2&gt;Download&lt;/h2&gt;  &lt;blockquote&gt;   &lt;p&gt;You can download and install the Session Tracker module along with the source code from &lt;a href="http://blogs.iis.net/blogs/yaminij/SessionTracker.zip" target="_blank" mce_href="http://blogs.iis.net/blogs/yaminij/SessionTracker.zip"&gt;here&lt;/a&gt;. A tiny disclaimer here, this is not an official Microsoft extension (hence not supported by Microsoft), but a personal contribution to the download centre. You can direct all queries and improvements to the module directly to me, and i will try my best to address them.&lt;/p&gt; &lt;/blockquote&gt;  &lt;h2&gt;Features&lt;/h2&gt;  &lt;blockquote&gt;   &lt;p&gt;The Session Tracker module comprises of a sessionTracking.xml and a SessionTracking.dll and has the following key features&lt;/p&gt;    &lt;ul&gt;     &lt;li&gt;The module when enabled, will attach a Set-Cookie header in the server response which will enable subsequent requests from the client to be tracked using Cookies. The module can also send a Cache-Control header in the response. &lt;/li&gt;      &lt;li&gt;The schema lets you disable/enable the SessionTracking module. &lt;/li&gt;      &lt;li&gt;The schema helps you dictate the name of the cookie and the cookie style information (whether you want to send Set-Cookie or a Set-Cookie2 header in the response). You can also set certain other attributes of the cookie like Max-Age, Path, Version, Secure, etc. as described in RFCs &lt;a href="http://www.ietf.org/rfc/rfc2109.txt" target="_blank" mce_href="http://www.ietf.org/rfc/rfc2109.txt"&gt;2109&lt;/a&gt; and &lt;a href="http://www.ietf.org/rfc/rfc2965.txt" target="_blank" mce_href="http://www.ietf.org/rfc/rfc2965.txt"&gt;2965&lt;/a&gt;. &lt;/li&gt;      &lt;li&gt;The schema also enables you to send Cache-Control headers in the response.&amp;#160; This is outlined in RFC &lt;a href="http://www.ietf.org/rfc/rfc2616.txt" target="_blank" mce_href="http://www.ietf.org/rfc/rfc2616.txt"&gt;2616&lt;/a&gt;. &lt;/li&gt;   &lt;/ul&gt; &lt;/blockquote&gt;  &lt;h2&gt;Installation&lt;/h2&gt;  &lt;blockquote&gt;   &lt;p&gt;You should be able to install the Session Tracker module on an IIS 7.0 machine, by following these simple steps.&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;    &lt;ol&gt;     &lt;li&gt;Install the SessionTracker.EXE installer onto a folder on your IIS 7.0 machine. The installer would copy the source code, Visual Studio project files, binaries (x86 and x64) and schema required for the working of the sessionTracker module. &lt;/li&gt;      &lt;li&gt;Run the installScript.js from this folder on an administrator command prompt. The script would copy SessionTracking.dll to %windir%\system32\inetsrv and to the %syswow64%\system32\inetsrv on an x64 machine. The script also copies the sessionTracking.xml schema file to %windir%\system32\inetsrv\config\schema. &lt;/li&gt;      &lt;li&gt;Install the SessionTrackingModule by using the following appcmd command        &lt;p&gt;&lt;font color="#800000"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; appcmd.exe install module /name:SessionTrackingModule /image:%windir%\system32\inetsrv\SessionTracking.dll&lt;/font&gt;&lt;/p&gt;     &lt;/li&gt;      &lt;li&gt;Make the following changes to \inetsrv\config\applicationHost.config file on your server.        &lt;p&gt;Declare the sessionTracking section in the &amp;lt;system.webServer&amp;gt; sectionGroup for it to be recognized by appcmd.exe&lt;/p&gt;        &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;              &amp;lt;&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;sectionGroup&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;system.webServer&amp;quot;&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
                       &lt;span class="kwrd"&gt;&amp;lt;&lt;/span&gt;&lt;span class="html"&gt;section&lt;/span&gt; &lt;span class="attr"&gt;name&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;sessionTracking&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;allowDefinition&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;AppHostOnly&amp;quot;&lt;/span&gt; &lt;span class="attr"&gt;overrideModeDefault&lt;/span&gt;&lt;span class="kwrd"&gt;=&amp;quot;Allow&amp;quot;&lt;/span&gt; &lt;span class="kwrd"&gt;/&amp;gt;&lt;/span&gt;
                &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;sectionGroup&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="kwrd"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="html"&gt;configSections&lt;/span&gt;&lt;span class="kwrd"&gt;&amp;gt;&lt;/span&gt; &lt;/pre&gt;
      &lt;style type="text/css"&gt;






.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/li&gt;

    &lt;li&gt;Now, you can enable the sessionTracking section at the server level using the following appcmd command &lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;&lt;font color="#800000"&gt;&lt;strong&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/strong&gt;appcmd.exe set config /section:sessionTracking /enabled:true&lt;/font&gt;&lt;/p&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160; 6.&amp;#160;&amp;#160; You can list the sessionTracking section, containing default values with the following appcmd command. &lt;/p&gt;

  &lt;p&gt;&lt;font color="#800000"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; appcmd.exe list config /section:sessionTracking /config:*&lt;/font&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;span class="kwrd"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&lt;span class="kwrd"&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/span&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Implementation&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p align="justify"&gt;The Session Tracker module kicks in during the RQ_BEGIN_REQUEST state of the request pipeline. &lt;/p&gt;

  &lt;p align="justify"&gt;If the module sees a Cookie header in the request already, it will be interpreted as a session already initiated by the server. In that case, the module will return control to the request pipeline by returning RQ_NOTIFICATION_CONTINUE. That way, default site functionality will not be interrupted.&lt;/p&gt;

  &lt;p align="justify"&gt;If the module does not see a Cookie header in the request, then this will be treated as a new request. The module, then reads the config data, and builds a Set-Cookie header using the information defined by the user in the config. It will then obtain the response from the server and&amp;#160; adds the Set-Cookie header to the response. &lt;/p&gt;

  &lt;p align="justify"&gt;The module also takes care of adding a Cache-Control header to the response. After adding this header, the module prevents any further processing of the request by returning an RQ_NOTIFICATION_FINISH_REQUEST.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Working&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;To see the working of the session tracker module, you can follow the steps below&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Enable &lt;a href="http://technet.microsoft.com/en-us/library/cc731798.aspx" target="_blank" mce_href="http://technet.microsoft.com/en-us/library/cc731798.aspx"&gt;Failed Request Tracing&lt;/a&gt; on your website for status codes 200-500. &lt;/li&gt;

    &lt;li&gt;Delete all previous cookies from IE and then browse once to the site. &lt;/li&gt;

    &lt;li&gt;Open the trace log file (default location %systemdriv%\inetpub\logs\FailedReqLogFiles). Your request and response headers will look like this. &lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://blogs.iis.net/blogs/yaminij/image_0D18A7A9.png" mce_href="http://blogs.iis.net/blogs/yaminij/image_0D18A7A9.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="120" alt="image" src="http://blogs.iis.net/blogs/yaminij/image_thumb_5A48A134.png" width="852" border="0" mce_src="http://blogs.iis.net/blogs/yaminij/image_thumb_5A48A134.png" /&gt;&lt;/a&gt; &lt;/p&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://blogs.iis.net/blogs/yaminij/image_3C6A1D33.png" mce_href="http://blogs.iis.net/blogs/yaminij/image_3C6A1D33.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="134" alt="image" src="http://blogs.iis.net/blogs/yaminij/image_thumb_5E557FB7.png" width="855" border="0" mce_src="http://blogs.iis.net/blogs/yaminij/image_thumb_5E557FB7.png" /&gt;&lt;/a&gt; &lt;/p&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; The Set-Cookie header in the response is generated and added to the response by the Session Tracker module. &lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;Refresh the site from the second step again with IE. &lt;/li&gt;

    &lt;li&gt;You will find another trace log file generated at the same location.&amp;#160; Your request header for the second request will now look like this &lt;/li&gt;
  &lt;/ul&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://blogs.iis.net/blogs/yaminij/image_472A0539.png" mce_href="http://blogs.iis.net/blogs/yaminij/image_472A0539.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="146" alt="image" src="http://blogs.iis.net/blogs/yaminij/image_thumb_50199778.png" width="878" border="0" mce_src="http://blogs.iis.net/blogs/yaminij/image_thumb_50199778.png" /&gt;&lt;/a&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; Thereafter all subsequent requests in the same session would have this Cookie header set.&lt;/p&gt;

&lt;h2&gt;Usage&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;You can use the Session Tracker module along with &lt;a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&amp;amp;displaylang=en" target="_blank" mce_href="http://www.microsoft.com/downloads/details.aspx?FamilyID=890cd06b-abf8-4c25-91b2-f8d975cf8c07&amp;amp;displaylang=en"&gt;LogParser 2.2&lt;/a&gt; to parse the IIS 7.0 logs and generate a log of user-activity on the website.&lt;/p&gt;

  &lt;ol&gt;
    &lt;li&gt;As a first step, enable logging on your website and select the cs(Cookie) w3c logging field. For more information, you can refer this &lt;a href="http://technet.microsoft.com/en-us/library/cc754702.aspx" target="_blank" mce_href="http://technet.microsoft.com/en-us/library/cc754702.aspx"&gt;link&lt;/a&gt;. &lt;/li&gt;

    &lt;li&gt;Now, you can execute the following LogParser query on the log file generated for the site (default location is %systemdrive%\inetpub\logs\LogFiles).to obtain a log of user-activity for a particular session. The &lt;font color="#ff0000"&gt;highlighted&lt;/font&gt; item is the name=value field from the cookie generated. &lt;/li&gt;
  &lt;/ol&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; LogParser &amp;quot;SELECT cs-uri-stem from u_ex090109.log where cs(Cookie)=&lt;font color="#ff0000"&gt;'IIS7SessionTracking=18302628887781179643'&lt;/font&gt;&amp;quot;&lt;/p&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;strong&gt;Output:&lt;/strong&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;/p&gt;

  &lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://blogs.iis.net/blogs/yaminij/image_0ADDD38A.png" mce_href="http://blogs.iis.net/blogs/yaminij/image_0ADDD38A.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="749" alt="image" src="http://blogs.iis.net/blogs/yaminij/image_thumb_01186C12.png" width="669" border="0" mce_src="http://blogs.iis.net/blogs/yaminij/image_thumb_01186C12.png" /&gt;&lt;/a&gt;&amp;#160; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; To obtain a list of all the Cookies given out by the server, you can execute the following LogParser command.&lt;/p&gt;

&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; LogParser &amp;quot;SELECT cs(Cookie),count(*) from&amp;#160; u_ex090109.log GROUP BY cs(Cookie)&amp;quot;&lt;/p&gt;

&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; &lt;a href="http://blogs.iis.net/blogs/yaminij/image_5C40BAC9.png" mce_href="http://blogs.iis.net/blogs/yaminij/image_5C40BAC9.png"&gt;&lt;img title="image" style="border-top-width: 0px; display: inline; border-left-width: 0px; border-bottom-width: 0px; border-right-width: 0px" height="507" alt="image" src="http://blogs.iis.net/blogs/yaminij/image_thumb_397F830C.png" width="796" border="0" mce_src="http://blogs.iis.net/blogs/yaminij/image_thumb_397F830C.png" /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p mce_keep="true"&gt;&amp;#160;&lt;/p&gt;

&lt;h2&gt;Acknowledgements&lt;/h2&gt;

&lt;p&gt;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160;&amp;#160; I would like to thank &lt;a href="http://blogs.iis.net/ksingla" target="_blank" mce_href="http://blogs.iis.net/ksingla"&gt;Kanwal&lt;/a&gt; for his invaluable feedback and initial research and Cip for the initial implementation of the Session Tracker module.&lt;/p&gt;

&lt;h2&gt;References&lt;/h2&gt;

&lt;p&gt;&lt;a title="http://learn.iis.net/page.aspx/169/develop-a-native-cc-module-for-iis-7/" href="http://learn.iis.net/page.aspx/169/develop-a-native-cc-module-for-iis-7/" mce_href="http://learn.iis.net/page.aspx/169/develop-a-native-cc-module-for-iis-7/"&gt;http://learn.iis.net/page.aspx/169/develop-a-native-cc-module-for-iis-7/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a title="http://blogs.iis.net/ksingla/archive/2008/12/21/using-imetadatainfo-getmodulecontextcontainer-to-store-configuration-data.aspx" href="http://blogs.iis.net/ksingla/archive/2008/12/21/using-imetadatainfo-getmodulecontextcontainer-to-store-configuration-data.aspx" mce_href="http://blogs.iis.net/ksingla/archive/2008/12/21/using-imetadatainfo-getmodulecontextcontainer-to-store-configuration-data.aspx"&gt;http://blogs.iis.net/ksingla/archive/2008/12/21/using-imetadatainfo-getmodulecontextcontainer-to-store-configuration-data.aspx&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.ietf.org/rfc/rfc2109.txt" mce_href="http://www.ietf.org/rfc/rfc2109.txt"&gt;http://www.ietf.org/rfc/rfc2109.txt&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://www.ietf.org/rfc/rfc2965.txt" mce_href="http://www.ietf.org/rfc/rfc2965.txt"&gt;http://www.ietf.org/rfc/rfc2965.txt&lt;/a&gt; 

  &lt;br /&gt;&lt;a href="http://www.ietf.org/rfc/rfc2616.txt" mce_href="http://www.ietf.org/rfc/rfc2616.txt"&gt;http://www.ietf.org/rfc/rfc2616.txt&lt;/a&gt;&lt;/p&gt;&lt;img src="http://blogs.iis.net/aggbug.aspx?PostID=2898763" width="1" height="1"&gt;</description></item><item><title>Getting started with writing a FastCGI Client application (FastCGI Test Client)</title><link>http://blogs.iis.net/yaminij/archive/2009/01/08/getting-started-with-writing-a-fastcgi-client-application-fastcgi-test-client.aspx</link><pubDate>Thu, 08 Jan 2009 02:05:00 GMT</pubDate><guid isPermaLink="false">50bcf3b4-f6fe-4638-adff-0c150e922e99:2853176</guid><dc:creator>yaminij</dc:creator><slash:comments>4</slash:comments><wfw:commentRss xmlns:wfw="http://wellformedweb.org/CommentAPI/">http://blogs.iis.net/yaminij/rsscomments.aspx?PostID=2853176</wfw:commentRss><comments>http://blogs.iis.net/yaminij/archive/2009/01/08/getting-started-with-writing-a-fastcgi-client-application-fastcgi-test-client.aspx#comments</comments><description>&lt;P&gt;I worked on the FastCGI for IIS&amp;nbsp;6.0&amp;nbsp;RTM release a while ago and during that time, I worked on developing a FastCGI Client application, in order to test FastCGI at a protocol level. I just decided to blog about it, just in case any of you are interested in getting started with writing a FastCGI client application from scratch.&amp;nbsp; 
&lt;P&gt;You can download the sample client application along with the source code from &lt;A class="" href="http://blogs.iis.net/blogs/yaminij/FCGIClient.zip" mce_href="http://blogs.iis.net/blogs/yaminij/FCGIClient.zip"&gt;here&lt;/A&gt;. This application can work both over TCP and Named Pipes. 
&lt;P&gt;The FastCGI Client application is a generic application that will be used to communicate with the Web Server (FastCGI handler) through FastCGI protocol either over Named Pipes or TCP.&amp;nbsp; The FastCGI test client communicates in the form of messages with the FastCGI Server.&amp;nbsp; All these messages are in the form of STDIN, STDOUT and STDERR. The Web Server (FastCGI Handler) creates a Named Pipe or a TCP stream for communication and duplicates these handles onto the stdout, stdin and stderr (parent processes can override the stdin, stdout and stderr of child). By this, the application just has to write it’s protocol messages to stdin, stdout and stderr and the details of the TCP/Named Pipe communication is abstracted out. 
&lt;P&gt;As a first step, you can determine if the application was invoked using CGI or FastCGI by calling getpeername on the STD_INPUT_HANDLE.&amp;nbsp; You should get a socket error if the client was invoked using a FastCGI application. Depending on whether your server uses TCP or Named Pipes, your WSAGetLastError() could return WASENOTCONN or WSAENOTSOCK respectively. &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; IsApplicationInvokedUsingFastCGI( HANDLE s )
{
        &lt;SPAN class=rem&gt;// Determine if this application was invoked using CGI or FastCGI&lt;/SPAN&gt;
        &lt;SPAN class=kwrd&gt;struct&lt;/SPAN&gt; sockaddr nameOfConnectedSocket;
        &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; nameLenOfConnectedSocket;
        HRESULT hr = S_OK;
        &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; errs; 

        errs = getpeername( (SOCKET)s, &amp;amp;nameOfConnectedSocket, &amp;amp;nameLenOfConnectedSocket );        
        &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt; ( errs == SOCKET_ERROR )
        {
            hr = HRESULT_FROM_WIN32( WSAGetLastError() );
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;(  hr == HRESULT_FROM_WIN32( WSAENOTCONN ) )
            {
                    &lt;SPAN class=rem&gt;//LogMessage( TRACE_MESSAGE, "Application was invoked using FastCGI over TCP, got a WSAENOTCONN on a call to getpeername()" );                    &lt;/SPAN&gt;
                    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; TRUE;
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;            
            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( hr == HRESULT_FROM_WIN32( WSAENOTSOCK ) ) 
            {                    
                    &lt;SPAN class=rem&gt;//LogMessage( TRACE_MESSAGE, "Application was invoked using FastCGI over Named Pipe, got a WSAENOTSOCK on a call to getpeername()" );                    &lt;/SPAN&gt;
                    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; TRUE;
            }            
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;            
            {                                        
                    &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; FALSE;            
            }
        }        
        &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
        {
            &lt;SPAN class=rem&gt;// Quit, this app is not compatible with FastCGI&lt;/SPAN&gt;
            &lt;SPAN class=rem&gt;//LogMessage( TRACE_MESSAGE, "Application was invoked using CGI, getpeername() successful" );&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; FALSE;
        }        
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;Next step to writing a client is to try and determine if the communication with the Web Server should happen over Named Pipes or TCP. Do an accept() socket call on the STDIN and if it succeeds, use TCP, else use Named Pipes.&amp;nbsp; &lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; IsNamedPipeOrSocket( HANDLE hStdin, FASTCGI_PROTOCOL * useNamedPipeOrSocket )
{
        HRESULT hr = S_OK; 

        &lt;SPAN class=kwrd&gt;try&lt;/SPAN&gt;
        {
            acceptSocket = accept( (SOCKET)hStdin, NULL, NULL ); 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( acceptSocket == INVALID_SOCKET )
            {
                (*useNamedPipeOrSocket) = FcgiConfigProtocolNamedPipe;                
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
            {
                (*useNamedPipeOrSocket) = FcgiConfigProtocolTcp;
            }            
        }
        &lt;SPAN class=kwrd&gt;catch&lt;/SPAN&gt;(...)
        {
            &lt;SPAN class=rem&gt;//LogMessage( TRACE_EXCEPTION, "Exception is IsNamedPipeOrSocket() function" );&lt;/SPAN&gt;
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; FALSE;
        }
        &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; TRUE;
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;P&gt;Then Initialize the transport connection and receive and send messages from and to the FastCGI Server respectively. For more information on this exchange please refer the &lt;A class="" href="http://www.fastcgi.com/devkit/doc/fcgi-spec.html" mce_href="http://www.fastcgi.com/devkit/doc/fcgi-spec.html"&gt;FastCGI protocol specification&lt;/A&gt;.&lt;PRE class=csharpcode&gt;&lt;SPAN class=rem&gt;// Initialize the transport connection based on whether the Server is using Named Pipes or TCP.&lt;/SPAN&gt;
&lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( namePipeOrSocket == FcgiConfigProtocolNamedPipe )
{
        pTransport = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; TRANSPORT_NAMEDPIPE();
}
&lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
{
        pTransport = &lt;SPAN class=kwrd&gt;new&lt;/SPAN&gt; TRANSPORT_TCP();
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt;: 

        TRANSPORT()
        {}
        ~TRANSPORT()
        {} 

        HRESULT Send( PBYTE pBuffer, DWORD dwSize)
        {
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; SendReceive( TRUE, pBuffer, dwSize );
        }
        HRESULT Receive( PBYTE pBuffer, DWORD dwSize)
        {
            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; SendReceive( FALSE, pBuffer, dwSize );
        } 

    &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt;: 

        &lt;SPAN class=kwrd&gt;virtual&lt;/SPAN&gt; HRESULT SendReceive( &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; fSend, PBYTE pBuffer, DWORD dwSize ) = 0;
}; &lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_NAMEDPIPE : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;

&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_TCP : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;}&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;.csharpcode {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	FONT-SIZE: small; COLOR: black; FONT-FAMILY: Consolas, "Courier New", Courier, Monospace; BACKGROUND-COLOR: #ffffff
}
.csharpcode PRE {
	MARGIN: 0em
}
.csharpcode .rem {
	COLOR: #008000
}
.csharpcode .kwrd {
	COLOR: #0000ff
}
.csharpcode .str {
	COLOR: #006080
}
.csharpcode .op {
	COLOR: #0000c0
}
.csharpcode .preproc {
	COLOR: #cc6633
}
.csharpcode .asp {
	BACKGROUND-COLOR: #ffff00
}
.csharpcode .html {
	COLOR: #800000
}
.csharpcode .attr {
	COLOR: #ff0000
}
.csharpcode .alt {
	MARGIN: 0em; WIDTH: 100%; BACKGROUND-COLOR: #f4f4f4
}
.csharpcode .lnum {
	COLOR: #606060
}
&lt;/STYLE&gt;
&lt;PRE class=csharpcode&gt;&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_NAMEDPIPE : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt;: 

        TRANSPORT_NAMEDPIPE()
        {}
        ~TRANSPORT_NAMEDPIPE()
        {}
    &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt;:            

        HRESULT SendReceive( &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; fSend, PBYTE pBuffer, DWORD dwSize )
        {
            BOOL fRet  = FALSE;
            DWORD dwLastError = 0;
            DWORD nNumberOfBytesRead = 0; 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( fSend == TRUE )
            {        
                fRet = WriteFile( hStdin, pBuffer, dwSize, &amp;amp;nNumberOfBytesRead, NULL );
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
            {
                fRet = ReadFile( hStdin, pBuffer, dwSize, &amp;amp;nNumberOfBytesRead, NULL );
            } 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;(!fRet)
            {
                dwLastError = GetLastError();
            } 

            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; HRESULT_FROM_WIN32( dwLastError );
        }
}; 

&lt;SPAN class=kwrd&gt;class&lt;/SPAN&gt; TRANSPORT_TCP : &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt; TRANSPORT
{
    &lt;SPAN class=kwrd&gt;public&lt;/SPAN&gt;: 

        TRANSPORT_TCP()
        {}
        ~TRANSPORT_TCP()
        {} 

    &lt;SPAN class=kwrd&gt;protected&lt;/SPAN&gt;: 

        HRESULT SendReceive( &lt;SPAN class=kwrd&gt;bool&lt;/SPAN&gt; fSend, PBYTE pBuffer, DWORD dwSize )
        {
            &lt;SPAN class=kwrd&gt;int&lt;/SPAN&gt; iRet = 0;
            WSABUF winsockBuffer;
            DWORD   dwBytesTransferred  = 0;
            DWORD   dwFlags             = 0;
            DWORD   dwLastError            = 0; 

            winsockBuffer.len = dwSize;
            winsockBuffer.buf = (&lt;SPAN class=kwrd&gt;char&lt;/SPAN&gt; *)pBuffer; 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( fSend == TRUE )
            {
                iRet = WSASend( acceptSocket, &amp;amp;winsockBuffer, 1, &amp;amp;dwBytesTransferred, 0, NULL, NULL ); 
            }
            &lt;SPAN class=kwrd&gt;else&lt;/SPAN&gt;
            {
                iRet = WSARecv( acceptSocket, &amp;amp;winsockBuffer, 1, &amp;amp;dwBytesTransferred, &amp;amp;dwFlags, NULL, NULL );
            } 

            &lt;SPAN class=kwrd&gt;if&lt;/SPAN&gt;( SOCKET_ERROR == iRet )
            {
                dwLastError = WSAGetLastError();
            } 

            &lt;SPAN class=kwrd&gt;return&lt;/SPAN&gt; HRESULT_FROM_WIN32( dwLastError );
        }
};&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;&lt;/PRE&gt;
&lt;P&gt;A while ago, Rick who was the developer of the FastCGI core module, published a &lt;A class="" href="http://blogs.iis.net/rickjames/archive/2007/02/04/fake-fastcgi-web-server.aspx" mce_href="http://blogs.iis.net/rickjames/archive/2007/02/04/fake-fastcgi-web-server.aspx"&gt;fake fastcgi server&lt;/A&gt;&amp;nbsp;that works only over Named Pipes. To quickly see the working of this client application, you can run it with the fake server as below. The &lt;FONT color=#ff0000&gt;highlighted&lt;/FONT&gt; messages are returned by the client application TestClient.exe. 
&lt;P&gt;D:\fake&amp;gt;fakefcgi.exe d:\php\hello.php TestClient.exe &lt;BR&gt;Fake FastCGI web server &lt;BR&gt;FCGI_PARAMS sent &lt;BR&gt;FCGI_STDIN sent &lt;BR&gt;Launching receive loop &lt;BR&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Obtained FCGI_BEGIN_REQUEST message from Server &lt;BR&gt;&lt;/FONT&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Obtained FCGI_PARAMS from Server &lt;BR&gt;&lt;/FONT&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Obtained FCGI_STDIN from Server &lt;BR&gt;&lt;/FONT&gt;FCGI_STDOUT: &lt;FONT color=#ff0000&gt;FCGIClient : Sending FCGI_END_REQUEST to Server &lt;BR&gt;&lt;/FONT&gt;FCGI_END_REQUEST received &lt;BR&gt;killing app &lt;BR&gt;FastCGI process exited with 0 &lt;/P&gt;&lt;img src="http://blogs.iis.net/aggbug.aspx?PostID=2853176" width="1" height="1"&gt;</description><category domain="http://blogs.iis.net/yaminij/archive/tags/FastCGI/default.aspx">FastCGI</category><category domain="http://blogs.iis.net/yaminij/archive/tags/FastCGI+Client/default.aspx">FastCGI Client</category></item></channel></rss>