1 | """ |
---|
2 | Ported to Python 3. |
---|
3 | """ |
---|
4 | from __future__ import annotations |
---|
5 | |
---|
6 | from urllib.parse import quote as urlquote |
---|
7 | |
---|
8 | from twisted.web import http |
---|
9 | from twisted.internet import defer |
---|
10 | from twisted.python.filepath import FilePath |
---|
11 | from twisted.web.resource import Resource |
---|
12 | from twisted.web.template import ( |
---|
13 | XMLFile, |
---|
14 | renderer, |
---|
15 | renderElement, |
---|
16 | tags, |
---|
17 | ) |
---|
18 | from allmydata.immutable.upload import FileHandle |
---|
19 | from allmydata.mutable.publish import MutableFileHandle |
---|
20 | from allmydata.web.common import ( |
---|
21 | get_keypair, |
---|
22 | get_arg, |
---|
23 | boolean_of_arg, |
---|
24 | convert_children_json, |
---|
25 | WebError, |
---|
26 | get_format, |
---|
27 | get_mutable_type, |
---|
28 | render_exception, |
---|
29 | url_for_string, |
---|
30 | ) |
---|
31 | from allmydata.web import status |
---|
32 | |
---|
33 | def PUTUnlinkedCHK(req, client): |
---|
34 | # "PUT /uri", to create an unlinked file. |
---|
35 | uploadable = FileHandle(req.content, client.convergence) |
---|
36 | d = client.upload(uploadable) |
---|
37 | d.addCallback(lambda results: results.get_uri()) |
---|
38 | # that fires with the URI of the new file |
---|
39 | return d |
---|
40 | |
---|
41 | def PUTUnlinkedSSK(req, client, version): |
---|
42 | # SDMF: files are small, and we can only upload data |
---|
43 | req.content.seek(0) |
---|
44 | data = MutableFileHandle(req.content) |
---|
45 | keypair = get_keypair(req) |
---|
46 | d = client.create_mutable_file(data, version=version, unique_keypair=keypair) |
---|
47 | d.addCallback(lambda n: n.get_uri()) |
---|
48 | return d |
---|
49 | |
---|
50 | def PUTUnlinkedCreateDirectory(req, client): |
---|
51 | # "PUT /uri?t=mkdir", to create an unlinked directory. |
---|
52 | file_format = get_format(req, None) |
---|
53 | if file_format == "CHK": |
---|
54 | raise WebError("format=CHK not accepted for PUT /uri?t=mkdir", |
---|
55 | http.BAD_REQUEST) |
---|
56 | mt = None |
---|
57 | if file_format: |
---|
58 | mt = get_mutable_type(file_format) |
---|
59 | d = client.create_dirnode(version=mt) |
---|
60 | d.addCallback(lambda dirnode: dirnode.get_uri()) |
---|
61 | # XXX add redirect_to_result |
---|
62 | return d |
---|
63 | |
---|
64 | |
---|
65 | def POSTUnlinkedCHK(req, client): |
---|
66 | fileobj = req.fields["file"].file |
---|
67 | uploadable = FileHandle(fileobj, client.convergence) |
---|
68 | d = client.upload(uploadable) |
---|
69 | when_done = get_arg(req, "when_done", None) |
---|
70 | if when_done: |
---|
71 | # if when_done= is provided, return a redirect instead of our |
---|
72 | # usual upload-results page |
---|
73 | def _done(upload_results, redir_to): |
---|
74 | if b"%(uri)s" in redir_to: |
---|
75 | redir_to = redir_to.replace(b"%(uri)s", urlquote(upload_results.get_uri()).encode("utf-8")) |
---|
76 | return url_for_string(req, redir_to) |
---|
77 | d.addCallback(_done, when_done) |
---|
78 | else: |
---|
79 | # return the Upload Results page, which includes the URI |
---|
80 | d.addCallback(UploadResultsPage) |
---|
81 | return d |
---|
82 | |
---|
83 | |
---|
84 | class UploadResultsPage(Resource, object): |
---|
85 | """'POST /uri', to create an unlinked file.""" |
---|
86 | |
---|
87 | def __init__(self, upload_results): |
---|
88 | """ |
---|
89 | :param IUploadResults upload_results: stats provider. |
---|
90 | """ |
---|
91 | super(UploadResultsPage, self).__init__() |
---|
92 | self._upload_results = upload_results |
---|
93 | |
---|
94 | @render_exception |
---|
95 | def render_POST(self, req): |
---|
96 | elem = UploadResultsElement(self._upload_results) |
---|
97 | return renderElement(req, elem) |
---|
98 | |
---|
99 | |
---|
100 | class UploadResultsElement(status.UploadResultsRendererMixin): |
---|
101 | |
---|
102 | loader = XMLFile(FilePath(__file__).sibling("upload-results.xhtml")) |
---|
103 | |
---|
104 | def __init__(self, upload_results): |
---|
105 | super(UploadResultsElement, self).__init__() |
---|
106 | self._upload_results = upload_results |
---|
107 | |
---|
108 | def upload_results(self): |
---|
109 | return defer.succeed(self._upload_results) |
---|
110 | |
---|
111 | @renderer |
---|
112 | def done(self, req, tag): |
---|
113 | d = self.upload_results() |
---|
114 | d.addCallback(lambda res: "done!") |
---|
115 | return d |
---|
116 | |
---|
117 | @renderer |
---|
118 | def uri(self, req, tag): |
---|
119 | d = self.upload_results() |
---|
120 | d.addCallback(lambda res: res.get_uri()) |
---|
121 | return d |
---|
122 | |
---|
123 | @renderer |
---|
124 | def download_link(self, req, tag): |
---|
125 | d = self.upload_results() |
---|
126 | d.addCallback(lambda res: |
---|
127 | tags.a("/uri/" + str(res.get_uri(), "utf-8"), |
---|
128 | href="/uri/" + urlquote(str(res.get_uri(), "utf-8")))) |
---|
129 | return d |
---|
130 | |
---|
131 | |
---|
132 | def POSTUnlinkedSSK(req, client, version): |
---|
133 | # "POST /uri", to create an unlinked file. |
---|
134 | # SDMF: files are small, and we can only upload data |
---|
135 | contents = req.fields["file"].file |
---|
136 | data = MutableFileHandle(contents) |
---|
137 | d = client.create_mutable_file(data, version=version) |
---|
138 | d.addCallback(lambda n: n.get_uri()) |
---|
139 | return d |
---|
140 | |
---|
141 | def POSTUnlinkedCreateDirectory(req, client): |
---|
142 | # "POST /uri?t=mkdir", to create an unlinked directory. |
---|
143 | ct = req.getHeader("content-type") or "" |
---|
144 | if not ct.startswith("multipart/form-data"): |
---|
145 | # guard against accidental attempts to call t=mkdir as if it were |
---|
146 | # t=mkdir-with-children, but make sure we tolerate the usual HTML |
---|
147 | # create-directory form (in which the t=mkdir and redirect_to_result= |
---|
148 | # and other arguments can be passed encoded as multipath/form-data, |
---|
149 | # in the request body). |
---|
150 | req.content.seek(0) |
---|
151 | kids_json = req.content.read() |
---|
152 | if kids_json: |
---|
153 | raise WebError("t=mkdir does not accept children=, " |
---|
154 | "try t=mkdir-with-children instead", |
---|
155 | http.BAD_REQUEST) |
---|
156 | file_format = get_format(req, None) |
---|
157 | if file_format == "CHK": |
---|
158 | raise WebError("format=CHK not currently accepted for POST /uri?t=mkdir", |
---|
159 | http.BAD_REQUEST) |
---|
160 | mt = None |
---|
161 | if file_format: |
---|
162 | mt = get_mutable_type(file_format) |
---|
163 | d = client.create_dirnode(version=mt, unique_keypair=get_keypair(req)) |
---|
164 | redirect = get_arg(req, "redirect_to_result", "false") |
---|
165 | if boolean_of_arg(redirect): |
---|
166 | def _then_redir(res): |
---|
167 | new_url = "uri/" + urlquote(res.get_uri()) |
---|
168 | req.setResponseCode(http.SEE_OTHER) # 303 |
---|
169 | req.setHeader('location', new_url) |
---|
170 | return '' |
---|
171 | d.addCallback(_then_redir) |
---|
172 | else: |
---|
173 | d.addCallback(lambda dirnode: dirnode.get_uri()) |
---|
174 | return d |
---|
175 | |
---|
176 | def POSTUnlinkedCreateDirectoryWithChildren(req, client): |
---|
177 | # "POST /uri?t=mkdir", to create an unlinked directory. |
---|
178 | req.content.seek(0) |
---|
179 | kids_json = req.content.read() |
---|
180 | kids = convert_children_json(client.nodemaker, kids_json) |
---|
181 | d = client.create_dirnode(initial_children=kids, unique_keypair=get_keypair(req)) |
---|
182 | redirect = get_arg(req, "redirect_to_result", "false") |
---|
183 | if boolean_of_arg(redirect): |
---|
184 | def _then_redir(res): |
---|
185 | new_url = "uri/" + urlquote(res.get_uri()) |
---|
186 | req.setResponseCode(http.SEE_OTHER) # 303 |
---|
187 | req.setHeader('location', new_url) |
---|
188 | return '' |
---|
189 | d.addCallback(_then_redir) |
---|
190 | else: |
---|
191 | d.addCallback(lambda dirnode: dirnode.get_uri()) |
---|
192 | return d |
---|
193 | |
---|
194 | def POSTUnlinkedCreateImmutableDirectory(req, client): |
---|
195 | # "POST /uri?t=mkdir", to create an unlinked directory. |
---|
196 | req.content.seek(0) |
---|
197 | kids_json = req.content.read() |
---|
198 | kids = convert_children_json(client.nodemaker, kids_json) |
---|
199 | d = client.create_immutable_dirnode(kids) |
---|
200 | redirect = get_arg(req, "redirect_to_result", "false") |
---|
201 | if boolean_of_arg(redirect): |
---|
202 | def _then_redir(res): |
---|
203 | new_url = "uri/" + urlquote(res.get_uri()) |
---|
204 | req.setResponseCode(http.SEE_OTHER) # 303 |
---|
205 | req.setHeader('location', new_url) |
---|
206 | return '' |
---|
207 | d.addCallback(_then_redir) |
---|
208 | else: |
---|
209 | d.addCallback(lambda dirnode: dirnode.get_uri()) |
---|
210 | return d |
---|