| ... |
... |
@@ -21,7 +21,8 @@ from urllib.parse import urlparse |
|
21
|
21
|
import mimetypes
|
|
22
|
22
|
|
|
23
|
23
|
import nbxmpp
|
|
24
|
|
-from nbxmpp import NS_HTTPUPLOAD
|
|
|
24
|
+from nbxmpp import NS_HTTPUPLOAD_0
|
|
|
25
|
+from nbxmpp.util import is_error_result
|
|
25
|
26
|
from gi.repository import GLib
|
|
26
|
27
|
from gi.repository import Soup
|
|
27
|
28
|
|
| ... |
... |
@@ -35,10 +36,11 @@ from gajim.common.connection_handlers_events import InformationEvent |
|
35
|
36
|
from gajim.common.connection_handlers_events import MessageOutgoingEvent
|
|
36
|
37
|
from gajim.common.connection_handlers_events import GcMessageOutgoingEvent
|
|
37
|
38
|
|
|
38
|
|
-NS_HTTPUPLOAD_0 = NS_HTTPUPLOAD + ':0'
|
|
39
|
|
-
|
|
40
|
39
|
|
|
41
|
40
|
class HTTPUpload(BaseModule):
|
|
|
41
|
+
|
|
|
42
|
+ _nbxmpp_extends = 'HTTPUpload'
|
|
|
43
|
+
|
|
42
|
44
|
def __init__(self, con):
|
|
43
|
45
|
BaseModule.__init__(self, con)
|
|
44
|
46
|
|
| ... |
... |
@@ -47,7 +49,6 @@ class HTTPUpload(BaseModule): |
|
47
|
49
|
self.httpupload_namespace = None
|
|
48
|
50
|
self.max_file_size = None # maximum file size in bytes
|
|
49
|
51
|
|
|
50
|
|
- self._allowed_headers = ['Authorization', 'Cookie', 'Expires']
|
|
51
|
52
|
self._text = []
|
|
52
|
53
|
self._queued_messages = {}
|
|
53
|
54
|
self._session = Soup.Session()
|
| ... |
... |
@@ -64,8 +65,6 @@ class HTTPUpload(BaseModule): |
|
64
|
65
|
def pass_disco(self, info):
|
|
65
|
66
|
if NS_HTTPUPLOAD_0 in info.features:
|
|
66
|
67
|
self.httpupload_namespace = NS_HTTPUPLOAD_0
|
|
67
|
|
- elif NS_HTTPUPLOAD in info.features:
|
|
68
|
|
- self.httpupload_namespace = NS_HTTPUPLOAD
|
|
69
|
68
|
else:
|
|
70
|
69
|
return
|
|
71
|
70
|
|
| ... |
... |
@@ -175,75 +174,35 @@ class HTTPUpload(BaseModule): |
|
175
|
174
|
|
|
176
|
175
|
def _request_slot(self, transfer):
|
|
177
|
176
|
transfer.set_preparing()
|
|
178
|
|
- iq = self._build_request(transfer)
|
|
179
|
|
- self._log.info("Sending request for slot")
|
|
180
|
|
- self._con.connection.SendAndCallForResponse(
|
|
181
|
|
- iq, self._received_slot, {'transfer': transfer})
|
|
182
|
|
-
|
|
183
|
|
- def _build_request(self, transfer):
|
|
184
|
|
- iq = nbxmpp.Iq(typ='get', to=self.component)
|
|
185
|
|
- id_ = app.get_an_id()
|
|
186
|
|
- iq.setID(id_)
|
|
187
|
|
- if self.httpupload_namespace == NS_HTTPUPLOAD:
|
|
188
|
|
- # experimental namespace
|
|
189
|
|
- request = iq.setTag(name="request",
|
|
190
|
|
- namespace=self.httpupload_namespace)
|
|
191
|
|
- request.addChild('filename',
|
|
192
|
|
- payload=os.path.basename(transfer.path))
|
|
193
|
|
- request.addChild('size', payload=transfer.size)
|
|
194
|
|
- request.addChild('content-type', payload=transfer.mime)
|
|
195
|
|
- else:
|
|
196
|
|
- attr = {'filename': os.path.basename(transfer.path),
|
|
197
|
|
- 'size': transfer.size,
|
|
198
|
|
- 'content-type': transfer.mime}
|
|
199
|
|
- iq.setTag(name="request",
|
|
200
|
|
- namespace=self.httpupload_namespace,
|
|
201
|
|
- attrs=attr)
|
|
202
|
|
- return iq
|
|
203
|
|
-
|
|
204
|
|
- @staticmethod
|
|
205
|
|
- def _get_slot_error_message(stanza):
|
|
206
|
|
- tmp = stanza.getTag('error').getTag('file-too-large')
|
|
|
177
|
+ self._log.info('Sending request for slot')
|
|
|
178
|
+ self._nbxmpp('HTTPUpload').request_slot(
|
|
|
179
|
+ jid=self.component,
|
|
|
180
|
+ filename=os.path.basename(transfer.path),
|
|
|
181
|
+ size=transfer.size,
|
|
|
182
|
+ content_type=transfer.mime,
|
|
|
183
|
+ callback=self._received_slot,
|
|
|
184
|
+ user_data=transfer)
|
|
|
185
|
+
|
|
|
186
|
+ def _received_slot(self, result, transfer):
|
|
|
187
|
+ if is_error_result(result):
|
|
|
188
|
+ transfer.set_error()
|
|
207
|
189
|
|
|
208
|
|
- if tmp is not None:
|
|
209
|
|
- max_file_size = float(tmp.getTag('max-file-size').getData())
|
|
210
|
|
- return _('File is too large, maximum allowed file size is: %s') % \
|
|
211
|
|
- GLib.format_size_full(max_file_size,
|
|
212
|
|
- GLib.FormatSizeFlags.IEC_UNITS)
|
|
|
190
|
+ if result.app_condition == 'file-too-large':
|
|
|
191
|
+ size_text = GLib.format_size_full(
|
|
|
192
|
+ result.get_max_file_size(),
|
|
|
193
|
+ GLib.FormatSizeFlags.IEC_UNITS)
|
|
213
|
194
|
|
|
214
|
|
- return stanza.getErrorMsg()
|
|
|
195
|
+ error_text = _('File is too large, '
|
|
|
196
|
+ 'maximum allowed file size is: %s' % size_text)
|
|
|
197
|
+ else:
|
|
|
198
|
+ error_text = str(result)
|
|
|
199
|
+ self._log.warning(result)
|
|
215
|
200
|
|
|
216
|
|
- def _received_slot(self, _con, stanza, transfer):
|
|
217
|
|
- self._log.info("Received slot")
|
|
218
|
|
- if stanza.getType() == 'error':
|
|
219
|
|
- transfer.set_error()
|
|
220
|
201
|
self._raise_information_event('request-upload-slot-error',
|
|
221
|
|
- self._get_slot_error_message(stanza))
|
|
222
|
|
- self._log.error(stanza)
|
|
|
202
|
+ error_text)
|
|
223
|
203
|
return
|
|
224
|
204
|
|
|
225
|
|
- try:
|
|
226
|
|
- if self.httpupload_namespace == NS_HTTPUPLOAD:
|
|
227
|
|
- transfer.put_uri = stanza.getTag('slot').getTag('put').getData()
|
|
228
|
|
- transfer.get_uri = stanza.getTag('slot').getTag('get').getData()
|
|
229
|
|
- else:
|
|
230
|
|
- slot = stanza.getTag('slot')
|
|
231
|
|
- transfer.put_uri = slot.getTagAttr('put', 'url')
|
|
232
|
|
- transfer.get_uri = slot.getTagAttr('get', 'url')
|
|
233
|
|
- for header in slot.getTag('put').getTags('header'):
|
|
234
|
|
- name = header.getAttr('name')
|
|
235
|
|
- if name not in self._allowed_headers:
|
|
236
|
|
- raise ValueError('Not allowed header')
|
|
237
|
|
- data = header.getData()
|
|
238
|
|
- if '\n' in data:
|
|
239
|
|
- raise ValueError('Newline in header data')
|
|
240
|
|
- transfer.append_header(name, data)
|
|
241
|
|
- except Exception:
|
|
242
|
|
- self._log.error("Got invalid stanza: %s", stanza)
|
|
243
|
|
- self._log.exception('Error')
|
|
244
|
|
- transfer.set_error()
|
|
245
|
|
- self._raise_information_event('request-upload-slot-error2')
|
|
246
|
|
- return
|
|
|
205
|
+ transfer.process_result(result)
|
|
247
|
206
|
|
|
248
|
207
|
if (urlparse(transfer.put_uri).scheme != 'https' or
|
|
249
|
208
|
urlparse(transfer.get_uri).scheme != 'https'):
|
| ... |
... |
@@ -264,7 +223,9 @@ class HTTPUpload(BaseModule): |
|
264
|
223
|
|
|
265
|
224
|
# Set CAN_REBUILD so chunks get discarded after they are beeing
|
|
266
|
225
|
# written to the network
|
|
267
|
|
- message.set_flags(Soup.MessageFlags.CAN_REBUILD)
|
|
|
226
|
+ message.set_flags(Soup.MessageFlags.CAN_REBUILD |
|
|
|
227
|
+ Soup.MessageFlags.NO_REDIRECT)
|
|
|
228
|
+
|
|
268
|
229
|
message.props.request_body.set_accumulate(False)
|
|
269
|
230
|
|
|
270
|
231
|
message.props.request_headers.set_content_type(transfer.mime, None)
|
| ... |
... |
@@ -407,9 +368,6 @@ class HTTPFileTransfer(FileTransfer): |
|
407
|
368
|
def path(self):
|
|
408
|
369
|
return self._path
|
|
409
|
370
|
|
|
410
|
|
- def append_header(self, name, value):
|
|
411
|
|
- self._headers[name] = value
|
|
412
|
|
-
|
|
413
|
371
|
def set_uri_transform_func(self, func):
|
|
414
|
372
|
self._uri_transform_func = func
|
|
415
|
373
|
|
| ... |
... |
@@ -449,6 +407,11 @@ class HTTPFileTransfer(FileTransfer): |
|
449
|
407
|
data = file.read()
|
|
450
|
408
|
return data
|
|
451
|
409
|
|
|
|
410
|
+ def process_result(self, result):
|
|
|
411
|
+ self.put_uri = result.put_uri
|
|
|
412
|
+ self.get_uri = result.get_uri
|
|
|
413
|
+ self._headers = result.headers
|
|
|
414
|
+
|
|
452
|
415
|
|
|
453
|
416
|
def get_instance(*args, **kwargs):
|
|
454
|
417
|
return HTTPUpload(*args, **kwargs), 'HTTPUpload'
|