~certify-web-dev/twisted/certify-trunk

« back to all changes in this revision

Viewing changes to twisted/web2/tap.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-01-17 14:52:35 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 etch)
  • Revision ID: james.westby@ubuntu.com-20070117145235-btmig6qfmqfen0om
Tags: 2.5.0-0ubuntu1
New upstream version, compatible with python2.5.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
import os
 
2
from zope.interface import implements
 
3
 
 
4
from twisted.python import usage, reflect
 
5
from twisted.application import internet, service, strports
 
6
from twisted.scripts.mktap import IServiceMaker
 
7
from twisted.plugin import IPlugin
 
8
 
 
9
from twisted.web2 import static, iweb, log, server, channel, vhost
 
10
from twisted.web2.dav import static as dav_static
 
11
 
 
12
class Options(usage.Options):
 
13
    optParameters = [["port", "p", "8080",
 
14
                      "Port to start the server on."],
 
15
                     ["logfile", "l", None,
 
16
                      ("Common Access Logging Format file to write to "
 
17
                       "if unspecified access log information will be "
 
18
                       "written to the standard twisted log file.")],
 
19
                     ["https", None, None,
 
20
                      "Port to listen on for Secure HTTP."],
 
21
                     ["certificate", "c", "server.pem",
 
22
                      "SSL certificate to use for HTTPS."],
 
23
                     ["privkey", "k", "server.pem",
 
24
                      "SSL certificate to use for HTTPS."]]
 
25
    
 
26
    zsh_actions = {"certificate" : "_files -g '*.pem'",
 
27
                   "privkey" : "_files -g '*.pem'"}
 
28
    
 
29
    longdesc = """\
 
30
This creates a web2.tap file that can be used by twistd.
 
31
 
 
32
Basic Examples:
 
33
 
 
34
To serve a static directory or file:
 
35
 
 
36
    mktap web2 --path=/tmp/
 
37
 
 
38
To serve a dav collection:
 
39
 
 
40
    mktap web2 --dav=/tmp/
 
41
 
 
42
To serve a dynamic resource:
 
43
 
 
44
    mktap web2 --class=fully.qualified.ClassName
 
45
 
 
46
To serve a directory of the form:
 
47
 
 
48
    /var/www/domain1/
 
49
    /var/www/domain2/
 
50
 
 
51
    mktap web2 --vhost-path=/var/www/
 
52
 
 
53
All the above options are incompatible as they all specify the
 
54
root resource.  However you can use the following options in
 
55
conjunction with --vhost-path
 
56
 
 
57
To serve a specific host name as a static file:
 
58
 
 
59
    mktap web2 --vhost-static=domain3=/some/other/root/domain3
 
60
 
 
61
Or to serve a specific host name as a dynamic resource:
 
62
 
 
63
    mktap web2 --vhost-class=domain4=fully.qualified.ClassName
 
64
 
 
65
"""
 
66
 
 
67
    def __init__(self):
 
68
        usage.Options.__init__(self)
 
69
        self['indexes'] = []
 
70
        self['root'] = None
 
71
        
 
72
    def opt_index(self, indexName):
 
73
        """Add the name of a file used to check for directory indexes.
 
74
        [default: index, index.html]
 
75
        """
 
76
        self['indexes'].append(indexName)
 
77
    
 
78
    opt_i = opt_index
 
79
 
 
80
    def opt_path(self, path):
 
81
        """A path that will be used to serve the root resource as a raw file
 
82
        or directory.
 
83
        """
 
84
 
 
85
        if self['root']:
 
86
            raise usage.UsageError("You may only have one root resource.")
 
87
 
 
88
        self['root'] = static.File(os.path.abspath(path))
 
89
 
 
90
    def opt_processor(self, proc):
 
91
        """`ext=class' where `class' is added as a Processor for files ending
 
92
        with `ext'.
 
93
        """
 
94
        if not isinstance(self['root'], static.File):
 
95
            raise usage.UsageError("You can only use --processor after --path.")
 
96
        ext, klass = proc.split('=', 1)
 
97
        self['root'].processors[ext] = reflect.namedClass(klass)
 
98
 
 
99
    def opt_class(self, className):
 
100
        """A class that will be used to serve the root resource.  Must implement twisted.web2.iweb.IResource and take no arguments.
 
101
        """
 
102
        if self['root']:
 
103
            raise usage.UsageError("You may only have one root resource.")
 
104
        
 
105
        classObj = reflect.namedClass(className)
 
106
        self['root'] = iweb.IResource(classObj())
 
107
 
 
108
    def opt_allow_ignore_ext(self):
 
109
        """Specify whether or not a request for 'foo' should return 'foo.ext'"""
 
110
        if not isinstance(self['root'], static.File):
 
111
            raise usage.UsageError("You can only use --allow_ignore_ext "
 
112
                                   "after --path.")
 
113
        self['root'].ignoreExt('*')
 
114
 
 
115
    def opt_ignore_ext(self, ext):
 
116
        """Specify an extension to ignore.  These will be processed in order.
 
117
        """
 
118
        if not isinstance(self['root'], static.File):
 
119
            raise usage.UsageError("You can only use --ignore_ext "
 
120
                                   "after --path.")
 
121
        self['root'].ignoreExt(ext)
 
122
 
 
123
    def opt_mimetype(self, mimetype):
 
124
        """Mapping from file extension to MIME Type in the form of 'ext=type'.
 
125
        Example: html=text/html
 
126
        """
 
127
 
 
128
        if not isinstance(self['root'], static.File):
 
129
            raise usage.UsageError("You can only use --mimetype "
 
130
                                   "after --path.")
 
131
 
 
132
        ext, mimetype = mimetype.split('=', 1)
 
133
 
 
134
        # this is really gross, there should be a public api for this.
 
135
        
 
136
        self['root']._sharedContentTypes.update({ext: mimetype})
 
137
 
 
138
    def opt_vhost_path(self, path):
 
139
        """Specify a directory to use for automatic named virtual hosts.
 
140
        It is assumed that this directory contains a series of
 
141
        subdirectories each representing a virtual host domain name
 
142
        and containing the files to be served at that domain.
 
143
        """
 
144
        
 
145
        if self['root']:
 
146
            if not isintance(self['root'], vhost.NameVirtualHost):
 
147
                raise usage.UsageError("You may only have one root resource")
 
148
        else:
 
149
            self['root'] = vhost.NameVirtualHost()
 
150
 
 
151
        path = os.path.abspath(path)
 
152
        
 
153
        for name in os.listdir(path):
 
154
            fullname = os.path.join(path, name)
 
155
            self['root'].addHost(name,
 
156
                                 static.File(fullname))
 
157
 
 
158
    def opt_vhost_static(self, virtualHost):
 
159
        """Specify a virtual host in the form of domain=path to be served as
 
160
        raw directory or file.
 
161
        """
 
162
        if (self['root'] and not \
 
163
            isinstance(self['root'], vhost.NameVirtualHost)):
 
164
 
 
165
            raise usage.UsageError("You can only use --vhost-static alone "
 
166
                                   "or with --vhost-class and --vhost-path")
 
167
 
 
168
        domain, path = virtualHost.split('=', 1)
 
169
 
 
170
        if not self['root']:
 
171
            self['root'] = vhost.NameVirtualHost()
 
172
 
 
173
        self['root'].addHost(domain, static.File(os.path.abspath(path)))
 
174
    
 
175
    def opt_vhost_class(self, virtualHost):
 
176
        """Specify a virtual host in the form of domain=class,
 
177
        where class can be adapted to an iweb.IResource and has a
 
178
        zero-argument constructor.
 
179
        """
 
180
        if (self['root'] and not \
 
181
            isinstance(self['root'], vhost.NameVirtualHost)):
 
182
 
 
183
            raise usage.UsageError("You can not use --vhost-class with "
 
184
                                   "--path or --class.")
 
185
 
 
186
        domain, className = virtualHost.split('=', 1)
 
187
 
 
188
        if not self['root']:
 
189
            self['root'] = vhost.NameVirtualHost()
 
190
 
 
191
        classObj = reflect.namedClass(className)
 
192
        self['root'].addHost(domain, iweb.IResource(classObj()))
 
193
 
 
194
    def opt_vhost_dav(self, virtualHost):
 
195
        """Specify a virtual host in the form of domain=path,
 
196
        to have path served as a DAV collection at the root of
 
197
        domain
 
198
        """
 
199
                
 
200
        if (self['root'] and not \
 
201
            isinstance(self['root'], vhost.NameVirtualHost)):
 
202
 
 
203
            raise usage.UsageError("You can only use --vhost-static alone "
 
204
                                   "or with --vhost-class and --vhost-path")
 
205
 
 
206
        domain, path = virtualHost.split('=', 1)
 
207
 
 
208
        if not self['root']:
 
209
            self['root'] = vhost.NameVirtualHost()
 
210
 
 
211
        self['root'].addHost(domain, dav_static.DAVFile(os.path.abspath(path)))
 
212
 
 
213
    def opt_dav(self, path):
 
214
        """A path that will be used to serve the root resource as a DAV Collection.
 
215
        """
 
216
 
 
217
        if self['root']:
 
218
            raise usage.UsageError("You may only have one root resource")
 
219
        
 
220
        self['root'] = dav_static.DAVFile(os.path.abspath(path))
 
221
    
 
222
    def postOptions(self):
 
223
        if self['https']:
 
224
            try:
 
225
                from twisted.internet.ssl import DefaultOpenSSLContextFactory
 
226
            except ImportError:
 
227
                raise usage.UsageError("SSL support not installed")
 
228
 
 
229
 
 
230
class Web2Service(service.MultiService):
 
231
    def __init__(self, logObserver):
 
232
        self.logObserver = logObserver
 
233
        service.MultiService.__init__(self)
 
234
 
 
235
    def startService(self):
 
236
        service.MultiService.startService(self)
 
237
        self.logObserver.start()
 
238
 
 
239
    def stopService(self):
 
240
        service.MultiService.stopService(self)
 
241
        self.logObserver.stop()
 
242
 
 
243
 
 
244
def makeService(config):
 
245
    if config['logfile']:
 
246
        logObserver = log.FileAccessLoggingObserver(config['logfile'])
 
247
    else:
 
248
        logObserver = log.DefaultCommonAccessLoggingObserver()
 
249
 
 
250
    if config['root']:
 
251
        if config['indexes']:
 
252
            config['root'].indexNames = config['indexes']
 
253
            
 
254
        root = log.LogWrapperResource(config['root'])
 
255
 
 
256
 
 
257
    s = Web2Service(logObserver)
 
258
 
 
259
    site = server.Site(root)
 
260
    chan = channel.HTTPFactory(site)
 
261
    
 
262
    if config['https']:
 
263
        from twisted.internet.ssl import DefaultOpenSSLContextFactory
 
264
        i = internet.SSLServer(int(config['https']), chan,
 
265
                               DefaultOpenSSLContextFactory(config['privkey'],
 
266
                                                            config['certificate']))
 
267
        i.setServiceParent(s)
 
268
        
 
269
    strports.service(config['port'], chan
 
270
                     ).setServiceParent(s)
 
271
 
 
272
    return s