We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add a --add-header flag to twist web
|[<img alt="alex's avatar" src="https://avatars.githubusercontent.com/u/772?s=50" width="50" height="50">](https://github.com/alex)| @alex reported|
|-|-|
|Trac ID|trac#9241|
|Type|enhancement|
|Created|2017-07-28 12:17:46Z|

This would make it easy to add headers to all responses. This is useful for things like "adding an HSTS header to all responses in a static web app, without writing code".

<details><summary>Searchable metadata</summary>

```
trac-id__9241 9241
type__enhancement enhancement
reporter__alex alex
priority__normal normal
milestone__None None
branch__ 
branch_author__ 
status__closed closed
resolution__fixed fixed
component__core core
keywords__None None
time__1501244266950695 1501244266950695
changetime__1501595055861628 1501595055861628
version__None None
owner__Alex Alex

```
</details>


--- END ISSUE ---

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

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/src/twisted/web/tap.py b/src/twisted/web/tap.py
--- a/src/twisted/web/tap.py
+++ b/src/twisted/web/tap.py
@@ -15,7 +15,7 @@
 from twisted.python import usage, reflect, threadpool
 from twisted.spread import pb
 from twisted.web import distrib
-from twisted.web import server, static, script, demo, wsgi
+from twisted.web import resource, server, static, script, demo, wsgi
 from twisted.web import twcgi
 
 
@@ -65,6 +65,7 @@
         usage.Options.__init__(self)
         self['indexes'] = []
         self['root'] = None
+        self['extraHeaders'] = []
 
 
     def opt_index(self, indexName):
@@ -174,6 +175,15 @@
         self['root'].ignoreExt(ext)
 
 
+    def opt_add_header(self, header):
+        """
+        Specify an additional header to be included in all responses. Specified
+        as "HeaderName: HeaderValue".
+        """
+        name, value = header.split(':', 1)
+        self['extraHeaders'].append((name.strip(), value.strip()))
+
+
     def postOptions(self):
         """
         Set up conditional defaults and check for dependencies.
@@ -211,6 +221,19 @@
 
 
 
+class _AddHeadersResource(resource.Resource):
+    def __init__(self, originalResource, headers):
+        self._originalResource = originalResource
+        self._headers = headers
+
+
+    def getChildWithDefault(self, name, request):
+        for k, v in self._headers:
+            request.responseHeaders.addRawHeader(k, v)
+        return self._originalResource.getChildWithDefault(name, request)
+
+
+
 def makeService(config):
     s = service.MultiService()
     if config['root']:
@@ -224,6 +247,9 @@
     if isinstance(root, static.File):
         root.registry.setComponent(interfaces.IServiceCollection, s)
 
+    if config['extraHeaders']:
+        root = _AddHeadersResource(root, config['extraHeaders'])
+
     if config['logfile']:
         site = server.Site(root, logPath=config['logfile'])
     else:

{"golden_diff": "diff --git a/src/twisted/web/tap.py b/src/twisted/web/tap.py\n--- a/src/twisted/web/tap.py\n+++ b/src/twisted/web/tap.py\n@@ -15,7 +15,7 @@\n from twisted.python import usage, reflect, threadpool\n from twisted.spread import pb\n from twisted.web import distrib\n-from twisted.web import server, static, script, demo, wsgi\n+from twisted.web import resource, server, static, script, demo, wsgi\n from twisted.web import twcgi\n \n \n@@ -65,6 +65,7 @@\n         usage.Options.__init__(self)\n         self['indexes'] = []\n         self['root'] = None\n+        self['extraHeaders'] = []\n \n \n     def opt_index(self, indexName):\n@@ -174,6 +175,15 @@\n         self['root'].ignoreExt(ext)\n \n \n+    def opt_add_header(self, header):\n+        \"\"\"\n+        Specify an additional header to be included in all responses. Specified\n+        as \"HeaderName: HeaderValue\".\n+        \"\"\"\n+        name, value = header.split(':', 1)\n+        self['extraHeaders'].append((name.strip(), value.strip()))\n+\n+\n     def postOptions(self):\n         \"\"\"\n         Set up conditional defaults and check for dependencies.\n@@ -211,6 +221,19 @@\n \n \n \n+class _AddHeadersResource(resource.Resource):\n+    def __init__(self, originalResource, headers):\n+        self._originalResource = originalResource\n+        self._headers = headers\n+\n+\n+    def getChildWithDefault(self, name, request):\n+        for k, v in self._headers:\n+            request.responseHeaders.addRawHeader(k, v)\n+        return self._originalResource.getChildWithDefault(name, request)\n+\n+\n+\n def makeService(config):\n     s = service.MultiService()\n     if config['root']:\n@@ -224,6 +247,9 @@\n     if isinstance(root, static.File):\n         root.registry.setComponent(interfaces.IServiceCollection, s)\n \n+    if config['extraHeaders']:\n+        root = _AddHeadersResource(root, config['extraHeaders'])\n+\n     if config['logfile']:\n         site = server.Site(root, logPath=config['logfile'])\n     else:\n", "issue": "Add a --add-header flag to twist web\n|[<img alt=\"alex's avatar\" src=\"https://avatars.githubusercontent.com/u/772?s=50\" width=\"50\" height=\"50\">](https://github.com/alex)| @alex reported|\n|-|-|\n|Trac ID|trac#9241|\n|Type|enhancement|\n|Created|2017-07-28 12:17:46Z|\n\nThis would make it easy to add headers to all responses. This is useful for things like \"adding an HSTS header to all responses in a static web app, without writing code\".\n\n<details><summary>Searchable metadata</summary>\n\n```\ntrac-id__9241 9241\ntype__enhancement enhancement\nreporter__alex alex\npriority__normal normal\nmilestone__None None\nbranch__ \nbranch_author__ \nstatus__closed closed\nresolution__fixed fixed\ncomponent__core core\nkeywords__None None\ntime__1501244266950695 1501244266950695\nchangetime__1501595055861628 1501595055861628\nversion__None None\nowner__Alex Alex\n\n```\n</details>\n\n", "before_files": [{"content": "# -*- test-case-name: twisted.web.test.test_tap -*-\n# Copyright (c) Twisted Matrix Laboratories.\n# See LICENSE for details.\n\n\"\"\"\nSupport for creating a service which runs a web server.\n\"\"\"\n\nfrom __future__ import absolute_import, division\n\nimport os\n\nfrom twisted.application import internet, service, strports\nfrom twisted.internet import interfaces, reactor\nfrom twisted.python import usage, reflect, threadpool\nfrom twisted.spread import pb\nfrom twisted.web import distrib\nfrom twisted.web import server, static, script, demo, wsgi\nfrom twisted.web import twcgi\n\n\n\nclass Options(usage.Options):\n    \"\"\"\n    Define the options accepted by the I{twistd web} plugin.\n    \"\"\"\n    synopsis = \"[web options]\"\n\n    optParameters = [[\"port\", \"p\", None, \"strports description of the port to \"\n                      \"start the server on.\"],\n                     [\"logfile\", \"l\", None,\n                      \"Path to web CLF (Combined Log Format) log file.\"],\n                     [\"https\", None, None,\n                      \"Port to listen on for Secure HTTP.\"],\n                     [\"certificate\", \"c\", \"server.pem\",\n                      \"SSL certificate to use for HTTPS. \"],\n                     [\"privkey\", \"k\", \"server.pem\",\n                      \"SSL certificate to use for HTTPS.\"],\n                     ]\n\n    optFlags = [\n        [\"notracebacks\", \"n\", (\n            \"Do not display tracebacks in broken web pages. Displaying \"\n            \"tracebacks to users may be security risk!\")],\n    ]\n\n    optFlags.append([\n        \"personal\", \"\",\n        \"Instead of generating a webserver, generate a \"\n        \"ResourcePublisher which listens on  the port given by \"\n        \"--port, or ~/%s \" % (distrib.UserDirectory.userSocketName,) +\n        \"if --port is not specified.\"])\n\n    compData = usage.Completions(\n                   optActions={\"logfile\" : usage.CompleteFiles(\"*.log\"),\n                               \"certificate\" : usage.CompleteFiles(\"*.pem\"),\n                               \"privkey\" : usage.CompleteFiles(\"*.pem\")}\n                   )\n\n    longdesc = \"\"\"\\\nThis starts a webserver.  If you specify no arguments, it will be a\ndemo webserver that has the Test class from twisted.web.demo in it.\"\"\"\n\n    def __init__(self):\n        usage.Options.__init__(self)\n        self['indexes'] = []\n        self['root'] = None\n\n\n    def opt_index(self, indexName):\n        \"\"\"\n        Add the name of a file used to check for directory indexes.\n        [default: index, index.html]\n        \"\"\"\n        self['indexes'].append(indexName)\n\n    opt_i = opt_index\n\n\n    def opt_user(self):\n        \"\"\"\n        Makes a server with ~/public_html and ~/.twistd-web-pb support for\n        users.\n        \"\"\"\n        self['root'] = distrib.UserDirectory()\n\n    opt_u = opt_user\n\n\n    def opt_path(self, path):\n        \"\"\"\n        <path> is either a specific file or a directory to be set as the root\n        of the web server. Use this if you have a directory full of HTML, cgi,\n        epy, or rpy files or any other files that you want to be served up raw.\n        \"\"\"\n        self['root'] = static.File(os.path.abspath(path))\n        self['root'].processors = {\n            '.epy': script.PythonScript,\n            '.rpy': script.ResourceScript,\n        }\n        self['root'].processors['.cgi'] = twcgi.CGIScript\n\n\n    def opt_processor(self, proc):\n        \"\"\"\n        `ext=class' where `class' is added as a Processor for files ending\n        with `ext'.\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\n                \"You can only use --processor after --path.\")\n        ext, klass = proc.split('=', 1)\n        self['root'].processors[ext] = reflect.namedClass(klass)\n\n\n    def opt_class(self, className):\n        \"\"\"\n        Create a Resource subclass with a zero-argument constructor.\n        \"\"\"\n        classObj = reflect.namedClass(className)\n        self['root'] = classObj()\n\n\n    def opt_resource_script(self, name):\n        \"\"\"\n        An .rpy file to be used as the root resource of the webserver.\n        \"\"\"\n        self['root'] = script.ResourceScriptWrapper(name)\n\n\n    def opt_wsgi(self, name):\n        \"\"\"\n        The FQPN of a WSGI application object to serve as the root resource of\n        the webserver.\n        \"\"\"\n        try:\n            application = reflect.namedAny(name)\n        except (AttributeError, ValueError):\n            raise usage.UsageError(\"No such WSGI application: %r\" % (name,))\n        pool = threadpool.ThreadPool()\n        reactor.callWhenRunning(pool.start)\n        reactor.addSystemEventTrigger('after', 'shutdown', pool.stop)\n        self['root'] = wsgi.WSGIResource(reactor, pool, application)\n\n\n    def opt_mime_type(self, defaultType):\n        \"\"\"\n        Specify the default mime-type for static files.\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\n                \"You can only use --mime_type after --path.\")\n        self['root'].defaultType = defaultType\n    opt_m = opt_mime_type\n\n\n    def opt_allow_ignore_ext(self):\n        \"\"\"\n        Specify whether or not a request for 'foo' should return 'foo.ext'\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\"You can only use --allow_ignore_ext \"\n                                   \"after --path.\")\n        self['root'].ignoreExt('*')\n\n\n    def opt_ignore_ext(self, ext):\n        \"\"\"\n        Specify an extension to ignore.  These will be processed in order.\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\"You can only use --ignore_ext \"\n                                   \"after --path.\")\n        self['root'].ignoreExt(ext)\n\n\n    def postOptions(self):\n        \"\"\"\n        Set up conditional defaults and check for dependencies.\n\n        If SSL is not available but an HTTPS server was configured, raise a\n        L{UsageError} indicating that this is not possible.\n\n        If no server port was supplied, select a default appropriate for the\n        other options supplied.\n        \"\"\"\n        if self['https']:\n            try:\n                reflect.namedModule('OpenSSL.SSL')\n            except ImportError:\n                raise usage.UsageError(\"SSL support not installed\")\n        if self['port'] is None:\n            if self['personal']:\n                path = os.path.expanduser(\n                    os.path.join('~', distrib.UserDirectory.userSocketName))\n                self['port'] = 'unix:' + path\n            else:\n                self['port'] = 'tcp:8080'\n\n\n\ndef makePersonalServerFactory(site):\n    \"\"\"\n    Create and return a factory which will respond to I{distrib} requests\n    against the given site.\n\n    @type site: L{twisted.web.server.Site}\n    @rtype: L{twisted.internet.protocol.Factory}\n    \"\"\"\n    return pb.PBServerFactory(distrib.ResourcePublisher(site))\n\n\n\ndef makeService(config):\n    s = service.MultiService()\n    if config['root']:\n        root = config['root']\n        if config['indexes']:\n            config['root'].indexNames = config['indexes']\n    else:\n        # This really ought to be web.Admin or something\n        root = demo.Test()\n\n    if isinstance(root, static.File):\n        root.registry.setComponent(interfaces.IServiceCollection, s)\n\n    if config['logfile']:\n        site = server.Site(root, logPath=config['logfile'])\n    else:\n        site = server.Site(root)\n\n    site.displayTracebacks = not config[\"notracebacks\"]\n\n    if config['personal']:\n        personal = strports.service(\n            config['port'], makePersonalServerFactory(site))\n        personal.setServiceParent(s)\n    else:\n        if config['https']:\n            from twisted.internet.ssl import DefaultOpenSSLContextFactory\n            i = internet.SSLServer(int(config['https']), site,\n                          DefaultOpenSSLContextFactory(config['privkey'],\n                                                       config['certificate']))\n            i.setServiceParent(s)\n        strports.service(config['port'], site).setServiceParent(s)\n\n    return s\n", "path": "src/twisted/web/tap.py"}], "after_files": [{"content": "# -*- test-case-name: twisted.web.test.test_tap -*-\n# Copyright (c) Twisted Matrix Laboratories.\n# See LICENSE for details.\n\n\"\"\"\nSupport for creating a service which runs a web server.\n\"\"\"\n\nfrom __future__ import absolute_import, division\n\nimport os\n\nfrom twisted.application import internet, service, strports\nfrom twisted.internet import interfaces, reactor\nfrom twisted.python import usage, reflect, threadpool\nfrom twisted.spread import pb\nfrom twisted.web import distrib\nfrom twisted.web import resource, server, static, script, demo, wsgi\nfrom twisted.web import twcgi\n\n\n\nclass Options(usage.Options):\n    \"\"\"\n    Define the options accepted by the I{twistd web} plugin.\n    \"\"\"\n    synopsis = \"[web options]\"\n\n    optParameters = [[\"port\", \"p\", None, \"strports description of the port to \"\n                      \"start the server on.\"],\n                     [\"logfile\", \"l\", None,\n                      \"Path to web CLF (Combined Log Format) log file.\"],\n                     [\"https\", None, None,\n                      \"Port to listen on for Secure HTTP.\"],\n                     [\"certificate\", \"c\", \"server.pem\",\n                      \"SSL certificate to use for HTTPS. \"],\n                     [\"privkey\", \"k\", \"server.pem\",\n                      \"SSL certificate to use for HTTPS.\"],\n                     ]\n\n    optFlags = [\n        [\"notracebacks\", \"n\", (\n            \"Do not display tracebacks in broken web pages. Displaying \"\n            \"tracebacks to users may be security risk!\")],\n    ]\n\n    optFlags.append([\n        \"personal\", \"\",\n        \"Instead of generating a webserver, generate a \"\n        \"ResourcePublisher which listens on  the port given by \"\n        \"--port, or ~/%s \" % (distrib.UserDirectory.userSocketName,) +\n        \"if --port is not specified.\"])\n\n    compData = usage.Completions(\n                   optActions={\"logfile\" : usage.CompleteFiles(\"*.log\"),\n                               \"certificate\" : usage.CompleteFiles(\"*.pem\"),\n                               \"privkey\" : usage.CompleteFiles(\"*.pem\")}\n                   )\n\n    longdesc = \"\"\"\\\nThis starts a webserver.  If you specify no arguments, it will be a\ndemo webserver that has the Test class from twisted.web.demo in it.\"\"\"\n\n    def __init__(self):\n        usage.Options.__init__(self)\n        self['indexes'] = []\n        self['root'] = None\n        self['extraHeaders'] = []\n\n\n    def opt_index(self, indexName):\n        \"\"\"\n        Add the name of a file used to check for directory indexes.\n        [default: index, index.html]\n        \"\"\"\n        self['indexes'].append(indexName)\n\n    opt_i = opt_index\n\n\n    def opt_user(self):\n        \"\"\"\n        Makes a server with ~/public_html and ~/.twistd-web-pb support for\n        users.\n        \"\"\"\n        self['root'] = distrib.UserDirectory()\n\n    opt_u = opt_user\n\n\n    def opt_path(self, path):\n        \"\"\"\n        <path> is either a specific file or a directory to be set as the root\n        of the web server. Use this if you have a directory full of HTML, cgi,\n        epy, or rpy files or any other files that you want to be served up raw.\n        \"\"\"\n        self['root'] = static.File(os.path.abspath(path))\n        self['root'].processors = {\n            '.epy': script.PythonScript,\n            '.rpy': script.ResourceScript,\n        }\n        self['root'].processors['.cgi'] = twcgi.CGIScript\n\n\n    def opt_processor(self, proc):\n        \"\"\"\n        `ext=class' where `class' is added as a Processor for files ending\n        with `ext'.\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\n                \"You can only use --processor after --path.\")\n        ext, klass = proc.split('=', 1)\n        self['root'].processors[ext] = reflect.namedClass(klass)\n\n\n    def opt_class(self, className):\n        \"\"\"\n        Create a Resource subclass with a zero-argument constructor.\n        \"\"\"\n        classObj = reflect.namedClass(className)\n        self['root'] = classObj()\n\n\n    def opt_resource_script(self, name):\n        \"\"\"\n        An .rpy file to be used as the root resource of the webserver.\n        \"\"\"\n        self['root'] = script.ResourceScriptWrapper(name)\n\n\n    def opt_wsgi(self, name):\n        \"\"\"\n        The FQPN of a WSGI application object to serve as the root resource of\n        the webserver.\n        \"\"\"\n        try:\n            application = reflect.namedAny(name)\n        except (AttributeError, ValueError):\n            raise usage.UsageError(\"No such WSGI application: %r\" % (name,))\n        pool = threadpool.ThreadPool()\n        reactor.callWhenRunning(pool.start)\n        reactor.addSystemEventTrigger('after', 'shutdown', pool.stop)\n        self['root'] = wsgi.WSGIResource(reactor, pool, application)\n\n\n    def opt_mime_type(self, defaultType):\n        \"\"\"\n        Specify the default mime-type for static files.\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\n                \"You can only use --mime_type after --path.\")\n        self['root'].defaultType = defaultType\n    opt_m = opt_mime_type\n\n\n    def opt_allow_ignore_ext(self):\n        \"\"\"\n        Specify whether or not a request for 'foo' should return 'foo.ext'\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\"You can only use --allow_ignore_ext \"\n                                   \"after --path.\")\n        self['root'].ignoreExt('*')\n\n\n    def opt_ignore_ext(self, ext):\n        \"\"\"\n        Specify an extension to ignore.  These will be processed in order.\n        \"\"\"\n        if not isinstance(self['root'], static.File):\n            raise usage.UsageError(\"You can only use --ignore_ext \"\n                                   \"after --path.\")\n        self['root'].ignoreExt(ext)\n\n\n    def opt_add_header(self, header):\n        \"\"\"\n        Specify an additional header to be included in all responses. Specified\n        as \"HeaderName: HeaderValue\".\n        \"\"\"\n        name, value = header.split(':', 1)\n        self['extraHeaders'].append((name.strip(), value.strip()))\n\n\n    def postOptions(self):\n        \"\"\"\n        Set up conditional defaults and check for dependencies.\n\n        If SSL is not available but an HTTPS server was configured, raise a\n        L{UsageError} indicating that this is not possible.\n\n        If no server port was supplied, select a default appropriate for the\n        other options supplied.\n        \"\"\"\n        if self['https']:\n            try:\n                reflect.namedModule('OpenSSL.SSL')\n            except ImportError:\n                raise usage.UsageError(\"SSL support not installed\")\n        if self['port'] is None:\n            if self['personal']:\n                path = os.path.expanduser(\n                    os.path.join('~', distrib.UserDirectory.userSocketName))\n                self['port'] = 'unix:' + path\n            else:\n                self['port'] = 'tcp:8080'\n\n\n\ndef makePersonalServerFactory(site):\n    \"\"\"\n    Create and return a factory which will respond to I{distrib} requests\n    against the given site.\n\n    @type site: L{twisted.web.server.Site}\n    @rtype: L{twisted.internet.protocol.Factory}\n    \"\"\"\n    return pb.PBServerFactory(distrib.ResourcePublisher(site))\n\n\n\nclass _AddHeadersResource(resource.Resource):\n    def __init__(self, originalResource, headers):\n        self._originalResource = originalResource\n        self._headers = headers\n\n\n    def getChildWithDefault(self, name, request):\n        for k, v in self._headers:\n            request.responseHeaders.addRawHeader(k, v)\n        return self._originalResource.getChildWithDefault(name, request)\n\n\n\ndef makeService(config):\n    s = service.MultiService()\n    if config['root']:\n        root = config['root']\n        if config['indexes']:\n            config['root'].indexNames = config['indexes']\n    else:\n        # This really ought to be web.Admin or something\n        root = demo.Test()\n\n    if isinstance(root, static.File):\n        root.registry.setComponent(interfaces.IServiceCollection, s)\n\n    if config['extraHeaders']:\n        root = _AddHeadersResource(root, config['extraHeaders'])\n\n    if config['logfile']:\n        site = server.Site(root, logPath=config['logfile'])\n    else:\n        site = server.Site(root)\n\n    site.displayTracebacks = not config[\"notracebacks\"]\n\n    if config['personal']:\n        personal = strports.service(\n            config['port'], makePersonalServerFactory(site))\n        personal.setServiceParent(s)\n    else:\n        if config['https']:\n            from twisted.internet.ssl import DefaultOpenSSLContextFactory\n            i = internet.SSLServer(int(config['https']), site,\n                          DefaultOpenSSLContextFactory(config['privkey'],\n                                                       config['certificate']))\n            i.setServiceParent(s)\n        strports.service(config['port'], site).setServiceParent(s)\n\n    return s\n", "path": "src/twisted/web/tap.py"}]}