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