Edgewall Software

Changes between Initial Version and Version 1 of TracOnWindowsIisPyISAPIe


Ignore:
Timestamp:
Jun 27, 2011, 12:36:23 PM (13 years ago)
Author:
aakoshh@…
Comment:

Legend:

Unmodified
Added
Removed
Modified
  • TracOnWindowsIisPyISAPIe

    v1 v1  
     1= Running Trac on IIS 6 using PyISAPIe =
     2
     3Contributed by: Aa`Koshh
     4
     5Configuration:
     6 * Windows Server 2003
     7 * Python 2.6
     8 * IIS 6
     9 * Trac 0.12
     10
     11I have multiple Django sites running on the server based on the instructions at [https://code.djangoproject.com/wiki/DjangoOnWindowsWithIISAndSQLServer], which suggests using PyISAPIe, so that each site can use its own application pool, which is necessary to support Django configuration. Using this setup, each site can be restarted independently from the others. I wanted Trac to be served up the same way, and with a few modifications, it works, more or less.
     12
     131. To support multiple sites, create a directory somewhere local to IIS and copy the PyISAPIe.dll and the Http module into it. This will only serve Trac.
     141. Follow the instructions on the Django site to set up a virtual directory based on the above copy of the dll, up until when the Info.py file works in its own application pool. Don't forget to add read permission on the dll to network service.
     151. Modify Isapy.py in the Http directory to call the Trac WSGI handler:
     16{{{
     17# $URL: https://pyisapie.svn.sourceforge.net/svnroot/pyisapie/Tags/1.1.0-rc4/PyISAPIe/Python/Examples/Django/Isapi.py $
     18from trac.web.main import dispatch_request
     19from Http.WSGI import RunWSGI
     20from Http import Env
     21import os
     22
     23os.environ['TRAC_ENV'] = r"\\myserver\path\to\trac\env"
     24os.environ['PYTHON_EGG_CACHE'] = r"\\myserver\path\to\trac\env\eggs"
     25
     26# This is how the WSGI module determines what part of the path
     27# SCRIPT_NAME should consist of. If you configure PyISAPIe as
     28# a wildcard map on the root of your site, you can leave this
     29# value as-is.
     30#
     31Base = "/Trac"
     32
     33# This is an example of what paths might need to be handled by
     34# other parts of IIS that still come here first. This value's
     35# default of "/media" assumes that you've mapped a virtual
     36# directory to Django's admin media folder and so expect the
     37# files to be served by the static file handler.
     38#
     39Exclude = ["/Trac/chrome/common", "/chrome/common"]
     40
     41# The main request handler.
     42
     43Handler = dispatch_request
     44
     45def Request():
     46  PathInfo = Env.PATH_INFO.lower()
     47
     48  # Check for anything we know shouldn't be handled by Python and
     49  # pass it back to IIS, which in most cases sends it to the static
     50  # file handler.
     51 
     52  if not PathInfo.startswith(Base.lower()):
     53    return True
     54 
     55  for Excl in Exclude:
     56    if PathInfo.startswith(Excl.lower()):
     57      return True
     58 
     59  return RunWSGI(Handler, Base=Base)
     60
     61}}}
     621. Edit the WSGI.py module in the Http directory and uncomment REMOTE_USER in the IsapeEnvAuto list so that Trac can pick up the logged in user.
     631. When there is an error, Trac tries to present its error.html template, but also passes the exception info to the WSGI function "start_response". PyISAPIe, however, re-raises the exception even though it was handled, so for example unhandled paths result in an IIS Internal Error page and a stack trace. I edited the WSGI.py again so that if Trac supports an exception info but headers are also present, no exception is raised to IIS:
     64{{{
     65def StartResponse(Status, Headers, ExcInfo = None):
     66  if ExcInfo and not Headers : # only raise exception to IIS if Trac is not about to present the error page
     67    try:
     68      raise ExcInfo[0], ExcInfo[1], ExcInfo[2]
     69     
     70    finally:
     71      ExcInfo = None
     72     
     73  Status = int(Status.split(" ",1)[0])
     74  Header(Status = Status)
     75 
     76  for NameValue in Headers:
     77    Lname = NameValue[0].lower()
     78   
     79    if Lname == "content-length":     
     80      Header(Length = int(NameValue[1]))       
     81      continue
     82     
     83    elif Lname == "connection":
     84      if NameValue[1].lower() == "close":
     85        Header(Close = True)
     86      continue
     87   
     88    Header("%s: %s" % NameValue)   
     89   
     90  return Write
     91}}}
     921. After changes are made to either Python modules or the trac.ini file, right click on the application pool and click recycle. The site should display at this point.
     931. I had some problems with static files (Trac css and Javascript) over 4K in size not being served. The exception seems to be raised when the content length header is set in StartResponse above, maybe it is sent twice. I ended up setting up an IIS virtual directory to serve the htdocs directory of Trac and added the htdocs_location = /trac_media entry to trac.ini
     941. create a virtual directory under the base Trac site in IIS and name it "login". Set directory security to Digest Authentication, it works behing Nginx. 1. I had some trouble with the admin account: when I accessed the site directly by IP and logged in with my Windows credentials, the remote user was "domain\user", but through our router it became "DOMAIN\user", and the roles defined were picked up only for the one explicitly granted. Whichever appears on the site, add permissions for that username like this: "trac-admin $ENV permission add DOMAIN\user TRAC_ADMIN"
     951. The header and footer did not appear on Trac pages (it did in the standalone server). I had to modify layout.html and remove the fallback tag at the bottom of the document like this:
     96{{{
     97  <xi:include href="$chrome.theme"></xi:include>
     98  <xi:include href="site.html"><xi:fallback /></xi:include>
     99</html>
     100}}}
     1011. I really hope nothing new will come up...