tag:blogger.com,1999:blog-358149412024-02-03T01:37:58.579-08:00David WangDavid Wang on IIS, ISAPI, Virtual Server, and whatever else I fancy...David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.comBlogger28125tag:blogger.com,1999:blog-35814941.post-88717511825484154962007-03-28T19:09:00.000-07:002007-03-28T19:35:35.635-07:00QA - Popular IIS7 Concepts<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Got another dumb question that I'm just struggling with.</P><P>What is meant by distributed configuration in IIS 7.0?</P><P>My guess (which I hate guessing) is that they are talking about the applicationHost.config file and web.config file(s). Would they also be talking about the ability to extend the schema?</P></span><br /><H3>Answer:</H3><P>I suggest first reading <A href="http://blogs.msdn.com/david.wang/archive/2006/05/09/Thoughts-on-Delegating-IIS-Configuration-and-Administration.aspx">this blog entry</A> on distributed configuration.</P><P>"Distributed Configuration" refers to unified configuration hierarchy merged from multiple sources (i.e. files in arbitrary directories). Pragmatic way to think about it involves applicationHost.config and web.config file(s) and how values contained in them are merged into an unambiguous and effective result for every possible URL. It is analogous to "distributed NTFS ACLs", where every file resource either inherits from its containing directory or has its own overrides, and when a CreateFile() call accesses the file, an effective access check is verified.</P><P>Ability to extend the schema would be called "Extensible Configuration". Just as IIS7 can be viewed as Microsoft providing 40+ modules to provide IIS6-level behavior on top of the new Integrated Pipeline, the IIS7 configuration system can be viewed as Microsoft shipping new/existing ConfigSectionHandlers to provide a web.config-like user experience on top of the new extensible configuration system.</P><P>A related topic - "Delegatable Administration" refers to multiple users able to administer their own website; which basically piggybacks on "Distributed Configuration" and "filesystem ACLs" to determine who can configure what and where, and "Integrated Pipeline" to control what actually executes for a given configuration.</P><br /><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com6tag:blogger.com,1999:blog-35814941.post-68385570063320343492007-03-07T02:52:00.000-08:002007-03-07T03:14:40.962-08:00HOWTO - Configure Orphaning on IIS6<H3>Question:</H3><span style="font-family:Courier new;color:#008000"><P>Hi. We are getting an error on the production server: A process serving application pool (pool name) was orphaned, but the specified orphan action (some action) could not be executed.</P><P>I remember someone added something to get a memory dump on application hangs there, but the file in (some action) is no longer there. How do I remove the action associated with it?</P></span><H3>Answer:</H3><P>Why, you simply remove that something that someone added which is no longer there, of course... :-P</P><P>Joking aside, the relevant metabase properties in your situation are:</P><UL><LI><A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/c0295a5b-4d6a-44e8-80b0-5928b1000384.mspx?mfr=true">OrphanActionEXE</A> - Command to run on orphaning<LI><A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/0d7ce45b-d1f8-400c-ac2d-81ba6319d500.mspx?mfr=true">OrphanActionParams</A> - Parameters to the orphan action<LI><A href="http://ms.helifan.net/technet/prodtechnol/WindowsServer2003/Library/IIS/79a1ad0b-cf56-4c87-ad75-3482ba1983eb.mspx?mfr=true">OrphanWorkerProcess</A> - Whether to orphan a worker process instead of recycling it</UL><P>How to find all this? Search with key terms like:</P><CODE>OrphanWorkerProcess site:microsoft.com</CODE><P>At this point, you have two basic choices to address the error:</P><OL><LI>Turn off Orphaning. This stops IIS from orphaning, which also prevents it from running the failing action<LI>Delete the OrphanActionEXE and OrphanActionParams properties. IIS continues to orphan worker processes but stops running the custom action</OL><P>Personally, I recommend #1 because Orphaning helps debugging when monitored... and hopefully you find the issues in test environments and do not intend to debug production servers</P><P>Now, suppose you want to delete the above Orphaning properties. How to find where they are set, what their current values are, and how to delete them? Use your friend <A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/d3df4bc9-0954-459a-b5e6-7a8bc462960c.mspx?mfr=true">ADSUTIL.VBS</A>. For example, the following illustrate sample management of worker process Orphaning.</P><PRE>PUSHD %SYSTEMDRIVE%\Inetpub\Adminscripts<br /><br />REM Identify all AppPools that set OrphanWorkerProcess<br />CSCRIPT ADSUTIL.VBS FIND OrphanWorkerProcess<br /><br />REM Retrieve the value of OrphanWorkerProcess at the global level<br />CSCRIPT ADSUTIL.VBS GET W3SVC/AppPools/OrphanWorkerProcess<br /><br />REM Delete the OrphanWorkerProcess property for the DefaultAppPool<br />CSCRIPT ADSUTIL.VBS DELETE W3SVC/AppPools/DefaultAppPool/OrphanWorkerProcess<br />POPD</PRE><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com6tag:blogger.com,1999:blog-35814941.post-5511644995808773712007-01-29T16:42:00.000-08:002007-01-29T16:48:23.048-08:00HOWTO: POST Resources to IIS<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>i'm working on a piece that requires companies to be able to POST data to one another's web sites using just the URL without page name (i.e. http://doc_uploads.partnetsite.com). there's also no need for any kind of web interface at either end, so i can't expect to grab the data from a form field and save to disk. simply put, using an application like CURL, i should be able to execute a command that says "post myFile.txt to http://doc_uploads.partnersite.com". </P><P>i need to figure out how to configure doc_uploads.mysite.com to listen for POST commands and start up an application to capture the POST data and save to disk.</P><P>i've seen a few articles on how to use microsoft's posting acceptor to do file uploads, but this requires having the user fill in fields on a page which i can't ask the sender to do.</P><P>anybody have any idea how to pull this off? i thought i knew IIS pretty well, but this one has me totally stumped.</P></span><H3>Answer:</H3><P>I can think of a few ways to do what you are asking on IIS, and each has its benefits and drawbacks. In no particular order:</P><UL><LI>Use IIsWebFile to configure a specific URL's Default Document to be the POST acceptor.<LI>Use ISAPI Filter to rewrite specific incoming URL without page name to URL with the POST acceptor as the page name<LI>Enable and use WebDAV PUT</UL><P>Whichever is "better" depends on which benefit(s)/drawback(s) you require. The benefits and drawbacks of each approach are as follows, in no particular order.</P><H4>DefaultDocument/IIsWebFile</H4><P>This solution is simply IIS configuration of the POST acceptor code. It requires IIS6 on Windows Server 2003, and the POST request URL <EM>must</EM> end with a backslash to invoke the Default Document without needing 302 courtesy redirection for POST support from the client (i.e. client sends POST to <CODE>http://doc_uploads.partnetsite.com/</CODE>).</P><H4>ISAPI Filter</H4><P>The ISAPI Filter solution requires writing and maintaining C code for the ISAPI Filter, code for the POST acceptor, and IIS configuration for both the ISAPI Filter and POST acceptor code. It works on any IIS version and there are no requirements on the format of the POST request URL.</P><H4>WebDAV</H4><P>WebDAV is purely IIS configuration - no POST acceptor nor C code required. It works on all IIS versions that support WebDAV (pretty much all currently supported IIS versions except the latest IIS7 release, but that should be fixed soon), and the request must look like <CODE>PUT http://doc_uploads.partnetsite.com/myFile.txt</CODE> and myFile.txt will be available for retrieval by anyone via <CODE>GET http://doc_uploads.partnetsite.com/myFile.txt</CODE> UNLESS you control all applications on IIS from inadvertently serving that resource via some mechanism (NTFS ACLs, IIS Access Permissions, etc).<P>i.e. once you PUT a file to the web server, it can be retrieved via GET. This is different from a POST acceptor which can be configured to store files outside the URL namespace to avoid inadvertent web-based access of those uploaded resources.</P><H4>Conclusion</H4><P>I have only provided the categories of solutions possible - the specific solution for your situation requires more details about your requirements. You do not need to worry about user interactivity, FORM fields, grabbing data, Posting Acceptor, etc - all those tasks can be automated. There are many ways to "post myFile.txt to http://doc_uploads.partnersite.com", and you have only scratched the surface of your requirements...</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com18tag:blogger.com,1999:blog-35814941.post-69036636999125615962007-01-12T15:35:00.000-08:002007-01-12T15:58:17.431-08:00Why IIS can lose configuration changes on server reboot<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>We are running IIS 6 on Windows 2003. Our public website is configured to to allow anonymous access using the default IUSR_<machinename> account.</P><P>Everything works just like it is supposed to until the server is rebooted. After a reboot, our public website challenges users to provide credentials. To fix this, we go into IIS Directory Security and re-enter the anonymous access account password to the same password that is in Active Directory. Then, everything works again.</P><P>What is going wrong that causes IIS to lose the anonymous password when the server reboots? Is there any way to fix this problem so that IIS will remember the password?</P></span><H3>Answer:</H3><P>By default, IIS remembers configuration changes, such as altering the anonymous user password, unless you terminate IIS before it persists that change to disk. IIS6 runtime configuration is hosted by the IISADMIN service inside the inetinfo.exe process.</P><P>So, the real question is whether something:<P><OL><LI>Killed IISADMIN service on the reboot, before it persisted the change to disk<LI>Or changed the anonymous user password to an invalid value on the server restart.</OL></P><P>To verify what is going awry:</P><OL><LI>Enter the password such that anonymous access works on IIS<LI>Open the IIS Manager UI, Right click on the Computer Name, select "All Tasks", and choose "Save Configuration to Disk". This forces IIS to persist the password to disk.<LI>Go ahead and reboot the server as you normally do</OL><P>If anonymous access works after the reboot, then your problem was that the reboot was killing IIS prior to it persisting the encryptped password to disk. You intentionally persisted the change to disk from within the UI, thus breaking the cycle.</P><P>If anonymous access still fails, then your problem is that something outside of IIS runs during the reboot/restart process with administrative privileges and changes AT LEAST the anonymous user password in IIS to an incorrect value. You will have to figure out the identity of that arbitrary something and correct it - it is running with Administrative privileges and may be doing other inappropriate things.</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com4tag:blogger.com,1999:blog-35814941.post-8287016985791662192006-12-27T00:05:00.000-08:002006-12-26T23:37:47.841-08:00QA: IIS and Environment Variable Updates<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Hi,</P><P>I want to store uploaded file in a directory C:\Inetpub\Users\Upload. c:\Inetpub is the home directory I have set, so it is pretty much HOME\Users\Upload.</P><P>However, when I use following commands, the file is stored in c:\Users\Uoload.</P><PRE>$upload_dir = "$HOME/Users/Upload";<br />$upload_filename = "$upload_dir/$filename";<br /><br />if (! open UPLOADFILE, ">$upload_filename")<br />{<br /> print "error-$!<br>\n";<br />}<br /><br />binmode UPLOADFILE;<br /><br />while ( <$upload_filehandle> )<br />{<br /> print UPLOADFILE;<br />}<br /><br />close UPLOADFILE;</PRE><P>My question is what am I doing wrong, and is there a predefined variable for home directory ?</P></span><H3>Answer:</H3><P>Sounds like the "HOME" environment variable is not set.</P><P>If you just added the environment variable, you need to reboot Windows for it to take effect for an NT service like IIS. This is because NT services like IIS inherit their environment from services.exe, which does not get updated when you change system environment until you reboot.</P><P>If you did not just add the HOME environment variable -- then the problem is that the HOME variable does not exist on Windows. The Windows environment variables most similar in function to the *nix HOME variable are HOMEDRIVE and HOMEPATH.</P><P>There is a generic way to "update" the environment variables of an NT service WITHOUT rebooting Windows, but it is not guaranteed to work for all services. You can edit:</P><CODE>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\<ServiceShortName>\Parameters\Environment</CODE> <P>and add a String Registry value with a name/value same as the environment variable name/value, i.e. with the command:</P><CODE>REG.EXE add "HKLM\SYSTEM\CurrentControlSet\Services\IISADMIN\Parameters\Environment" /v HOME /t REG_SZ /d "C:\Inetpub" /f</CODE><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com30tag:blogger.com,1999:blog-35814941.post-26469641348862499112006-12-26T01:02:00.000-08:002006-12-26T10:15:19.516-08:00QA - Setting up IIS Virtual Host<h3>Question:</h3><span style="font-family:courier new;color:#008000"><pre>I am a web developer and I would like to setup IIS to do this:<br />1. My physical structure:<br /> d:/www/company1<br /> d:/www/company2<br /> ...<br /> d:/www/companyN<br /> Each folder is a website for that company<br />2. On my local system, I would like to access to a company's website as:<br /> http://company1/index.php<br /> http://company2/index.php<br /><br />Before using IIS, I was using Apache and we can setup httpd.conf as:<br /> <VirtualHost 127.0.0.1><br /> DocumentRoot "d:/www/company1"<br /> ServerName company1<br /> </VirtualHost><br /> <VirtualHost 127.0.0.1><br /> DocumentRoot "d:/www/company2"<br /> ServerName company2<br /> </VirtualHost><br /><br />and define domain company1, company2 in<br />c:/windows/system32/drivers/etc/hosts as:<br /> 127.0.0.1 company1<br /> 127.0.0.1 company2<br /><br />How do I setup this feature in IIS. Thanks very much for your help.</pre></span><br /><h3>Answer:</h3><P>In general, one can set up similar web server configuration on IIS and Apache, given comparable customization module(s) and configuration. In this case, the desired configuration can be performed in a couple of ways using the scriptable administration interface of IIS.</P><P>With IIS6, there is a commandline tool, <A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/aee71684-36c0-40e1-b387-a19d2d0509f0.mspx?mfr=true">iisweb.vbs</A>, which uses the scriptable administration interface and illustrates how to perform and automate the task:</P><P><CODE>iisweb.vbs /create D:\www\company1 Company1 /d:company1</CODE></P><P>The same configuration can be set more manually on prior IIS versions with a more generic tool, <A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/d3df4bc9-0954-459a-b5e6-7a8bc462960c.mspx?mfr=true">adsutil.vbs</A>, located in %systemdrive%\inetpub\adminscripts. The following command sequence works on all IIS versions and is equivalent to what iisweb.vbs performs:</P><PRE>adsutil.vbs CREATE W3SVC/1000 IIsWebServer<br />adsutil.vbs SET W3SVC/1000/ServerBindings "127.0.0.1:80:company1"<br />adsutil.vbs CREATE W3SVC/1000/ROOT IIsWebVirtualDir<br />adsutil.vbs SET W3SVC/1000/ROOT/Path "D:\www\company1"</PRE><P>Note it is important to use a unique ID # for each website (i.e. I chose 1000) and the proper KeyType (case sensitive) for each configuration node needs to be provided on the CREATE - and iisweb.vbs takes care of that amongst other features and details.</P><P>You can use <A href="http://blogs.msdn.com/david.wang/archive/2005/07/13/HOWTO_Enumerate_IIS_Website_Configuration.aspx">this script</A> to check your website configuration.</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com6tag:blogger.com,1999:blog-35814941.post-21718814500121546812006-12-21T17:41:00.000-08:002006-12-21T18:15:14.882-08:00QA - COM Initialization and IIS<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Sometimes people (my customers) have a problem with COM Initialization in an ISAPI application. It seems sometimes they do not have to call CoInitializeEx and sometimes they do. Since CoInitializeEx "must" be called prior to using COM and sometimes the isapi works without calling this function, it seems IIS or something else has already called this function.<P><P>Can someone tell me, what is IIS's behavior in regard to COM initialization?</P></span><H3>Answer:</H3><P>IIS's behavior in regards to COM initialization is clean - it simply does nothing.</P><P>Thus, the behavior you describe sounds like a common bug with some ISAPI DLL running on IIS - calling <A href="http://msdn2.microsoft.com/en-us/library/ms886306.aspx">CoInitializeEx()</A> on threads not owned by the ISAPI. Since IIS reuses threads from its thread pool to call into ISAPI, the following sequence can occur and cause what you observe:</P><OL><LI>IIS does not call CoInitializeEx() on any of the threads in its thread pool.<LI>IIS uses thread 1 from its thread pool to call the ISAPI entrypoint.<LI>In the entrypoint, ISAPI calls CoInitializeEx() on thread 1 but does not call CoUninitialize() prior to exiting the entrypoint and returning control to IIS.<P><span style="color:#ff0000">thread 1 has now called CoInitializeEx() once</span>.</P><LI>IIS later uses thread 2 from its thread pool to call the ISAPI entrypoint. Since this thread has never called CoInitializeEx(), <span style="color:#ff0000">thread 2 has called CoInitializeEx() once</span>.<LI>IIS later re-uses thread 1 from its thread pool to call the ISAPI entrypoint.<P><span style="color:#ff0000">thread 1 has now called CoInitializeEx() twice</span>.</P></OL><P>At this point, this ISAPI has seriously confused things. There is no way for it to call the correct number of <A href="http://msdn2.microsoft.com/en-us/library/ms886943.aspx">CoUninitialize()</A> on all the IIS threads (suppose the ISAPI entrypoint is never invoked again by IIS - no chance for it to call CoUninitialize() correct number of times, and no way for new user of the same thread to know how many times to call CoUninitialize()). It has tainted the thread pool shared by all other ISAPIs. All sorts of badness can commence at this point.</P><P>The simple rule of thumb: do not call CoInitialize()/CoUninitialize() on a thread which you do not own.</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com5tag:blogger.com,1999:blog-35814941.post-26593566025680083062006-12-20T00:52:00.000-08:002006-12-20T01:09:48.519-08:00QA - IIS6 Debugging with NTSD, Setup<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Using some very helpful guidence from this forum, I made my first attempt at trying to catch a problem I see perioidcally in my ISAPI module.</P><P>I installed the latest NTSD.EXE and supporting DLL's on the server of interest and loaded them by adding the following registry entry and restarting IIS:</P><CODE>REG ADD "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe" /v Debugger /d "C:\DEBUG\NTSD.EXE -g -G" /t REG_SZ /f</CODE><P>Note I wasn't attempting at this point to monitor remotely as I have RDO access to this server.</P><P>NTSD loaded as expected as a process along with W3WP.EXE (as shown in Task Manager). My ISAPI app was exposed to the load overnight and when the morning heavy loads hit, the event log posted the two events shown below. At that point in time, IIS stopped processing requests (although it still seemed to be running). So we removed this server from the WLBS array and began to look for some signs of the debugger's dump.</P><P>The problem is I can't find any results from the debugging process. Now this might have been as simple as not having a client running on that server which is monitoring the debug process. But I figured NTSD would throw up some sort of message box indicating a dump was occuring and where. But we didn't see anything like that.</P><P>I'm likely missing something obvious in this overall process -- can anyone see what I'm doing wrong?</P> <PRE>Event Type: Warning<br />Event Source: W3SVC<br />Event Category: None<br />Event ID: 1010<br />Date: 12/15/2006<br />Time: 3:01:16 PM<br />User: N/A<br />Computer: DAZLOADBAL3<br />Description:<br />A process serving application pool 'DefaultAppPool' failed to respond to a ping.<br />The process id was '3800'.<br /><br />Event Type: Information<br />Event Source: W3SVC<br />Event Category: None<br />Event ID: 1082<br />Date: 12/15/2006<br />Time: 3:01:16 PM<br />User: N/A<br />Computer: DAZLOADBAL3<br />Description:<br />A worker process with pid '3800' that serves application pool<br />'DefaultAppPool' has been determined to be unhealthy (see previous event log<br />message), but because a debugger is attached to it, the World Wide Web<br />Publishing Service will ignore the error.</PRE></span><H3>Answer:</H3><P>Ah, this attempt is correct except for one tiny detail - how to manipulate the debugger when it is auto-attached to an NT Service via Image File Execution Options. Unfortunately, the current situation is unrecoverable, so you will have to start over and account for the missing but critical detail.</P><P>Debuggers like CDB, NTSD, and WINDBG from the <A href="http://www.microsoft.com/whdc/devtools/debugging/default.mspx">Microsoft Debugging Toolkit</A> are general purpose debuggers which expect interactive command input to perform tasks like taking a crash dump, disassemble instructions, examine memory, etc. On the other hand, JIT Debuggers like OCA and Dr. Watson are specialized debuggers which automatically perform certain pre-programmed tasks upon triggering.</P><H4>Common Ways to Manipulate a Debugger</H4><P>Basically, the question is "now that I have a debugger attached to the process of interest, how do I manipulate the debugger to do what I want?"</P><P>The following are some common ways to manipulate a NTSD debugger:</P><UL><LI>Make the debugger command window show up on a WinStation which you can access by launching the debugger interactively as the logged-on user<LI>Make the debugger command window show up on a WinStation which you can access by making the NT Service interactive with the Console desktop (WinStation#0)<LI>Make the debugger into a "conduit" for an eventual debugging client by piping usermode output into a kernel mode debugger with -d<LI>Make the debugger into a "conduit" for an eventual debugging client by opening a TCP/IP port or NamedPipe with -server</UL><P>The Astute reader should note that there are other debugging methods, such as JIT Debugger, Kernel Debugger, etc... but they are not really relevant nor useful here, so I will skip them for the sake of logical clarity.</P><P>Yes, it may seem like a large number of choices for something as simple as "how do I manipulate the debugger", but rest assured, they exist because at one point or another some Microsoft product team needed the feature to debug some aspect of Windows. One may never need to use all of the options, but the utility of having the right option for the right situation means everything in a debugger. Remember, this is the same Debugging Toolkit used within Microsoft to debug native code, so it is plenty powerful when properly wielded.</P><H4>The Issue, Reformulated</H4><P>Now that I have enumerated some options, the issue should hopefully make more sense.</P><UL><LI>The NTSD debugger is configured to auto-attach via Image File Execution Options to the W3WP.EXE process launched by an NT Service, which does not interact with the Console desktop by default.<LI>An unhandled exception occurred in the W3WP.EXE process, is caught by the attached NTSD debugger (also non-interactive with the Console desktop), and this halts all code execution within the W3WP.EXE process.<LI>The NTSD debugger is awaiting commands following the caught exception, but you cannot input them into any debugger commandline window since it is not interacting with the Console Desktop, nor are there any queued commands to the debugger.<LI>And since a Windows Process only has one Debugger port, you cannot attach a second debugger via any other method to regain control of the debugger/process...<LI>Thus, the current debugging session is inaccessible and dead.<LI>To add insult to injury - when W3SVC wants to recycle and/or terminate a monitored W3WP, and it detects that a debugger is already attached onto that W3WP, it will simply skip over taking action against it (i.e. the second event log entry mentioned above). So, not only is the W3WP.EXE halted from executing code and is inaccessible for debugging, IIS also skips cleaning it up.<P>This is ok, though, because the feature was added during IIS6 development as a fail-safe against losing W3WP.EXE for investigations. Yes, the behavior looks silly when misconfigured, but the benefits outweigh the occassional mishap.</UL><H4>Corrective Actions</H4><P>How to address this issue? Well, one can reconfigure the system to support debugging in any of the above ways that I specied earlier. This is how to do each:</P><UL><LI>Make the debugger command window show up on a WinStation which you can access by launching the debugger interactively as the logged-on user<P>With the target W3WP.EXE already running, run: <CODE>C:\DEBUG\NTSD -g -G -p {PID of W3WP.EXE}</CODE> If there is only one W3WP.EXE, you can use <CODE>-pn w3wp.exe</CODE> to select the unambiguous process name "w3wp.exe" to attach to.</P><LI>Make the debugger command window show up on a WinStation which you can access by making the NT Service interactive with the Console desktop (WinStation#0)<P><PRE>REG ADD "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe" /v Debugger /d "C:\DEBUG\NTSD.EXE -g -G" /t REG_SZ /f<br />SC CONFIG IISADMIN type= share type= interact<br />SC CONFIG W3SVC type= own type= interact<br />NET STOP /y IISADMIN<br />NET START W3SVC</PRE></P><P>Be careful with the SC commands - the exact parameters and whitespacing are (unfortunately) important. In particular, neither <CODE>type=interact</CODE>, nor <CODE>type =interact</CODE>, nor just <CODE>type= interact</CODE> work.</P><P>The NTSD window now automatically shows up in WinStation#0 (the local console) for each new W3WP.EXE.</P><LI>Make the debugger into a "conduit" for an eventual debugging client by piping usermode output into a kernel mode debugger with -d<P><CODE>REG ADD "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe" /v Debugger /d "C:\DEBUG\NTSD.EXE -g -G <span style="color:ff0000">-d</span>" /t REG_SZ /f</CODE><LI>Make the debugger into a "conduit" for an eventual debugging client by opening a TCP/IP port or NamedPipe with -server<P><UL><LI><CODE>REG ADD "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe" /v Debugger /d "C:\DEBUG\NTSD.EXE <span style="color:ff0000">-server tcp:port=%d</span> -g -G" /t REG_SZ /f</CODE><LI><CODE>REG ADD "HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options\w3wp.exe" /v Debugger /d "C:\DEBUG\NTSD.EXE <span style="color:ff0000">-server npipe:pipe=w3wp%d</span> -g -G" /t REG_SZ /f</CODE></UL></P></UL><H4>Conclusion</H4><P>Which one is "best"? They are all "best" for certain situations and painfully inadequate for the wrong situations... so "best" is really subjective to the debugging task at hand. I recommend evaluating the needs of the debugging situation and then selecting the proper debugging approach that you are comfortable with. While the above list is not conclusive, it should suffice for most debugging situations.</P><P>Personally, I favor the -server TCP/IP accessed via a non-console WinStation on the server because it alters no service/server configuration. Yes, the commandline syntax can be complicated, but that's what batch scripting is for. :-)</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com4tag:blogger.com,1999:blog-35814941.post-80381864721562541952006-12-07T02:51:00.000-08:002006-12-07T03:23:48.378-08:00QA - On Process, Threading, and DLL Lifetimes<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>In a thread "Critical Section shared between ISAPI", David Wang promised a "blog entry about how ISAPI/CGI/ASP.Net binaries load in various IIS versions and configurations".</P><P>A serious background about process/thread issues in ISAPI and extension DLL loading/unloading sequence would be very much welcome, because 1) the topic was never covered thoroughly in official docs, 2) things changed in IIS6.</P><P>Here are few questions that come to my mind.</P><P>* Knowing if my extension will be loaded into one or more process spaces is crucial, because DLL's data will either be shared by instances, or exist as separate copies and this, of course, leads to different synchronization strategy. According to David, I can enforce IIS to keep my extension within one w3wp.exe process, provided I do not use Web Garden. Is this 100% guaranteed? I suspect it is not true on error or overload circumstances.</P><P>Let's assume 1st instance of worker process is not responding to ping. Will IIS try politely to terminate 1st instance BEFORE launching the 2nd one? From ISS point of view, 1st instance is inactive and useless, but actually it may still work and use shared resource.</P><P>* Is there any occasion for IIS to SUSPEND an extension's thread? (I mean - a thread of one instance, without suspending a thread of another instance). I hope not, because this would play havoc with any concurrency efforts!</P><P>* As Ian suggested in the same thread, mutex may solve the problem in case we are afraid of cross-process interaction. Fine, but sometimes we must have a singleton for other reasons than synchronization. My extension, for example, may load about 100-300MB in response to single request. I do not want this stuff to be loaded into memory twice. I need a single process instance - can I be sure?</P><P>* IIS5 docs claim that GetExtensionVersion and TerminateExtension functions get called once per DLL's lifetime in IIS space. Was it true? Is this still true in IIS6?</P><P>* Is it reasonable and save to spawn a new thread from within an extension? Is it save to leave "something" running between subsequent HTTPExtensionProc calls? (what I did is monitoring/logging thread that performs every 5 seconds or so) How about a timer?</P><P>* What is the relation of IIS6 "Application Pool" to Windows API "Thread Pool"?</P></span><H3>Answer:</H3><P>Excellent questions... Sorry I have not yet gotten around to writing that blog entry yet... I have many, many others yet to write. They are all in various stages of construction. Maybe during the upcoming holiday downtime I will find some time to wrap some of them up. But in the meantime, let me attend to your direct questions...</P><CODE>According to David, I can enforce IIS to keep my extension within one w3wp.exe process, provided I do not use Web Garden. Is this 100% guaranteed?</CODE><P>That conclusion is not 100% correct because the devil's in the details. I did not mention the details earlier because the simpler explanation of Web Garden suffices for most people. And... people's eyes usually glaze over when I start on the details, so I try to withhold them unless someone asks for them. ;-)</P><P>Now, IIS does NOT have a feature to enforce a "singleton w3wp.exe process loads a given ISAPI Extension DLL" no matter what. However, IIS does have features which when properly configured CAN result in a "singleton w3wp.exe process loading a given ISAPI Extension DLL".</P><P>Thus, if you can control IIS Application Pool and ISAPI Execution configuration for the entire server, you can create an environment of a "singleton w3wp.exe process loading a given ISAPI Extension DLL". If you cannot control those configurations for the entire IIS server, then you MUST rely on other mechanisms to ensure your desired behavior.</P><P>The following configuration options must be controlled on the entire server to create your desired behavior:</P><UL><LI><A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/ec26f50e-dcc9-4439-acc1-d7d8cff8e0ee.mspx?mfr=true">DisallowOverlappingRotation</A> - Ensure the replacement w3wp.exe process comes up AFTER the old w3wp.exe terminates.<LI><A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/c63664f5-5180-4ca7-86e4-089baca0405c.mspx?mfr=true">MaxProcesses</A> - Maximum number of w3wp.exe to concurrently service a given Application Pool. Web Garden has a value greater than 1.<LI><A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/12510852-9168-44f8-ad0a-e455ff156e35.mspx?mfr=true">AppPoolId</A> - The Application Pool which services a given URL namespace. Since Application Pools partition the URL namespace and ISAPI Extensions load and execute inside some partition of the URL namespace serviced by IIS, controlling the Application Pool directly affects the number of times an ISAPI Extension DLL image loads.<LI>[Optional]<A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/45e717d0-20f6-459c-9183-cf6019f2edab.mspx?mfr=true">ScriptMaps</A> - Application Mappings determine which ISAPI Extension DLL or CGI EXE execute for any resource types. This configuration is at a per-URL level.<LI>The URL itself to invoke the ISAPI Extension DLL.</UL><P>What you must ensure is that the URL used to invoke your ISAPI Extension DLL, and [optionally] any ScriptMap settings that map that ISAPI Extension DLL, all execute within one specific AppPoolId whose MaxProcesses value is 1 and DisallowOverlappingRotation is TRUE.</P><P>Now, I think I shall pause for a moment for the full meaning of the prior sentence to sink in... :-) Yes, there are many possible solution configurations, but they all fit the above criteria.</P><P>Of course, if you CANNOT control those IIS configuration values for the entire server, then you CANNOT ensure "singleton w3wp.exe process loads a given ISAPI Extension DLL" and must use other mechanisms. The only alternative I can think of is to load your code into a separate Singleton process on the server and inter-process communicate between it and w3wp.exe.</P><CODE>Will IIS try politely to terminate 1st instance BEFORE launching the 2nd one? From ISS point of view, 1st instance is inactive and useless, but actually it may still work and use shared resource.</CODE><P>IIS behavior depends on the configuration of <A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/ec26f50e-dcc9-4439-acc1-d7d8cff8e0ee.mspx?mfr=true">DisallowOverlappingRotation</A>. If FALSE (default), then IIS will launch the 2nd one before terminating the 1st one. If TRUE, then IIS will launch the 2nd one after the 1st one terminates and stops using shared resources.</P><CODE>* Is there any occasion for IIS to SUSPEND an extension's thread?</CODE><P>No, IIS does not suspend an ISAPI Extension's threads during execution.</P><CODE>* IIS5 docs claim that GetExtensionVersion and TerminateExtension functions get called once per DLL's lifetime in IIS space. Was it true? Is this still true in IIS6?</CODE><P>Yes and Yes. IIS always calls GetExtensionVersion() right after it loads the ISAPI DLL into a given process's memory address space and TerminateExtension() before unloading the ISAPI DLL from memory. In addition, various IIS features affect when an ISAPI DLL is loaded and unloaded.</P><P>Unfortunately, most people do not understand when an ISAPI DLL loads/unloads and incorrectly assume IIS guarantees random behavior/properties such as the number of times or timing of when those entry points are invoked... thus leading to confusion between IIS versions. In reality, you just need to understand when and what causes IIS to load/unload an ISAPI DLL.</P><P>IIS loads ISAPI Extension DLLs on demand to handle any given request. IIS also caches (i.e. leaves the DLL loaded in memory) the ISAPI Extension DLLs between requests to improve performance. This <A href="http://blogs.msdn.com/david.wang/archive/2005/10/14/HOWTO_IIS_6_Request_Processing_Basics_Part_1.aspx">blog entry</A> details how IIS selects the handler for a given request, so you know how to trigger your ISAPI Extension DLL. And the "Cache ISAPI application" checkbox in the "App Mappings" tab controls whether IIS loads/unloads the ISAPI Extension DLL between every single request, or just load on the first request and unload when the process terminates.</P><CODE>* Is it reasonable and save to spawn a new thread from within an extension? Is it save to leave "something" running between subsequent HTTPExtensionProc calls? (what I did is monitoring/logging thread that performs every 5 seconds or so) How about a timer?</CODE><P>Whether the action is "Reasonable" depends more on the function and design of the ISAPI Extension DLL. IIS places no requirements one way or another.</P><P>As for safety - it is safe to spawn your own threads from within an ISAPI Extension - for example, ISAPI Extension using a Thread Pool to queue/process requests asynchronously does this, by design. What you need to ensure is that if those threads touch the ECB (or any other memory, for that matter), that the ECB is valid. For synchronous request, the ECB will not be valid in between HttpExtensionProc calls (its lifetime is tied to the HttpExtensionProc lifetime for that particular request). For asynchronous requests, ECB will stay valid until HSE_REQ_DONE_WITH_SESSION is called on that ECB.</P><CODE>* What is the relation of IIS6 "Application Pool" to Windows API "Thread Pool"?</CODE><P>No direct relation. IIS6 "Application Pool" merely groups process-oriented configuration to partitions of URL namespace. "Thread Pool" is a method of scheduling code execution amongst threads vying for CPU time-slices</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com2tag:blogger.com,1999:blog-35814941.post-67088181134105837312006-11-30T10:12:00.000-08:002006-11-30T10:58:02.811-08:00QA - Maximizing IIS6 Concurrent Connections<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Dear All,</P><P>We are using Win 2003 sp1 with IIS 6.0 installed Default website properties connection set to 30 sec Running IIS with ASP Files, all working good</P><P>The problem is: when we have 10,000 con current session on the server, the IIS Stop Responding on port 80 and the clients get error Connection TimeOut ,</P><P>Is there any IIS or Port 80 Limits</P><P>Any Advice will be appreciated ?</P><P>p.s</P><P>the server CPU and memory are very Low</P><P>Thanks</P></span><H3>Answer:</H3><P>The connection limit you observe comes from HTTP.SYS because each HTTP connection takes a small chunk of kernel NonPagedPool memory.</P><P>On 32bit Windows, this memory is FAR smaller than the amount of physical memory available, around 250MB, and it will usually run out long before available physical memory and cause symptoms that look like <A href="http://blogs.msdn.com/david.wang/archive/2005/09/21/HOWTO-Diagnose-IIS6-failing-to-accept-connections-due-to-Connections-Refused.aspx">this</A>... especially if you have long-lived concurrent connections.</P><P>Thus, to maximize the number of concurrent users to IIS6, you want to do all of the following:</P><UL><LI>Make the connections timeout faster (<A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/73566f83-c257-4941-8ed8-7ae45b2e7985.mspx?mfr=true">ConnectionTimeout</A> metabase property).<LI>Make the connections non-keepalive (<A href="http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/3cd7a3d4-1cf2-4c58-8d9d-18479b8df5f6.mspx?mfr=true">AllowKeepAlive</A> metabase property).<LI>Remove any of the following <A href="http://blogs.msdn.com/david.wang/archive/2006/04/12/HOWTO-Maximize-the-Number-of-Concurrent-Connections-to-IIS6.aspx<br />">artificial limits</A>.<P>But, remember that HTTP.SYS is still constrained by available NonPagedPool memory, so this change only helps if you had an artificially lower limit to begin with (i.e. on 32bit Windows, if MaxConnections was set to 5,000 for whatever reason, you can remove the artificially lower limit by changing it to 100,000, but you will never get to 100K).</P><LI>Move to a Windows OS with a Memory Manager that utilizes the Dynamic Memory model, such as Windows Server 2003 SP1 64bit or Windows Vista.<P>This memory model removes all the hard-coded and soft-coded limits on various memory pools of Windows, such as NonPagedPool, and allows them to dynamically grow and shrink according to utilization and up to all available physical memory. This means you can add more concurrent connections by simply adding more RAM.</UL><P>All of the above are EXACTLY what microsoft.com and msn.com does across all their servers that serve low-latency, high-volume traffic - such as their image servers that house static content shared across the entire web farm. At a massive scale, the speed gained from KeepAlive is not worth the concurrent users capacity lost by consuming kernel NonPagedPool memory, and they remove both artificial and soft-coded limits of NonPagedPool memory by using Windows Server 2003 SP1 64bit.</P><P>Good luck,</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com18tag:blogger.com,1999:blog-35814941.post-35420224041017255692006-11-20T13:15:00.000-08:002006-11-20T13:35:50.129-08:00QA - On Application Pool Time Limits<span style="font-family:courier new;color:#008000"><P>My ISAPI errors seem to be settling down a bit and I'm left with a periodic message like the one below. First, by "recycle" does this mean that IIS restarts automatically? It seems like that's what's happening.</P><P>Secondly, how and where does one set the processing time limit? Is this a relatively short time like seconds or hours?</P><P>Thirdly, what causes a worker process to exceed it's time limit.</P><P>And finally, how can I associate the process ID with a specific ISAPI module?</P><P>Lots of questions!! Sorry!</P><PRE>Event Type: Information<br />Event Source: W3SVC<br />Event Category: None<br />Event ID: 1074<br />Date: 11/20/2006<br />Time: 3:46:54 PM<br />User: N/A<br />Computer: DAZLOADBAL3<br />Description:<br />A worker process with process id of '2260' serving application pool <br />'DefaultAppPool' has requested a recycle because the worker process reached <br />its allowed processing time limit.<br /> <br />For more information, see Help and Support Center at <br />http://go.microsoft.com/fwlink/events.asp.</PRE></span><H3>Answer:</H3><P><br /><OL><LI>It depends on what you mean by "IIS". The event says that a worker process of a particular application pool is recycling. To me, IIS is not "any particular application pool or worker process" but rather "the service that maintains the activity and availability of all application pools (and subordinate worker processes)". Thus to me, this "recycle" does not mean that IIS is automatically restarting.<LI>Process recycling configuration is associated with an Application Pool - in this case, DefaultAppPool. "Processing Time Limit" is associated with the "Recycle worker processes (in minutes):" configuration option of the Application Pool. Its default value is 1740 (29 hours) and can be customized.<LI><P>You can view process recycling as either caused by unexpected error or by expected benign condition. By default, IIS only reports unexpected error-caused recycling to the event log. However, you are seeing an event for an usually benign recycling metric -- Processing Time Limit -- which basically happens X minutes after a request triggers the Application Pool to start, regardless if the worker process is healthy or not. These benign recycling events are normally not logged, so your server has non-standard configuration of the LogEventOnRecycle property.</P><P>In other words, suppose it is set to 5 minutes. It means that 5 minutes AFTER you have made a request to that application pool to spin up a w3wp.exe, the Process Time Limit will be reached and the w3wp.exe recycled. You should note the benign nature of this recycle metric - nothing is wrong; the Application Pool is just proactively recycling on its own. This is why this recycle metric does not log an event in default configuration.</P><P>Plus, if you make no subsequent requests to the application pool after the recycling, this recycling metric will not be in effect because no w3wp.exe of the application pool is running.</P><LI>Use the following command to determine which PID has the ISAPI DLL loaded: <CODE>tasklist /m <ISAPI_Module_Name.dll></CODE><P>Use the following command to determine which Application Pool the PID belongs to: <CODE>iisapp.vbs /p <PID></CODE><br /></OL><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com3tag:blogger.com,1999:blog-35814941.post-14276691075680120372006-11-20T04:38:00.000-08:002006-11-20T04:47:10.535-08:00QA - URL Authentication... or is it Authorization?<P>Authentication, Authorization... what's the difference? Actually, a whole lot, as you can read in the following...</P><H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>I need to authenticate users agains an Active Directory (or rather ADAM)...</P><P>I've red about a new feature in IIS 6.0: URL Authentication and I did manage to set-up a situation where users are authenticated by use of LDAP query: (&(objectCategory=user)(CN=*)))</P><P>But, now comes the stange part, only users logged-in on the server where IIS is configured are authenticated correctly. For example:</P><UL><LI>IIS/URL Authentication is configured at server Server1 to protect virtual directory /URLTest.<LI>When user 'admin' is logged in Server1, he is able to go to http://localhost/URLTest <LI>When user 'test' is logged in Server1, he is also able to go to the url above, <LI>When users 'admin' or 'test' are logged-in on another server, they are not able to navigate to Server1/URLTest because they cannot be authenticated... </UL><P>What is wrong?</P></span><H3>Answer:</H3><P>The problem is that "URL Authentication" does not exist.</P><P>The feature is actually called "URL Authorization". Authorization (i.e. what can a user do?) is totally different than Authentication (i.e. what user are you?)</P><P>"URL Authorization" takes effect AFTER Authentication completes, since you need to know WHO the user is before trying to determine WHAT the user is authorized to do. </P><P>Since you say you cannot authenticate to this server when logged into a remote machine, what you configured for "URL Authorization" is not involved at all. </P><P>Your problem has to do with why those users cannot authenticate from a remote machine. The best way is to look at the IIS web log entries for these remote access attempts to see what is wrong. I suggest reading this <A href="http://blogs.msdn.com/david.wang/archive/2005/12/31/HOWTO_Basics_of_IIS6_Troubleshooting.aspx">blog entry</A>.</P><P>//David </P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com1tag:blogger.com,1999:blog-35814941.post-91565268887464990482006-11-08T04:50:00.000-08:002006-11-08T05:05:31.399-08:00HOWTO - Update Applications under Debug on IIS 6<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Hi,</P><P>we are using a IIS 6.0 server as remote webserver for developing vstudio .NET applications. When debugging we always have to restart IIS (or recycle application pool), in order to overwrite the new compiled DLLs.</P><P>The DLL is locked by the w3wp.dll process and the dll therefore cannot be overwritten.</P><P>Is there any way to tell IIS (w3wp.dll) not the cache the dll or better free the dll directly after execution?</P></span><H3>Answer:</H3><P>Standard debugging procedures differ depending on the type of application.</P><H4>ISAPI Extension DLL</H4><P>You can uncheck the "Cache application files" option under the "App Mappings" tab of the application to force IIS to load/unload the ISAPI Extension DLL for every single request to that resource extension's handler. Be warned that this option is debug-only (do NOT uncheck this on production servers) and often exposes startup/shutdown bugs in your ISAPI Extension DLL.</P><H4>ISAPI Filter DLL</H4><P>You should simply recycle the Application Pool(s) which have loaded the Filter DLL. If it is a Global Filter, then you must recycle all Application Pools. If it is a Site Filter, then you must recycle all Application Pools used by applications of the Website which loads that Site Filter.</P><H4>ASP.Net httpModule and httpHandler</H4><P>You can dynamically change either the DLL in /bin or source code in global.asax or /App_Code, depending on how you configured the httpModule or httpHandler. No restart/recycle required.</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com4tag:blogger.com,1999:blog-35814941.post-3609826605193680542006-11-03T02:51:00.000-08:002006-11-03T03:04:48.597-08:00QA - Obscure Behavior simultaneously across Multiple Machines?<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>On our IIS 5 (w2k server etc) using perl 5, our bulletin board has suddenly stopped adding new files. After some testing, its fine updating existing ones, but seems unable to add new - writing them via code. Since I havne't changed anything in the code, is it possibly some obscure piece of system-wide policy has caused this?</P><P>The exact same symptoms are happening on another server, and the problem is not restricted to one folder either.</P></span><H3>Answer:</H3><P>Come now... baffling events can be viewed as logical events whose logic is not immediately clear to the observing party. It does not mean toss logic aside in favor of random fantasies. ;-) I mean, computers do not yet dream/fantasize... they are stubbornly logical and require strict instructions in the form of binary code.</P><P>Put another way (proof through contradiction) - suppose the issue is some obscure piece of system-wide policy - how likely is the same SYSTEM-WIDE policy simultaneously applied on two DIFFERENT servers and multiple folders?</P><P>Since you observe the same behavior from multiple servers, and it is highly unlikely for two random system-wide configuration changes to generate matching behaviors, I do not believe in merely blaming "obscurities in Windows". Instead, I would look for what resources are COMMON to both servers and look for limits in them - such as:</P><UL><LI>The Bulletin Board software itself<LI>Commonly shared UNC fileshares used by the BBS (Are you sure "adding new files to the BBS" actually creates files in the FileSystem? Having URLs do not mean there are real files because URLs are merely resource descriptors and not strictly mapped to filenames on a FileSystem)<LI>Commonly shared SQL database between the servers<LI>etc.</UL><P>I mean, here are some suggested thoughts:</P><UL><LI>Maybe the Bulletin Board software has a built-in limit on the number of posts for a given forum, so as soon as you reached it from one server, the other server will also fail for that forum<LI>Or the NTFS Disk Quota on a commonly shared UNC fileshare for a commonly shared access-user is reached by one server and seen from the other<LI>Or the number of rows in your SQL database table is capped and you cannot add any more files/posts</UL><P>In general, I do not believe in "obscure behavior" on a Computer because it usually means I have not tried hard enough to think outside the box, to gather information and knowledge, to make sense of the situation. I mean, it is tempting to hypothesize from one's knowledge of the system even if it is better to logically deduce from facts.<P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com0tag:blogger.com,1999:blog-35814941.post-33508265192544937262006-11-02T00:05:00.000-08:002006-11-01T23:43:03.762-08:00HOWTO: Change the ID of an IIS Website<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Hello,</P><P>When I install Sharepoint Services, it creates a web site with an identifier. (Ex. ID 4).</P><P>I need to change that ID for another one. So I use this command :</P><CODE>cscript adsutil.vbs move w3svc/4 w3svc/4243.</CODE><P>It does the trick...</P><P>But, when I look in IIS I see that the site is stopped and I have this error in the event logs:</P><PRE>Event Type: Error <br />Event Source: W3SVC <br />Event Category: None <br />Event ID: 1007 <br />Date: 2006-10-25 <br />Time: 13:19:46 <br />User: N/A <br />Computer: U1U206V <br />Description: <br /><br />Cannot register the URL prefix 'http://*:24051/' for site '42'. The <br />necessary network binding may already be in use. The site has been <br />deactivated. The data field contains the error number. <br /><br />For more information, see Help and Support Center at <br />http://go.microsoft.com/fwlink/events.asp. <br /><br />Data: <br />0000: b7 00 07 80 ·..€ </PRE><P>If I start the site manually, the site starts fine with no errors.</P><P>I just want to know if there's a way to not receive this error message when I change the ID of my site.</P><P>Can someone confirm that?</P><P>Or is there another way to do it to prevent errors?</P><P>Thx in advance for your help.</span></P><H3>Answer:</H3><P>The reason you get that error event when you MOVE a running website is due to how ADSUTIL.VBS MOVE works. You can treat the MOVE operation as a non-atomic COPY-then-DELETE... because it is designed to move arbitrary metabase nodes (for example, one vdir to another vdir in a different tree hierarchy).</P><P>Thus, when you use it to move from website ID 4 to website ID 42, what happens is this:</P><OL><LI>The entire metabase node under website ID 4 is copied to website node with ID 42<br /><LI>Since website ID 4 is running and website node with ID 42 is a website, website ID 42 also attempts to run<br /><LI>However, since both website nodes are duplicates and have the exact same bindings, the new website ID 42 cannot start due to duplicate bindings and trigger the error event<br /><LI>After website ID 42 finishes copying, node ID 4 is deleted<br /><LI>But website ID 42 has already failed to start; there is no state change here<br /></OL><P>The key is to STOP the source website ID prior to executing the MOVE. In that case, there will be no duplicate bindings simultaneously running during the COPY-the-DELETE, and one will not see the error event.</P><br /><PRE>CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\adsutil.vbs STOP_SERVER W3SVC/4<br />CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\adsutil.vbs MOVE W3SVC/4 W3SVC/42<br />CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\adsutil.vbs START_SERVER W3SVC/42</PRE><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com9tag:blogger.com,1999:blog-35814941.post-82345677777991627952006-11-01T00:05:00.000-08:002006-10-31T21:57:45.135-08:00QA - IIS and Windows Firewall<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>ok after I install IIS windows fire wall is disabled and their is now way to enable it due to the Fire wall setting is grayed out. Any Ideas?</P></span><H3>Answer:</H3><P>IIS installation routines do NOT interact with the Windows Firewall. Period. IIS installation routines do NOT enable/disable the Windows Firewall, nor does it configure Port Exceptions or Program Exceptions on the Windows Firewall. IIS has no knowledge of external Security measures.</P><P>Now, fresh Windows Server 2003 installation do start with a "Configure Your Server" (CYS) wizard console window, which if you dismiss, will stop and disable the Windows Firewall service. The text in the window basically tells you that the Windows Firewall is enabled so that you can get patches, and once you dismiss the window, the Firewall will be stopped and disabled. Other Personal Security Software (other firewall software) may choose to disable the Windows Firewall as well.</P><P>In any case, if you make sure to enable the "Windows Firewall" service, the Windows Firewall control panel applet should become active again. This can be done with:</P><UL><LI>The "Services" Administrative Applet from the Start Menu<LI>Running "services.msc" on the command shell<LI>Running: <CODE>SC CONFIG ShareAccess start= auto & NET START SharedAccess</CODE> in the command shell</UL><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com4tag:blogger.com,1999:blog-35814941.post-84671542922190508122006-10-31T03:39:00.000-08:002006-10-31T03:47:23.306-08:00QA - ISAPI Extension and Logged Status Code<H3>Question:</H3><SPAN style="font-family:courier new;color:#008000"><P>Hi,</P><P>My ISAPI extension returns "404 xxx" status using</P><PRE>(*ecb->ServerSupportFunction) (ecb->ConnID,<br /> HSE_REQ_SEND_RESPONSE_HEADER_EX,<br /> &vBuffer,<br /> (LPDWORD) NULL,<br /> (LPDWORD) NULL);</PRE><P>but the log file in C:\WINDOWS\SYSTEM32\logfiles\W3SVC1\ex061030.log always shows a status code of 200:</P><CODE>23:00:55 10.10.36.235 GET /bvcgi-bin/michen.dll 200 </CODE><P>How to force the log entry to reflect the true status code set by the ISAPI extension?</P><P>Thanks for your help!</P></SPAN><H3>Answer:</H3><P>Each ISAPI Extension DLL is responsible for setting the logged HTTP status code for the request it handled. This is done via the <A href="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/iissdk/html/bef4d00f-29e3-4a0b-8d72-c9f23fde0e61.asp">dwHttpStatusCode</A> member of the EXTENSION_CONTROL_BLOCK associated with the request. If the ISAPI Extension DLL does not set the HTTP status code, the default value is 200.</P><H4>Where's the Magic Fairy Dust?</H4><P>Now, one may be wondering WHY IIS cannot magically set the logged HTTP status code for the ISAPI Extension. After all, it knows the sequence of ServerSupportFunction calls made by ISAPI; why doesn't IIS just "figure out" what gets sent as the response status line and automagically log it?</P><P>Well, that behavior assumes that IIS buffers the response data sent by ISAPIs, which then allows IIS to parse the buffered response to determine the actual response status line... and IIS simply does not buffer the response, so it cannot correctly determine the response status line.</P><P>For example, suppose you have this sequence of ISAPI function calls:<P><OL><LI>WriteClient() of "HTTP/1.0 401 Access Denied\r\nContent-Length: 100\r\n\r\n"<LI>HSE_REQ_SEND_RESPONSE_HEADER with a "404 xxx" status</OL><P>Now, since IIS does not buffer nor parse the response, the WriteClient() data just goes straight to the client. Thus, the client sees a 401 response header with the subsequent 100 bytes (consisting of some part of the "404 xxx" response header) as response entity. Meanwhile, IIS can detect a 404 status line sent by HSE_REQ_SEND_RESPONSE_HEADER. So what should be logged? 401? 404? 200?</P><P>If IIS buffered and parsed the response, it would notice that the 401 is the status line preceeding the double \r\n, so it can log the same HTTP status code that the client perceives.</P><P>IIS makes no attempt to sort through the above ambiguous situations, so it leaves the choice to the ISAPI making the function calls. After all, the ISAPI should know its effective response status since it must generate the response...</P><H4>Other Considerations</H4><P>Now, the ISAPI is responsible for correctly setting the logged HTTP status code for both synchronous and asynchronous IO calls. For synchronous IO calls, the logic is straight forward - make sure to set dwHttpStatusCode on the ECB before returning from HttpExtensionProc.</P><SPAN style="color:#008000"><PRE>DWORD WINAPI HttpExtensionProc(<br /> LPEXTENSION_CONTROL_BLOCK pecb<br />)<br />{<br /> ...<br /> //<br /> // Send 404 response header<br /> //<br /> pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_SEND_RESPONSE_HEADER,<br /> "404 Not Found",<br /> (LPDWORD)NULL,<br /> (LPDWORD)NULL);<br /> //<br /> // log 404 HTTP status code<br /> //<br /> pecb->dwHttpStatusCode = 404;<br /><br /> return HSE_STATUS_SUCCESS;<br />}</PRE></SPAN><P>For asynchronous IO calls, the logic is slightly different - make sure to set the dwHttpStatusCode on the ECB in the asynchronous callback function prior to calling HSE_REQ_DONE_WITH_SESSION.</P><SPAN style="color:#008000"><PRE>VOID WINAPI * PFN_HSE_IO_COMPLETION AsyncIOCompletionFunction(<br /> LPEXTENSION_CONTROL_BLOCK pecb,<br /> PVOID pContext,<br /> DWORD cbIO,<br /> DWORD dwError<br />);<br /><br />DWORD WINAPI HttpExtensionProc(<br /> LPEXTENSION_CONTROL_BLOCK pecb<br />)<br />{<br /> HSE_CUSTOM_ERROR_INFO* pErrorInfo = NULL;<br /><br /> ...<br /><br /> //<br /> // Setup for asynchronous IO<br /> //<br /> // Create IO objects on heap and make sure its memory<br /> // remains valid throughout the lifetime of the<br /> // asynchronous IO call.<br /> //<br /> pErrorInfo = new HSE_CUSTOM_ERROR_INFO;<br /> if ( NULL == pErrorInfo )<br /> {<br /> goto Finished;<br /> }<br /><br /> ZeroMemory( pErrorInfo, sizeof( HSE_CUSTOM_ERROR_INFO ) );<br /> pErrorInfo->pszStatus = "403 Forbidden";<br /> pErrorInfo->uHttpSubError = 2;<br /> pErrorInfo->fAsync = TRUE;<br /><br /> //<br /> // Keep track of memory used on asynchronous IO call<br /> // with the "context" of the IO Completion function.<br /> //<br /> pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_IO_COMPLETION,<br /> AsyncIOCompletionFunction,<br /> (LPDWORD)NULL,<br /> (LPDWORD)pErrorInfo );<br /><br /> //<br /> // Make the asynchronous IO call.<br /> // - On success, do not touch pErrorInfo and<br /> // immediately return HSE_STATUS_PENDING<br /> // - On failure, immediately cleanup and<br /> // return HSE_STATUS_ERROR<br /> //<br /> if ( pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_SEND_CUSTOM_ERROR,<br /> pErrorInfo,<br /> (LPDWORD)NULL,<br /> (LPDWORD)NULL) )<br /> {<br /> return HSE_STATUS_PENDING;<br /> }<br /><br />Finished:<br /><br /> if ( NULL != pErrorInfo )<br /> {<br /> delete pErrorInfo;<br /> pErrorInfo = NULL;<br /> }<br /><br /> return HSE_STATUS_ERROR;<br />}<br /><br />VOID WINAPI * PFN_HSE_IO_COMPLETION AsyncIOCompletionFunction(<br /> LPEXTENSION_CONTROL_BLOCK pecb,<br /> PVOID pContext,<br /> DWORD cbIO,<br /> DWORD dwError<br />)<br />{<br /> HSE_CUSTOM_ERROR_INFO* pErrorInfo = (HSE_CUSTOM_ERROR_INFO*)pContext;<br /> DWORD dwIOStatus = dwError == NO_ERROR ?<br /> HSE_STATUS_SUCCESS :<br /> HSE_STATUS_ERROR;<br /><br /> if ( NULL != pErrorInfo )<br /> {<br /> //<br /> // log HTTP status code<br /> //<br /> pecb->dwHttpStatusCode = atoi( pErrorInfo->pszStatus );<br /><br /> delete pErrorInfo;<br /> pErrorInfo = NULL;<br /> }<br /><br /> pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_DONE_WITH_SESSION,<br /> &dwIOStatus,<br /> (LPDWORD)NULL,<br /> (LPDWORD)NULL );<br />}</PRE></SPAN><P>And the tricky one - the asynchronous callback function of HSE_REQ_EXEC_URL. The parent wildcard application mapping which called HSE_REQ_EXEC_URL controls the logged HTTP status code, but that value should come from the execution of the child - you want to log the fact that the child got a 401 during execution and not the fact that the parent reports 200 for being able to transfer execution to the child. Thus, the parent must remember to retrieve the HTTP status code from the child via HSE_REQ_GET_EXEC_URL_STATUS and record that in the dwHttpStatusCode of the parent's ECB in the asynchronous callback.</P><SPAN style="color:#008000"><PRE>VOID WINAPI * PFN_HSE_IO_COMPLETION AsyncIOCompletionFunction(<br /> LPEXTENSION_CONTROL_BLOCK pecb,<br /> PVOID pContext,<br /> DWORD cbIO,<br /> DWORD dwError<br />);<br /><br />DWORD WINAPI HttpExtensionProc(<br /> LPEXTENSION_CONTROL_BLOCK pecb<br />)<br />{<br /> HSE_EXEC_URL_INFO* pExecInfo = NULL;<br /><br /> ...<br /><br /> //<br /> // Setup for asynchronous IO<br /> //<br /> // Create IO objects on heap and make sure its memory<br /> // remains valid throughout the lifetime of the<br /> // asynchronous IO call.<br /> //<br /> pExecInfo = new HSE_EXEC_URL_INFO;<br /> if ( NULL == pErrorInfo )<br /> {<br /> goto Finished;<br /> }<br /><br /> ZeroMemory( pExecInfo, sizeof( HSE_EXEC_URL_INFO ) );<br /><br /> //<br /> // Keep track of memory used on asynchronous IO call<br /> // with the "context" of the IO Completion function.<br /> //<br /> pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_IO_COMPLETION,<br /> AsyncIOCompletionFunction,<br /> (LPDWORD)NULL,<br /> (LPDWORD)pErrorInfo );<br /><br /> //<br /> // Make the asynchronous IO call.<br /> // - On success, do not touch pErrorInfo and<br /> // immediately return HSE_STATUS_PENDING<br /> // - On failure, immediately cleanup and<br /> // return HSE_STATUS_ERROR<br /> //<br /> if ( pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_EXEC_URL,<br /> pExecInfo,<br /> (LPDWORD)NULL,<br /> (LPDWORD)NULL) )<br /> {<br /> return HSE_STATUS_PENDING;<br /> }<br /><br />Finished:<br /><br /> if ( NULL != pExecInfo )<br /> {<br /> delete pExecInfo;<br /> pExecInfo = NULL;<br /> }<br /><br /> return HSE_STATUS_ERROR;<br />}<br /><br />VOID WINAPI * PFN_HSE_IO_COMPLETION AsyncIOCompletionFunction(<br /> LPEXTENSION_CONTROL_BLOCK pecb,<br /> PVOID pContext,<br /> DWORD cbIO,<br /> DWORD dwError<br />)<br />{<br /> HSE_EXEC_URL_INFO* pExecInfo = (HSE_EXEC_URL_INFO*)pContext;<br /> HSE_EXEC_URL_STATUS ExecStatus;<br /><br /> DWORD dwIOStatus = dwError == NO_ERROR ?<br /> HSE_STATUS_SUCCESS :<br /> HSE_STATUS_ERROR;<br /><br /> if ( pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_GET_EXEC_URL_STATUS,<br /> &ExecStatus,<br /> (LPDWORD)NULL,<br /> (LPDWORD)NULL ) )<br /> {<br /> //<br /> // log HTTP status code<br /> //<br /> pecb->dwHttpStatusCode = ExecStatus.uHttpStatusCode;<br /> }<br /><br /> if ( NULL != pExecInfo )<br /> {<br /> delete pExecInfo;<br /> pExecInfo = NULL;<br /> }<br /><br /> pecb->ServerSupportFunction(<br /> pecb->ConnID,<br /> HSE_REQ_DONE_WITH_SESSION,<br /> &dwIOStatus,<br /> (LPDWORD)NULL,<br /> (LPDWORD)NULL );<br />}</PRE></SPAN><H3>Conclusion</H3><P>IIS provides ISAPI a lot of control when it comes to the HTTP status code logged for requests it handles. And with such power comes responsibility...</P><P>One final thought... the astute reader should realize that this entire HTTP status code logging scheme has one little flaw since IIS6 - ISAPI is NOT able to manipulate the HTTP SubStatus Code introduced in IIS6. Thus, ISAPI can only log 401.0 but not 401.3, even if it called HSE_REQ_SEND_CUSTOM_ERROR to send the 401.3 custom error. Alas, this flaw will likely remain... unless someone really complains about it. :-)</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com5tag:blogger.com,1999:blog-35814941.post-56828408045398144592006-10-27T21:05:00.000-07:002006-10-27T21:37:26.395-07:00QA - Commonly Misunderstood Concepts, Part 1<H3>Question:</H3><span style="font-family:courier new;color:#008000">I am running IIS 6 on 2003 servers. If I configuration Integrated Windows Authentication, is it possible to pass one of the user headers to a J2EE application server on another 2003 box?</span><H3>Answer:</H3><P>There are several commonly misunderstood concepts exemplified by this question, so I am going to clarify them.</P><UL><br /><LI>First, the question actually has nothing to do with IIS. Why? Well, IIS is a web server, which accepts requests from clients and generate responses. In particular, IIS does not make requests to other servers. Now, your question asks about the functionality of "something" which makes a request to a J2EE application server. Since IIS does not make a request, it has nothing to do with the question.<br /><LI>The answer actually depends on the unknown "something" which makes the requests from the IIS server to the J2EE application server. Since we are talking about software, it is theoretically possible, but we do not know if you have the software to do it.<br /><LI>Authentication protocols, such as Integrated Windows Authentication, have no correlation/influence on ability to make requests or pass values to another server. Authentication influences the user identity which executes code on that server, not what that code chooses to do.<br /><LI>LogonUser, AuthUser, RemoteUser are not user headers. They are Server Variables whose values derive from HTTP request headers. When authentication is enabled, they can be non-empty after authentication completes.</UL><P>Thus, one can conceivably configure a program on IIS which runs after Integrated Authentication finishes populating the LogonUser, AuthUser, and RemoteUser Server Variables and makes a request to the J2EE Application Server with those values stored in the request header - and pass those values to the J2EE Application Server.</P><P>IIS does not provide such a program, but anyone can write such a program for IIS.</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com0tag:blogger.com,1999:blog-35814941.post-48235404688831615202006-10-17T04:57:00.000-07:002006-10-17T06:13:45.006-07:00QA - Is it possible to detect Browser-side UI events from the Server<h3>Question:</h3><span style="font-family:courier new;color:#008000;"><p>Hi all,</p><p>If user clicked on a link, he will get a dialog box with Open/save/cancel/more. How to detect which button user clicked. Is there any way to detect that user has clicked the cancel button from IIS.</p><p>The constrain is we dont have any permissions to touch the application. Everything has to be done from IIS only. Does IIS log file be helpful in anyway for me?</p><p>Regards</p></span><h3>Answer:</h3><p>If I may rephrase your question - you are asking if client-side UI events are detectable from the server - and the simple answer is no, the server has no idea about those client-side events. Let me explain what actually happens between the browser and server during that time period...</p><p>I assume that the user just caused a request to be sent to the server, which resulted in particular Content-Type response header to come back to the browser which indicates that the browser should pop up the Open/Save/Cancel/More dialog box. The request could be triggered by client-side scripting making an HTTP request, user clicking on a link, 302 redirection, etc - doesn't matter. The client somehow made a request to the server, and the response from the server has attributes which make the client pop up the Open/Save/Cancel/More dialog box.</p><ul><li>When the user clicks "More" in the client-side dialog box, the browser handles all of it and sends nothing to IIS. IIS has no clue about it.</li><li>When the user clicks "Cancel" in the client-side dialog box, the browser handles all of it and sends nothing to IIS. IIS has no clue about it.</li><li>When the user clicks "Save" in the client-side dialog box, the browser handles the response and saves it to the directed location as a file.</li><li>When the user clicks "Open" in the client-side dialog box, the browser handles the response, saves it to some temporary location to the client, and launches the associated handler application according to the response's Content-Type MIME mapping.</li></ul><p>As you can see, IIS has no idea about "More" and "Cancel" and cannot distinguish between them. IIS also has no way to distinguish between "Save" and "Open"... in fact, it cannot distinguish between them and the user clicking on an URL that is rendered by the browser - because it is the same as a "Save" and "Open" where the browser is the associated handler application according to the response's Content-Type MIME mapping.</p><p>Basically, without touching the application for any custom client-side and server-side assistance, the server remains oblivious to it all. I am not 100% certain that client-side scripts can even detect these UI events because they are likely specific to each browser's Application Model with no common specifications.</p><p>In short, the sort of interactivity you are looking for is NOT present between HTTP browsers and servers. The HTTP protocol simply has no provisions for it.</p><p>//David</p>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com0tag:blogger.com,1999:blog-35814941.post-22935210947870119292006-10-16T00:16:00.000-07:002006-10-15T23:58:37.251-07:00Moving over to Blogger Beta<P>Heh... I may have just started using Blogger.com but a week ago, but I have already shifted over to using the Blogger Beta. Yes, I may not like being on the bleeding edge, but when the software has the features I want, AND I see active and fresh feedback loops between the users and its <A href="http://knownissues.blogspot.com/">product development team</A>, I am far more inclined to give it a try.</P><P>Why? Well, having participated in all parts of the product development cycle, I see something very healthy, refreshing, and encouraging with the Blogger team's active interaction with its users, which helps mitigate the sorts of risks of being on the bleeding edge. Issues get reported and promptly acknowledged and usually resolved. Kudos to the Blogger team on the transparency!</P><P>One of the big motivating factors for me to move to Blogger Beta is Tagging - a process I had gotten accustomed to on Community Server and distinctly missed on Blogger.com. I am a big fan of simplicity through organization (remember, things naturally tend toward Chaos), and Tagging allows me to better categorize and organize my information to the querying audience. I mean, the Internet has enough Noise... ;-)</P><P>Now, some of you may point out that I do own and use Mac OS X on a Mac Mini... the self-proclaimed computer "for the rest of us" (i.e. those who willingly pony up the 50% Apple premium ;-) ) which promotes ease of use through dumping things to iPhoto, iTunes, iDrive, and the "Macintosh HD". I honestly do not know where my data hides on a Mac; I only know what the applications show me. It reminds me of the feeling of "ignorance is bliss".</P><P>For me, it is a very tenuous sort of "trust" because I do not feel in control of my own information. I do not believe in haphazardly "dumping" data into some limitless-sized bin and relying on a search engine to come along and rescue me from myself. Yes, "everyone is doing it" and "it's easy", and I have no aversion towards using tools to simplify my life, but I firmly believe in fundamentally being able to help myself and others instead of relying on someone/something else for help.</P><P>In other words, I have no problems using trigonometric functions on a calculator AFTER I know where they came from and HOW to apply them; I will never view them as an unnecessary detail of life because a calculator can do the work for me. It may seem like an unnecessary burden to some, but it is one I am willing to carry. I believe that Life is not about doing what's easiest but rather what is best for all.</P><P>I mean, the Internet slowly tends towards lethargy - with over half its daily traffic consisting of useless spam and even greater percentage of persistent content as broken links and aged cruft. I think that this is what happens when people decide to just "dump" everything into a bin... because it then requires dumping even more stuff just to get one's attention and a search engine to find the needle in the haystack of increasing stuff... and the vicious cycle continues.</P><P>Anyways... enough divergence for now. :-) I will be poking along the Blogger Beta like anything else - with a fair but critical eye - because I feel that the Blogger team appreciates it.</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com1tag:blogger.com,1999:blog-35814941.post-1160734133763779812006-10-16T00:08:00.000-07:002006-10-17T06:13:02.254-07:00QA - problems using MSXML4 on 64bit Windows<h3>Question:</h3><span style="font-family:courier new;color:#008000;"><p>I ran the iismt to move a site from a 32bit server to a 64bit server. I am getting all kinds of ASP errors and have been told by the code boys that it is a problem with getting msxml4.dll to work properly through the SysWOW64 "layer". The people in the know here have tried registering all the msxml*.dll's they could but we still get the errors. Is there a special MSXML install for 64 bit? I'm sure this isn't enough infor for a full answer but it is all I have. Just hoping someone has ran in to this before and can maybe point me in the right direction? Thanks for any help</p></span><h3>Answer:</h3><p>There is no 64bit MSXML4.DLL. Starting with MSXML6.DLL, there is a native 64bit version.</p><p><a href="http://www.microsoft.com/downloads/details.aspx?FamilyID=993C0BCF-3BCF-4009-BE21-27E85E1857B1&displaylang=en">http://www.microsoft.com/downloads/details.aspx?FamilyID=993C0BCF-3BCF-4009-BE21-27E85E1857B1&displaylang=en</a></p><p>I guess that your application was not tested against MSXML6.DLL, but I suggest that you:</p><ol><li>First try to upgrade to MSXML6.DLL 64bit and make your application work with it<br /><li>If MSXML6.DLL is not working for whatever reason, then try to figure out why your application fails with MSXML4.DLL and WOW64.<br /></li></ol><h4>Details</h4><p>I believe your issue is not with MSXML4.DLL nor WOW64 but rather with the mysteries of WOW64 Compatibility (i.e. 32bit apps on 64bit Windows). Let me try to explain what is going on:</p><ul><br /><li>There is only 32bit MSXML4.DLL, and its ProgID (i.e. what ASP page tries to instantiate) is only in the 32bit "section" of the 64bit Registry and available to 32bit processes.<br /><li>By default, IIS6 runs 64bit w3wp.exe processes and 64bit ASP DLL (you can only load 64bit DLLs into 64bit processes; likewise only 32bit DLLs into 32bit processes)<br /><li>Thus, it is impossible for an ASP page running in 64bit w3wp.exe to instantiate 32bit MSXML4.DLL.<br /><li>No amount of re-registration will help - REGSVR32.EXE can determine if a DLL is 32bit or 64bit and only registers 32bit DLLs in the 32bit section of the Registry.<br /></li></ul><p>To allow your ASP pages to use 32bit MSXML4.DLL, you must configure IIS6 to run its worker processes as 32bit. This is a global setting (i.e. IIS6 will only run all 32bit or all 64bit worker processes - so if you choose 32bit worker process, you are really not getting any 64bit benefits from an IIS perspective). You change IIS6 to run 32bit worker processes by running the following command:</p><p>CSCRIPT %SYSTEMDRIVE%\Inetpub\AdminScripts\adsutil.vbs SET W3SVC/AppPools/Enable32bitAppOnWin64 1</p><h4>Conclusion</h4><p>Long story short - compatibility shims like WOW64 can be confusing and down-right convoluted if you go back and forth between bitness. I suggest that you go Native (64bit) as the first option and only fall back to WOW64 when you run out of options. If you remember a decade ago how painful running Win16 programs were on Win95 or NT4, and how much nicer native Win32 apps ran on Win95 and NT4... same story here.</p><p>//David</p>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com1tag:blogger.com,1999:blog-35814941.post-1160536602438630352006-10-15T00:02:00.000-07:002006-10-17T06:11:56.052-07:00QA - problems running WScript.Shell on 64bit Windows<h3>Question:</h3><span style="font-family:courier new;color:#008000;"><p>Hi,</p><p>I'm having trouble running a bat file from an ASP page. It works fine on Windows 2003 Std x32 server but fails now we have upgraded to the x64 edition</p><p>In the ASP we are trying to run the following</p><br /><pre>Set oWSH= Server.CreateObject("WScript.Shell")<br /><br />errmsg = oWSH.Run("d:\\scripts\\copyiissettings.bat 10.0.0.156",0,True)<br /><br />set oWSH = nothing<br /></pre><br /><p>The errmsg is returning 1 (not very helpful)</p><p>In the BAT file we are running the following command: cscript.exe c:\windows\System32\iiscnfg.vbs /copy /ts %1 /tu machineusername /tp machinepassword</p><p>I am sure the permissions are setup correctly in IIS as both the Application Pool and Authenticated Anonymous User are set as the Administrator. We are also running IIS with he following flag enabled Enable32BitAppOnWin64=True</p><p>I can only think maybe there is a problem being related to the fact we are running x64 and perhaps there is a registry setting or group policy setting i need to change?</p><p>Thanks,</p><br /><p>i figured it out.</p><p>problem is that when you call the bat from the ASP it runs as a 32 bit process and runs the cscript.exe from the SYSWOW64 directory and this fails. i copied the cscript.exe from the System32 into the SYSWOW64 directory and this fixed the problem. hopefully this wont cause another problem somewhere else?!</p></span><h3>Answer:</h3><p>Yes, your resulution is one way to address your specific issue, but in general I prefer to modify/manipulate system files only after understanding what is going on and the full ramifications of the change.</p><p>Because you configured Enable32bitAppOnWin64=1, WOW64 interactions came into play and complicated matters. Here is what is going on:</p><ol><li>When you configure Enable32bitAppOnWin64=1 in IIS6, it makes IIS launch 32bit worker process (w3wp.exe) to handle requests. You see it as w3wp.exe*32 with 64bit Task Manager<br /><li>The 32bit worker process reads configuration and determines that .ASP is handled by C:\windows\System32\ASP.DLL and attempts to load that DLL<br /><li>WOW64 subsystem on 64bit Windows triggers when a 32bit process attempt to reach C:\windows\System32 and transparently redirects it to C:\windows\SYSWOW64. So, C:\windows\SYSWOW64\ASP.DLL (32bit DLL installed by IIS6 on 64bit Windows) is loaded by the worker process<br /><li>32bit ASP DLL parses the ASP page and looks up ProgId for WScript.Shell in the registry. The Registry also transparently redirects access to Registry by 32bit process to the appropriate Wow6432Node inside the Registry. End result is that the 32bit OCX implementing WScript.Shell eventually gets located and loaded<br /><li>oWSH.Run( "d:\\scripts\\copyiissettings.bat 10.0.0.156" ) eventually translates into a CreateProcess() Win32 API call made by the 32bit worker process. The .BAT extension is looked up to be processed by C:\windows\System32\CMD.EXE , but will get redirected by WOW64 to C:\windows\SYSWOW64\CMD.EXE (32bit) in the same way as ASP.DLL earlier<br /><li>32bit CMD.EXE eventually encounters the CSCRIPT.EXE statement, and after a path lookup and WOW64 redirection, it will run C:\windows\SYSWOW64\CSCRIPT.EXE (32bit) to process c:\windows\System32\iiscnfg.vbs<br /><li>When 32bit CSCRIPT.EXE tries to load c:\windows\System32\iiscnfg.vbs , WOW64 will redirect it to c:\windows\SYSWOW64\iiscnfg.vbs - which does not exist - and the execution fails with a file-not-found<br /></li></ol><p>Based on the above, the following are possible resolutions:</p><ul><li>Set Enable32BitAppOnWin64=0. This turns off WOW64 everywhere at the source. This may not be possible because you may have legacy web applications which require 32bit. However, if this is the case, I question why you run 64bit Windows at all - running IIS6 in 32bit compatibility mode on 64bit Windows drags in all the WOW64 compatibility cruft without giving much 64bit advantages (the 32bit w3wp.exe still has a 32bit Address Space)<br /><li>Copy 64bit CMD.EXE to %systemroot%\SYSWOW64 . This may not be desirable because legacy applications may depend on 32bit CMD shell behavior<br /><li>Copy 64bit CSCRIPT.EXE to %systemroot%\SYSWOW64 . This may not be desirable because legacy applications may depend on 32bit Windows Scripting behavior<br /><li>Duplicate the IIS Admin .vbs Scripts and IISSCHLP.WSC from %systemroot%\System32 to %systemroot%\SYSWOW64 and use %systemroot%\SYSWOW64\REGSVR32.EXE to register IISCHLP.WSC into the 32bit Registry on 64bit Windows. This creates duplicate .vbs cruft but accomplishes your task without impacting any other part of the system<br /></li></ul><p>Good luck</p><p>//David</p>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com6tag:blogger.com,1999:blog-35814941.post-1160831640397085502006-10-14T20:11:00.000-07:002006-10-17T06:09:45.765-07:00QA - The PUT Method and WebDAV<h3>Question:</h3><span style="font-family:courier new;color:#008000;"><p>Hi,</p><p>On a Win 2003 enterprise server with SP1 and IIS 6.0, when my program tries to execure HTTP PUT request, IIS returns error 501. If WebDAV is enabled then this works OK. Customer doesn't want WebDAV to be enabled so how can I get this to work ?</p><p>I have checked the permissions on the folder where PUT is supposed to write (I opened up to EVERYONE), i've also checked the Directory Security and have set Basic and NTLM on the VDIR in IIS.</p><p>Thank you in advance</p></span><h3>Answer:</h3><p>You have some contradictory desires in your statement, so I can only explain what is going on and some options. You will have to decide what works in your situation.</p><ul><li>The WebDAV specification defines the PUT Method, along with other methods and abilities. The HTTP specification does not define a PUT Method.</li><li>IIS6 provides a global switch controlling the enablement of all WebDAV behaviors. There are no provisions to "only enable a subset of WebDAV behaviors", such as only PUT. There are provisions to allow the PUT verb (assuming it is enabled) on a per-URL basis using the "Write" IIS permission from within the IIS Manager UI.<P>This is frequently confused with the "Write" NTFS ACL permission. The "Write" IIS permission controls allowing/denying the PUT Method. The "Write" permission in NTFS ACL controls whether a Windows user SID has permissions to write to that resource. Both permissions need to be aligned to allow the user feature of "uploading a file to the server" because one controls whether a user can use PUT to send the file as a data blob to the server, and the other controls whether the user's authenticated identity can write that data blob to the filesystem on the server.</P></li><li>Since your program uses PUT method to upload files to the server, it has a requirement on WebDAV.</li></ul><p>So, your current observation is by-design. Since your program uses PUT, it has a dependency on WebDAV. And if WebDAV is disabled on IIS6, then you will get 501 errors when you make PUT requests. There is no resolution through mere configuration because your client does not want to meet the requirements of your program.</p><p>Let's think about other ways to resolve the issue by changing requirements/definitions.</p><ol><li>Change the WebDAV and HTTP specifications so that PUT is HTTP. But this is highly, highly unlikely to ever happen.</li><li>Change the client requirement to allow WebDAV. This may be possible.</li><li>Change WebDAV implementation in IIS to allow configurable subset of WebDAV behaviors. This is highly, highly unlikely to ever happen.</li><li>Configure IIS to allow full-blown WebDAV, and run some other filter in front of IIS to remove all requests containing WebDAV methods except for PUT.</li><li>Change your application to use another mechanism, like HTTP POST, along with a server-side POST Acceptor, to upload files.</li></ol><p>Changing user permissions/ACLs and Authentication protocols have no affect on the issue of enablement of WebDAV in the virtual URL namespace because they affect operations in the physical filesystem namespace.</p><p>//David</p>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com5tag:blogger.com,1999:blog-35814941.post-1160608722301618082006-10-11T16:30:00.000-07:002006-10-17T06:09:19.067-07:00QA - IIS Websites vs Applications<H3>Question:</H3><span style="font-family:courier new;color:#008000"><P>Should we create multiple sites (perhaps one site for each of our home grown applications) or one site with many applications in it?</P></span><H3>Answer:</H3><P>The answer completely depends on your needs and requirements. Here are some food for thought.</P><P>You can view a website as something that has website features along with a "root" application named "/", so a website has a superset of features over an application. The line between an application and virtual directory is mostly a matter of ancient legacy starting with IIS6, so I will not distinguish between them much.</P><P>Considerations between website and application include:</P><UL><br /><LI>Logging format/file/configuration is per-website, not per-app<br /><LI>SSL Server Certificate binding is per-website<br /><LI>Host header binding is per web-site<br /><LI>etc...<br /></UL><P>So, your considerations should contain the following:</P><P>IIS only provides per-website based logging, so if you need each application to have its own individual web server log file, then each application must be its own website. Of course, you can also write/find an ISAPI Filter which produces customized per-app Request Log File, but that's not a core component shipped with IIS.</P><P>If you are ok with https://server/app1 and https://server/app2 sending the same SSL Server Certificate as identification, then they can be applications on the same website. If you need them to send different SSL Server Certificates, then they must be on different websites since IIS supports only one SSL Server Certificate per website. Note that I say one SSL Server Certificate and NOT one SSL host per website... read the next option.</P><P>If you need https://app1.server.com and https://app2.server.com to send the same SSL Server Certificate as identification, then they can be applications on the same website using a wildcard SSL Certificate for *.server.com. This is possible starting with IIS6 on Windows Server 2003 SP1. They can also be applications on two different websites sending the same SSL Server Certificate.</P><P>If you need https://app1.com and https://app2.com, then they must be on different websites. IIS supports only one SSL Server Certificate per website, and you probably will not be able to get a *.com wildcard SSL Certificate... ;-)</P><P>Finally... since websites have a superset of features over application, it also uses a bit more memory resources. But, you probably do not need to worry about this difference unless you are talking about 10,000 websites...</P><P>So... it all depends on what you need. And this is just a subset of all the possible considerations.</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com6tag:blogger.com,1999:blog-35814941.post-1160604430878618732006-10-11T15:00:00.000-07:002006-10-17T06:07:48.185-07:00Comments, Comments, Read all about it...<P>Hmm... unlike other blog software that I have used, this blog does not give you the ability to send anonymous email via a form from the blog to me.</P><P>So, I will try to simulate such functionality by dedicating this blog entry's comment section towards allowing you to send anonymous email to me. I hope that the CAPTCHA requirement on comments will limit anonymous blog comment spam that I have seen in the past.</P><P>Yes... yours and my email addresses remain private, but the comment contents are no longer private. That should be ok for the most part because my answers to your questions will be publicly posted anyway...</P><P>Plus, you get to see all of what have been asked before... and maybe find that you no longer need to comment...</P><P>But, if you truly need to send a private email to me, that can be separately arranged. :-)</P><P>Cheers!</P><P>//David</P>David Wanghttp://www.blogger.com/profile/03586686487919158929noreply@blogger.com12