summaryrefslogtreecommitdiff
path: root/client/src/leap/soledad/client/http_target/support.py
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/leap/soledad/client/http_target/support.py')
-rw-r--r--client/src/leap/soledad/client/http_target/support.py220
1 files changed, 0 insertions, 220 deletions
diff --git a/client/src/leap/soledad/client/http_target/support.py b/client/src/leap/soledad/client/http_target/support.py
deleted file mode 100644
index d8d8e420..00000000
--- a/client/src/leap/soledad/client/http_target/support.py
+++ /dev/null
@@ -1,220 +0,0 @@
-# -*- coding: utf-8 -*-
-# support.py
-# Copyright (C) 2015 LEAP
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import warnings
-import json
-
-from twisted.internet import defer
-from twisted.web.client import _ReadBodyProtocol
-from twisted.web.client import PartialDownloadError
-from twisted.web._newclient import ResponseDone
-from twisted.web._newclient import PotentialDataLoss
-
-from leap.soledad.common.l2db import errors
-from leap.soledad.common.l2db.remote import http_errors
-
-# we want to make sure that HTTP errors will raise appropriate u1db errors,
-# that is, fire errbacks with the appropriate failures, in the context of
-# twisted. Because of that, we redefine the http body reader used by the HTTP
-# client below.
-
-
-class ReadBodyProtocol(_ReadBodyProtocol):
- """
- From original Twisted implementation, focused on adding our error
- handling and ensuring that the proper u1db error is raised.
- """
-
- def __init__(self, response, deferred):
- """
- Initialize the protocol, additionally storing the response headers.
- """
- _ReadBodyProtocol.__init__(
- self, response.code, response.phrase, deferred)
- self.headers = response.headers
-
- # ---8<--- snippet from u1db.remote.http_client, modified to use errbacks
- def _error(self, respdic):
- descr = respdic.get("error")
- exc_cls = errors.wire_description_to_exc.get(descr)
- if exc_cls is not None:
- message = respdic.get("message")
- self.deferred.errback(exc_cls(message))
- else:
- self.deferred.errback(
- errors.HTTPError(self.status, respdic, self.headers))
- # ---8<--- end of snippet from u1db.remote.http_client
-
- def connectionLost(self, reason):
- """
- Deliver the accumulated response bytes to the waiting L{Deferred}, if
- the response body has been completely received without error.
- """
- if reason.check(ResponseDone):
-
- body = b''.join(self.dataBuffer)
-
- # ---8<--- snippet from u1db.remote.http_client
- if self.status in (200, 201):
- self.deferred.callback(body)
- elif self.status in http_errors.ERROR_STATUSES:
- try:
- respdic = json.loads(body)
- except ValueError:
- self.deferred.errback(
- errors.HTTPError(self.status, body, self.headers))
- else:
- self._error(respdic)
- # special cases
- elif self.status == 503:
- self.deferred.errback(errors.Unavailable(body, self.headers))
- else:
- self.deferred.errback(
- errors.HTTPError(self.status, body, self.headers))
- # ---8<--- end of snippet from u1db.remote.http_client
-
- elif reason.check(PotentialDataLoss):
- self.deferred.errback(
- PartialDownloadError(self.status, self.message,
- b''.join(self.dataBuffer)))
- else:
- self.deferred.errback(reason)
-
-
-def readBody(response, protocolClass=ReadBodyProtocol):
- """
- Get the body of an L{IResponse} and return it as a byte string.
-
- This is a helper function for clients that don't want to incrementally
- receive the body of an HTTP response.
-
- @param response: The HTTP response for which the body will be read.
- @type response: L{IResponse} provider
-
- @return: A L{Deferred} which will fire with the body of the response.
- Cancelling it will close the connection to the server immediately.
- """
- def cancel(deferred):
- """
- Cancel a L{readBody} call, close the connection to the HTTP server
- immediately, if it is still open.
-
- @param deferred: The cancelled L{defer.Deferred}.
- """
- abort = getAbort()
- if abort is not None:
- abort()
-
- d = defer.Deferred(cancel)
- protocol = protocolClass(response, d)
-
- def getAbort():
- return getattr(protocol.transport, 'abortConnection', None)
-
- response.deliverBody(protocol)
-
- if protocol.transport is not None and getAbort() is None:
- warnings.warn(
- 'Using readBody with a transport that does not have an '
- 'abortConnection method',
- category=DeprecationWarning,
- stacklevel=2)
-
- return d
-
-
-class RequestBody(object):
- """
- This class is a helper to generate send and fetch requests.
- The expected format is something like:
- [
- {headers},
- {entry1},
- {...},
- {entryN},
- ]
- """
-
- def __init__(self, **header_dict):
- """
- Creates a new RequestBody holding header information.
-
- :param header_dict: A dictionary with the headers.
- :type header_dict: dict
- """
- self.headers = header_dict
- self.entries = []
- self.consumed = 0
-
- def insert_info(self, **entry_dict):
- """
- Dumps an entry into JSON format and add it to entries list.
- Adds 'content' key on a new line if it's present.
-
- :param entry_dict: Entry as a dictionary
- :type entry_dict: dict
- """
- content = ''
- if 'content' in entry_dict:
- content = ',\r\n' + (entry_dict['content'] or '')
- entry = json.dumps(entry_dict) + content
- self.entries.append(entry)
-
- def pop(self, amount=10, leave_open=False):
- """
- Removes entries and returns it formatted and ready
- to be sent.
-
- :param amount: number of entries to pop and format
- :type amount: int
-
- :param leave_open: flag to skip stream closing
- :type amount: bool
-
- :return: formatted body ready to be sent
- :rtype: str
- """
- start = self.consumed == 0
- amount = min([len(self.entries), amount])
- entries = [self.entries.pop(0) for i in xrange(amount)]
- self.consumed += amount
- end = len(self.entries) == 0 if not leave_open else False
- return self.entries_to_str(entries, start, end)
-
- def __str__(self):
- return self.pop(len(self.entries))
-
- def __len__(self):
- return len(self.entries)
-
- def entries_to_str(self, entries=None, start=True, end=True):
- """
- Format a list of entries into the body format expected
- by the server.
-
- :param entries: entries to format
- :type entries: list
-
- :return: formatted body ready to be sent
- :rtype: str
- """
- data = ''
- if start:
- data = '[\r\n' + json.dumps(self.headers)
- data += ''.join(',\r\n' + entry for entry in entries)
- if end:
- data += '\r\n]'
- return data