text: # -*- coding: utf-8  -*-
  """Http backend layer, formerly providing a httplib2 wrapper."""
  from __future__ import absolute_import, unicode_literals
  # (C) Pywikibot team, 2007-2015
  
  __version__ = '$Id: 2c3be335176d048d1068d89725e57bf52a3a5535 $'
  __docformat__ = 'epytext'
  
  # standard python libraries
  import codecs
  import sys
  
  if sys.version_info[0] > 2:
      from urllib.parse import urlparse
  else:
      from urlparse import urlparse
  
  import pywikibot
  
  from pywikibot.tools import UnicodeMixin
  
  _logger = "comm.threadedhttp"
  
  
  class HttpRequest(UnicodeMixin):
  
      """Object wrapper for HTTP requests that need to block origin thread.
  
      self.data will be either:
      * a tuple of (dict, unicode) if the request was successful
      * an exception
      """
  
      def __init__(self, uri, method="GET", body=None, headers=None,
                   callbacks=None, charset=None, **kwargs):
          """
          Constructor.
  
          See C{Http.request} for parameters.
          """
          self.uri = uri
          self.method = method
          self.body = body
          self.headers = headers
          if isinstance(charset, codecs.CodecInfo):
              self.charset = charset.name
          elif charset:
              self.charset = charset
          elif headers and 'accept-charset' in headers:
              self.charset = headers['accept-charset']
          else:
              self.charset = None
  
          self.callbacks = callbacks
  
          self.args = [uri, method, body, headers]
          self.kwargs = kwargs
  
          self._parsed_uri = None
          self._data = None
  
      @property
      def data(self):
          """Return the requests response tuple."""
          assert(self._data is not None)
          return self._data
  
      @data.setter
      def data(self, value):
          """Set the requests response and invoke each callback."""
          self._data = value
  
          if self.callbacks:
              for callback in self.callbacks:
                  callback(self)
  
      @property
      def exception(self):
          """Get the exception, if any."""
          if isinstance(self.data, Exception):
              return self.data
  
      @property
      def response_headers(self):
          """Return the response headers."""
          if not self.exception:
              return self.data.headers
  
      @property
      def raw(self):
          """Return the raw response body."""
          if not self.exception:
              return self.data.content
  
      @property
      def parsed_uri(self):
          """Return the parsed requested uri."""
          if not self._parsed_uri:
              self._parsed_uri = urlparse(self.uri)
          return self._parsed_uri
  
      @property
      def hostname(self):
          """Return the host of the request."""
          return self.parsed_uri.netloc
  
      @property
      def status(self):
          """Return the HTTP response status.
  
          @rtype: int
          """
          if not self.exception:
              return self.data.status_code
  
      @property
      def header_encoding(self):
          """Return charset given by the response header."""
          if not hasattr(self, '_header_encoding'):
              pos = self.response_headers['content-type'].find('charset=')
              if pos >= 0:
                  pos += len('charset=')
                  encoding = self.response_headers['content-type'][pos:]
                  self._header_encoding = encoding
              else:
                  self._header_encoding = None
          return self._header_encoding
  
      @property
      def encoding(self):
          """Detect the response encoding."""
          if not hasattr(self, '_encoding'):
              if not self.charset and not self.header_encoding:
                  pywikibot.log(u"Http response doesn't contain a charset.")
                  charset = 'latin1'
              else:
                  charset = self.charset
              if (self.header_encoding and codecs.lookup(self.header_encoding) !=
                      (codecs.lookup(charset) if charset else None)):
                  if charset:
                      pywikibot.warning(
                          'Encoding "{0}" requested but "{1}" '
                          'received in the header.'.format(
                              charset, self.header_encoding))
                  try:
                      # TODO: Buffer decoded content, weakref does remove it too
                      #       early (directly after this method)
                      self.raw.decode(self.header_encoding)
                  except UnicodeError as e:
                      self._encoding = e
                  else:
                      self._encoding = self.header_encoding
              else:
                  self._encoding = None
  
              if charset and (isinstance(self._encoding, Exception) or
                              not self._encoding):
                  try:
                      self.raw.decode(charset)
                  except UnicodeError as e:
                      self._encoding = e
                  else:
                      self._encoding = charset
  
          if isinstance(self._encoding, Exception):
              raise self._encoding
          return self._encoding
  
      def decode(self, encoding, errors='strict'):
          """Return the decoded response."""
          return self.raw.decode(encoding, errors)
  
      @property
      def content(self):
          """Return the response decoded by the detected encoding."""
          return self.decode(self.encoding)
  
      def __unicode__(self):
          """Return the response decoded by the detected encoding."""
          return self.content
  
      def __bytes__(self):
          """Return the undecoded response."""
          return self.raw
  