1 # This is a sample ISAPI extension written in Python. 2 3 # This is like the other 'redirector' samples, but uses asnch IO when writing 4 # back to the client (it does *not* use asynch io talking to the remote 5 # server!) 6 7 import sys 8 import urllib.error 9 import urllib.parse 10 import urllib.request 11 12 from isapi import isapicon, threaded_extension 13 14 # sys.isapidllhandle will exist when we are loaded by the IIS framework. 15 # In this case we redirect our output to the win32traceutil collector. 16 if hasattr(sys, "isapidllhandle"): 17 import win32traceutil 18 19 # The site we are proxying. 20 proxy = "https://www.python.org" 21 22 # We synchronously read chunks of this size then asynchronously write them. 23 CHUNK_SIZE = 8192 24 25 26 # The callback made when IIS completes the asynch write. 27 def io_callback(ecb, fp, cbIO, errcode): 28 print("IO callback", ecb, fp, cbIO, errcode) 29 chunk = fp.read(CHUNK_SIZE) 30 if chunk: 31 ecb.WriteClient(chunk, isapicon.HSE_IO_ASYNC) 32 # and wait for the next callback to say this chunk is done. 33 else: 34 # eof - say we are complete. 35 fp.close() 36 ecb.DoneWithSession() 37 38 39 # The ISAPI extension - handles all requests in the site. 40 class Extension(threaded_extension.ThreadPoolExtension): 41 "Python sample proxy server - asynch version." 42 43 def Dispatch(self, ecb): 44 print('IIS dispatching "{}"'.format(ecb.GetServerVariable("URL"))) 45 url = ecb.GetServerVariable("URL") 46 47 new_url = proxy + url 48 print("Opening %s" % new_url) 49 fp = urllib.request.urlopen(new_url) 50 headers = fp.info() 51 ecb.SendResponseHeaders("200 OK", str(headers) + "\r\n", False) 52 # now send the first chunk asynchronously 53 ecb.ReqIOCompletion(io_callback, fp) 54 chunk = fp.read(CHUNK_SIZE) 55 if chunk: 56 ecb.WriteClient(chunk, isapicon.HSE_IO_ASYNC) 57 return isapicon.HSE_STATUS_PENDING 58 # no data - just close things now. 59 ecb.DoneWithSession() 60 return isapicon.HSE_STATUS_SUCCESS 61 62 63 # The entry points for the ISAPI extension. 64 def __ExtensionFactory__(): 65 return Extension() 66 67 68 if __name__ == "__main__": 69 # If run from the command-line, install ourselves. 70 from isapi.install import * 71 72 params = ISAPIParameters() 73 # Setup the virtual directories - this is a list of directories our 74 # extension uses - in this case only 1. 75 # Each extension has a "script map" - this is the mapping of ISAPI 76 # extensions. 77 sm = [ScriptMapParams(Extension="*", Flags=0)] 78 vd = VirtualDirParameters( 79 Name="/", 80 Description=Extension.__doc__, 81 ScriptMaps=sm, 82 ScriptMapUpdate="replace", 83 ) 84 params.VirtualDirs = [vd] 85 HandleCommandLine(params) 86