Initial import to Tizen
[profile/ivi/python-twisted.git] / twisted / web / tap.py
1 # Copyright (c) Twisted Matrix Laboratories.
2 # See LICENSE for details.
3
4 """
5 Support for creating a service which runs a web server.
6 """
7
8 import os
9
10 # Twisted Imports
11 from twisted.web import server, static, twcgi, script, demo, distrib, wsgi
12 from twisted.internet import interfaces, reactor
13 from twisted.python import usage, reflect, threadpool
14 from twisted.spread import pb
15 from twisted.application import internet, service, strports
16
17
18 class Options(usage.Options):
19     """
20     Define the options accepted by the I{twistd web} plugin.
21     """
22     synopsis = "[web options]"
23
24     optParameters = [["port", "p", None, "strports description of the port to "
25                       "start the server on."],
26                      ["logfile", "l", None, "Path to web CLF (Combined Log Format) log file."],
27                      ["https", None, None, "Port to listen on for Secure HTTP."],
28                      ["certificate", "c", "server.pem", "SSL certificate to use for HTTPS. "],
29                      ["privkey", "k", "server.pem", "SSL certificate to use for HTTPS."],
30                      ]
31
32     optFlags = [["personal", "",
33                  "Instead of generating a webserver, generate a "
34                  "ResourcePublisher which listens on  the port given by "
35                  "--port, or ~/%s " % (distrib.UserDirectory.userSocketName,) +
36                  "if --port is not specified."],
37                 ["notracebacks", "n", "Do not display tracebacks in broken web pages. " +
38                  "Displaying tracebacks to users may be security risk!"],
39                 ]
40
41     compData = usage.Completions(
42                    optActions={"logfile" : usage.CompleteFiles("*.log"),
43                                "certificate" : usage.CompleteFiles("*.pem"),
44                                "privkey" : usage.CompleteFiles("*.pem")}
45                    )
46
47     longdesc = """\
48 This starts a webserver.  If you specify no arguments, it will be a
49 demo webserver that has the Test class from twisted.web.demo in it."""
50
51     def __init__(self):
52         usage.Options.__init__(self)
53         self['indexes'] = []
54         self['root'] = None
55
56
57     def opt_index(self, indexName):
58         """
59         Add the name of a file used to check for directory indexes.
60         [default: index, index.html]
61         """
62         self['indexes'].append(indexName)
63
64     opt_i = opt_index
65
66
67     def opt_user(self):
68         """
69         Makes a server with ~/public_html and ~/.twistd-web-pb support for
70         users.
71         """
72         self['root'] = distrib.UserDirectory()
73
74     opt_u = opt_user
75
76
77     def opt_path(self, path):
78         """
79         <path> is either a specific file or a directory to be set as the root
80         of the web server. Use this if you have a directory full of HTML, cgi,
81         epy, or rpy files or any other files that you want to be served up raw.
82         """
83         self['root'] = static.File(os.path.abspath(path))
84         self['root'].processors = {
85             '.cgi': twcgi.CGIScript,
86             '.epy': script.PythonScript,
87             '.rpy': script.ResourceScript,
88             }
89
90
91     def opt_processor(self, proc):
92         """
93         `ext=class' where `class' is added as a Processor for files ending
94         with `ext'.
95         """
96         if not isinstance(self['root'], static.File):
97             raise usage.UsageError("You can only use --processor after --path.")
98         ext, klass = proc.split('=', 1)
99         self['root'].processors[ext] = reflect.namedClass(klass)
100
101
102     def opt_class(self, className):
103         """
104         Create a Resource subclass with a zero-argument constructor.
105         """
106         classObj = reflect.namedClass(className)
107         self['root'] = classObj()
108
109
110     def opt_resource_script(self, name):
111         """
112         An .rpy file to be used as the root resource of the webserver.
113         """
114         self['root'] = script.ResourceScriptWrapper(name)
115
116
117     def opt_wsgi(self, name):
118         """
119         The FQPN of a WSGI application object to serve as the root resource of
120         the webserver.
121         """
122         pool = threadpool.ThreadPool()
123         reactor.callWhenRunning(pool.start)
124         reactor.addSystemEventTrigger('after', 'shutdown', pool.stop)
125         try:
126             application = reflect.namedAny(name)
127         except (AttributeError, ValueError):
128             raise usage.UsageError("No such WSGI application: %r" % (name,))
129         self['root'] = wsgi.WSGIResource(reactor, pool, application)
130
131
132     def opt_mime_type(self, defaultType):
133         """
134         Specify the default mime-type for static files.
135         """
136         if not isinstance(self['root'], static.File):
137             raise usage.UsageError("You can only use --mime_type after --path.")
138         self['root'].defaultType = defaultType
139     opt_m = opt_mime_type
140
141
142     def opt_allow_ignore_ext(self):
143         """
144         Specify whether or not a request for 'foo' should return 'foo.ext'
145         """
146         if not isinstance(self['root'], static.File):
147             raise usage.UsageError("You can only use --allow_ignore_ext "
148                                    "after --path.")
149         self['root'].ignoreExt('*')
150
151
152     def opt_ignore_ext(self, ext):
153         """
154         Specify an extension to ignore.  These will be processed in order.
155         """
156         if not isinstance(self['root'], static.File):
157             raise usage.UsageError("You can only use --ignore_ext "
158                                    "after --path.")
159         self['root'].ignoreExt(ext)
160
161
162     def postOptions(self):
163         """
164         Set up conditional defaults and check for dependencies.
165
166         If SSL is not available but an HTTPS server was configured, raise a
167         L{UsageError} indicating that this is not possible.
168
169         If no server port was supplied, select a default appropriate for the
170         other options supplied.
171         """
172         if self['https']:
173             try:
174                 from twisted.internet.ssl import DefaultOpenSSLContextFactory
175             except ImportError:
176                 raise usage.UsageError("SSL support not installed")
177         if self['port'] is None:
178             if self['personal']:
179                 path = os.path.expanduser(
180                     os.path.join('~', distrib.UserDirectory.userSocketName))
181                 self['port'] = 'unix:' + path
182             else:
183                 self['port'] = 'tcp:8080'
184
185
186
187 def makePersonalServerFactory(site):
188     """
189     Create and return a factory which will respond to I{distrib} requests
190     against the given site.
191
192     @type site: L{twisted.web.server.Site}
193     @rtype: L{twisted.internet.protocol.Factory}
194     """
195     return pb.PBServerFactory(distrib.ResourcePublisher(site))
196
197
198
199 def makeService(config):
200     s = service.MultiService()
201     if config['root']:
202         root = config['root']
203         if config['indexes']:
204             config['root'].indexNames = config['indexes']
205     else:
206         # This really ought to be web.Admin or something
207         root = demo.Test()
208
209     if isinstance(root, static.File):
210         root.registry.setComponent(interfaces.IServiceCollection, s)
211
212     if config['logfile']:
213         site = server.Site(root, logPath=config['logfile'])
214     else:
215         site = server.Site(root)
216
217     site.displayTracebacks = not config["notracebacks"]
218
219     if config['personal']:
220         personal = strports.service(
221             config['port'], makePersonalServerFactory(site))
222         personal.setServiceParent(s)
223     else:
224         if config['https']:
225             from twisted.internet.ssl import DefaultOpenSSLContextFactory
226             i = internet.SSLServer(int(config['https']), site,
227                           DefaultOpenSSLContextFactory(config['privkey'],
228                                                        config['certificate']))
229             i.setServiceParent(s)
230         strports.service(config['port'], site).setServiceParent(s)
231
232     return s