~landscape/zope3/newer-from-ztk

« back to all changes in this revision

Viewing changes to src/twisted/web/proxy.py

  • Committer: Thomas Hervé
  • Date: 2009-07-08 13:52:04 UTC
  • Revision ID: thomas@canonical.com-20090708135204-df5eesrthifpylf8
Remove twisted copy

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (c) 2001-2004 Twisted Matrix Laboratories.
2
 
# See LICENSE for details.
3
 
 
4
 
 
5
 
"""Simplistic HTTP proxy support.
6
 
 
7
 
This comes in two main variants - the Proxy and the ReverseProxy.
8
 
 
9
 
When a Proxy is in use, a browser trying to connect to a server (say,
10
 
www.yahoo.com) will be intercepted by the Proxy, and the proxy will covertly
11
 
connect to the server, and return the result.
12
 
 
13
 
When a ReverseProxy is in use, the client connects directly to the ReverseProxy
14
 
(say, www.yahoo.com) which farms off the request to one of a pool of servers,
15
 
and returns the result.
16
 
 
17
 
Normally, a Proxy is used on the client end of an Internet connection, while a
18
 
ReverseProxy is used on the server end.
19
 
"""
20
 
 
21
 
# twisted imports
22
 
from twisted.internet import reactor, protocol
23
 
from twisted.web import resource, server, http
24
 
 
25
 
# system imports
26
 
import urlparse
27
 
 
28
 
 
29
 
class ProxyClient(http.HTTPClient):
30
 
    """Used by ProxyClientFactory to implement a simple web proxy."""
31
 
 
32
 
    def __init__(self, command, rest, version, headers, data, father):
33
 
        self.father = father
34
 
        self.command = command
35
 
        self.rest = rest
36
 
        if headers.has_key("proxy-connection"):
37
 
            del headers["proxy-connection"]
38
 
        headers["connection"] = "close"
39
 
        self.headers = headers
40
 
        self.data = data
41
 
 
42
 
    def connectionMade(self):
43
 
        self.sendCommand(self.command, self.rest)
44
 
        for header, value in self.headers.items():
45
 
            self.sendHeader(header, value)
46
 
        self.endHeaders()
47
 
        self.transport.write(self.data)
48
 
 
49
 
    def handleStatus(self, version, code, message):
50
 
        self.father.transport.write("%s %s %s\r\n" % (version, code, message))
51
 
 
52
 
    def handleHeader(self, key, value):
53
 
        self.father.transport.write("%s: %s\r\n" % (key, value))
54
 
 
55
 
    def handleEndHeaders(self):
56
 
        self.father.transport.write("\r\n")
57
 
    
58
 
    def handleResponsePart(self, buffer):
59
 
        self.father.transport.write(buffer)
60
 
 
61
 
    def handleResponseEnd(self):
62
 
        self.transport.loseConnection()
63
 
        self.father.channel.transport.loseConnection()
64
 
 
65
 
 
66
 
class ProxyClientFactory(protocol.ClientFactory):
67
 
    """Used by ProxyRequest to implement a simple web proxy."""
68
 
 
69
 
    protocol = ProxyClient
70
 
 
71
 
    def __init__(self, command, rest, version, headers, data, father):
72
 
        self.father = father
73
 
        self.command = command
74
 
        self.rest = rest
75
 
        self.headers = headers
76
 
        self.data = data
77
 
        self.version = version
78
 
 
79
 
 
80
 
    def buildProtocol(self, addr):
81
 
        return self.protocol(self.command, self.rest, self.version,
82
 
                             self.headers, self.data, self.father)
83
 
 
84
 
 
85
 
    def clientConnectionFailed(self, connector, reason):
86
 
        self.father.transport.write("HTTP/1.0 501 Gateway error\r\n")
87
 
        self.father.transport.write("Content-Type: text/html\r\n")
88
 
        self.father.transport.write("\r\n")
89
 
        self.father.transport.write('''<H1>Could not connect</H1>''')
90
 
 
91
 
 
92
 
 
93
 
class ProxyRequest(http.Request):
94
 
    """Used by Proxy to implement a simple web proxy."""
95
 
 
96
 
    protocols = {'http': ProxyClientFactory}
97
 
    ports = {'http': 80}
98
 
 
99
 
    def process(self):
100
 
        parsed = urlparse.urlparse(self.uri)
101
 
        protocol = parsed[0]
102
 
        host = parsed[1]
103
 
        port = self.ports[protocol]
104
 
        if ':' in host:
105
 
            host, port = host.split(':')
106
 
            port = int(port)
107
 
        rest = urlparse.urlunparse(('','')+parsed[2:])
108
 
        if not rest:
109
 
            rest = rest+'/'
110
 
        class_ = self.protocols[protocol]
111
 
        headers = self.getAllHeaders().copy()
112
 
        if not headers.has_key('host'):
113
 
            headers['host'] = host
114
 
        self.content.seek(0, 0)
115
 
        s = self.content.read()
116
 
        clientFactory = class_(self.method, rest, self.clientproto, headers,
117
 
                               s, self)
118
 
        reactor.connectTCP(host, port, clientFactory)
119
 
 
120
 
 
121
 
class Proxy(http.HTTPChannel):
122
 
    """This class implements a simple web proxy.
123
 
 
124
 
    Since it inherits from twisted.protocols.http.HTTPChannel, to use it you
125
 
    should do something like this::
126
 
 
127
 
        from twisted.web import http
128
 
        f = http.HTTPFactory()
129
 
        f.protocol = Proxy
130
 
 
131
 
    Make the HTTPFactory a listener on a port as per usual, and you have
132
 
    a fully-functioning web proxy!
133
 
    """
134
 
 
135
 
    requestFactory = ProxyRequest
136
 
 
137
 
 
138
 
class ReverseProxyRequest(http.Request):
139
 
    """Used by ReverseProxy to implement a simple reverse proxy."""
140
 
 
141
 
    def process(self):
142
 
        self.received_headers['host'] = self.factory.host
143
 
        clientFactory = ProxyClientFactory(self.method, self.uri,
144
 
                                            self.clientproto,
145
 
                                            self.getAllHeaders(), 
146
 
                                            self.content.read(), self)
147
 
        reactor.connectTCP(self.factory.host, self.factory.port,
148
 
                           clientFactory)
149
 
 
150
 
class ReverseProxy(http.HTTPChannel):
151
 
    """Implements a simple reverse proxy.
152
 
 
153
 
    For details of usage, see the file examples/proxy.py"""
154
 
 
155
 
    requestFactory = ReverseProxyRequest
156
 
 
157
 
 
158
 
class ReverseProxyResource(resource.Resource):
159
 
    """Resource that renders the results gotten from another server
160
 
 
161
 
    Put this resource in the tree to cause everything below it to be relayed
162
 
    to a different server.
163
 
    """
164
 
 
165
 
    def __init__(self, host, port, path):
166
 
        resource.Resource.__init__(self)
167
 
        self.host = host
168
 
        self.port = port
169
 
        self.path = path
170
 
 
171
 
    def getChild(self, path, request):
172
 
        return ReverseProxyResource(self.host, self.port, self.path+'/'+path)
173
 
 
174
 
    def render(self, request):
175
 
        request.received_headers['host'] = self.host
176
 
        request.content.seek(0, 0)
177
 
        qs = urlparse.urlparse(request.uri)[4]
178
 
        if qs:
179
 
            rest = self.path + '?' + qs
180
 
        else:
181
 
            rest = self.path
182
 
        clientFactory = ProxyClientFactory(request.method, rest, 
183
 
                                     request.clientproto, 
184
 
                                     request.getAllHeaders(),
185
 
                                     request.content.read(),
186
 
                                     request)
187
 
        reactor.connectTCP(self.host, self.port, clientFactory)
188
 
        return server.NOT_DONE_YET