11235.8.3
by Abel Deuring
change the bug attachment download URL for +text bug pages; ensure that spaces in file names are properly escaped in theURLs returned by ProxiedLibraryFileAlias.httl_ur; utf-8-encode these filenames |
1 |
# Copyright 2010 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).
|
4195.1.1
by Brad Crittenden
Implement upload and management of files associated with a product release. |
3 |
|
4 |
"""Browser file for LibraryFileAlias."""
|
|
5 |
||
6 |
__metaclass__ = type |
|
7 |
||
8 |
__all__ = [ |
|
8450.1.2
by Celso Providelo
Stop ProxiedLibraryFileAlias traversals on deleted LFAs. Raising an appropriate error on failures, so broken callsites can be traced in the OOPS reports. |
9 |
'DeletedProxiedLibraryFileAlias', |
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
10 |
'FileNavigationMixin', |
11 |
'LibraryFileAliasMD5View', |
|
4195.1.1
by Brad Crittenden
Implement upload and management of files associated with a product release. |
12 |
'LibraryFileAliasView', |
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
13 |
'ProxiedLibraryFileAlias', |
4195.1.1
by Brad Crittenden
Implement upload and management of files associated with a product release. |
14 |
]
|
15 |
||
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
16 |
from lazr.delegates import delegates |
13324.1.2
by Steve Kowalik
Use GoneError, rather than setting the status. |
17 |
from lazr.restful.interfaces import IWebBrowserOriginatingRequest |
13931.2.1
by Steve Kowalik
Chip away at canonical.lazr a little more. |
18 |
from lazr.restful.utils import get_current_browser_request |
7077.2.12
by Celso Providelo
testing StreamOrRedirectLibraryFileAliasView. |
19 |
from zope.publisher.interfaces import NotFound |
7077.2.16
by Celso Providelo
applying review comments, r=bac. |
20 |
from zope.security.interfaces import Unauthorized |
7077.2.6
by Celso Providelo
Spliting IArchive & IBuild getFileByName(), both used to traverse on +files/<filename> to StreamOrRedirectLibraryFileAliasView. |
21 |
|
14606.2.2
by William Grant
Move canonical.librarian.{client,utils} to lp.services.librarian. |
22 |
from lp.app.errors import GoneError |
14600.1.8
by Curtis Hovey
Move c.l.layers to lp. |
23 |
from lp.layers import WebServiceLayer |
14606.2.2
by William Grant
Move canonical.librarian.{client,utils} to lp.services.librarian. |
24 |
from lp.services.librarian.client import url_path_quote |
25 |
from lp.services.librarian.interfaces import ILibraryFileAlias |
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
26 |
from lp.services.webapp.authorization import check_permission |
27 |
from lp.services.webapp.publisher import ( |
|
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
28 |
canonical_url, |
29 |
LaunchpadView, |
|
12670.2.17
by William Grant
Fix import order. |
30 |
RedirectionView, |
11403.1.4
by Henning Eggers
Reformatted imports using format-imports script r32. |
31 |
stepthrough, |
32 |
)
|
|
14600.2.2
by Curtis Hovey
Moved webapp to lp.services. |
33 |
from lp.services.webapp.url import urlappend |
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
34 |
|
4195.1.1
by Brad Crittenden
Implement upload and management of files associated with a product release. |
35 |
|
36 |
class LibraryFileAliasView(LaunchpadView): |
|
4195.1.12
by Brad Crittenden
Post-review changes |
37 |
"""View to handle redirection for downloading files by URL.
|
4195.1.1
by Brad Crittenden
Implement upload and management of files associated with a product release. |
38 |
|
39 |
Rather than reference downloadable files via the obscure Librarian
|
|
7675.764.1
by Abel Deuring
class SafeStreamOrRedirectLibraryFileAliasView added which always sets the HTTP header Content-Disposition to 'attachment' for restricted LFAs; used this class to serve LFAs of bug attachments |
40 |
URL, downloadable files can be referenced via the Product Release URL,
|
41 |
e.g. http://launchpad.net/firefox/1.0./1.0.0/+download/firefox-1.0.0.tgz.
|
|
7077.2.6
by Celso Providelo
Spliting IArchive & IBuild getFileByName(), both used to traverse on +files/<filename> to StreamOrRedirectLibraryFileAliasView. |
42 |
"""
|
43 |
||
12670.2.9
by William Grant
Merge RedirectPerhapsWithTokenLibraryFileAliasView into LibraryFileAliasView. It's no longer an IBrowerPublisher, instead redirecting in initialize() like LFAV did. |
44 |
def initialize(self): |
45 |
"""Redirect the request to the URL of the file in the Librarian."""
|
|
12670.2.12
by William Grant
Use LFA.getURL in LibraryFileAliasView, and forbid it from being used on restricted files. Alter FileNavigation to bypass LFAV, since it needs to work for restricted files. We're not sure that it isn't possible to get an LFAV on a file that you shouldn't be able to see. |
46 |
# Refuse to serve restricted files. We're not sure that no
|
47 |
# restricted files are being leaked in the traversal hierarchy.
|
|
48 |
assert not self.context.restricted |
|
13324.1.1
by Steve Kowalik
Return a 410 for deleted LFAs in LibraryFileAliasView. |
49 |
# If the LFA is deleted, throw a 410.
|
50 |
if self.context.deleted: |
|
13324.1.2
by Steve Kowalik
Use GoneError, rather than setting the status. |
51 |
raise GoneError("File deleted.") |
12670.2.12
by William Grant
Use LFA.getURL in LibraryFileAliasView, and forbid it from being used on restricted files. Alter FileNavigation to bypass LFAV, since it needs to work for restricted files. We're not sure that it isn't possible to get an LFAV on a file that you shouldn't be able to see. |
52 |
# Redirect based on the scheme of the request, as set by
|
53 |
# Apache in the 'X-SCHEME' environment variable, which is
|
|
54 |
# mapped to 'HTTP_X_SCHEME. Note that only some requests
|
|
55 |
# for librarian files are allowed to come in via http as
|
|
56 |
# most are forced to https via Apache redirection.
|
|
57 |
self.request.response.redirect( |
|
58 |
self.context.getURL( |
|
59 |
secure=self.request.get('HTTP_X_SCHEME') != 'http')) |
|
12670.2.9
by William Grant
Merge RedirectPerhapsWithTokenLibraryFileAliasView into LibraryFileAliasView. It's no longer an IBrowerPublisher, instead redirecting in initialize() like LFAV did. |
60 |
|
61 |
||
62 |
class LibraryFileAliasMD5View(LaunchpadView): |
|
63 |
"""View to show the MD5 digest for a librarian file."""
|
|
64 |
||
65 |
def render(self): |
|
66 |
"""Return the plain text MD5 signature"""
|
|
67 |
self.request.response.setHeader('Content-type', 'text/plain') |
|
68 |
return '%s %s' % (self.context.content.md5, self.context.filename) |
|
7077.2.16
by Celso Providelo
applying review comments, r=bac. |
69 |
|
7675.809.24
by Robert Collins
Make the public restricted librarian facility be controlled by a feature flag in the appservers. |
70 |
|
8450.1.2
by Celso Providelo
Stop ProxiedLibraryFileAlias traversals on deleted LFAs. Raising an appropriate error on failures, so broken callsites can be traced in the OOPS reports. |
71 |
class DeletedProxiedLibraryFileAlias(NotFound): |
72 |
"""Raised when a deleted `ProxiedLibraryFileAlias` is accessed."""
|
|
73 |
||
74 |
||
7077.2.16
by Celso Providelo
applying review comments, r=bac. |
75 |
class FileNavigationMixin: |
76 |
"""Navigate to `LibraryFileAlias` hosted in a context.
|
|
77 |
||
78 |
The navigation goes through +files/<filename> where file reference is
|
|
79 |
provided by context `getFileByName(filename)`.
|
|
80 |
||
12670.2.9
by William Grant
Merge RedirectPerhapsWithTokenLibraryFileAliasView into LibraryFileAliasView. It's no longer an IBrowerPublisher, instead redirecting in initialize() like LFAV did. |
81 |
The requested file is proxied via `LibraryFileAliasView`,
|
12670.2.8
by William Grant
Clean up docstrings. |
82 |
making it possible to serve both public and restricted files.
|
7077.2.18
by Celso Providelo
Allowing our test infrastructure to support responses containing streamed files (missing content-length), r=stub. |
83 |
|
7077.2.19
by Celso Providelo
typo-matic ... |
84 |
This navigation approach only supports domains with unique filenames,
|
85 |
which is the case of IArchive and IBuild. It will probably have to be
|
|
86 |
extended in order to allow traversing to multiple files potentially
|
|
87 |
with the same filename (product files or bug attachments).
|
|
7077.2.16
by Celso Providelo
applying review comments, r=bac. |
88 |
"""
|
7675.764.1
by Abel Deuring
class SafeStreamOrRedirectLibraryFileAliasView added which always sets the HTTP header Content-Disposition to 'attachment' for restricted LFAs; used this class to serve LFAs of bug attachments |
89 |
|
7077.2.16
by Celso Providelo
applying review comments, r=bac. |
90 |
@stepthrough('+files') |
91 |
def traverse_files(self, filename): |
|
92 |
"""Traverse on filename in the archive domain."""
|
|
93 |
if not check_permission('launchpad.View', self.context): |
|
94 |
raise Unauthorized() |
|
7675.764.1
by Abel Deuring
class SafeStreamOrRedirectLibraryFileAliasView added which always sets the HTTP header Content-Disposition to 'attachment' for restricted LFAs; used this class to serve LFAs of bug attachments |
95 |
library_file = self.context.getFileByName(filename) |
8450.1.2
by Celso Providelo
Stop ProxiedLibraryFileAlias traversals on deleted LFAs. Raising an appropriate error on failures, so broken callsites can be traced in the OOPS reports. |
96 |
|
97 |
# Deleted library files result in NotFound-like error.
|
|
7675.415.4
by Abel Deuring
adjust storm classes to no longer define and use the dropped columns LibraryFileContent.deleted, LibraryFileContent.datemirrored (exception: librarian_gc.py is not yet fixed); add a property 'deleted' to LibraryFileAlias; replace usage of LibraryFileAlias.content.deleted by LibraryFileAlias.deleted; fix failing tests, except test_gc.py |
98 |
if library_file.deleted: |
8450.1.2
by Celso Providelo
Stop ProxiedLibraryFileAlias traversals on deleted LFAs. Raising an appropriate error on failures, so broken callsites can be traced in the OOPS reports. |
99 |
raise DeletedProxiedLibraryFileAlias(filename, self.context) |
100 |
||
12924.2.1
by William Grant
FileNavigationMixin now requires that the filename be the final path segment. |
101 |
# There can be no further path segments.
|
102 |
if len(self.request.stepstogo) > 0: |
|
103 |
return None |
|
104 |
||
12670.2.12
by William Grant
Use LFA.getURL in LibraryFileAliasView, and forbid it from being used on restricted files. Alter FileNavigation to bypass LFAV, since it needs to work for restricted files. We're not sure that it isn't possible to get an LFAV on a file that you shouldn't be able to see. |
105 |
return RedirectionView( |
106 |
library_file.getURL(include_token=True), |
|
107 |
self.request) |
|
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
108 |
|
109 |
||
110 |
class ProxiedLibraryFileAlias: |
|
7675.809.22
by Robert Collins
More commentary. |
111 |
"""A `LibraryFileAlias` decorator for use in URL generation.
|
112 |
||
12113.1.1
by Abel Deuring
Back out hack to serve restricted files directly from the internal restricted librarian port; LibraryBackedByteStorage.alias_url returns a URL with an access token for restricted files. |
113 |
The URL's output by this decorator will always point at the webapp. This
|
114 |
is useful when:
|
|
115 |
- the webapp has to be contacted to get access to a file (required for
|
|
116 |
restricted files).
|
|
7675.809.22
by Robert Collins
More commentary. |
117 |
- files might change from public to private and thus not work even if the
|
118 |
user has access to the once its private, unless they go via the webapp.
|
|
119 |
||
120 |
This should be used anywhere we are outputting URL's to LibraryFileAliases
|
|
121 |
other than directly in rendered pages. For rendered pages, using a
|
|
122 |
LibraryFileAlias directly is OK as at that point the status of the file
|
|
12113.1.1
by Abel Deuring
Back out hack to serve restricted files directly from the internal restricted librarian port; LibraryBackedByteStorage.alias_url returns a URL with an access token for restricted files. |
123 |
is known.
|
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
124 |
|
125 |
Overrides `ILibraryFileAlias.http_url` to always point to the webapp URL,
|
|
126 |
even when called from the webservice domain.
|
|
127 |
"""
|
|
128 |
delegates(ILibraryFileAlias) |
|
129 |
||
130 |
def __init__(self, context, parent): |
|
131 |
self.context = context |
|
132 |
self.parent = parent |
|
133 |
||
11495.1.1
by Robert Collins
Rollback rev 11491. |
134 |
@property
|
135 |
def http_url(self): |
|
136 |
"""Return the webapp URL for the context `LibraryFileAlias`.
|
|
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
137 |
|
8450.1.3
by Celso Providelo
ProxiedLibraryFileAlias.http_url returns None for deleted files, it should prevent files to be linkified in the UI. |
138 |
Preserve the `LibraryFileAlias.http_url` behavior for deleted
|
139 |
files, returning None.
|
|
11495.1.1
by Robert Collins
Rollback rev 11491. |
140 |
|
141 |
Mask webservice requests if it's the case, so the returned URL will
|
|
142 |
be always relative to the parent webapp URL.
|
|
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
143 |
"""
|
7675.415.4
by Abel Deuring
adjust storm classes to no longer define and use the dropped columns LibraryFileContent.deleted, LibraryFileContent.datemirrored (exception: librarian_gc.py is not yet fixed); add a property 'deleted' to LibraryFileAlias; replace usage of LibraryFileAlias.content.deleted by LibraryFileAlias.deleted; fix failing tests, except test_gc.py |
144 |
if self.context.deleted: |
8450.1.3
by Celso Providelo
ProxiedLibraryFileAlias.http_url returns None for deleted files, it should prevent files to be linkified in the UI. |
145 |
return None |
146 |
||
11495.1.1
by Robert Collins
Rollback rev 11491. |
147 |
request = get_current_browser_request() |
148 |
if WebServiceLayer.providedBy(request): |
|
149 |
request = IWebBrowserOriginatingRequest(request) |
|
150 |
||
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
151 |
parent_url = canonical_url(self.parent, request=request) |
152 |
traversal_url = urlappend(parent_url, '+files') |
|
11235.8.3
by Abel Deuring
change the bug attachment download URL for +text bug pages; ensure that spaces in file names are properly escaped in theURLs returned by ProxiedLibraryFileAlias.httl_ur; utf-8-encode these filenames |
153 |
url = urlappend( |
11204.7.10
by Jeroen Vermeulen
So that caused it--sneaky merge conflict. |
154 |
traversal_url, |
155 |
url_path_quote(self.context.filename.encode('utf-8'))) |
|
8137.8.1
by Celso Providelo
Fixing #354373 (exposing IBuild.{build_log_url, upload_log_url} in the API relative to the webapp url, not the webservice one). |
156 |
return url |