Attachment 'MoinIIS_for_1.5.py'

Download

   1 #
   2 # MoinIIS v.3
   3 #
   4 # IIS ISAPI extension to start MoinMoin from under IIS effectively
   5 #
   6 # Set the virtual path to your wiki instanse
   7 #
   8 virtualPath = '/mywiki'
   9 
  10 import sys
  11 #
  12 # If MoinMoin is not set to the default package path, 
  13 # uncomment and edit this:
  14 #
  15 #sys.path.append('C:/MoinWiki-1.3.5/Lib/site-packages')
  16 sys.path.append('C:/Moin/Lib/site-packages')
  17 
  18 from StringIO import StringIO
  19 from MoinMoin import config, wikiutil
  20 from MoinMoin.request import RequestBase
  21 from isapi import InternalReloadException
  22 from isapi import isapicon
  23 from isapi.simple import SimpleExtension
  24 import MoinMoin
  25 import cgi, urllib, os, stat, threading
  26 import win32event, win32file, winerror, win32con, threading
  27 from MoinMoin.auth import http
  28 
  29 def debug(log):
  30     f = open('/tmp/env.log', 'a+')
  31     try:
  32         f.write(log + '\n')
  33     finally:
  34         f.close()
  35 
  36 if hasattr(sys, "isapidllhandle"):
  37     import win32traceutil
  38 
  39 try:
  40     reload_counter += 1
  41     reload( wikiconfig )
  42     reload( MoinMoin.multiconfig )
  43     reload( MoinMoin )
  44     print 'Modules reloaded'
  45 except NameError:
  46     reload_counter = 0
  47     import wikiconfig
  48         
  49 class ReloadWatcherThread(threading.Thread):
  50     def __init__(self):
  51         self.filename = __file__
  52         self.change_detected = False
  53         if self.filename[:4] == '\\\\?\\':
  54             self.filename = self.filename[4:];
  55         if self.filename.endswith("c") or self.filename.endswith("o"):
  56             self.filename = self.filename[:-1]
  57         self.root_dir = os.path.dirname(self.filename)
  58         self.handle = win32file.FindFirstChangeNotification(
  59                         self.root_dir,
  60                         False, # watch tree?
  61                         win32con.FILE_NOTIFY_CHANGE_LAST_WRITE)
  62         threading.Thread.__init__(self)
  63 
  64     def run(self):
  65         last_time = os.stat(self.filename)[stat.ST_MTIME]
  66         while 1:
  67             try:
  68                 win32event.WaitForSingleObject(self.handle, 
  69                                                     win32event.INFINITE)
  70                 win32file.FindNextChangeNotification(self.handle)
  71             except win32event.error, details:
  72                 # handle closed - thread should terminate.
  73                 if details[0] != winerror.ERROR_INVALID_HANDLE:
  74                     raise
  75                 break
  76             this_time = os.stat(self.filename)[stat.ST_MTIME]
  77 #            print "Detected file change - flagging for reload."
  78             self.change_detected = True
  79 #===============================================================================
  80 #            if this_time != last_time:
  81 #                last_time = this_time
  82 #===============================================================================
  83     
  84     def stop(self):
  85         win32file.FindCloseChangeNotification(self.handle)
  86 
  87 # The moinmoin start extention
  88 
  89 class Extension(SimpleExtension):
  90     ''' The MoinMoin Wiki IIS ISAPI starter
  91     '''
  92     def __init__(self):
  93         self.reload_watcher = ReloadWatcherThread()
  94         self.reload_watcher.start()
  95 
  96     def HttpExtensionProc(self, ecb):
  97         if self.reload_watcher.change_detected:
  98             raise InternalReloadException
  99         
 100 #        print "serving request, changind dir to ",self.reload_watcher.root_dir
 101         os.chdir(self.reload_watcher.root_dir)
 102         try:
 103             r = RequestISAPI(ecb)
 104             r.run()
 105         except:
 106             einfo = sys.exc_info()
 107             print >>ecb, "Content-type: text/html\r\n\r\n<html><head></head><body>"
 108             print >>ecb, "<h1>Exception</h1>: "
 109             import traceback
 110             print >>ecb, '<p><pre>',traceback.format_exc(),'</pre>'
 111             print traceback.format_exc()
 112             print >>ecb, '</body></html>'
 113 
 114         ecb.close()
 115         return isapicon.HSE_STATUS_SUCCESS
 116     
 117     def TerminateExtension(self, status):
 118         self.reload_watcher.stop()
 119 
 120 # The entry points for the ISAPI extension.
 121 def __ExtensionFactory__():
 122     return Extension()
 123 
 124 class EnvAdaptor(dict):
 125     """Adaptor from ecb to env."""
 126     
 127     def __init__(self, ecb, force_env={}):
 128         self.ecb = ecb
 129         self.force_env = force_env
 130     
 131     def get(self, key, default=None):
 132         try:
 133             return self.force_env[key]
 134         except KeyError:
 135             try:
 136                 return self[key]
 137             except KeyError:
 138                 val = self.ecb.GetServerVariable(key, default)
 139                 if val:
 140                     #debug('add key %s' % key)
 141                     self[key] = val
 142                 return val
 143     
 144     def __contains__(self, key):
 145         #debug('%s in env?' % key)
 146         haskey = self.force_env.has_key(key) or self.has_key(key)
 147         if haskey:
 148             #debug('haskey')
 149             return True
 150         else:
 151             val = self.ecb.GetServerVariable(key, None)
 152             if val:
 153                 self[key] = val
 154                 #debug('getkey')
 155                 return True
 156             else:
 157                 #debug('nokey')
 158                 return False
 159 
 160 class RequestISAPI( RequestBase ):
 161     
 162     def __init__(self, ecb=None):
 163         """ Sets the common Request members by parsing an ISAPI extension
 164             environment
 165         """
 166         self.buffer = []
 167         self.ecb = ecb
 168         env = self.env = EnvAdaptor(self.ecb)
 169         self.response = None
 170         sname = virtualPath
 171         
 172         # different from _setup_vars_from_std_env's implement
 173         env.force_env['SCRIPT_NAME'] = sname
 174         # Make sure http referer use only ascii (IE again)
 175         env.force_env['HTTP_REFERER'] = unicode(
 176             env.get('HTTP_REFERER', ''), 'ascii', 'replace').encode(
 177                 'ascii', 'replace')
 178         # not the same as _setup_vars_from_std_env believe
 179         env.force_env['PATH_INFO'] = wikiutil.decodeWindowsPath(
 180             ecb.PathInfo.replace(sname, '', 1)).encode("utf-8")
 181         # cgi.FieldStorage need this var, or will treat the environment as CGI.
 182         env['QUERY_STRING'] = env.get('QUERY_STRING', '')
 183         # _setup_vars_from_std_env doesn't deal with it
 184         ac = env.get('HTTP_ACCEPT_CHARSET', '')
 185         self.setAcceptedCharsets(ac)
 186         
 187         self._setup_vars_from_std_env(self.env)
 188 
 189         RequestBase.__init__(self)
 190 
 191         self.ret_code = None;
 192         
 193     def open_logs(self):
 194         # create log file for catching stderr output
 195         if not self.opened_logs: #IGNORE:E0203
 196             self.opened_logs = 1
 197             sys.stderr = open(os.path.join(self.cfg.data_dir, 'error.log'), 'at')
 198    
 199     def setup_args(self, form=None):
 200         sio = StringIO()
 201         ecb = self.ecb
 202         sio.write(ecb.AvailableData)
 203         rest = ecb.TotalBytes - sio.len
 204         if rest > 0:
 205             sio.write( ecb.ReadClient( rest ) )
 206         sio.seek(0)
 207         if self.ecb.Method.upper() == "POST":
 208             h = {'content-type': self.ecb.ContentType }
 209             form = cgi.FieldStorage(fp=sio, environ=self.env, headers=h)
 210         else:
 211             form = cgi.FieldStorage(fp=sio, environ=self.env)
 212         return self._setup_args_from_cgi_form(form)
 213     
 214     def read(self, n=None):
 215         print "Ignoring read", n
 216         
 217     def write(self, *data):
 218         """ Write to output stream.
 219         """
 220         self.buffer.extend(data)
 221 
 222     def flush(self):
 223         pass
 224     
 225     def setResponseCode(self, code, message=None):
 226         if not code:
 227             raise 'ERROR: response code is None!'
 228         self.response = str(code)
 229         if message != None:
 230             self.response += ' ' + message;
 231     
 232     def finish(self):
 233         RequestBase.finish(self)
 234         headers = '\r\n'.join(self.all_headers)
 235         response = self.getHeader('Status')
 236         if response:
 237             self.response = response       
 238         if not self.response: self.response = '200 Ok'
 239         self.ecb.SendResponseHeaders( self.response, headers )
 240         if headers.find('text/html') > 0:
 241             self.ecb.write( 
 242                 '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd><html>' )
 243         self.ecb.write('\r\n' * 2)
 244         self.ecb.write(self.encode(self.buffer))
 245         
 246     def getHeader(self,name):
 247         name = name.lower()+': '
 248         for x in self.all_headers:
 249             if x.lower().startswith(name):
 250                 return x[len(name):]
 251         return None
 252         
 253     # Accessors --------------------------------------------------------
 254     
 255     def getPathinfo(self):
 256         """ Return the remaining part of the URL. """
 257         pathinfo = self.path_info
 258 
 259         # Fix for bug in IIS/4.0
 260         if os.name == 'nt':
 261             scriptname = self.getScriptname()
 262             if pathinfo.startswith(scriptname):
 263                 pathinfo = pathinfo[len(scriptname):]
 264 
 265         return pathinfo
 266 
 267     # Headers ----------------------------------------------------------
 268     
 269     def setHttpHeader(self, header):
 270         self.user_headers.append(header)
 271 
 272     def http_headers(self, more_headers=[]):
 273         # Send only once
 274         if getattr(self, 'sent_headers', None):
 275             return
 276         
 277         self.sent_headers = 1
 278         
 279         have_ct = 0
 280         self.all_headers = []
 281         # send http headers
 282         for header in more_headers + getattr(self, 'user_headers', []):
 283             if header.lower().startswith("content-type:"):
 284                 # don't send content-type multiple times!
 285                 if have_ct: continue
 286                 have_ct = 1
 287             if type(header) is unicode:
 288                 header = header.encode('ascii')
 289             self.all_headers.append(header)
 290 
 291         if not have_ct:
 292             self.all_headers.append("Content-type: text/html;charset=%s" % config.charset)
 293         #from pprint import pformat
 294         #sys.stderr.write(pformat(more_headers))
 295         #sys.stderr.write(pformat(self.user_headers))
 296 
 297 # Post install hook for our entire script
 298 def PostInstall(params, options):
 299     print
 300     print "The MoinMoin ISAPI is installed."
 301     print "Point your browser to ",virtualPath,"to check it"
 302 
 303 if __name__=='__main__':
 304     # If run from the command-line, install ourselves.
 305     from isapi.install import *
 306     params = ISAPIParameters(PostInstall = PostInstall)
 307     # Setup the virtual directories - this is a list of directories our
 308     # extension uses - in this case only 1.
 309     # Each extension has a "script map" - this is the mapping of ISAPI
 310     # extensions.
 311     sm = [
 312         ScriptMapParams(Extension="*", Flags=0)
 313     ]
 314     vd = VirtualDirParameters(Name=virtualPath,
 315                               Description = Extension.__doc__,
 316                               ScriptMaps = sm,
 317                               ScriptMapUpdate = "replace"
 318                               )
 319     params.VirtualDirs = [vd]
 320     # Setup our custom option parser.
 321     from optparse import OptionParser
 322     parser = OptionParser('') # black usage, so isapi sets it.
 323     HandleCommandLine(params, opt_parser=parser)
 324         

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2006-03-14 00:54:15, 11.8 KB) [[attachment:MoinIIS.py]]
  • [get | view] (2007-04-03 08:04:21, 11.0 KB) [[attachment:MoinIIS_for_1.5.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.