test.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. # This extension is used mainly for testing purposes - it is not
  2. # designed to be a simple sample, but instead is a hotch-potch of things
  3. # that attempts to exercise the framework.
  4. from isapi import isapicon
  5. from isapi.simple import SimpleExtension
  6. import sys, os, stat
  7. if hasattr(sys, "isapidllhandle"):
  8. import win32traceutil
  9. # We use the same reload support as 'advanced.py' demonstrates.
  10. from isapi import InternalReloadException
  11. import win32event, win32file, winerror, win32con, threading
  12. # A watcher thread that checks for __file__ changing.
  13. # When it detects it, it simply sets "change_detected" to true.
  14. class ReloadWatcherThread(threading.Thread):
  15. def __init__(self):
  16. self.change_detected = False
  17. self.filename = __file__
  18. if self.filename.endswith("c") or self.filename.endswith("o"):
  19. self.filename = self.filename[:-1]
  20. self.handle = win32file.FindFirstChangeNotification(
  21. os.path.dirname(self.filename),
  22. False, # watch tree?
  23. win32con.FILE_NOTIFY_CHANGE_LAST_WRITE)
  24. threading.Thread.__init__(self)
  25. def run(self):
  26. last_time = os.stat(self.filename)[stat.ST_MTIME]
  27. while 1:
  28. try:
  29. rc = win32event.WaitForSingleObject(self.handle,
  30. win32event.INFINITE)
  31. win32file.FindNextChangeNotification(self.handle)
  32. except win32event.error as details:
  33. # handle closed - thread should terminate.
  34. if details.winerror != winerror.ERROR_INVALID_HANDLE:
  35. raise
  36. break
  37. this_time = os.stat(self.filename)[stat.ST_MTIME]
  38. if this_time != last_time:
  39. print("Detected file change - flagging for reload.")
  40. self.change_detected = True
  41. last_time = this_time
  42. def stop(self):
  43. win32file.FindCloseChangeNotification(self.handle)
  44. def TransmitFileCallback(ecb, hFile, cbIO, errCode):
  45. print("Transmit complete!")
  46. ecb.close()
  47. # The ISAPI extension - handles requests in our virtual dir, and sends the
  48. # response to the client.
  49. class Extension(SimpleExtension):
  50. "Python test Extension"
  51. def __init__(self):
  52. self.reload_watcher = ReloadWatcherThread()
  53. self.reload_watcher.start()
  54. def HttpExtensionProc(self, ecb):
  55. # NOTE: If you use a ThreadPoolExtension, you must still perform
  56. # this check in HttpExtensionProc - raising the exception from
  57. # The "Dispatch" method will just cause the exception to be
  58. # rendered to the browser.
  59. if self.reload_watcher.change_detected:
  60. print("Doing reload")
  61. raise InternalReloadException
  62. if ecb.GetServerVariable("UNICODE_URL").endswith("test.py"):
  63. file_flags = win32con.FILE_FLAG_SEQUENTIAL_SCAN | win32con.FILE_FLAG_OVERLAPPED
  64. hfile = win32file.CreateFile(__file__, win32con.GENERIC_READ,
  65. 0, None, win32con.OPEN_EXISTING,
  66. file_flags, None)
  67. flags = isapicon.HSE_IO_ASYNC | isapicon.HSE_IO_DISCONNECT_AFTER_SEND | \
  68. isapicon.HSE_IO_SEND_HEADERS
  69. # We pass hFile to the callback simply as a way of keeping it alive
  70. # for the duration of the transmission
  71. try:
  72. ecb.TransmitFile(TransmitFileCallback, hfile,
  73. int(hfile),
  74. "200 OK",
  75. 0, 0, None, None, flags)
  76. except:
  77. # Errors keep this source file open!
  78. hfile.Close()
  79. raise
  80. else:
  81. # default response
  82. ecb.SendResponseHeaders("200 OK", "Content-Type: text/html\r\n\r\n", 0)
  83. print("<HTML><BODY>", file=ecb)
  84. print("The root of this site is at", ecb.MapURLToPath("/"), file=ecb)
  85. print("</BODY></HTML>", file=ecb)
  86. ecb.close()
  87. return isapicon.HSE_STATUS_SUCCESS
  88. def TerminateExtension(self, status):
  89. self.reload_watcher.stop()
  90. # The entry points for the ISAPI extension.
  91. def __ExtensionFactory__():
  92. return Extension()
  93. # Our special command line customization.
  94. # Pre-install hook for our virtual directory.
  95. def PreInstallDirectory(params, options):
  96. # If the user used our special '--description' option,
  97. # then we override our default.
  98. if options.description:
  99. params.Description = options.description
  100. # Post install hook for our entire script
  101. def PostInstall(params, options):
  102. print()
  103. print("The sample has been installed.")
  104. print("Point your browser to /PyISAPITest")
  105. # Handler for our custom 'status' argument.
  106. def status_handler(options, log, arg):
  107. "Query the status of something"
  108. print("Everything seems to be fine!")
  109. custom_arg_handlers = {"status": status_handler}
  110. if __name__=='__main__':
  111. # If run from the command-line, install ourselves.
  112. from isapi.install import *
  113. params = ISAPIParameters(PostInstall = PostInstall)
  114. # Setup the virtual directories - this is a list of directories our
  115. # extension uses - in this case only 1.
  116. # Each extension has a "script map" - this is the mapping of ISAPI
  117. # extensions.
  118. sm = [
  119. ScriptMapParams(Extension="*", Flags=0)
  120. ]
  121. vd = VirtualDirParameters(Name="PyISAPITest",
  122. Description = Extension.__doc__,
  123. ScriptMaps = sm,
  124. ScriptMapUpdate = "replace",
  125. # specify the pre-install hook.
  126. PreInstall = PreInstallDirectory
  127. )
  128. params.VirtualDirs = [vd]
  129. # Setup our custom option parser.
  130. from optparse import OptionParser
  131. parser = OptionParser('') # blank usage, so isapi sets it.
  132. parser.add_option("", "--description",
  133. action="store",
  134. help="custom description to use for the virtual directory")
  135. HandleCommandLine(params, opt_parser=parser,
  136. custom_arg_handlers = custom_arg_handlers)