14080.3.14
by Gavin Panella
Update copyright. |
1 |
# Copyright 2009-2011 Canonical Ltd. This software is licensed under the
|
8687.15.18
by Karl Fogel
Add the copyright header block to files under lib/canonical/. |
2 |
# GNU Affero General Public License version 3 (see the file LICENSE).
|
3 |
||
10512.1.2
by Guilherme Salgado
Remove some lint |
4 |
# pylint: disable-msg=W0231,E1002
|
4823.6.7
by Barry Warsaw
Much simplification and improvement in the way private ports are done. |
5 |
|
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
6 |
"""Definition of the internet servers that Launchpad uses."""
|
7 |
||
8 |
__metaclass__ = type |
|
9 |
||
7666.3.5
by Michael Nelson
Added query_string_params to LaunchpadBrowserRequest as suggested by Gary. |
10 |
import cgi |
3691.3.2
by Steve Alexander
set up new host header based virtual hosting, make canonical_url able to be configured with a rootsite, removal of unused IDefaultViewDirective, fix race condition in request publication factory. |
11 |
import threading |
4246.2.1
by James Henstridge
catch non-Fault exceptions in XML-RPC and display the OOPS code |
12 |
import xmlrpclib |
3691.3.2
by Steve Alexander
set up new host header based virtual hosting, make canonical_url able to be configured with a rootsite, removal of unused IDefaultViewDirective, fix race condition in request publication factory. |
13 |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
14 |
from lazr.restful.interfaces import ( |
11351.1.3
by Diogo Matsubara
Merge from trunk, fix 1 conflict on servers.py |
15 |
ICollectionResource, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
16 |
IWebServiceConfiguration, |
17 |
IWebServiceVersion, |
|
18 |
)
|
|
19 |
from lazr.restful.publisher import ( |
|
20 |
WebServicePublicationMixin, |
|
21 |
WebServiceRequestTraversal, |
|
22 |
)
|
|
23 |
from lazr.uri import URI |
|
7055.2.15
by Michael Hudson
clear the cache on commit() |
24 |
import transaction |
25 |
from transaction.interfaces import ISynchronizer |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
26 |
from zc.zservertracelog.tracelog import Server as ZServerTracelogServer |
27 |
from zope.app.form.browser.itemswidgets import MultiDataHelper |
|
4311.2.2
by Francis J. Lacoste
Show how the regular widgets fail. Allow uninstallation of the monkey patch. |
28 |
from zope.app.form.browser.widget import SimpleInputWidget |
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
29 |
from zope.app.publication.httpfactory import HTTPPublicationRequestFactory |
3673.5.2
by Bjorn Tillenius
convert the xmlrpc server to WSGIHTTPServer. |
30 |
from zope.app.publication.interfaces import IRequestPublicationFactory |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
31 |
from zope.app.publication.requestpublicationregistry import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
32 |
factoryRegistry as publisher_factory_registry, |
33 |
)
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
34 |
from zope.app.server import wsgi |
35 |
from zope.app.wsgi import WSGIPublisherApplication |
|
7893.3.4
by Francis J. Lacoste
Moved generic webservice publisher stuff to canonical.lazr.rest.publisher. |
36 |
from zope.component import getUtility |
14080.3.9
by Gavin Panella
Demonstrate the FinishReadOnlyRequestEvent is fired by both LaunchpadBrowserPublication and WebServicePublication. |
37 |
from zope.event import notify |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
38 |
from zope.interface import ( |
39 |
alsoProvides, |
|
40 |
implements, |
|
41 |
)
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
42 |
from zope.publisher.browser import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
43 |
BrowserRequest, |
44 |
BrowserResponse, |
|
45 |
TestRequest, |
|
46 |
)
|
|
5206.2.1
by Leonard Richardson
Added test and fix. |
47 |
from zope.publisher.interfaces import NotFound |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
48 |
from zope.publisher.xmlrpc import ( |
49 |
XMLRPCRequest, |
|
50 |
XMLRPCResponse, |
|
51 |
)
|
|
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
52 |
from zope.security.interfaces import ( |
53 |
IParticipation, |
|
54 |
Unauthorized, |
|
55 |
)
|
|
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
56 |
from zope.security.proxy import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
57 |
isinstance as zope_isinstance, |
58 |
removeSecurityProxy, |
|
59 |
)
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
60 |
from zope.server.http.commonaccesslogger import CommonAccessLogger |
7362.11.64
by Jonathan Lange
Clean up lint |
61 |
from zope.server.http.wsgihttpserver import PMDBWSGIHTTPServer |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
62 |
from zope.session.interfaces import ISession |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
63 |
|
14606.4.3
by William Grant
Move the interfaces across too. |
64 |
from lp.app.errors import UnexpectedFormData |
65 |
import lp.layers |
|
14605.1.1
by Curtis Hovey
Moved canonical.config to lp.services. |
66 |
from lp.services.config import config |
14606.4.3
by William Grant
Move the interfaces across too. |
67 |
from lp.services.features import get_relevant_feature_controller |
68 |
from lp.services.features.flags import NullFeatureController |
|
69 |
from lp.services.feeds.interfaces.application import IFeedsApplication |
|
70 |
from lp.services.feeds.interfaces.feed import IFeed |
|
71 |
from lp.services.oauth.interfaces import ( |
|
72 |
IOAuthConsumerSet, |
|
73 |
IOAuthSignedRequest, |
|
74 |
TokenException, |
|
75 |
)
|
|
76 |
from lp.services.propertycache import cachedproperty |
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
77 |
from lp.services.webapp.authentication import ( |
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
78 |
check_oauth_signature, |
79 |
get_oauth_authorization, |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
80 |
)
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
81 |
from lp.services.webapp.authorization import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
82 |
LAUNCHPAD_SECURITY_POLICY_CACHE_KEY, |
83 |
)
|
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
84 |
from lp.services.webapp.errorlog import ErrorReportRequest |
85 |
from lp.services.webapp.interfaces import ( |
|
14080.3.9
by Gavin Panella
Demonstrate the FinishReadOnlyRequestEvent is fired by both LaunchpadBrowserPublication and WebServicePublication. |
86 |
FinishReadOnlyRequestEvent, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
87 |
IAPIDocRoot, |
88 |
IBasicLaunchpadRequest, |
|
89 |
IBrowserFormNG, |
|
90 |
ILaunchpadBrowserApplicationRequest, |
|
91 |
ILaunchpadProtocolError, |
|
92 |
INotificationRequest, |
|
93 |
INotificationResponse, |
|
94 |
IPlacelessAuthUtility, |
|
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
95 |
IPlacelessLoginSource, |
96 |
OAuthPermission, |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
97 |
)
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
98 |
from lp.services.webapp.notifications import ( |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
99 |
NotificationList, |
100 |
NotificationRequest, |
|
101 |
NotificationResponse, |
|
102 |
)
|
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
103 |
from lp.services.webapp.opstats import OpStats |
104 |
from lp.services.webapp.publication import LaunchpadBrowserPublication |
|
105 |
from lp.services.webapp.publisher import ( |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
106 |
get_current_browser_request, |
107 |
RedirectionView, |
|
108 |
)
|
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
109 |
from lp.services.webapp.vhosts import allvhosts |
14560.2.24
by Curtis Hovey
Moved IWebServiceApplication to lp.services.webservice. |
110 |
from lp.services.webservice.interfaces import IWebServiceApplication |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
111 |
from lp.testopenid.interfaces.server import ITestOpenIDApplication |
14606.4.3
by William Grant
Move the interfaces across too. |
112 |
from lp.xmlrpc.interfaces import IPrivateApplication |
7675.754.40
by Martin Pool
Add a NullFeatureController and use that in LaunchpadTestRequest |
113 |
|
5435.1.11
by Leonard Richardson
Refactoring and response to feedback. |
114 |
|
2649
by Canonical.com Patch Queue Manager
[trivial] small refactor of the request type used in launchpad, to make certain traversal tricks more straightforward. |
115 |
class StepsToGo: |
116 |
"""
|
|
117 |
||
118 |
>>> class FakeRequest:
|
|
119 |
... def __init__(self, traversed, stack):
|
|
120 |
... self._traversed_names = traversed
|
|
121 |
... self.stack = stack
|
|
122 |
... def getTraversalStack(self):
|
|
123 |
... return self.stack
|
|
124 |
... def setTraversalStack(self, stack):
|
|
125 |
... self.stack = stack
|
|
126 |
||
127 |
>>> request = FakeRequest([], ['baz', 'bar', 'foo'])
|
|
128 |
>>> stepstogo = StepsToGo(request)
|
|
129 |
>>> stepstogo.startswith()
|
|
130 |
True
|
|
131 |
>>> stepstogo.startswith('foo')
|
|
132 |
True
|
|
133 |
>>> stepstogo.startswith('foo', 'bar')
|
|
134 |
True
|
|
135 |
>>> stepstogo.startswith('foo', 'baz')
|
|
136 |
False
|
|
137 |
>>> len(stepstogo)
|
|
138 |
3
|
|
139 |
>>> print stepstogo.consume()
|
|
140 |
foo
|
|
141 |
>>> request._traversed_names
|
|
142 |
['foo']
|
|
143 |
>>> request.stack
|
|
144 |
['baz', 'bar']
|
|
145 |
>>> print stepstogo.consume()
|
|
146 |
bar
|
|
147 |
>>> bool(stepstogo)
|
|
148 |
True
|
|
149 |
>>> print stepstogo.consume()
|
|
150 |
baz
|
|
151 |
>>> print stepstogo.consume()
|
|
152 |
None
|
|
153 |
>>> bool(stepstogo)
|
|
154 |
False
|
|
155 |
||
7634.2.1
by Michael Hudson
a bundle of confusatrons and no mistake |
156 |
>>> request = FakeRequest([], ['baz', 'bar', 'foo'])
|
157 |
>>> list(StepsToGo(request))
|
|
158 |
['foo', 'bar', 'baz']
|
|
159 |
||
2649
by Canonical.com Patch Queue Manager
[trivial] small refactor of the request type used in launchpad, to make certain traversal tricks more straightforward. |
160 |
"""
|
161 |
||
162 |
@property
|
|
163 |
def _stack(self): |
|
164 |
return self.request.getTraversalStack() |
|
165 |
||
166 |
def __init__(self, request): |
|
167 |
self.request = request |
|
168 |
||
7362.11.34
by Jonathan Lange
Make stepstogo an iterator, so that we can write more generic code in |
169 |
def __iter__(self): |
170 |
return self |
|
171 |
||
2649
by Canonical.com Patch Queue Manager
[trivial] small refactor of the request type used in launchpad, to make certain traversal tricks more straightforward. |
172 |
def consume(self): |
173 |
"""Remove the next path step and return it.
|
|
174 |
||
175 |
Returns None if there are no path steps left.
|
|
176 |
"""
|
|
177 |
stack = self.request.getTraversalStack() |
|
178 |
try: |
|
179 |
nextstep = stack.pop() |
|
180 |
except IndexError: |
|
181 |
return None |
|
182 |
self.request._traversed_names.append(nextstep) |
|
183 |
self.request.setTraversalStack(stack) |
|
184 |
return nextstep |
|
185 |
||
7634.2.1
by Michael Hudson
a bundle of confusatrons and no mistake |
186 |
def next(self): |
187 |
value = self.consume() |
|
188 |
if value is None: |
|
189 |
raise StopIteration |
|
190 |
return value |
|
7362.11.34
by Jonathan Lange
Make stepstogo an iterator, so that we can write more generic code in |
191 |
|
2649
by Canonical.com Patch Queue Manager
[trivial] small refactor of the request type used in launchpad, to make certain traversal tricks more straightforward. |
192 |
def startswith(self, *args): |
193 |
"""Return whether the steps to go start with the names given."""
|
|
194 |
if not args: |
|
195 |
return True |
|
196 |
return self._stack[-len(args):] == list(reversed(args)) |
|
197 |
||
198 |
def __len__(self): |
|
199 |
return len(self._stack) |
|
200 |
||
201 |
def __nonzero__(self): |
|
202 |
return bool(self._stack) |
|
203 |
||
204 |
||
3691.3.9
by Steve Alexander
factor out Url class into webapp.url, and improve its test coverage. Add a wrapper factory for requests that calls setApplicationServer after construction, to get virtual hosting state into the request for rendering Location headers, <base> tags and so on. |
205 |
class ApplicationServerSettingRequestFactory: |
206 |
"""Create a request and call its setApplicationServer method.
|
|
207 |
||
208 |
Due to the factory-fanatical design of this part of Zope3, we need
|
|
209 |
to have a kind of proxying factory here so that we can create an
|
|
4823.6.1
by Barry Warsaw
Implementation of private XML-RPC ports. Here's the approach: |
210 |
appropriate request and call its setApplicationServer method before it
|
3691.3.9
by Steve Alexander
factor out Url class into webapp.url, and improve its test coverage. Add a wrapper factory for requests that calls setApplicationServer after construction, to get virtual hosting state into the request for rendering Location headers, <base> tags and so on. |
211 |
is used.
|
212 |
"""
|
|
213 |
||
214 |
def __init__(self, requestfactory, host, protocol, port): |
|
215 |
self.requestfactory = requestfactory |
|
216 |
self.host = host |
|
217 |
self.protocol = protocol |
|
218 |
self.port = port |
|
219 |
||
220 |
def __call__(self, body_instream, environ, response=None): |
|
221 |
"""Equivalent to the request's __init__ method."""
|
|
7575.1.1
by Francis J. Lacoste
Sets the HTTPS environment on request whose rooturl uses https so that getURL() does the right thing. |
222 |
# Make sure that HTTPS variable is set so that request.getURL() is
|
223 |
# sane
|
|
224 |
if self.protocol == 'https': |
|
7575.1.2
by Francis J. Lacoste
Review feedback. |
225 |
environ['HTTPS'] = 'on' |
3691.3.9
by Steve Alexander
factor out Url class into webapp.url, and improve its test coverage. Add a wrapper factory for requests that calls setApplicationServer after construction, to get virtual hosting state into the request for rendering Location headers, <base> tags and so on. |
226 |
request = self.requestfactory(body_instream, environ, response) |
227 |
request.setApplicationServer(self.host, self.protocol, self.port) |
|
228 |
return request |
|
229 |
||
7014.5.13
by Maris Fogels
Added tests for allowed and denied HTTP methods. |
230 |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
231 |
class VirtualHostRequestPublicationFactory: |
232 |
"""An `IRequestPublicationFactory` handling request to a Launchpad vhost.
|
|
233 |
||
234 |
This factory will accepts requests to a particular Launchpad virtual host
|
|
235 |
that matches a particular port and set of HTTP methods.
|
|
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
236 |
"""
|
2976.10.68
by Stuart Bishop
Tweak publication machinery |
237 |
implements(IRequestPublicationFactory) |
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
238 |
|
7014.5.14
by Maris Fogels
Added the default_methods class attribute, and fixed the tests a bit. |
239 |
default_methods = ['GET', 'HEAD', 'POST'] |
240 |
||
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
241 |
def __init__(self, vhost_name, request_factory, publication_factory, |
242 |
port=None, methods=None, handle_default_host=False): |
|
243 |
"""Creates a new factory.
|
|
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
244 |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
245 |
:param vhost_name: The config section defining the virtual host
|
246 |
handled by this factory.
|
|
247 |
:param request_factory: The request factory to use for this virtual
|
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
248 |
host's requests.
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
249 |
:param publication_factory: The publication factory to use for this
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
250 |
virtual host's requests.
|
251 |
:param port: The port which is handled by this factory. If
|
|
252 |
this is None, this factory will handle requests that
|
|
253 |
originate on any port.
|
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
254 |
:param methods: A sequence of HTTP methods that this factory handles.
|
255 |
:param handle_default_host: Whether or not this factory is
|
|
256 |
capable of handling requests that specify no hostname.
|
|
3618.1.47
by Steve Alexander
improvements from kiko's review, and other improvements. |
257 |
"""
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
258 |
|
259 |
self.vhost_name = vhost_name |
|
260 |
self.request_factory = request_factory |
|
261 |
self.publication_factory = publication_factory |
|
262 |
self.port = port |
|
5435.1.2
by Leonard Richardson
Added an 'api' vhost that responds to all major HTTP methods. |
263 |
if methods is None: |
7014.5.14
by Maris Fogels
Added the default_methods class attribute, and fixed the tests a bit. |
264 |
methods = self.default_methods |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
265 |
self.methods = methods |
266 |
self.handle_default_host = handle_default_host |
|
267 |
||
268 |
self.vhost_config = allvhosts.configs[self.vhost_name] |
|
269 |
self.all_hostnames = set(self.vhost_config.althostnames |
|
270 |
+ [self.vhost_config.hostname]) |
|
3691.3.2
by Steve Alexander
set up new host header based virtual hosting, make canonical_url able to be configured with a rootsite, removal of unused IDefaultViewDirective, fix race condition in request publication factory. |
271 |
self._thread_local = threading.local() |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
272 |
self._thread_local.environment = None |
3691.3.2
by Steve Alexander
set up new host header based virtual hosting, make canonical_url able to be configured with a rootsite, removal of unused IDefaultViewDirective, fix race condition in request publication factory. |
273 |
|
2976.10.68
by Stuart Bishop
Tweak publication machinery |
274 |
def canHandle(self, environment): |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
275 |
"""See `IRequestPublicationFactory`.
|
276 |
||
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
277 |
Returns true if the HTTP host and port of the incoming request
|
278 |
match the ones this factory is equipped to handle.
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
279 |
"""
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
280 |
# We look at the wsgi environment to get the port this request
|
281 |
# is coming in over. The port number can be in one of two
|
|
282 |
# places; either it's on the SERVER_PORT environment variable
|
|
283 |
# or, as is the case with the test suite, it's on the
|
|
284 |
# HTTP_HOST variable after a colon.
|
|
6377.1.1
by Francis J. Lacoste
SERVER_PORT takes precedence over Host-header specified port instead of raising an AssertionError. |
285 |
# The former takes precedence, the port from the host variable is
|
286 |
# only checked because the test suite doesn't set SERVER_PORT.
|
|
6278.1.17
by Barry Warsaw
Handle the fact that the environment may not always have HTTP_HOST in it. |
287 |
host = environment.get('HTTP_HOST', '') |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
288 |
port = environment.get('SERVER_PORT') |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
289 |
if ":" in host: |
290 |
assert len(host.split(':')) == 2, ( |
|
291 |
"Having a ':' in the host name isn't allowed.") |
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
292 |
host, new_port = host.split(':') |
6377.1.1
by Francis J. Lacoste
SERVER_PORT takes precedence over Host-header specified port instead of raising an AssertionError. |
293 |
if port is None: |
294 |
port = new_port |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
295 |
|
296 |
if host == '': |
|
297 |
if not self.handle_default_host: |
|
298 |
return False |
|
299 |
elif host not in self.all_hostnames: |
|
300 |
return False |
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
301 |
else: |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
302 |
# This factory handles this host.
|
4823.6.3
by Barry Warsaw
Add a test for the private XML-RPC port functionality. |
303 |
pass
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
304 |
|
305 |
if self.port is not None: |
|
306 |
if port is not None: |
|
307 |
try: |
|
308 |
port = int(port) |
|
309 |
except (ValueError): |
|
310 |
port = None |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
311 |
if self.port != port: |
312 |
return False |
|
313 |
||
314 |
self._thread_local.environment = environment |
|
5138.5.5
by Leonard Richardson
Restored old functionality where requests to the local host didn't have the application server set. |
315 |
self._thread_local.host = host |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
316 |
return True |
317 |
||
2976.10.68
by Stuart Bishop
Tweak publication machinery |
318 |
def __call__(self): |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
319 |
"""See `IRequestPublicationFactory`.
|
320 |
||
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
321 |
We know that this factory is the right one for the given host
|
322 |
and port. But there might be something else wrong with the
|
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
323 |
request. For instance, it might have the wrong HTTP method.
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
324 |
"""
|
325 |
environment = self._thread_local.environment |
|
326 |
if environment is None: |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
327 |
raise AssertionError('This factory declined the request.') |
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
328 |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
329 |
root_url = URI(self.vhost_config.rooturl) |
330 |
||
331 |
real_request_factory, publication_factory = ( |
|
332 |
self.checkRequest(environment)) |
|
333 |
||
334 |
if not real_request_factory: |
|
7014.5.23
by Francis J. Lacoste
Made /api requests on standard applications virtual host served using the webservice. |
335 |
real_request_factory, publication_factory = ( |
336 |
self.getRequestAndPublicationFactories(environment)) |
|
5138.5.5
by Leonard Richardson
Restored old functionality where requests to the local host didn't have the application server set. |
337 |
|
6278.1.17
by Barry Warsaw
Handle the fact that the environment may not always have HTTP_HOST in it. |
338 |
host = environment.get('HTTP_HOST', '').split(':')[0] |
5138.5.5
by Leonard Richardson
Restored old functionality where requests to the local host didn't have the application server set. |
339 |
if host in ['', 'localhost']: |
340 |
# Sometimes requests come in to the default or local host.
|
|
341 |
# If we set the application server for these requests,
|
|
342 |
# they'll be handled as launchpad.net requests, and
|
|
343 |
# responses will go out containing launchpad.net URLs.
|
|
344 |
# That's a little unelegant, so we don't set the application
|
|
345 |
# server for these requests.
|
|
346 |
request_factory = real_request_factory |
|
347 |
else: |
|
348 |
request_factory = ApplicationServerSettingRequestFactory( |
|
349 |
real_request_factory, |
|
350 |
root_url.host, |
|
351 |
root_url.scheme, |
|
352 |
root_url.port) |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
353 |
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
354 |
self._thread_local.environment = None |
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
355 |
return (request_factory, publication_factory) |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
356 |
|
7014.5.23
by Francis J. Lacoste
Made /api requests on standard applications virtual host served using the webservice. |
357 |
def getRequestAndPublicationFactories(self, environment): |
358 |
"""Return the request and publication factories to use.
|
|
359 |
||
360 |
You can override this method if the request and publication can
|
|
361 |
vary based on the environment.
|
|
362 |
"""
|
|
363 |
return self.request_factory, self.publication_factory |
|
364 |
||
365 |
def getAcceptableMethods(self, environment): |
|
7014.5.26
by Francis J. Lacoste
Typos. |
366 |
"""Return the HTTP methods acceptable in this particular environment.
|
7014.5.23
by Francis J. Lacoste
Made /api requests on standard applications virtual host served using the webservice. |
367 |
"""
|
368 |
return self.methods |
|
369 |
||
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
370 |
def checkRequest(self, environment): |
371 |
"""Makes sure that the incoming HTTP request is of an expected type.
|
|
372 |
||
373 |
This is different from canHandle() because we know the request
|
|
374 |
went to the right place. It's just that it might be an invalid
|
|
375 |
request for this handler.
|
|
376 |
||
377 |
:return: An appropriate ProtocolErrorPublicationFactory if the
|
|
378 |
HTTP request doesn't comply with the expected protocol. If
|
|
5138.5.1
by Leonard Richardson
Missing part of the initial import. |
379 |
the request does comply, (None, None).
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
380 |
"""
|
381 |
method = environment.get('REQUEST_METHOD') |
|
7014.5.16
by Maris Fogels
Changed and simplified the checkRequest() method override. |
382 |
|
7014.5.23
by Francis J. Lacoste
Made /api requests on standard applications virtual host served using the webservice. |
383 |
if method in self.getAcceptableMethods(environment): |
7014.5.16
by Maris Fogels
Changed and simplified the checkRequest() method override. |
384 |
factories = (None, None) |
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
385 |
else: |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
386 |
request_factory = ProtocolErrorRequest |
387 |
publication_factory = ProtocolErrorPublicationFactory( |
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
388 |
405, headers={'Allow': " ".join(self.methods)}) |
7014.5.16
by Maris Fogels
Changed and simplified the checkRequest() method override. |
389 |
factories = (request_factory, publication_factory) |
390 |
||
391 |
return factories |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
392 |
|
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
393 |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
394 |
class XMLRPCRequestPublicationFactory(VirtualHostRequestPublicationFactory): |
395 |
"""A VirtualHostRequestPublicationFactory for XML-RPC.
|
|
396 |
||
397 |
This factory only accepts XML-RPC method calls.
|
|
398 |
"""
|
|
399 |
||
400 |
def __init__(self, vhost_name, request_factory, publication_factory, |
|
401 |
port=None): |
|
402 |
super(XMLRPCRequestPublicationFactory, self).__init__( |
|
403 |
vhost_name, request_factory, publication_factory, port, ['POST']) |
|
404 |
||
405 |
def checkRequest(self, environment): |
|
406 |
"""See `VirtualHostRequestPublicationFactory`.
|
|
407 |
||
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
408 |
Accept only requests where the MIME type is text/xml.
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
409 |
"""
|
410 |
request_factory, publication_factory = ( |
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
411 |
super(XMLRPCRequestPublicationFactory, self).checkRequest( |
412 |
environment)) |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
413 |
if request_factory is None: |
414 |
mime_type = environment.get('CONTENT_TYPE') |
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
415 |
if mime_type != 'text/xml': |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
416 |
request_factory = ProtocolErrorRequest |
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
417 |
# 415 - Unsupported Media Type
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
418 |
publication_factory = ProtocolErrorPublicationFactory(415) |
419 |
return request_factory, publication_factory |
|
420 |
||
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
421 |
|
5435.1.3
by Leonard Richardson
Minor changes in response to feedback. |
422 |
class WebServiceRequestPublicationFactory( |
423 |
VirtualHostRequestPublicationFactory): |
|
5435.1.2
by Leonard Richardson
Added an 'api' vhost that responds to all major HTTP methods. |
424 |
"""A VirtualHostRequestPublicationFactory for requests against
|
425 |
resources published through a web service.
|
|
426 |
"""
|
|
427 |
||
7014.5.14
by Maris Fogels
Added the default_methods class attribute, and fixed the tests a bit. |
428 |
default_methods = [ |
429 |
'GET', 'HEAD', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS'] |
|
430 |
||
5435.1.2
by Leonard Richardson
Added an 'api' vhost that responds to all major HTTP methods. |
431 |
def __init__(self, vhost_name, request_factory, publication_factory, |
432 |
port=None): |
|
433 |
"""This factory accepts requests that use all five major HTTP methods.
|
|
434 |
"""
|
|
435 |
super(WebServiceRequestPublicationFactory, self).__init__( |
|
7014.5.14
by Maris Fogels
Added the default_methods class attribute, and fixed the tests a bit. |
436 |
vhost_name, request_factory, publication_factory, port) |
5435.1.2
by Leonard Richardson
Added an 'api' vhost that responds to all major HTTP methods. |
437 |
|
438 |
||
7014.5.13
by Maris Fogels
Added tests for allowed and denied HTTP methods. |
439 |
class VHostWebServiceRequestPublicationFactory( |
440 |
VirtualHostRequestPublicationFactory): |
|
7014.5.11
by Maris Fogels
Made the new factory understand webservice resource paths. |
441 |
"""An `IRequestPublicationFactory` handling requests to vhosts.
|
442 |
||
443 |
It also handles requests to the launchpad web service, if the
|
|
444 |
request's path points to a web service resource.
|
|
445 |
"""
|
|
446 |
||
7014.5.23
by Francis J. Lacoste
Made /api requests on standard applications virtual host served using the webservice. |
447 |
def getAcceptableMethods(self, environment): |
448 |
"""See `VirtualHostRequestPublicationFactory`.
|
|
449 |
||
450 |
If this is a request for a webservice path, returns the appropriate
|
|
451 |
methods.
|
|
452 |
"""
|
|
453 |
if self.isWebServicePath(environment.get('PATH_INFO', '')): |
|
454 |
return WebServiceRequestPublicationFactory.default_methods |
|
455 |
else: |
|
456 |
return super( |
|
457 |
VHostWebServiceRequestPublicationFactory, |
|
458 |
self).getAcceptableMethods(environment) |
|
459 |
||
460 |
def getRequestAndPublicationFactories(self, environment): |
|
461 |
"""See `VirtualHostRequestPublicationFactory`.
|
|
462 |
||
463 |
If this is a request for a webservice path, returns the appropriate
|
|
464 |
factories.
|
|
465 |
"""
|
|
466 |
if self.isWebServicePath(environment.get('PATH_INFO', '')): |
|
467 |
return WebServiceClientRequest, WebServicePublication |
|
468 |
else: |
|
469 |
return super( |
|
470 |
VHostWebServiceRequestPublicationFactory, |
|
471 |
self).getRequestAndPublicationFactories(environment) |
|
7014.5.16
by Maris Fogels
Changed and simplified the checkRequest() method override. |
472 |
|
7014.5.11
by Maris Fogels
Made the new factory understand webservice resource paths. |
473 |
def isWebServicePath(self, path): |
474 |
"""Does the path refer to a web service resource?"""
|
|
475 |
# Add a trailing slash, if it is missing.
|
|
476 |
if not path.endswith('/'): |
|
477 |
path = path + '/' |
|
7893.3.14
by Francis J. Lacoste
Silence some lint. |
478 |
ws_config = getUtility(IWebServiceConfiguration) |
479 |
return path.startswith('/%s/' % ws_config.path_override) |
|
7014.5.11
by Maris Fogels
Made the new factory understand webservice resource paths. |
480 |
|
481 |
||
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
482 |
class NotFoundRequestPublicationFactory: |
483 |
"""An IRequestPublicationFactory which always yields a 404."""
|
|
484 |
||
485 |
def canHandle(self, environment): |
|
486 |
"""See `IRequestPublicationFactory`."""
|
|
487 |
return True |
|
488 |
||
489 |
def __call__(self): |
|
490 |
"""See `IRequestPublicationFactory`.
|
|
491 |
||
492 |
Unlike other publication factories, this one doesn't wrap its
|
|
493 |
request factory in an ApplicationServerSettingRequestFactory.
|
|
494 |
That's because it's only triggered when there's no valid hostname.
|
|
495 |
"""
|
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
496 |
return (ProtocolErrorRequest, ProtocolErrorPublicationFactory(404)) |
497 |
||
498 |
||
7666.3.11
by Michael Nelson
Implemented Guilhermes' suggestions. |
499 |
def get_query_string_params(request): |
7675.284.3
by Celso Providelo
applying review comments, r=abentley. |
500 |
"""Return a dict of the decoded query string params for a request.
|
501 |
||
502 |
The parameter values will be decoded as unicodes, exactly as
|
|
503 |
`BrowserRequest` would do to build the request form.
|
|
7666.3.11
by Michael Nelson
Implemented Guilhermes' suggestions. |
504 |
|
505 |
Defined here so that it can be used in both BasicLaunchpadRequest and
|
|
506 |
the LaunchpadTestRequest (which doesn't inherit from
|
|
507 |
BasicLaunchpadRequest).
|
|
508 |
"""
|
|
509 |
query_string = request.get('QUERY_STRING', '') |
|
510 |
||
7666.3.12
by Michael Nelson
Gary's further changes. |
511 |
# Just in case QUERY_STRING is in the environment explicitly as
|
7666.3.11
by Michael Nelson
Implemented Guilhermes' suggestions. |
512 |
# None (Some tests seem to do this, but not sure if it can ever
|
513 |
# happen outside of tests.)
|
|
514 |
if query_string is None: |
|
515 |
query_string = '' |
|
516 |
||
7675.284.3
by Celso Providelo
applying review comments, r=abentley. |
517 |
parsed_qs = cgi.parse_qs(query_string, keep_blank_values=True) |
518 |
# Use BrowserRequest._decode() for decoding the received parameters.
|
|
519 |
decoded_qs = {} |
|
520 |
for key, values in parsed_qs.iteritems(): |
|
521 |
decoded_qs[key] = [ |
|
522 |
request._decode(value) for value in values] |
|
523 |
return decoded_qs |
|
524 |
||
7666.3.11
by Michael Nelson
Implemented Guilhermes' suggestions. |
525 |
|
7675.834.9
by Michael Nelson
Updated is_ajax. |
526 |
class LaunchpadBrowserRequestMixin: |
7675.834.19
by Michael Nelson
Small changes from henninge's review - splitting up tests and typos. |
527 |
"""Provides methods used for both API and web browser requests."""
|
7675.834.9
by Michael Nelson
Updated is_ajax. |
528 |
|
529 |
def getRootURL(self, rootsite): |
|
530 |
"""See IBasicLaunchpadRequest."""
|
|
531 |
if rootsite is not None: |
|
532 |
assert rootsite in allvhosts.configs, ( |
|
533 |
"rootsite is %s. Must be in %r." % ( |
|
534 |
rootsite, sorted(allvhosts.configs.keys()))) |
|
535 |
root_url = allvhosts.configs[rootsite].rooturl |
|
536 |
else: |
|
537 |
root_url = self.getApplicationURL() + '/' |
|
538 |
return root_url |
|
539 |
||
540 |
@property
|
|
541 |
def is_ajax(self): |
|
542 |
"""See `IBasicLaunchpadRequest`."""
|
|
543 |
return 'XMLHttpRequest' == self.getHeader('HTTP_X_REQUESTED_WITH') |
|
544 |
||
13588.10.6
by Gavin Panella
Add include_query parameter to <request>.getURL(). |
545 |
def getURL(self, level=0, path_only=False, include_query=False): |
546 |
"""See `IBasicLaunchpadRequest`."""
|
|
547 |
sup = super(LaunchpadBrowserRequestMixin, self) |
|
548 |
url = sup.getURL(level, path_only) |
|
549 |
if include_query: |
|
550 |
query_string = self.get('QUERY_STRING') |
|
551 |
if query_string is not None and len(query_string) > 0: |
|
552 |
url = "%s?%s" % (url, query_string) |
|
553 |
return url |
|
554 |
||
7675.834.9
by Michael Nelson
Updated is_ajax. |
555 |
|
556 |
class BasicLaunchpadRequest(LaunchpadBrowserRequestMixin): |
|
14104.3.8
by Michael Hudson-Doyle
squish IParticipationExtras |
557 |
"""Mixin request class to provide stepstogo."""
|
558 |
||
559 |
implements(IBasicLaunchpadRequest) |
|
2677
by Canonical.com Patch Queue Manager
[r=salgado, trivial] various improvements to navigation, and also breadcrumbs, and also redirection as a result of traversal. |
560 |
|
2976.10.3
by Stuart Bishop
Launchpad is running. Test suite untried |
561 |
def __init__(self, body_instream, environ, response=None): |
2909.1.1
by James Henstridge
Keep track of the traversed objects in the request, so they can be |
562 |
self.traversed_objects = [] |
4167.1.1
by James Henstridge
allow setInWSGIEnvironment() to change values it had previously set |
563 |
self._wsgi_keys = set() |
5369.1.1
by Mark Shuttleworth
Add PopCalXP in date and datetime picker configurations |
564 |
self.needs_datepicker_iframe = False |
565 |
self.needs_datetimepicker_iframe = False |
|
3258.4.4
by Steve Alexander
Made navigation components be used for XMLRPC traversal by registering them |
566 |
super(BasicLaunchpadRequest, self).__init__( |
2976.10.3
by Stuart Bishop
Launchpad is running. Test suite untried |
567 |
body_instream, environ, response) |
2677
by Canonical.com Patch Queue Manager
[r=salgado, trivial] various improvements to navigation, and also breadcrumbs, and also redirection as a result of traversal. |
568 |
|
7703.4.1
by Francis J. Lacoste
Add Vary header to our response. |
569 |
# Our response always vary based on authentication.
|
7703.4.7
by Francis J. Lacoste
Use Authorization instead of WWW-Authenticate in Vary header. |
570 |
self.response.setHeader('Vary', 'Cookie, Authorization') |
7703.4.1
by Francis J. Lacoste
Add Vary header to our response. |
571 |
|
2649
by Canonical.com Patch Queue Manager
[trivial] small refactor of the request type used in launchpad, to make certain traversal tricks more straightforward. |
572 |
@property
|
573 |
def stepstogo(self): |
|
574 |
return StepsToGo(self) |
|
575 |
||
3485.3.54
by James Henstridge
Preserve the list of set WSGI keys over request retries, to really fix bug 92164 |
576 |
def retry(self): |
577 |
"""See IPublisherRequest."""
|
|
578 |
new_request = super(BasicLaunchpadRequest, self).retry() |
|
7703.4.1
by Francis J. Lacoste
Add Vary header to our response. |
579 |
# Propagate the list of keys we have set in the WSGI environment.
|
3485.3.54
by James Henstridge
Preserve the list of set WSGI keys over request retries, to really fix bug 92164 |
580 |
new_request._wsgi_keys = self._wsgi_keys |
581 |
return new_request |
|
582 |
||
2909.1.1
by James Henstridge
Keep track of the traversed objects in the request, so they can be |
583 |
def getNearest(self, *some_interfaces): |
2909.1.10
by James Henstridge
Fix issues brought up in SteveA's review |
584 |
"""See ILaunchpadBrowserApplicationRequest.getNearest()"""
|
2909.1.1
by James Henstridge
Keep track of the traversed objects in the request, so they can be |
585 |
for context in reversed(self.traversed_objects): |
586 |
for iface in some_interfaces: |
|
587 |
if iface.providedBy(context): |
|
2909.1.10
by James Henstridge
Fix issues brought up in SteveA's review |
588 |
return context, iface |
589 |
return None, None |
|
2909.1.1
by James Henstridge
Keep track of the traversed objects in the request, so they can be |
590 |
|
3750.1.60
by Steve Alexander
support setting wsgi environment key+value pairs from xmlrpc requests. |
591 |
def setInWSGIEnvironment(self, key, value): |
592 |
"""Set a key-value pair in the WSGI environment of this request.
|
|
593 |
||
4167.1.1
by James Henstridge
allow setInWSGIEnvironment() to change values it had previously set |
594 |
Raises KeyError if the key is already present in the environment
|
595 |
but not set with setInWSGIEnvironment().
|
|
3750.1.60
by Steve Alexander
support setting wsgi environment key+value pairs from xmlrpc requests. |
596 |
"""
|
597 |
# This method expects the BasicLaunchpadRequest mixin to be used
|
|
598 |
# with a base that provides self._orig_env.
|
|
4167.1.1
by James Henstridge
allow setInWSGIEnvironment() to change values it had previously set |
599 |
if key not in self._wsgi_keys and key in self._orig_env: |
3750.1.60
by Steve Alexander
support setting wsgi environment key+value pairs from xmlrpc requests. |
600 |
raise KeyError("'%s' already present in wsgi environment." % key) |
601 |
self._orig_env[key] = value |
|
4167.1.1
by James Henstridge
allow setInWSGIEnvironment() to change values it had previously set |
602 |
self._wsgi_keys.add(key) |
3750.1.60
by Steve Alexander
support setting wsgi environment key+value pairs from xmlrpc requests. |
603 |
|
7666.3.8
by Michael Nelson
Moved the query_string_params dict into BasicLaunchpadRequest as the web service calls BatchNavigator.init and expects it to be in the request. |
604 |
@cachedproperty
|
605 |
def query_string_params(self): |
|
606 |
"""See ILaunchpadBrowserApplicationRequest."""
|
|
7666.3.11
by Michael Nelson
Implemented Guilhermes' suggestions. |
607 |
return get_query_string_params(self) |
7666.3.8
by Michael Nelson
Moved the query_string_params dict into BasicLaunchpadRequest as the web service calls BatchNavigator.init and expects it to be in the request. |
608 |
|
8310.1.14
by Guilherme Salgado
Get rid of shipit-specific code from canonical_url() |
609 |
|
3258.4.4
by Steve Alexander
Made navigation components be used for XMLRPC traversal by registering them |
610 |
class LaunchpadBrowserRequest(BasicLaunchpadRequest, BrowserRequest, |
7675.834.9
by Michael Nelson
Updated is_ajax. |
611 |
NotificationRequest, ErrorReportRequest): |
3258.4.4
by Steve Alexander
Made navigation components be used for XMLRPC traversal by registering them |
612 |
"""Integration of launchpad mixin request classes to make an uber
|
613 |
launchpad request class.
|
|
614 |
"""
|
|
615 |
||
11132.1.3
by James Westby
Have LaunchpadBrowserRequest implement LaunchpadLayer. |
616 |
implements( |
617 |
ILaunchpadBrowserApplicationRequest, ISynchronizer, |
|
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
618 |
lp.layers.LaunchpadLayer) |
3258.4.4
by Steve Alexander
Made navigation components be used for XMLRPC traversal by registering them |
619 |
|
3519.1.5
by Stuart Bishop
Increase retry count to 5 |
620 |
retry_max_count = 5 # How many times we're willing to retry |
621 |
||
7055.2.15
by Michael Hudson
clear the cache on commit() |
622 |
def __init__(self, body_instream, environ, response=None): |
623 |
BasicLaunchpadRequest.__init__(self, body_instream, environ, response) |
|
624 |
transaction.manager.registerSynch(self) |
|
625 |
||
2976.10.112
by Stuart Bishop
Fix _createReponse method signature |
626 |
def _createResponse(self): |
3258.4.4
by Steve Alexander
Made navigation components be used for XMLRPC traversal by registering them |
627 |
"""As per zope.publisher.browser.BrowserRequest._createResponse"""
|
2976.10.109
by Stuart Bishop
Merge from Rocketfuel |
628 |
return LaunchpadBrowserResponse() |
3258.4.4
by Steve Alexander
Made navigation components be used for XMLRPC traversal by registering them |
629 |
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
630 |
@cachedproperty
|
631 |
def form_ng(self): |
|
632 |
"""See ILaunchpadBrowserApplicationRequest."""
|
|
633 |
return BrowserFormNG(self.form) |
|
634 |
||
7055.2.3
by Michael Hudson
this seems like a good idea. |
635 |
def setPrincipal(self, principal): |
7055.2.14
by Michael Hudson
fix remaining failure |
636 |
self.clearSecurityPolicyCache() |
637 |
BrowserRequest.setPrincipal(self, principal) |
|
638 |
||
639 |
def clearSecurityPolicyCache(self): |
|
7055.2.10
by Michael Hudson
parameterize the cache key |
640 |
if LAUNCHPAD_SECURITY_POLICY_CACHE_KEY in self.annotations: |
641 |
del self.annotations[LAUNCHPAD_SECURITY_POLICY_CACHE_KEY] |
|
7055.2.3
by Michael Hudson
this seems like a good idea. |
642 |
|
7055.2.15
by Michael Hudson
clear the cache on commit() |
643 |
def beforeCompletion(self, transaction): |
644 |
"""See `ISynchronizer`."""
|
|
645 |
pass
|
|
646 |
||
647 |
def afterCompletion(self, transaction): |
|
7055.2.16
by Michael Hudson
extend docstring |
648 |
"""See `ISynchronizer`.
|
649 |
||
650 |
We clear the cache of security policy results on commit, as objects
|
|
651 |
will be refetched from the database and the security checks may result
|
|
652 |
in different answers.
|
|
653 |
"""
|
|
7055.2.15
by Michael Hudson
clear the cache on commit() |
654 |
self.clearSecurityPolicyCache() |
655 |
||
656 |
def newTransaction(self, transaction): |
|
657 |
"""See `ISynchronizer`."""
|
|
658 |
pass
|
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
659 |
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
660 |
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
661 |
class BrowserFormNG: |
662 |
"""Wrapper that provides IBrowserFormNG around a regular form dict."""
|
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
663 |
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
664 |
implements(IBrowserFormNG) |
665 |
||
666 |
def __init__(self, form): |
|
5318.1.2
by Edwin Grubbs
Fixed doctests |
667 |
"""Create a new BrowserFormNG that wraps a dict containing form data.
|
668 |
"""
|
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
669 |
self.form = form |
670 |
||
671 |
def __contains__(self, name): |
|
672 |
"""See IBrowserFormNG."""
|
|
673 |
return name in self.form |
|
674 |
||
4173.1.2
by Francis J. Lacoste
Add __iter__ to IBrowserFormNG. |
675 |
def __iter__(self): |
676 |
"""See IBrowserFormNG."""
|
|
677 |
return iter(self.form) |
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
678 |
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
679 |
def getOne(self, name, default=None): |
680 |
"""See IBrowserFormNG."""
|
|
681 |
value = self.form.get(name, default) |
|
682 |
if zope_isinstance(value, (list, tuple)): |
|
683 |
raise UnexpectedFormData( |
|
684 |
'Expected only one value form field %s: %s' % (name, value)) |
|
685 |
return value |
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
686 |
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
687 |
def getAll(self, name, default=None): |
688 |
"""See IBrowserFormNG."""
|
|
689 |
# We don't want a mutable as a default parameter, so we use None as a
|
|
690 |
# marker.
|
|
691 |
if default is None: |
|
692 |
default = [] |
|
4173.1.8
by Francis J. Lacoste
Only accept list as default for getAll |
693 |
else: |
694 |
assert zope_isinstance(default, list), ( |
|
695 |
"default should be a list: %s" % default) |
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
696 |
value = self.form.get(name, default) |
697 |
if not zope_isinstance(value, list): |
|
698 |
value = [value] |
|
699 |
return value |
|
700 |
||
3258.4.4
by Steve Alexander
Made navigation components be used for XMLRPC traversal by registering them |
701 |
|
8137.8.2
by Celso Providelo
Isolating the code for converting webservice requests to webapp ones. |
702 |
def web_service_request_to_browser_request(webservice_request): |
703 |
"""Convert a given webservice request into a webapp one.
|
|
704 |
||
13702.1.1
by Aaron Bentley
Handle unicode URL paths gracefully in web_service_request_to_browser_request. |
705 |
Overrides 'SERVER_URL' to the 'mainsite', preserving headers and
|
706 |
body. Encodes PATH_INFO because it is unconditionally decoded by
|
|
707 |
zope.publisher.http.sane_environment.
|
|
8137.8.2
by Celso Providelo
Isolating the code for converting webservice requests to webapp ones. |
708 |
"""
|
709 |
body = webservice_request.bodyStream.getCacheStream().read() |
|
710 |
environ = dict(webservice_request.environment) |
|
711 |
environ['SERVER_URL'] = allvhosts.configs['mainsite'].rooturl |
|
13702.1.1
by Aaron Bentley
Handle unicode URL paths gracefully in web_service_request_to_browser_request. |
712 |
if 'PATH_INFO' in environ: |
713 |
environ['PATH_INFO'] = environ['PATH_INFO'].encode('utf-8') |
|
8137.8.2
by Celso Providelo
Isolating the code for converting webservice requests to webapp ones. |
714 |
return LaunchpadBrowserRequest(body, environ) |
715 |
||
716 |
||
4311.2.2
by Francis J. Lacoste
Show how the regular widgets fail. Allow uninstallation of the monkey patch. |
717 |
class Zope3WidgetsUseIBrowserFormNGMonkeyPatch: |
718 |
"""Make Zope3 widgets use IBrowserFormNG.
|
|
719 |
||
720 |
Replace the SimpleInputWidget._getFormInput method with one using
|
|
721 |
`IBrowserFormNG`.
|
|
722 |
"""
|
|
723 |
||
724 |
installed = False |
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
725 |
|
4311.2.2
by Francis J. Lacoste
Show how the regular widgets fail. Allow uninstallation of the monkey patch. |
726 |
@classmethod
|
727 |
def install(cls): |
|
728 |
"""Install the monkey patch."""
|
|
729 |
assert not cls.installed, "Monkey patch is already installed." |
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
730 |
|
4311.2.2
by Francis J. Lacoste
Show how the regular widgets fail. Allow uninstallation of the monkey patch. |
731 |
def _getFormInput_single(self): |
732 |
"""Return the submitted form value.
|
|
733 |
||
734 |
:raises UnexpectedFormData: If more than one value is submitted.
|
|
735 |
"""
|
|
736 |
return self.request.form_ng.getOne(self.name) |
|
737 |
||
738 |
def _getFormInput_multi(self): |
|
739 |
"""Return the submitted form values.
|
|
740 |
"""
|
|
741 |
return self.request.form_ng.getAll(self.name) |
|
742 |
||
743 |
# Save the original method and replace it with fixed ones.
|
|
4311.2.7
by Francis J. Lacoste
Change variable name. |
744 |
# We don't save MultiDataHelper._getFormInput because it doesn't
|
745 |
# override the one in SimpleInputWidget.
|
|
746 |
cls._original__getFormInput = SimpleInputWidget._getFormInput |
|
4311.2.2
by Francis J. Lacoste
Show how the regular widgets fail. Allow uninstallation of the monkey patch. |
747 |
SimpleInputWidget._getFormInput = _getFormInput_single |
748 |
MultiDataHelper._getFormInput = _getFormInput_multi |
|
749 |
cls.installed = True |
|
4785.3.7
by Jeroen Vermeulen
Removed whitespace at ends of lines |
750 |
|
4311.2.2
by Francis J. Lacoste
Show how the regular widgets fail. Allow uninstallation of the monkey patch. |
751 |
@classmethod
|
752 |
def uninstall(cls): |
|
753 |
"""Uninstall the monkey patch."""
|
|
754 |
assert cls.installed, "Monkey patch is not installed." |
|
755 |
||
4311.2.7
by Francis J. Lacoste
Change variable name. |
756 |
# Restore saved method.
|
757 |
SimpleInputWidget._getFormInput = cls._original__getFormInput |
|
4311.2.2
by Francis J. Lacoste
Show how the regular widgets fail. Allow uninstallation of the monkey patch. |
758 |
del MultiDataHelper._getFormInput |
759 |
cls.installed = False |
|
760 |
||
761 |
||
762 |
Zope3WidgetsUseIBrowserFormNGMonkeyPatch.install() |
|
4311.2.1
by Francis J. Lacoste
Monkey patch SimpleInputWidget._getFormValue to use IBrowserFormNG. |
763 |
|
764 |
||
2728
by Canonical.com Patch Queue Manager
[r=SteveA] LaunchpadBrowserNotifications |
765 |
class LaunchpadBrowserResponse(NotificationResponse, BrowserResponse): |
766 |
||
767 |
# Note that NotificationResponse defines a 'redirect' method which
|
|
768 |
# needs to override the 'redirect' method in BrowserResponse
|
|
2976.10.5
by Stuart Bishop
Merge from Rocketfuel |
769 |
def __init__(self, header_output=None, http_transaction=None): |
6061.7.2
by Curtis Hovey
This is the minimal set of changes to get make run to complete. |
770 |
super(LaunchpadBrowserResponse, self).__init__() |
2728
by Canonical.com Patch Queue Manager
[r=SteveA] LaunchpadBrowserNotifications |
771 |
|
9678.4.43
by Guilherme Salgado
[r=gary] Change LaunchpadBrowserResponse.redirect() to define trusted=True so that we don't have to change all callsites that might redirect to vhosts. |
772 |
def redirect(self, location, status=None, trusted=True, |
9678.4.30
by Guilherme Salgado
[r=barry] Update our custom implementations of HttpResponse.redirect() to accept the new 'trusted' argument and make it default to True in LaunchpadTestResponse so that our tests can redirect anywhere they want. |
773 |
temporary_if_possible=False): |
3618.1.40
by Steve Alexander
add a team-restricted mode to launchpad |
774 |
"""Do a redirect.
|
775 |
||
9678.4.43
by Guilherme Salgado
[r=gary] Change LaunchpadBrowserResponse.redirect() to define trusted=True so that we don't have to change all callsites that might redirect to vhosts. |
776 |
Unlike Zope's BrowserResponse.redirect(), consider all redirects to be
|
777 |
trusted. Otherwise we'd have to change all callsites that redirect
|
|
778 |
from lp.net to vhost.lp.net to pass trusted=True.
|
|
779 |
||
3618.1.40
by Steve Alexander
add a team-restricted mode to launchpad |
780 |
If temporary_if_possible is True, then do a temporary redirect
|
781 |
if this is a HEAD or GET, otherwise do a 303.
|
|
782 |
||
783 |
See RFC 2616.
|
|
3618.1.43
by Steve Alexander
add note about response.redirect() semantics and fix some trivially failing page tests. |
784 |
|
785 |
The interface doesn't say that redirect returns anything.
|
|
786 |
However, Zope's implementation does return the location given. This
|
|
787 |
is largely useless, as it is just the location given which is often
|
|
788 |
relative. So we won't return anything.
|
|
3618.1.40
by Steve Alexander
add a team-restricted mode to launchpad |
789 |
"""
|
790 |
if temporary_if_possible: |
|
791 |
assert status is None, ( |
|
5318.1.2
by Edwin Grubbs
Fixed doctests |
792 |
"Do not set 'status' if also setting "
|
793 |
"'temporary_if_possible'.") |
|
3618.1.40
by Steve Alexander
add a team-restricted mode to launchpad |
794 |
method = self._request.method |
795 |
if method == 'GET' or method == 'HEAD': |
|
796 |
status = 307 |
|
797 |
else: |
|
798 |
status = 303 |
|
4159.1.1
by Stuart Bishop
Fixes Bug #78780 (Handle redirects containing non-ascii characters) |
799 |
super(LaunchpadBrowserResponse, self).redirect( |
9678.4.30
by Guilherme Salgado
[r=barry] Update our custom implementations of HttpResponse.redirect() to accept the new 'trusted' argument and make it default to True in LaunchpadTestResponse so that our tests can redirect anywhere they want. |
800 |
unicode(location).encode('UTF-8'), status=status, trusted=trusted) |
2728
by Canonical.com Patch Queue Manager
[r=SteveA] LaunchpadBrowserNotifications |
801 |
|
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
802 |
|
2728
by Canonical.com Patch Queue Manager
[r=SteveA] LaunchpadBrowserNotifications |
803 |
def adaptResponseToSession(response): |
804 |
"""Adapt LaunchpadBrowserResponse to ISession"""
|
|
805 |
return ISession(response._request) |
|
806 |
||
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
807 |
|
2728
by Canonical.com Patch Queue Manager
[r=SteveA] LaunchpadBrowserNotifications |
808 |
def adaptRequestToResponse(request): |
809 |
"""Adapt LaunchpadBrowserRequest to LaunchpadBrowserResponse"""
|
|
810 |
return request.response |
|
811 |
||
2649
by Canonical.com Patch Queue Manager
[trivial] small refactor of the request type used in launchpad, to make certain traversal tricks more straightforward. |
812 |
|
13588.10.7
by Gavin Panella
Test both LaunchpadBrowserRequest and LaunchpadTestRequest. |
813 |
class LaunchpadTestRequest(LaunchpadBrowserRequestMixin, |
814 |
TestRequest, ErrorReportRequest): |
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
815 |
"""Mock request for use in unit and functional tests.
|
3258.4.1
by Steve Alexander
Disable trebuchet. Make XMLRPC work, with an (untested) self-check API. |
816 |
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
817 |
>>> request = LaunchpadTestRequest(SERVER_URL='http://127.0.0.1/foo/bar')
|
818 |
||
819 |
This class subclasses TestRequest - the standard Mock request object
|
|
820 |
used in unit tests
|
|
821 |
||
822 |
>>> isinstance(request, TestRequest)
|
|
823 |
True
|
|
824 |
||
4108.4.10
by Guilherme Salgado
Make it possible to choose a team's renewal policy when creating/editing a team |
825 |
It provides LaunchpadLayer and adds a mock INotificationRequest
|
826 |
implementation.
|
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
827 |
|
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
828 |
>>> lp.layers.LaunchpadLayer.providedBy(request)
|
4108.4.10
by Guilherme Salgado
Make it possible to choose a team's renewal policy when creating/editing a team |
829 |
True
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
830 |
>>> INotificationRequest.providedBy(request)
|
831 |
True
|
|
832 |
>>> request.uuid == request.response.uuid
|
|
833 |
True
|
|
834 |
>>> request.notifications is request.response.notifications
|
|
835 |
True
|
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
836 |
|
837 |
It also provides the form_ng attribute that is available from
|
|
838 |
LaunchpadBrowserRequest.
|
|
839 |
||
840 |
>>> from zope.interface.verify import verifyObject
|
|
841 |
>>> verifyObject(IBrowserFormNG, request.form_ng)
|
|
842 |
True
|
|
5369.1.12
by Mark Shuttleworth
Test fixes |
843 |
|
7666.3.5
by Michael Nelson
Added query_string_params to LaunchpadBrowserRequest as suggested by Gary. |
844 |
It also provides the query_string_params dict that is available from
|
845 |
LaunchpadBrowserRequest.
|
|
846 |
||
847 |
>>> request = LaunchpadTestRequest(SERVER_URL='http://127.0.0.1/foo/bar',
|
|
848 |
... QUERY_STRING='a=1&b=2&c=3')
|
|
7675.284.4
by Celso Providelo
fixing test failure. |
849 |
>>> request.charsets = ['utf-8']
|
7666.3.15
by Michael Nelson
Updated after xx-question-search-multiple-languages.txt failed. |
850 |
>>> request.query_string_params == {'a': ['1'], 'b': ['2'], 'c': ['3']}
|
7666.3.5
by Michael Nelson
Added query_string_params to LaunchpadBrowserRequest as suggested by Gary. |
851 |
True
|
852 |
||
5369.1.12
by Mark Shuttleworth
Test fixes |
853 |
It also provides the hooks for popup calendar iframes:
|
854 |
||
855 |
>>> request.needs_datetimepicker_iframe
|
|
5369.1.16
by Mark Shuttleworth
Changes based on review from JamesH |
856 |
False
|
5369.1.12
by Mark Shuttleworth
Test fixes |
857 |
>>> request.needs_datepicker_iframe
|
5369.1.16
by Mark Shuttleworth
Changes based on review from JamesH |
858 |
False
|
6520.3.2
by Guilherme Salgado
Change main-template to include javascript for json/googlemaps if the pages need them. |
859 |
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
860 |
"""
|
14104.3.1
by Michael Hudson-Doyle
sort of manually cherry pick the introduction of IParticipationExtras |
861 |
implements( |
862 |
INotificationRequest, IBasicLaunchpadRequest, IParticipation, |
|
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
863 |
lp.layers.LaunchpadLayer) |
14104.3.1
by Michael Hudson-Doyle
sort of manually cherry pick the introduction of IParticipationExtras |
864 |
|
6141.3.9
by Curtis Hovey
Revisions per review. |
865 |
# These two attributes satisfy IParticipation.
|
6141.3.7
by Curtis Hovey
Removed over-engineered implementation. |
866 |
principal = None |
867 |
interaction = None |
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
868 |
|
4177.4.11
by James Henstridge
add a method keyword argument to LaunchpadTestRequest |
869 |
def __init__(self, body_instream=None, environ=None, form=None, |
870 |
skin=None, outstream=None, method='GET', **kw): |
|
871 |
super(LaunchpadTestRequest, self).__init__( |
|
872 |
body_instream=body_instream, environ=environ, form=form, |
|
873 |
skin=skin, outstream=outstream, REQUEST_METHOD=method, **kw) |
|
4331.4.19
by James Henstridge
clean up loginservice.txt doc test, and make LaunchpadTestRequest more like a real Launchpad request object |
874 |
self.traversed_objects = [] |
5369.1.16
by Mark Shuttleworth
Changes based on review from JamesH |
875 |
self.needs_datepicker_iframe = False |
876 |
self.needs_datetimepicker_iframe = False |
|
12809.1.2
by Brad Crittenden
Removed unnecessary comment |
877 |
# Use an existing feature controller if one exists, otherwise use the
|
878 |
# null controller.
|
|
879 |
self.features = get_relevant_feature_controller() |
|
880 |
if self.features is None: |
|
881 |
self.features = NullFeatureController() |
|
4177.4.11
by James Henstridge
add a method keyword argument to LaunchpadTestRequest |
882 |
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
883 |
@property
|
884 |
def uuid(self): |
|
885 |
return self.response.uuid |
|
886 |
||
887 |
@property
|
|
888 |
def notifications(self): |
|
4331.4.19
by James Henstridge
clean up loginservice.txt doc test, and make LaunchpadTestRequest more like a real Launchpad request object |
889 |
"""See INotificationRequest."""
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
890 |
return self.response.notifications |
891 |
||
4331.4.19
by James Henstridge
clean up loginservice.txt doc test, and make LaunchpadTestRequest more like a real Launchpad request object |
892 |
@property
|
893 |
def stepstogo(self): |
|
894 |
"""See IBasicLaunchpadRequest."""
|
|
895 |
return StepsToGo(self) |
|
896 |
||
897 |
def getNearest(self, *some_interfaces): |
|
898 |
"""See IBasicLaunchpadRequest."""
|
|
899 |
return None, None |
|
900 |
||
5985.5.2
by Francis J. Lacoste
Add references leak debugging to endRequest. |
901 |
def setInWSGIEnvironment(self, key, value): |
902 |
"""See IBasicLaunchpadRequest."""
|
|
903 |
self._orig_env[key] = value |
|
904 |
||
2976.10.29
by Stuart Bishop
Filter WSGI deprecation warning and update _createResponse for new Zope 3.2 design |
905 |
def _createResponse(self): |
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
906 |
"""As per zope.publisher.browser.BrowserRequest._createResponse"""
|
2976.10.29
by Stuart Bishop
Filter WSGI deprecation warning and update _createResponse for new Zope 3.2 design |
907 |
return LaunchpadTestResponse() |
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
908 |
|
4173.1.4
by Francis J. Lacoste
Do not use a cached property for LaunchpadTestRequest, since test something overwrite form. |
909 |
@property
|
4173.1.1
by Francis J. Lacoste
- Add IBrowserFormNG and its implementation. |
910 |
def form_ng(self): |
911 |
"""See ILaunchpadBrowserApplicationRequest."""
|
|
912 |
return BrowserFormNG(self.form) |
|
913 |
||
7666.3.5
by Michael Nelson
Added query_string_params to LaunchpadBrowserRequest as suggested by Gary. |
914 |
@property
|
915 |
def query_string_params(self): |
|
916 |
"""See ILaunchpadBrowserApplicationRequest."""
|
|
7666.3.11
by Michael Nelson
Implemented Guilhermes' suggestions. |
917 |
return get_query_string_params(self) |
7666.3.5
by Michael Nelson
Added query_string_params to LaunchpadBrowserRequest as suggested by Gary. |
918 |
|
6141.3.12
by Curtis Hovey
Added missing setPrincipal method to LaunchpadTestRequest. Curse me for removing it to |
919 |
def setPrincipal(self, principal): |
920 |
"""See `IPublicationRequest`."""
|
|
921 |
self.principal = principal |
|
922 |
||
11843.1.5
by Graham Binns
Added tests for unsubscribing and for the default value when updating. |
923 |
def clearSecurityPolicyCache(self): |
924 |
"""See ILaunchpadBrowserApplicationRequest."""
|
|
925 |
return
|
|
926 |
||
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
927 |
|
3112.1.22
by Brad Bollenbach
fix bug 6026 (Oops from changing bug's product when milestone is set) |
928 |
class LaunchpadTestResponse(LaunchpadBrowserResponse): |
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
929 |
"""Mock response for use in unit and functional tests.
|
930 |
||
931 |
>>> request = LaunchpadTestRequest()
|
|
932 |
>>> response = request.response
|
|
933 |
>>> isinstance(response, LaunchpadTestResponse)
|
|
934 |
True
|
|
935 |
>>> INotificationResponse.providedBy(response)
|
|
936 |
True
|
|
937 |
||
5594.1.10
by Maris Fogels
Fixed all of the calls to addWarningNotification() that contain HTML so that they use the structured() class. |
938 |
>>> response.addWarningNotification('Warning Notification')
|
2856.1.1
by Stuart Bishop
Add LaunchpadTestRequest and LaunchpadTestResponse for unit tests needing access to the notifications machinery |
939 |
>>> request.notifications[0].message
|
940 |
u'Warning Notification'
|
|
941 |
"""
|
|
942 |
implements(INotificationResponse) |
|
943 |
||
944 |
uuid = 'LaunchpadTestResponse' |
|
945 |
||
946 |
_notifications = None |
|
947 |
||
948 |
@property
|
|
949 |
def notifications(self): |
|
950 |
if self._notifications is None: |
|
951 |
self._notifications = NotificationList() |
|
952 |
return self._notifications |
|
953 |
||
954 |
||
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
955 |
class DebugLayerRequestFactory(HTTPPublicationRequestFactory): |
956 |
"""RequestFactory that sets the DebugLayer on a request."""
|
|
957 |
||
2976.10.11
by Stuart Bishop
Resource fix and zcml tweaks. Disable trebuchet. |
958 |
def __call__(self, input_stream, env, output_stream=None): |
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
959 |
"""See zope.app.publication.interfaces.IPublicationRequestFactory"""
|
2976.10.3
by Stuart Bishop
Launchpad is running. Test suite untried |
960 |
assert output_stream is None, 'output_stream is deprecated in Z3.2' |
961 |
||
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
962 |
# Mark the request with the 'lp.layers.debug' layer
|
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
963 |
request = HTTPPublicationRequestFactory.__call__( |
2976.10.3
by Stuart Bishop
Launchpad is running. Test suite untried |
964 |
self, input_stream, env) |
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
965 |
lp.layers.setFirstLayer( |
966 |
request, lp.layers.DebugLayer) |
|
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
967 |
return request |
968 |
||
969 |
||
3750.1.57
by Steve Alexander
checkpoint on footprints work |
970 |
class LaunchpadAccessLogger(CommonAccessLogger): |
971 |
||
972 |
def log(self, task): |
|
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
973 |
"""Receives a completed task and logs it in launchpad log format.
|
974 |
||
975 |
task IP address
|
|
4318.1.1
by Tom Haddon
Changing HTTP_X_FORWARDED_FOR to X_FORWARDED_FOR as Pound and Apache both use that variable |
976 |
X_FORWARDED_FOR
|
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
977 |
HOST
|
978 |
datetime task started
|
|
979 |
request string (1st line of request)
|
|
980 |
response status
|
|
981 |
response bytes written
|
|
11416.3.6
by Robert Collins
Generalise the server stats from SQL to nonpython statements. |
982 |
number of nonpython statements (sql, email, memcache, rabbit etc)
|
5521.3.2
by Guilherme Salgado
Change LaunchpadAccessLogger to log number of sqlstatements, ticks and the request duration. Also monkey patch HTTPCaller.__call__ when running pagetests to log each request. |
983 |
request duration
|
984 |
number of ticks during traversal
|
|
985 |
number of ticks during publication
|
|
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
986 |
launchpad user id
|
987 |
launchpad page id
|
|
988 |
REFERER
|
|
989 |
USER_AGENT
|
|
990 |
||
991 |
"""
|
|
992 |
request_headers = task.request_data.headers |
|
993 |
cgi_env = task.getCGIEnvironment() |
|
994 |
||
4318.1.1
by Tom Haddon
Changing HTTP_X_FORWARDED_FOR to X_FORWARDED_FOR as Pound and Apache both use that variable |
995 |
x_forwarded_for = request_headers.get('X_FORWARDED_FOR', '') |
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
996 |
host = request_headers.get('HOST', '') |
997 |
start_time = self.log_date_string(task.start_time) |
|
998 |
first_line = task.request_data.first_line |
|
999 |
status = task.status |
|
1000 |
bytes_written = task.bytes_written |
|
1001 |
userid = cgi_env.get('launchpad.userid', '') |
|
1002 |
pageid = cgi_env.get('launchpad.pageid', '') |
|
11416.3.14
by Robert Collins
More consistently call blocking things actions. |
1003 |
nonpython_actions = cgi_env.get('launchpad.nonpythonactions', 0) |
5521.3.2
by Guilherme Salgado
Change LaunchpadAccessLogger to log number of sqlstatements, ticks and the request duration. Also monkey patch HTTPCaller.__call__ when running pagetests to log each request. |
1004 |
request_duration = cgi_env.get('launchpad.requestduration', 0) |
1005 |
traversal_ticks = cgi_env.get('launchpad.traversalticks', 0) |
|
1006 |
publication_ticks = cgi_env.get('launchpad.publicationticks', 0) |
|
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
1007 |
referer = request_headers.get('REFERER', '') |
1008 |
user_agent = request_headers.get('USER_AGENT', '') |
|
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1009 |
|
5585.2.8
by Brad Crittenden
Fix code formatting to adhere to coding standards. |
1010 |
log_template = (' - "%s" "%s" [%s] "%s" %s %d %d %s %s ' |
1011 |
'%s "%s" "%s" "%s" "%s"\n') |
|
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1012 |
self.output.logRequest( |
1013 |
task.channel.addr[0], |
|
5585.2.8
by Brad Crittenden
Fix code formatting to adhere to coding standards. |
1014 |
log_template % ( |
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
1015 |
x_forwarded_for, |
1016 |
host, |
|
1017 |
start_time, |
|
1018 |
first_line, |
|
1019 |
status, |
|
1020 |
bytes_written, |
|
11416.3.14
by Robert Collins
More consistently call blocking things actions. |
1021 |
nonpython_actions, |
5521.3.2
by Guilherme Salgado
Change LaunchpadAccessLogger to log number of sqlstatements, ticks and the request duration. Also monkey patch HTTPCaller.__call__ when running pagetests to log each request. |
1022 |
request_duration, |
1023 |
traversal_ticks, |
|
1024 |
publication_ticks, |
|
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
1025 |
userid, |
1026 |
pageid, |
|
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1027 |
referer, |
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
1028 |
user_agent, |
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1029 |
)
|
3750.1.59
by Steve Alexander
launchpad request logging, including page id, launchpad user id and remote ip address |
1030 |
)
|
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1031 |
|
1032 |
||
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
1033 |
http = wsgi.ServerType( |
13125.1.2
by Brad Crittenden
Fixed lint |
1034 |
ZServerTracelogServer, # subclass of WSGIHTTPServer |
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
1035 |
WSGIPublisherApplication, |
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1036 |
LaunchpadAccessLogger, |
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
1037 |
8080, |
1038 |
True) |
|
1039 |
||
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
1040 |
pmhttp = wsgi.ServerType( |
1041 |
PMDBWSGIHTTPServer, |
|
1042 |
WSGIPublisherApplication, |
|
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1043 |
LaunchpadAccessLogger, |
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
1044 |
8081, |
1045 |
True) |
|
1046 |
||
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
1047 |
debughttp = wsgi.ServerType( |
13125.1.2
by Brad Crittenden
Fixed lint |
1048 |
ZServerTracelogServer, # subclass of WSGIHTTPServer |
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
1049 |
WSGIPublisherApplication, |
3750.1.57
by Steve Alexander
checkpoint on footprints work |
1050 |
LaunchpadAccessLogger, |
2438
by Canonical.com Patch Queue Manager
r=spiv new tests for some menu system functionality. reorganisation of browser publication code. |
1051 |
8082, |
3673.4.1
by Bjorn Tillenius
switch to use WSGI servers instead of the old ones. initial go at choosing request,publication by looking at the Host header. |
1052 |
True, |
1053 |
requestFactory=DebugLayerRequestFactory) |
|
3618.1.49
by Steve Alexander
various small refactorings, change features.launchpad.dev to blueprint.launchpad.dev, implement code.launchpad.dev |
1054 |
|
4823.6.1
by Barry Warsaw
Implementation of private XML-RPC ports. Here's the approach: |
1055 |
privatexmlrpc = wsgi.ServerType( |
13125.1.2
by Brad Crittenden
Fixed lint |
1056 |
ZServerTracelogServer, # subclass of WSGIHTTPServer |
4823.6.1
by Barry Warsaw
Implementation of private XML-RPC ports. Here's the approach: |
1057 |
WSGIPublisherApplication, |
1058 |
LaunchpadAccessLogger, |
|
1059 |
8080, |
|
1060 |
True) |
|
3618.1.49
by Steve Alexander
various small refactorings, change features.launchpad.dev to blueprint.launchpad.dev, implement code.launchpad.dev |
1061 |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1062 |
|
3618.1.49
by Steve Alexander
various small refactorings, change features.launchpad.dev to blueprint.launchpad.dev, implement code.launchpad.dev |
1063 |
# ---- mainsite
|
1064 |
||
1065 |
class MainLaunchpadPublication(LaunchpadBrowserPublication): |
|
1066 |
"""The publication used for the main Launchpad site."""
|
|
1067 |
||
7703.4.3
by Francis J. Lacoste
Use proper Vary for answers and web service. |
1068 |
|
7675.117.11
by Francis J. Lacoste
Extracted AccountPrincipalMixin so that ShipItPublication doesn't inherit from IdPublication |
1069 |
class AccountPrincipalMixin: |
1070 |
"""Mixin for publication that works with person-less accounts."""
|
|
7675.85.2
by Jonathan Lange
Undo revision generated by step 2 of process. |
1071 |
|
1072 |
def getPrincipal(self, request): |
|
1073 |
"""Return the authenticated principal for this request.
|
|
1074 |
||
1075 |
This is only necessary because, unlike in LaunchpadBrowserPublication,
|
|
1076 |
here we want principals representing personless accounts to be
|
|
1077 |
returned, so that personless accounts can use our OpenID server.
|
|
1078 |
"""
|
|
1079 |
auth_utility = getUtility(IPlacelessAuthUtility) |
|
1080 |
principal = auth_utility.authenticate(request) |
|
1081 |
if principal is None: |
|
1082 |
principal = auth_utility.unauthenticatedPrincipal() |
|
1083 |
assert principal is not None, "Missing unauthenticated principal." |
|
1084 |
return principal |
|
1085 |
||
1086 |
||
4934.3.2
by Elliot Murphy
checkpoint after adding FeedsLayer |
1087 |
# ---- feeds
|
4823.6.1
by Barry Warsaw
Implementation of private XML-RPC ports. Here's the approach: |
1088 |
|
4934.3.9
by Elliot Murphy
Renaming from Feed to Feeds. |
1089 |
class FeedsPublication(LaunchpadBrowserPublication): |
4934.3.1
by Elliot Murphy
checkpoint |
1090 |
"""The publication used for Launchpad feed requests."""
|
1091 |
||
4934.3.9
by Elliot Murphy
Renaming from Feed to Feeds. |
1092 |
root_object_interface = IFeedsApplication |
5318.1.2
by Edwin Grubbs
Fixed doctests |
1093 |
|
5318.1.1
by Edwin Grubbs
Restricted feed.lp.net to serving feeds |
1094 |
def traverseName(self, request, ob, name): |
5318.1.2
by Edwin Grubbs
Fixed doctests |
1095 |
"""Override traverseName to restrict urls on feeds.launchpad.net.
|
1096 |
||
1097 |
Feeds.lp.net should only serve classes that implement the IFeed
|
|
1098 |
interface or redirect to some other url.
|
|
1099 |
"""
|
|
6768.2.4
by Edwin Grubbs
Allow images to be served from feeds.lp.net subdomain |
1100 |
# LaunchpadImageFolder is imported here to avoid an import loop.
|
13130.1.1
by Curtis Hovey
Moved launchpad.py to lp.app.browser |
1101 |
from lp.app.browser.launchpad import LaunchpadImageFolder |
5318.1.1
by Edwin Grubbs
Restricted feed.lp.net to serving feeds |
1102 |
result = super(FeedsPublication, self).traverseName(request, ob, name) |
1103 |
if len(request.stepstogo) == 0: |
|
5318.1.2
by Edwin Grubbs
Fixed doctests |
1104 |
# The url has been fully traversed. Now we can check that
|
6768.2.4
by Edwin Grubbs
Allow images to be served from feeds.lp.net subdomain |
1105 |
# the result is a feed, an image, or a redirection.
|
5318.1.1
by Edwin Grubbs
Restricted feed.lp.net to serving feeds |
1106 |
naked_result = removeSecurityProxy(result) |
5318.1.2
by Edwin Grubbs
Fixed doctests |
1107 |
if (IFeed.providedBy(result) or |
6768.2.4
by Edwin Grubbs
Allow images to be served from feeds.lp.net subdomain |
1108 |
isinstance(naked_result, LaunchpadImageFolder) or |
5318.1.2
by Edwin Grubbs
Fixed doctests |
1109 |
getattr(naked_result, 'status', None) == 301): |
5318.1.1
by Edwin Grubbs
Restricted feed.lp.net to serving feeds |
1110 |
return result |
1111 |
else: |
|
5494.2.1
by Edwin Grubbs
Fixed bug 177949. http://feeds.launchpad.net/bugs should be NotFound instead of an oops |
1112 |
raise NotFound(self, '', request) |
5318.1.1
by Edwin Grubbs
Restricted feed.lp.net to serving feeds |
1113 |
else: |
5318.1.2
by Edwin Grubbs
Fixed doctests |
1114 |
# There are still url segments to traverse.
|
5318.1.1
by Edwin Grubbs
Restricted feed.lp.net to serving feeds |
1115 |
return result |
4934.3.9
by Elliot Murphy
Renaming from Feed to Feeds. |
1116 |
|
5585.2.2
by Brad Crittenden
Extracted getPrincipal method from LaunchpadBrowserPublication. |
1117 |
def getPrincipal(self, request): |
1118 |
"""For feeds always return the anonymous user."""
|
|
1119 |
auth_utility = getUtility(IPlacelessAuthUtility) |
|
1120 |
return auth_utility.unauthenticatedPrincipal() |
|
1121 |
||
4934.3.9
by Elliot Murphy
Renaming from Feed to Feeds. |
1122 |
|
1123 |
class FeedsBrowserRequest(LaunchpadBrowserRequest): |
|
4934.3.1
by Elliot Murphy
checkpoint |
1124 |
"""Request type for a launchpad feed."""
|
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
1125 |
implements(lp.layers.FeedsLayer) |
4934.3.1
by Elliot Murphy
checkpoint |
1126 |
|
10065.2.3
by Guilherme Salgado
Move the test openid views under a newly created testopenid vhost. |
1127 |
|
11073.1.6
by Guilherme Salgado
Fix the IAbsoluteURL issue |
1128 |
# ---- apidoc
|
1129 |
||
1130 |
class APIDocBrowserRequest(LaunchpadBrowserRequest): |
|
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
1131 |
implements(lp.layers.APIDocLayer) |
11073.1.6
by Guilherme Salgado
Fix the IAbsoluteURL issue |
1132 |
|
1133 |
||
1134 |
class APIDocBrowserPublication(LaunchpadBrowserPublication): |
|
1135 |
root_object_interface = IAPIDocRoot |
|
1136 |
||
1137 |
||
10065.2.3
by Guilherme Salgado
Move the test openid views under a newly created testopenid vhost. |
1138 |
# ---- testopenid
|
1139 |
||
1140 |
class TestOpenIDBrowserRequest(LaunchpadBrowserRequest): |
|
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
1141 |
implements(lp.layers.TestOpenIDLayer) |
10065.2.3
by Guilherme Salgado
Move the test openid views under a newly created testopenid vhost. |
1142 |
|
1143 |
||
1144 |
class TestOpenIDBrowserPublication(LaunchpadBrowserPublication): |
|
1145 |
root_object_interface = ITestOpenIDApplication |
|
1146 |
||
1147 |
||
5435.1.2
by Leonard Richardson
Added an 'api' vhost that responds to all major HTTP methods. |
1148 |
# ---- web service
|
1149 |
||
7893.3.4
by Francis J. Lacoste
Moved generic webservice publisher stuff to canonical.lazr.rest.publisher. |
1150 |
class WebServicePublication(WebServicePublicationMixin, |
1151 |
LaunchpadBrowserPublication): |
|
5435.1.6
by Leonard Richardson
Implement a 'hello world' web service. |
1152 |
"""The publication used for Launchpad web service requests."""
|
1153 |
||
1154 |
root_object_interface = IWebServiceApplication |
|
1155 |
||
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
1156 |
def constructPageID(self, view, context): |
11351.1.4
by Diogo Matsubara
review comments: change test to be more clear about the pageid for CollectionResource, add comment explaining where the additional page id info comes from and a pointer to wiki page explaining WebService page ids. |
1157 |
"""Add the web service named operation (if any) to the page ID.
|
1158 |
||
1159 |
See https://dev.launchpad.net/Foundations/Webservice for more
|
|
1160 |
information about WebService page IDs.
|
|
1161 |
"""
|
|
11178.1.2
by Benji York
implement Gary's suggested improvments |
1162 |
pageid = super(WebServicePublication, self).constructPageID( |
1163 |
view, context) |
|
11351.1.1
by Diogo Matsubara
Fix bug 606184 (API Pageid for collections is 'scopedcollection:collectionresource' which does not mention the origin page id) |
1164 |
if ICollectionResource.providedBy(view): |
11351.1.4
by Diogo Matsubara
review comments: change test to be more clear about the pageid for CollectionResource, add comment explaining where the additional page id info comes from and a pointer to wiki page explaining WebService page ids. |
1165 |
# collection_identifier is a way to differentiate between
|
1166 |
# CollectionResource objects. CollectionResource objects are
|
|
1167 |
# objects that serve a list of Entry resources through the
|
|
1168 |
# WebService, so by querying the CollectionResource.type_url
|
|
1169 |
# attribute we're able to find out the resource type the
|
|
1170 |
# collection holds. See lazr.restful._resource.py to see how
|
|
1171 |
# the type_url is constructed.
|
|
1172 |
# We don't need the full URL, just the type of the resource.
|
|
11351.1.1
by Diogo Matsubara
Fix bug 606184 (API Pageid for collections is 'scopedcollection:collectionresource' which does not mention the origin page id) |
1173 |
collection_identifier = view.type_url.split('/')[-1] |
1174 |
if collection_identifier: |
|
1175 |
pageid += ':' + collection_identifier |
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
1176 |
op = (view.request.get('ws.op') |
1177 |
or view.request.query_string_params.get('ws.op')) |
|
13840.1.1
by Benji York
fix bug |
1178 |
if op and isinstance(op, basestring): |
11178.1.2
by Benji York
implement Gary's suggested improvments |
1179 |
pageid += ':' + op |
1180 |
return pageid |
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
1181 |
|
5863.16.3
by Leonard Richardson
Objects served through the web service should always be served with the WebServiceApplication, no matter what application is used to serve them through the web site. |
1182 |
def getApplication(self, request): |
1183 |
"""See `zope.publisher.interfaces.IPublication`.
|
|
1184 |
||
1185 |
Always use the web service application to serve web service
|
|
1186 |
resources, no matter what application is normally used to serve
|
|
1187 |
the underlying objects.
|
|
1188 |
"""
|
|
1189 |
return getUtility(IWebServiceApplication) |
|
1190 |
||
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1191 |
def getResource(self, request, ob): |
5835.6.21
by Francis J. Lacoste
Updated grammar and style based on sinzui's comments. |
1192 |
"""Return the resource that can publish the object ob.
|
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1193 |
|
1194 |
This is done at the end of traversal. If the published object
|
|
1195 |
supports the ICollection, or IEntry interface we wrap it into the
|
|
1196 |
appropriate resource.
|
|
1197 |
"""
|
|
7893.3.4
by Francis J. Lacoste
Moved generic webservice publisher stuff to canonical.lazr.rest.publisher. |
1198 |
if zope_isinstance(ob, RedirectionView): |
6793.3.1
by Leonard Richardson
Renamed class, fixed test. |
1199 |
# A redirection should be served as is.
|
1200 |
return ob |
|
5835.6.14
by Francis J. Lacoste
Only allow publishing of IHTTPResource or objects that have an IEntry or ICollection adapters. |
1201 |
else: |
7893.3.4
by Francis J. Lacoste
Moved generic webservice publisher stuff to canonical.lazr.rest.publisher. |
1202 |
return super(WebServicePublication, self).getResource(request, ob) |
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1203 |
|
14080.3.1
by Gavin Panella
Issue an FinishReadOnlyRequestEvent at the end of a read-only request. |
1204 |
def finishReadOnlyRequest(self, request, ob, txn): |
5796.17.1
by Guilherme Salgado
Do not abort the transaction in GET requests on api.launchpad.dev in order to make sure newly created nonces are actually stored. |
1205 |
"""Commit the transaction so that created OAuthNonces are stored."""
|
14080.3.9
by Gavin Panella
Demonstrate the FinishReadOnlyRequestEvent is fired by both LaunchpadBrowserPublication and WebServicePublication. |
1206 |
notify(FinishReadOnlyRequestEvent(ob, request)) |
6061.2.57
by Gary Poster
Add handling of doomed transactions to our custom publisher. |
1207 |
# Transaction commits usually need to be aware of the possibility of
|
1208 |
# a doomed transaction. We do not expect that this code will
|
|
1209 |
# encounter doomed transactions. If it does, this will need to be
|
|
1210 |
# revisited.
|
|
5796.17.1
by Guilherme Salgado
Do not abort the transaction in GET requests on api.launchpad.dev in order to make sure newly created nonces are actually stored. |
1211 |
txn.commit() |
1212 |
||
5796.16.2
by Guilherme Salgado
Change WebServicePublication.getPrincipal() to return the person associated with the access token in the request, if everything is okay in the request and the signature matches. |
1213 |
def getPrincipal(self, request): |
7014.5.24
by Francis J. Lacoste
Use regular authentication on non-API host. |
1214 |
"""See `LaunchpadBrowserPublication`.
|
1215 |
||
7014.5.26
by Francis J. Lacoste
Typos. |
1216 |
Web service requests are authenticated using OAuth, except for the
|
7014.5.24
by Francis J. Lacoste
Use regular authentication on non-API host. |
1217 |
one made using (presumably) JavaScript on the /api override path.
|
13125.1.1
by Brad Crittenden
Prevent API token errors from causing an OOPS |
1218 |
|
1219 |
Raises a variety of token errors (ClockSkew, NonceAlreadyUsed,
|
|
1220 |
TimestampOrderingError, TokenException) which have a webservice error
|
|
1221 |
status of Unauthorized - 401. All of these exceptions represent
|
|
1222 |
errors on the part of the client.
|
|
1223 |
||
1224 |
Raises Unauthorized directly in the case where the consumer is None
|
|
1225 |
for a non-anonymous request as it may represent a server error.
|
|
7014.5.24
by Francis J. Lacoste
Use regular authentication on non-API host. |
1226 |
"""
|
1227 |
# Use the regular HTTP authentication, when the request is not
|
|
1228 |
# on the API virtual host but comes through the path_override on
|
|
1229 |
# the other regular virtual hosts.
|
|
1230 |
request_path = request.get('PATH_INFO', '') |
|
7895.1.10
by Leonard Richardson
Fixed test failures. |
1231 |
web_service_config = getUtility(IWebServiceConfiguration) |
1232 |
if request_path.startswith("/%s" % web_service_config.path_override): |
|
7014.5.24
by Francis J. Lacoste
Use regular authentication on non-API host. |
1233 |
return super(WebServicePublication, self).getPrincipal(request) |
1234 |
||
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
1235 |
# Fetch OAuth authorization information from the request.
|
1236 |
form = get_oauth_authorization(request) |
|
1237 |
||
1238 |
consumer_key = form.get('oauth_consumer_key') |
|
1239 |
consumers = getUtility(IOAuthConsumerSet) |
|
1240 |
consumer = consumers.getByKey(consumer_key) |
|
1241 |
token_key = form.get('oauth_token') |
|
1242 |
anonymous_request = (token_key == '') |
|
1243 |
||
1244 |
if consumer_key is None: |
|
1245 |
# Either the client's OAuth implementation is broken, or
|
|
1246 |
# the user is trying to make an unauthenticated request
|
|
1247 |
# using wget or another OAuth-ignorant application.
|
|
1248 |
# Try to retrieve a consumer based on the User-Agent
|
|
1249 |
# header.
|
|
1250 |
anonymous_request = True |
|
13085.3.10
by Deryck Hodge
need to preserve getting the consumer key from user agent after all. |
1251 |
consumer_key = request.getHeader('User-Agent', '') |
1252 |
if consumer_key == '': |
|
1253 |
consumer_key = 'anonymous client' |
|
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
1254 |
consumer = consumers.getByKey(consumer_key) |
1255 |
||
1256 |
if consumer is None: |
|
1257 |
if anonymous_request: |
|
1258 |
# This is the first time anyone has tried to make an
|
|
1259 |
# anonymous request using this consumer name (or user
|
|
1260 |
# agent). Dynamically create the consumer.
|
|
1261 |
#
|
|
1262 |
# In the normal website this wouldn't be possible
|
|
1263 |
# because GET requests have their transactions rolled
|
|
1264 |
# back. But webservice requests always have their
|
|
1265 |
# transactions committed so that we can keep track of
|
|
1266 |
# the OAuth nonces and prevent replay attacks.
|
|
1267 |
if consumer_key == '' or consumer_key is None: |
|
13125.1.1
by Brad Crittenden
Prevent API token errors from causing an OOPS |
1268 |
raise TokenException("No consumer key specified.") |
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
1269 |
consumer = consumers.new(consumer_key, '') |
1270 |
else: |
|
1271 |
# An unknown consumer can never make a non-anonymous
|
|
1272 |
# request, because access tokens are registered with a
|
|
1273 |
# specific, known consumer.
|
|
1274 |
raise Unauthorized('Unknown consumer (%s).' % consumer_key) |
|
1275 |
if anonymous_request: |
|
1276 |
# Skip the OAuth verification step and let the user access the
|
|
1277 |
# web service as an unauthenticated user.
|
|
1278 |
#
|
|
1279 |
# XXX leonardr 2009-12-15 bug=496964: Ideally we'd be
|
|
1280 |
# auto-creating a token for the anonymous user the first
|
|
1281 |
# time, passing it through the OAuth verification step,
|
|
1282 |
# and using it on all subsequent anonymous requests.
|
|
1283 |
alsoProvides(request, IOAuthSignedRequest) |
|
1284 |
auth_utility = getUtility(IPlacelessAuthUtility) |
|
1285 |
return auth_utility.unauthenticatedPrincipal() |
|
1286 |
token = consumer.getAccessToken(token_key) |
|
1287 |
if token is None: |
|
13125.1.1
by Brad Crittenden
Prevent API token errors from causing an OOPS |
1288 |
raise TokenException('Unknown access token (%s).' % token_key) |
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
1289 |
nonce = form.get('oauth_nonce') |
1290 |
timestamp = form.get('oauth_timestamp') |
|
13125.1.1
by Brad Crittenden
Prevent API token errors from causing an OOPS |
1291 |
token.checkNonceAndTimestamp(nonce, timestamp) |
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
1292 |
if token.permission == OAuthPermission.UNAUTHORIZED: |
13125.1.1
by Brad Crittenden
Prevent API token errors from causing an OOPS |
1293 |
raise TokenException('Unauthorized token (%s).' % token.key) |
11694.2.1
by Leonard Richardson
Initial implementation. |
1294 |
elif token.is_expired: |
13125.1.1
by Brad Crittenden
Prevent API token errors from causing an OOPS |
1295 |
raise TokenException('Expired token (%s).' % token.key) |
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
1296 |
elif not check_oauth_signature(request, consumer, token): |
13125.1.1
by Brad Crittenden
Prevent API token errors from causing an OOPS |
1297 |
raise TokenException('Invalid signature.') |
11579.1.1
by Leonard Richardson
Reverted my earlier change. |
1298 |
else: |
1299 |
# Everything is fine, let's return the principal.
|
|
1300 |
pass
|
|
1301 |
alsoProvides(request, IOAuthSignedRequest) |
|
1302 |
principal = getUtility(IPlacelessLoginSource).getPrincipal( |
|
1303 |
token.person.account.id, access_level=token.permission, |
|
1304 |
scope=token.context) |
|
1305 |
||
1306 |
return principal |
|
6314.7.1
by Leonard Richardson
Initial implementation. |
1307 |
|
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1308 |
|
11936.1.3
by Abel Deuring
revert patch for LaunchpadWebServiceRequestTraversal. We need the method getRootURL() of mixin class WebServiceClientRequest not only in WebServiceClientRequest, but also in WebServiceTestRequest |
1309 |
class LaunchpadWebServiceRequestTraversal(WebServiceRequestTraversal): |
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
1310 |
implements(lp.layers.WebServiceLayer) |
11936.1.3
by Abel Deuring
revert patch for LaunchpadWebServiceRequestTraversal. We need the method getRootURL() of mixin class WebServiceClientRequest not only in WebServiceClientRequest, but also in WebServiceTestRequest |
1311 |
|
1312 |
def getRootURL(self, rootsite): |
|
1313 |
"""See IBasicLaunchpadRequest."""
|
|
1314 |
# When browsing the web service, we want URLs to point back at the web
|
|
1315 |
# service, so we basically ignore rootsite.
|
|
1316 |
return self.getApplicationURL() + '/' |
|
1317 |
||
1318 |
||
1319 |
class WebServiceClientRequest(LaunchpadWebServiceRequestTraversal, |
|
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1320 |
LaunchpadBrowserRequest): |
5435.1.2
by Leonard Richardson
Added an 'api' vhost that responds to all major HTTP methods. |
1321 |
"""Request type for a resource published through the web service."""
|
1322 |
||
7703.4.3
by Francis J. Lacoste
Use proper Vary for answers and web service. |
1323 |
def __init__(self, body_instream, environ, response=None): |
1324 |
super(WebServiceClientRequest, self).__init__( |
|
1325 |
body_instream, environ, response) |
|
10790.2.1
by Leonard Richardson
Merged already-reviewed diff into a new branch to avoid having to resolve lots of conflicts. |
1326 |
# Web service requests use content negotiation, so we put
|
1327 |
# 'Accept' in the Vary header. They don't use cookies, so
|
|
1328 |
# there's no point in putting 'Cookie' in the Vary header, and
|
|
1329 |
# putting 'Authorization' in the Vary header totally destroys
|
|
1330 |
# caching because every web service request contains a
|
|
1331 |
# distinct OAuth nonce in its Authorization header.
|
|
1332 |
#
|
|
1333 |
# Because 'Authorization' is not in the Vary header, a client
|
|
1334 |
# that reuses a single cache for different OAuth credentials
|
|
1335 |
# could conceivably leak private information to an
|
|
1336 |
# unprivileged user via the cache. This won't happen for the
|
|
1337 |
# web service root resource because the service root is the
|
|
1338 |
# same for everybody. It won't happen for entry resources
|
|
1339 |
# because if two users have a different representation of an
|
|
1340 |
# entry, the ETag will also be different and a conditional
|
|
1341 |
# request will fail.
|
|
1342 |
#
|
|
1343 |
# Once lazr.restful starts setting caching directives other
|
|
1344 |
# than ETag, we may have to revisit this.
|
|
1345 |
self.response.setHeader('Vary', 'Accept') |
|
7703.4.3
by Francis J. Lacoste
Use proper Vary for answers and web service. |
1346 |
|
11936.1.3
by Abel Deuring
revert patch for LaunchpadWebServiceRequestTraversal. We need the method getRootURL() of mixin class WebServiceClientRequest not only in WebServiceClientRequest, but also in WebServiceTestRequest |
1347 |
|
1348 |
class WebServiceTestRequest(LaunchpadWebServiceRequestTraversal, |
|
1349 |
LaunchpadTestRequest): |
|
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1350 |
"""Test request for the webservice.
|
1351 |
||
1352 |
It provides the WebServiceLayer and supports the getResource()
|
|
1353 |
web publication hook.
|
|
1354 |
"""
|
|
1355 |
||
10304.5.3
by Leonard Richardson
Mark test requests with a version-specific marker interface. |
1356 |
def __init__(self, body_instream=None, environ=None, version=None, **kw): |
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1357 |
test_environ = { |
10420.4.7
by Leonard Richardson
Code cleanup. |
1358 |
'SERVER_URL': 'http://api.launchpad.dev', |
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1359 |
'HTTP_HOST': 'api.launchpad.dev', |
1360 |
}
|
|
1361 |
if environ is not None: |
|
1362 |
test_environ.update(environ) |
|
1363 |
super(WebServiceTestRequest, self).__init__( |
|
1364 |
body_instream=body_instream, environ=test_environ, **kw) |
|
10304.5.3
by Leonard Richardson
Mark test requests with a version-specific marker interface. |
1365 |
if version is None: |
1366 |
version = getUtility(IWebServiceConfiguration).active_versions[-1] |
|
1367 |
self.version = version |
|
1368 |
version_marker = getUtility(IWebServiceVersion, name=version) |
|
1369 |
alsoProvides(self, version_marker) |
|
5835.6.7
by Francis J. Lacoste
Remove code related to having our resources provide IPublishTraverse and ICanonicalUrlData. Regular Nanvigation and browser:url will be used to setup traversal/canonical_url. |
1370 |
|
1371 |
||
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1372 |
# ---- xmlrpc
|
1373 |
||
1374 |
class PublicXMLRPCPublication(LaunchpadBrowserPublication): |
|
1375 |
"""The publication used for public XML-RPC requests."""
|
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
1376 |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1377 |
def handleException(self, object, request, exc_info, retry_allowed=True): |
1378 |
LaunchpadBrowserPublication.handleException( |
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
1379 |
self, object, request, exc_info, retry_allowed) |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1380 |
OpStats.stats['xml-rpc faults'] += 1 |
1381 |
||
1382 |
def endRequest(self, request, object): |
|
1383 |
OpStats.stats['xml-rpc requests'] += 1 |
|
1384 |
return LaunchpadBrowserPublication.endRequest(self, request, object) |
|
1385 |
||
1386 |
||
1387 |
class PublicXMLRPCRequest(BasicLaunchpadRequest, XMLRPCRequest, |
|
7675.834.9
by Michael Nelson
Updated is_ajax. |
1388 |
ErrorReportRequest): |
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1389 |
"""Request type for doing public XML-RPC in Launchpad."""
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1390 |
|
1391 |
def _createResponse(self): |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1392 |
return PublicXMLRPCResponse() |
1393 |
||
1394 |
||
1395 |
class PublicXMLRPCResponse(XMLRPCResponse): |
|
1396 |
"""Response type for doing public XML-RPC in Launchpad."""
|
|
1397 |
||
1398 |
def handleException(self, exc_info): |
|
1399 |
# If we don't have a proper xmlrpclib.Fault, and we have
|
|
1400 |
# logged an OOPS, create a Fault that reports the OOPS ID to
|
|
1401 |
# the user.
|
|
1402 |
exc_value = exc_info[1] |
|
1403 |
if not isinstance(exc_value, xmlrpclib.Fault): |
|
1404 |
request = get_current_browser_request() |
|
1405 |
if request is not None and request.oopsid is not None: |
|
1406 |
exc_info = (xmlrpclib.Fault, |
|
1407 |
xmlrpclib.Fault(-1, request.oopsid), |
|
1408 |
None) |
|
1409 |
XMLRPCResponse.handleException(self, exc_info) |
|
1410 |
||
1411 |
||
1412 |
class PrivateXMLRPCPublication(PublicXMLRPCPublication): |
|
1413 |
"""The publication used for private XML-RPC requests."""
|
|
1414 |
||
1415 |
root_object_interface = IPrivateApplication |
|
1416 |
||
1417 |
def traverseName(self, request, ob, name): |
|
1418 |
"""Traverse to an end point or let normal traversal do its thing."""
|
|
1419 |
assert isinstance(request, PrivateXMLRPCRequest), ( |
|
1420 |
'Not a private XML-RPC request') |
|
1421 |
missing = object() |
|
1422 |
end_point = getattr(ob, name, missing) |
|
1423 |
if end_point is missing: |
|
1424 |
return super(PrivateXMLRPCPublication, self).traverseName( |
|
1425 |
request, ob, name) |
|
1426 |
return end_point |
|
1427 |
||
1428 |
||
1429 |
class PrivateXMLRPCRequest(PublicXMLRPCRequest): |
|
1430 |
"""Request type for doing private XML-RPC in Launchpad."""
|
|
1431 |
# For now, the same as public requests.
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1432 |
|
9601.1.1
by Barry Warsaw
Fix the OOPSes in bug 403606 by passing holdMessage() data wrapped in an |
1433 |
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1434 |
# ---- Protocol errors
|
1435 |
||
1436 |
class ProtocolErrorRequest(LaunchpadBrowserRequest): |
|
1437 |
"""An HTTP request that happened to result in an HTTP error."""
|
|
1438 |
||
11073.1.7
by Guilherme Salgado
Fix a bunch of remaining minor issues. |
1439 |
def traverse(self, object): |
1440 |
"""It's already been determined that there's an error. Return None."""
|
|
1441 |
return None |
|
1442 |
||
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1443 |
|
1444 |
class ProtocolErrorPublicationFactory: |
|
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1445 |
"""This class publishes error messages in response to protocol errors."""
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1446 |
|
1447 |
def __init__(self, status, headers=None): |
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
1448 |
"""Store the headers and status for turning into a parameterized
|
1449 |
publication.
|
|
1450 |
"""
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1451 |
if not headers: |
1452 |
headers = {} |
|
1453 |
self.status = status |
|
1454 |
self.headers = headers |
|
1455 |
||
1456 |
def __call__(self, db): |
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
1457 |
"""Create a parameterized publication object."""
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1458 |
return ProtocolErrorPublication(self.status, self.headers) |
1459 |
||
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1460 |
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1461 |
class ProtocolErrorPublication(LaunchpadBrowserPublication): |
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1462 |
"""Publication used for requests that turn out to be protocol errors."""
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1463 |
|
1464 |
def __init__(self, status, headers): |
|
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1465 |
"""Prepare to construct a ProtocolErrorException
|
1466 |
||
1467 |
:param status: The HTTP status to send
|
|
1468 |
:param headers: Any HTTP headers that should be sent.
|
|
1469 |
"""
|
|
5318.1.6
by Edwin Grubbs
Fixed call to LaunchpadBrowserPublication.__init__ |
1470 |
super(ProtocolErrorPublication, self).__init__(None) |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1471 |
self.status = status |
1472 |
self.headers = headers |
|
1473 |
||
1474 |
def callObject(self, request, object): |
|
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1475 |
"""Raise an approprate exception for this protocol error."""
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1476 |
if self.status == 404: |
5206.2.1
by Leonard Richardson
Added test and fix. |
1477 |
raise NotFound(self, '', request) |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1478 |
else: |
1479 |
raise ProtocolErrorException(self.status, self.headers) |
|
1480 |
||
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1481 |
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1482 |
class ProtocolErrorException(Exception): |
5318.1.2
by Edwin Grubbs
Fixed doctests |
1483 |
"""An exception for requests that turn out to be protocol errors."""
|
5088.2.3
by Leonard Richardson
Added a view for protocol errors so they'll be published as objects instead of being treated as catastrophes. |
1484 |
implements(ILaunchpadProtocolError) |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1485 |
|
1486 |
def __init__(self, status, headers): |
|
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1487 |
"""Store status and headers for rendering in the HTTP response."""
|
5318.1.2
by Edwin Grubbs
Fixed doctests |
1488 |
Exception.__init__(self) |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1489 |
self.status = status |
1490 |
self.headers = headers |
|
1491 |
||
1492 |
def __str__(self): |
|
5318.1.2
by Edwin Grubbs
Fixed doctests |
1493 |
"""A protocol error can be well-represented by its HTTP status code.
|
1494 |
"""
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1495 |
return "Protocol error: %s" % self.status |
1496 |
||
6279.1.8
by Francis J. Lacoste
Use time before hard timeout expires as Launchpad default time out value. |
1497 |
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1498 |
def register_launchpad_request_publication_factories(): |
1499 |
"""Register our factories with the Zope3 publisher.
|
|
1500 |
||
1501 |
DEATH TO ZCML!
|
|
1502 |
"""
|
|
1503 |
VHRP = VirtualHostRequestPublicationFactory |
|
7014.5.23
by Francis J. Lacoste
Made /api requests on standard applications virtual host served using the webservice. |
1504 |
VWSHRP = VHostWebServiceRequestPublicationFactory |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1505 |
|
1506 |
factories = [ |
|
7014.5.23
by Francis J. Lacoste
Made /api requests on standard applications virtual host served using the webservice. |
1507 |
VWSHRP('mainsite', LaunchpadBrowserRequest, MainLaunchpadPublication, |
1508 |
handle_default_host=True), |
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1509 |
VHRP('feeds', FeedsBrowserRequest, FeedsPublication), |
7893.3.4
by Francis J. Lacoste
Moved generic webservice publisher stuff to canonical.lazr.rest.publisher. |
1510 |
WebServiceRequestPublicationFactory( |
1511 |
'api', WebServiceClientRequest, WebServicePublication), |
|
1512 |
XMLRPCRequestPublicationFactory( |
|
11178.1.1
by Benji York
add code/tests for generating the page ID differently for web service requests |
1513 |
'xmlrpc', PublicXMLRPCRequest, PublicXMLRPCPublication), |
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1514 |
]
|
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1515 |
|
10212.5.8
by Guilherme Salgado
New config to decide whether or not to enable the test openid provider |
1516 |
if config.launchpad.enable_test_openid_provider: |
10065.2.3
by Guilherme Salgado
Move the test openid views under a newly created testopenid vhost. |
1517 |
factories.append(VHRP('testopenid', TestOpenIDBrowserRequest, |
1518 |
TestOpenIDBrowserPublication)) |
|
1519 |
||
11073.1.6
by Guilherme Salgado
Fix the IAbsoluteURL issue |
1520 |
if config.devmode: |
1521 |
factories.append( |
|
1522 |
VHRP('apidoc', APIDocBrowserRequest, APIDocBrowserPublication)) |
|
1523 |
||
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1524 |
# We may also have a private XML-RPC server.
|
1525 |
private_port = None |
|
1526 |
for server in config.servers: |
|
1527 |
if server.type == 'PrivateXMLRPC': |
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
1528 |
ip, private_port = server.address |
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1529 |
break
|
1530 |
||
1531 |
if private_port is not None: |
|
1532 |
factories.append(XMLRPCRequestPublicationFactory( |
|
1533 |
'xmlrpc_private', PrivateXMLRPCRequest, |
|
1534 |
PrivateXMLRPCPublication, port=private_port)) |
|
1535 |
||
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
1536 |
# Register those factories, in priority order corresponding to
|
1537 |
# their order in the list. This means picking a large number for
|
|
1538 |
# the first factory and giving each subsequent factory the next
|
|
1539 |
# lower number. We need to leave one space left over for the
|
|
1540 |
# catch-all handler defined below, so we start at
|
|
1541 |
# len(factories)+1.
|
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1542 |
for priority, factory in enumerate(factories): |
1543 |
publisher_factory_registry.register( |
|
13125.1.2
by Brad Crittenden
Fixed lint |
1544 |
"*", "*", factory.vhost_name, len(factories) - priority + 1, |
1545 |
factory) |
|
5088.2.5
by Leonard Richardson
Revised in response to flacoste feedback |
1546 |
|
1547 |
# Register a catch-all "not found" handler at the lowest priority.
|
|
5088.2.2
by Leonard Richardson
Got all the tests to pass except the one that wasn't passing before. |
1548 |
publisher_factory_registry.register( |
1549 |
"*", "*", "*", 0, NotFoundRequestPublicationFactory()) |
|
5088.2.6
by Leonard Richardson
Cleanup in response to review. |
1550 |
|
5088.2.1
by Leonard Richardson
Mysterious test and code from another dimension. |
1551 |
register_launchpad_request_publication_factories() |