Ejemplo n.º 1
0
    def _process_response(self, resp, content):
        """Process the response from a single chunk upload.

    Args:
      resp: httplib2.Response, the response object.
      content: string, the content of the response.

    Returns:
      (status, body): (ResumableMediaStatus, object)
         The body will be None until the resumable media is fully uploaded.

    Raises:
      apiclient.errors.HttpError if the response was not a 2xx or a 308.
    """
        if resp.status in [200, 201]:
            self._in_error_state = False
            return None, self.postproc(resp, content)
        elif resp.status == 308:
            self._in_error_state = False
            # A "308 Resume Incomplete" indicates we are not done.
            self.resumable_progress = int(resp['range'].split('-')[1]) + 1
            if 'location' in resp:
                self.resumable_uri = resp['location']
        else:
            self._in_error_state = True
            raise HttpError(resp, content, self.uri)

        return (MediaUploadProgress(self.resumable_progress,
                                    self.resumable.size()), None)
Ejemplo n.º 2
0
def build(serviceName,
          version,
          http=None,
          discoveryServiceUrl=DISCOVERY_URI,
          developerKey=None,
          model=None,
          requestBuilder=HttpRequest):
    """Construct a Resource for interacting with an API.

  Construct a Resource object for interacting with
  an API. The serviceName and version are the
  names from the Discovery service.

  Args:
    serviceName: string, name of the service
    version: string, the version of the service
    discoveryServiceUrl: string, a URI Template that points to
      the location of the discovery service. It should have two
      parameters {api} and {apiVersion} that when filled in
      produce an absolute URI to the discovery document for
      that service.
    developerKey: string, key obtained
      from https://code.google.com/apis/console
    model: apiclient.Model, converts to and from the wire format
    requestBuilder: apiclient.http.HttpRequest, encapsulator for
      an HTTP request

  Returns:
    A Resource object with methods for interacting with
    the service.
  """
    params = {'api': serviceName, 'apiVersion': version}

    if http is None:
        http = httplib2.Http()

    requested_url = uritemplate.expand(discoveryServiceUrl, params)

    # REMOTE_ADDR is defined by the CGI spec [RFC3875] as the environment variable
    # that contains the network address of the client sending the request. If it
    # exists then add that to the request for the discovery document to avoid
    # exceeding the quota on discovery requests.
    if 'REMOTE_ADDR' in os.environ:
        requested_url = _add_query_parameter(requested_url, 'userIp',
                                             os.environ['REMOTE_ADDR'])
    logging.info('URL being requested: %s' % requested_url)

    resp, content = http.request(requested_url)

    if resp.status == 404:
        raise UnknownApiNameOrVersion("name: %s  version: %s" %
                                      (serviceName, version))
    if resp.status >= 400:
        raise HttpError(resp, content, requested_url)

    try:
        service = simplejson.loads(content)
    except ValueError, e:
        logging.error('Failed to parse as JSON: ' + content)
        raise InvalidJsonError()
Ejemplo n.º 3
0
    def execute(self, http=None):
        """Execute the request.

    Args:
      http: httplib2.Http, an http object to be used in place of the
            one the HttpRequest request object was constructed with.

    Returns:
      A deserialized object model of the response body as determined
      by the postproc.

    Raises:
      apiclient.errors.HttpError if the response was not a 2xx.
      httplib2.Error if a transport error has occured.
    """
        if http is None:
            http = self.http
        if self.resumable:
            body = None
            while body is None:
                _, body = self.next_chunk(http)
            return body
        else:
            resp, content = http.request(self.uri,
                                         self.method,
                                         body=self.body,
                                         headers=self.headers)

            if resp.status >= 300:
                raise HttpError(resp, content, self.uri)
        return self.postproc(resp, content)
Ejemplo n.º 4
0
    def response(self, resp, content):
        """Convert the response wire format into a Python object.

    Args:
      resp: httplib2.Response, the HTTP response headers and status
      content: string, the body of the HTTP response

    Returns:
      The body de-serialized as a Python object.

    Raises:
      apiclient.errors.HttpError if a non 2xx response is received.
    """
        # Error handling is TBD, for example, do we retry
        # for some operation/error combinations?
        if resp.status < 300:
            if resp.status == 204:
                # A 204: No Content response should be treated differently
                # to all the other success states
                return simplejson.loads('{}')
            body = simplejson.loads(content)
            if isinstance(body, dict) and 'data' in body:
                body = body['data']
            return body
        else:
            logging.debug('Content from bad request was: %s' % content)
            raise HttpError(resp, content)
Ejemplo n.º 5
0
  def _execute(self, http, order, requests):
    """Serialize batch request, send to server, process response.

    Args:
      http: httplib2.Http, an http object to be used to make the request with.
      order: list, list of request ids in the order they were added to the
        batch.
      request: list, list of request objects to send.

    Raises:
      httplib2.HttpLib2Error if a transport error has occured.
      apiclient.errors.BatchError if the response is the wrong format.
    """
    message = MIMEMultipart('mixed')
    # Message should not write out it's own headers.
    setattr(message, '_write_headers', lambda self: None)

    # Add all the individual requests.
    for request_id in order:
      request = requests[request_id]

      msg = MIMENonMultipart('application', 'http')
      msg['Content-Transfer-Encoding'] = 'binary'
      msg['Content-ID'] = self._id_to_header(request_id)

      body = self._serialize_request(request)
      msg.set_payload(body)
      message.attach(msg)

    body = message.as_string()

    headers = {}
    headers['content-type'] = ('multipart/mixed; '
                               'boundary="%s"') % message.get_boundary()

    resp, content = http.request(self._batch_uri, 'POST', body=body,
                                 headers=headers)

    if resp.status >= 300:
      raise HttpError(resp, content, uri=self._batch_uri)

    # Now break out the individual responses and store each one.
    boundary, _ = content.split(None, 1)

    # Prepend with a content-type header so FeedParser can handle it.
    header = 'content-type: %s\r\n\r\n' % resp['content-type']
    for_parser = header + content

    parser = FeedParser()
    parser.feed(for_parser)
    mime_response = parser.close()

    if not mime_response.is_multipart():
      raise BatchError("Response not in multipart/mixed format.", resp=resp,
                       content=content)

    for part in mime_response.get_payload():
      request_id = self._header_to_id(part['Content-ID'])
      response, content = self._deserialize_response(part.get_payload())
      self._responses[request_id] = (response, content)
Ejemplo n.º 6
0
    def response(self, resp, content):
        """Convert the response wire format into a Python object.

    Args:
      resp: httplib2.Response, the HTTP response headers and status
      content: string, the body of the HTTP response

    Returns:
      The body de-serialized as a Python object.

    Raises:
      apiclient.errors.HttpError if a non 2xx response is received.
    """
        self._log_response(resp, content)
        # Error handling is TBD, for example, do we retry
        # for some operation/error combinations?
        if resp.status < 300:
            if resp.status == 204:
                # A 204: No Content response should be treated differently
                # to all the other success states
                return self.no_content_response
            return self.deserialize(content)
        else:
            logging.debug('Content from bad request was: %s' % content)
            raise HttpError(resp, content)
Ejemplo n.º 7
0
def subscribe_app():
    subscription_endpoint = '/me/subscription'
    subscribe_uri = URIHandler(subscription_endpoint).configure()
    request = base.exec_request('POST', subscribe_uri)
    if request:
        return request
    else:
        raise HttpError('Unable to complete request.')
Ejemplo n.º 8
0
def validate_webhook(**kwargs):
    validation_endpoint = 'subscriptions_sample'
    validation_uri = URIHandler(validation_endpoint).configure(
        uri_format='appIDFirst', request_args=kwargs)
    request = base.exec_request('POST', validation_uri)
    if request:
        return request
    else:
        raise HttpError('Unable to complete request.')
Ejemplo n.º 9
0
def build(serviceName, version,
          http=None,
          discoveryServiceUrl=DISCOVERY_URI,
          developerKey=None,
          model=None,
          requestBuilder=HttpRequest):
  """Construct a Resource for interacting with an API.

  Construct a Resource object for interacting with
  an API. The serviceName and version are the
  names from the Discovery service.

  Args:
    serviceName: string, name of the service
    version: string, the version of the service
    discoveryServiceUrl: string, a URI Template that points to
      the location of the discovery service. It should have two
      parameters {api} and {apiVersion} that when filled in
      produce an absolute URI to the discovery document for
      that service.
    developerKey: string, key obtained
      from https://code.google.com/apis/console
    model: apiclient.Model, converts to and from the wire format
    requestBuilder: apiclient.http.HttpRequest, encapsulator for
      an HTTP request

  Returns:
    A Resource object with methods for interacting with
    the service.
  """
  params = {
      'api': serviceName,
      'apiVersion': version
      }

  if http is None:
    http = httplib2.Http()
  requested_url = uritemplate.expand(discoveryServiceUrl, params)
  logging.info('URL being requested: %s' % requested_url)
  resp, content = http.request(requested_url)
  if resp.status > 400:
    raise HttpError(resp, content, requested_url)
  try:
    service = simplejson.loads(content)
  except ValueError, e:
    logging.error('Failed to parse as JSON: ' + content)
    raise InvalidJsonError()
Ejemplo n.º 10
0
  def execute(self, http=None):
    """Execute the request.

    Args:
      http: httplib2.Http, an http object to be used in place of the
            one the HttpRequest request object was constructed with.

    Returns:
      A deserialized object model of the response body as determined
      by the postproc.

    Raises:
      apiclient.errors.HttpError if the response was not a 2xx.
      httplib2.HttpLib2Error if a transport error has occured.
    """
    if http is None:
      http = self.http
    if self.resumable:
      body = None
      while body is None:
        _, body = self.next_chunk(http=http)
      return body
    else:
      if 'content-length' not in self.headers:
        self.headers['content-length'] = str(self.body_size)
      # If the request URI is too long then turn it into a POST request.
      if len(self.uri) > MAX_URI_LENGTH and self.method == 'GET':
        self.method = 'POST'
        self.headers['x-http-method-override'] = 'GET'
        self.headers['content-type'] = 'application/x-www-form-urlencoded'
        parsed = urlparse.urlparse(self.uri)
        self.uri = urlparse.urlunparse(
            (parsed.scheme, parsed.netloc, parsed.path, parsed.params, None,
             None)
            )
        self.body = parsed.query
        self.headers['content-length'] = str(len(self.body))

      resp, content = http.request(str(self.uri), method=str(self.method),
                                   body=self.body, headers=self.headers)
      for callback in self.response_callbacks:
        callback(resp)
      if resp.status >= 300:
        raise HttpError(resp, content, uri=self.uri)
    return self.postproc(resp, content)
Ejemplo n.º 11
0
    def next_chunk(self):
        """Get the next chunk of the download.

    Returns:
      (status, done): (MediaDownloadStatus, boolean)
         The value of 'done' will be True when the media has been fully
         downloaded.

    Raises:
      apiclient.errors.HttpError if the response was not a 2xx.
      httplib2.Error if a transport error has occured.
    """
        headers = {
            'range':
            'bytes=%d-%d' % (self.progress_, self.progress_ + self.chunksize_)
        }
        http = self.request_.http
        http.follow_redirects = False

        resp, content = http.request(self.uri_, headers=headers)
        if resp.status in [301, 302, 303, 307, 308] and 'location' in resp:
            self.uri_ = resp['location']
            resp, content = http.request(self.uri_, headers=headers)
        if resp.status in [200, 206]:
            self.progress_ += len(content)
            self.fh_.write(content)

            if 'content-range' in resp:
                content_range = resp['content-range']
                length = content_range.rsplit('/', 1)[1]
                self.total_size_ = int(length)

            if self.progress_ == self.total_size_:
                self.done_ = True
            return MediaDownloadProgress(self.progress_,
                                         self.total_size_), self.done_
        else:
            raise HttpError(resp, content, self.uri_)
Ejemplo n.º 12
0
    def execute(self, http=None):
        """Execute all the requests as a single batched HTTP request.

    Args:
      http: httplib2.Http, an http object to be used in place of the one the
        HttpRequest request object was constructed with.  If one isn't supplied
        then use a http object from the requests in this batch.

    Returns:
      None

    Raises:
      apiclient.errors.HttpError if the response was not a 2xx.
      httplib2.Error if a transport error has occured.
    """
        if http is None:
            for request_id in self._order:
                request, callback = self._requests[request_id]
                if request is not None:
                    http = request.http
                    break
        if http is None:
            raise ValueError("Missing a valid http object.")

        msgRoot = MIMEMultipart('mixed')
        # msgRoot should not write out it's own headers
        setattr(msgRoot, '_write_headers', lambda self: None)

        # Add all the individual requests.
        for request_id in self._order:
            request, callback = self._requests[request_id]

            msg = MIMENonMultipart('application', 'http')
            msg['Content-Transfer-Encoding'] = 'binary'
            msg['Content-ID'] = self._id_to_header(request_id)

            body = self._serialize_request(request)
            msg.set_payload(body)
            msgRoot.attach(msg)

        body = msgRoot.as_string()

        headers = {}
        headers['content-type'] = ('multipart/mixed; '
                                   'boundary="%s"') % msgRoot.get_boundary()

        resp, content = http.request(self._batch_uri,
                                     'POST',
                                     body=body,
                                     headers=headers)

        if resp.status >= 300:
            raise HttpError(resp, content, self._batch_uri)

        # Now break up the response and process each one with the correct postproc
        # and trigger the right callbacks.
        boundary, _ = content.split(None, 1)

        # Prepend with a content-type header so FeedParser can handle it.
        header = 'Content-Type: %s\r\n\r\n' % resp['content-type']
        content = header + content

        parser = FeedParser()
        parser.feed(content)
        respRoot = parser.close()

        if not respRoot.is_multipart():
            raise BatchError("Response not in multipart/mixed format.")

        parts = respRoot.get_payload()
        for part in parts:
            request_id = self._header_to_id(part['Content-ID'])

            headers, content = self._deserialize_response(part.get_payload())

            # TODO(jcgregorio) Remove this temporary hack once the server stops
            # gzipping individual response bodies.
            if content[0] != '{':
                gzipped_content = content
                content = gzip.GzipFile(
                    fileobj=StringIO.StringIO(gzipped_content)).read()

            request, cb = self._requests[request_id]
            postproc = request.postproc
            response = postproc(resp, content)
            if cb is not None:
                cb(request_id, response)
            if self._callback is not None:
                self._callback(request_id, response)
Ejemplo n.º 13
0
    def next_chunk(self, http=None):
        """Execute the next step of a resumable upload.

    Can only be used if the method being executed supports media uploads and
    the MediaUpload object passed in was flagged as using resumable upload.

    Example:

      media = MediaFileUpload('smiley.png', mimetype='image/png',
                              chunksize=1000, resumable=True)
      request = service.objects().insert(
          bucket=buckets['items'][0]['id'],
          name='smiley.png',
          media_body=media)

      response = None
      while response is None:
        status, response = request.next_chunk()
        if status:
          print "Upload %d%% complete." % int(status.progress() * 100)


    Returns:
      (status, body): (ResumableMediaStatus, object)
         The body will be None until the resumable media is fully uploaded.
    """
        if http is None:
            http = self.http

        if self.resumable_uri is None:
            start_headers = copy.copy(self.headers)
            start_headers['X-Upload-Content-Type'] = self.resumable.mimetype()
            start_headers['X-Upload-Content-Length'] = str(
                self.resumable.size())
            start_headers['Content-Length'] = '0'
            resp, content = http.request(self.uri,
                                         self.method,
                                         body="",
                                         headers=start_headers)
            if resp.status == 200 and 'location' in resp:
                self.resumable_uri = resp['location']
            else:
                raise ResumableUploadError("Failed to retrieve starting URI.")
        if self.body:
            begin = 0
            data = self.body
        else:
            begin = self.resumable_progress - self.multipart_size
            data = self.resumable.getbytes(begin, self.resumable.chunksize())

        # Tack on the multipart/related boundary if we are at the end of the file.
        if begin + self.resumable.chunksize() >= self.resumable.size():
            data += self.multipart_boundary
        headers = {
            'Content-Range':
            'bytes %d-%d/%d' %
            (self.resumable_progress, self.resumable_progress + len(data) - 1,
             self.total_size),
        }
        resp, content = http.request(self.resumable_uri,
                                     'PUT',
                                     body=data,
                                     headers=headers)
        if resp.status in [200, 201]:
            return None, self.postproc(resp, content)
        elif resp.status == 308:
            # A "308 Resume Incomplete" indicates we are not done.
            self.resumable_progress = int(resp['range'].split('-')[1]) + 1
            if self.resumable_progress >= self.multipart_size:
                self.body = None
            if 'location' in resp:
                self.resumable_uri = resp['location']
        else:
            raise HttpError(resp, content, self.uri)

        return MediaUploadProgress(self.resumable_progress,
                                   self.total_size), None
Ejemplo n.º 14
0
 def get_text(self):
     request = base.exec_request('GET', self.graphAPIURLGET)
     if request:
         return request
     else:
         raise HttpError('Unable to complete request.')
Ejemplo n.º 15
0
 def set_text(self, payload):
     request = base.exec_request('POST', self.graphAPIURL, data=payload)
     if request:
         print(request)
     else:
         raise HttpError('Unable to complete request.')
Ejemplo n.º 16
0
 def delete_message(self):
     request = base.exec_request('DELETE', self.graphAPIURLGET)
     if request:
         return request
     else:
         raise HttpError('Unable to complete request.')
Ejemplo n.º 17
0
  def execute(self, http=None):
    """Execute all the requests as a single batched HTTP request.

    Args:
      http: httplib2.Http, an http object to be used in place of the one the
        HttpRequest request object was constructed with. If one isn't supplied
        then use a http object from the requests in this batch.

    Returns:
      None

    Raises:
      httplib2.HttpLib2Error if a transport error has occured.
      apiclient.errors.BatchError if the response is the wrong format.
    """

    # If http is not supplied use the first valid one given in the requests.
    if http is None:
      for request_id in self._order:
        request = self._requests[request_id]
        if request is not None:
          http = request.http
          break

    if http is None:
      raise ValueError("Missing a valid http object.")

    self._execute(http, self._order, self._requests)

    # Loop over all the requests and check for 401s. For each 401 request the
    # credentials should be refreshed and then sent again in a separate batch.
    redo_requests = {}
    redo_order = []

    for request_id in self._order:
      resp, content = self._responses[request_id]
      if resp['status'] == '401':
        redo_order.append(request_id)
        request = self._requests[request_id]
        self._refresh_and_apply_credentials(request, http)
        redo_requests[request_id] = request

    if redo_requests:
      self._execute(http, redo_order, redo_requests)

    # Now process all callbacks that are erroring, and raise an exception for
    # ones that return a non-2xx response? Or add extra parameter to callback
    # that contains an HttpError?

    for request_id in self._order:
      resp, content = self._responses[request_id]

      request = self._requests[request_id]
      callback = self._callbacks[request_id]

      response = None
      exception = None
      try:
        if resp.status >= 300:
          raise HttpError(resp, content, uri=request.uri)
        response = request.postproc(resp, content)
      except HttpError, e:
        exception = e

      if callback is not None:
        callback(request_id, response, exception)
      if self._callback is not None:
        self._callback(request_id, response, exception)