1
by Jesse Andrews
initial commit |
1 |
# -*- test-case-name: twisted.web.
|
2 |
# Copyright (c) 2001-2009 Twisted Matrix Laboratories.
|
|
3 |
# See LICENSE for details.
|
|
4 |
||
5 |
"""
|
|
6 |
I am a virtual hosts implementation.
|
|
7 |
"""
|
|
8 |
||
9 |
# Twisted Imports
|
|
10 |
from twisted.python import roots |
|
11 |
from twisted.web import resource |
|
12 |
||
13 |
||
14 |
class VirtualHostCollection(roots.Homogenous): |
|
15 |
"""Wrapper for virtual hosts collection.
|
|
16 |
||
17 |
This exists for configuration purposes.
|
|
18 |
"""
|
|
19 |
entityType = resource.Resource |
|
20 |
||
21 |
def __init__(self, nvh): |
|
22 |
self.nvh = nvh |
|
23 |
||
24 |
def listStaticEntities(self): |
|
25 |
return self.nvh.hosts.items() |
|
26 |
||
27 |
def getStaticEntity(self, name): |
|
28 |
return self.nvh.hosts.get(self) |
|
29 |
||
30 |
def reallyPutEntity(self, name, entity): |
|
31 |
self.nvh.addHost(name, entity) |
|
32 |
||
33 |
def delEntity(self, name): |
|
34 |
self.nvh.removeHost(name) |
|
35 |
||
36 |
||
37 |
class NameVirtualHost(resource.Resource): |
|
38 |
"""I am a resource which represents named virtual hosts.
|
|
39 |
"""
|
|
40 |
||
41 |
default = None |
|
42 |
||
43 |
def __init__(self): |
|
44 |
"""Initialize.
|
|
45 |
"""
|
|
46 |
resource.Resource.__init__(self) |
|
47 |
self.hosts = {} |
|
48 |
||
49 |
def listStaticEntities(self): |
|
50 |
return resource.Resource.listStaticEntities(self) + [("Virtual Hosts", VirtualHostCollection(self))] |
|
51 |
||
52 |
def getStaticEntity(self, name): |
|
53 |
if name == "Virtual Hosts": |
|
54 |
return VirtualHostCollection(self) |
|
55 |
else: |
|
56 |
return resource.Resource.getStaticEntity(self, name) |
|
57 |
||
58 |
def addHost(self, name, resrc): |
|
59 |
"""Add a host to this virtual host.
|
|
60 |
||
61 |
This will take a host named `name', and map it to a resource
|
|
62 |
`resrc'. For example, a setup for our virtual hosts would be::
|
|
63 |
||
64 |
nvh.addHost('divunal.com', divunalDirectory)
|
|
65 |
nvh.addHost('www.divunal.com', divunalDirectory)
|
|
66 |
nvh.addHost('twistedmatrix.com', twistedMatrixDirectory)
|
|
67 |
nvh.addHost('www.twistedmatrix.com', twistedMatrixDirectory)
|
|
68 |
"""
|
|
69 |
self.hosts[name] = resrc |
|
70 |
||
71 |
def removeHost(self, name): |
|
72 |
"""Remove a host."""
|
|
73 |
del self.hosts[name] |
|
74 |
||
75 |
def _getResourceForRequest(self, request): |
|
76 |
"""(Internal) Get the appropriate resource for the given host.
|
|
77 |
"""
|
|
78 |
hostHeader = request.getHeader('host') |
|
79 |
if hostHeader == None: |
|
80 |
return self.default or resource.NoResource() |
|
81 |
else: |
|
82 |
host = hostHeader.lower().split(':', 1)[0] |
|
83 |
return (self.hosts.get(host, self.default) |
|
84 |
or resource.NoResource("host %s not in vhost map" % repr(host))) |
|
85 |
||
86 |
def render(self, request): |
|
87 |
"""Implementation of resource.Resource's render method.
|
|
88 |
"""
|
|
89 |
resrc = self._getResourceForRequest(request) |
|
90 |
return resrc.render(request) |
|
91 |
||
92 |
def getChild(self, path, request): |
|
93 |
"""Implementation of resource.Resource's getChild method.
|
|
94 |
"""
|
|
95 |
resrc = self._getResourceForRequest(request) |
|
96 |
if resrc.isLeaf: |
|
97 |
request.postpath.insert(0,request.prepath.pop(-1)) |
|
98 |
return resrc |
|
99 |
else: |
|
100 |
return resrc.getChildWithDefault(path, request) |
|
101 |
||
102 |
class _HostResource(resource.Resource): |
|
103 |
||
104 |
def getChild(self, path, request): |
|
105 |
if ':' in path: |
|
106 |
host, port = path.split(':', 1) |
|
107 |
port = int(port) |
|
108 |
else: |
|
109 |
host, port = path, 80 |
|
110 |
request.setHost(host, port) |
|
111 |
prefixLen = 3+request.isSecure()+4+len(path)+len(request.prepath[-3]) |
|
112 |
request.path = '/'+'/'.join(request.postpath) |
|
113 |
request.uri = request.uri[prefixLen:] |
|
114 |
del request.prepath[:3] |
|
115 |
return request.site.getResourceFor(request) |
|
116 |
||
117 |
||
118 |
class VHostMonsterResource(resource.Resource): |
|
119 |
||
120 |
"""
|
|
121 |
Use this to be able to record the hostname and method (http vs. https)
|
|
122 |
in the URL without disturbing your web site. If you put this resource
|
|
123 |
in a URL http://foo.com/bar then requests to
|
|
124 |
http://foo.com/bar/http/baz.com/something will be equivalent to
|
|
125 |
http://foo.com/something, except that the hostname the request will
|
|
126 |
appear to be accessing will be "baz.com". So if "baz.com" is redirecting
|
|
127 |
all requests for to foo.com, while foo.com is inaccessible from the outside,
|
|
128 |
then redirect and url generation will work correctly
|
|
129 |
"""
|
|
130 |
def getChild(self, path, request): |
|
131 |
if path == 'http': |
|
132 |
request.isSecure = lambda: 0 |
|
133 |
elif path == 'https': |
|
134 |
request.isSecure = lambda: 1 |
|
135 |
return _HostResource() |