Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2978)

Unified Diff: appengine/chromium_build_logs/third_party/apiclient/http.py

Issue 1260293009: make version of ts_mon compatible with appengine (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: clean up code Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/chromium_build_logs/third_party/apiclient/http.py
diff --git a/appengine/chromium_build_logs/third_party/apiclient/http.py b/appengine/chromium_build_logs/third_party/apiclient/http.py
deleted file mode 100644
index 8e15e1116e5bbc922471f2a870347f4f88862489..0000000000000000000000000000000000000000
--- a/appengine/chromium_build_logs/third_party/apiclient/http.py
+++ /dev/null
@@ -1,922 +0,0 @@
-# Copyright (C) 2010 Google Inc.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Classes to encapsulate a single HTTP request.
-
-The classes implement a command pattern, with every
-object supporting an execute() method that does the
-actuall HTTP request.
-"""
-
-__author__ = 'jcgregorio@google.com (Joe Gregorio)'
-__all__ = [
- 'HttpRequest', 'RequestMockBuilder', 'HttpMock'
- 'set_user_agent', 'tunnel_patch'
- ]
-
-import StringIO
-import copy
-import gzip
-import httplib2
-import mimeparse
-import mimetypes
-import os
-import urllib
-import urlparse
-import uuid
-
-from email.mime.multipart import MIMEMultipart
-from email.mime.nonmultipart import MIMENonMultipart
-from email.parser import FeedParser
-from errors import BatchError
-from errors import HttpError
-from errors import ResumableUploadError
-from errors import UnexpectedBodyError
-from errors import UnexpectedMethodError
-from model import JsonModel
-from oauth2client.anyjson import simplejson
-
-
-class MediaUploadProgress(object):
- """Status of a resumable upload."""
-
- def __init__(self, resumable_progress, total_size):
- """Constructor.
-
- Args:
- resumable_progress: int, bytes sent so far.
- total_size: int, total bytes in complete upload.
- """
- self.resumable_progress = resumable_progress
- self.total_size = total_size
-
- def progress(self):
- """Percent of upload completed, as a float."""
- return float(self.resumable_progress) / float(self.total_size)
-
-
-class MediaUpload(object):
- """Describes a media object to upload.
-
- Base class that defines the interface of MediaUpload subclasses.
- """
-
- def getbytes(self, begin, end):
- raise NotImplementedError()
-
- def size(self):
- raise NotImplementedError()
-
- def chunksize(self):
- raise NotImplementedError()
-
- def mimetype(self):
- return 'application/octet-stream'
-
- def resumable(self):
- return False
-
- def _to_json(self, strip=None):
- """Utility function for creating a JSON representation of a MediaUpload.
-
- Args:
- strip: array, An array of names of members to not include in the JSON.
-
- Returns:
- string, a JSON representation of this instance, suitable to pass to
- from_json().
- """
- t = type(self)
- d = copy.copy(self.__dict__)
- if strip is not None:
- for member in strip:
- del d[member]
- d['_class'] = t.__name__
- d['_module'] = t.__module__
- return simplejson.dumps(d)
-
- def to_json(self):
- """Create a JSON representation of an instance of MediaUpload.
-
- Returns:
- string, a JSON representation of this instance, suitable to pass to
- from_json().
- """
- return self._to_json()
-
- @classmethod
- def new_from_json(cls, s):
- """Utility class method to instantiate a MediaUpload subclass from a JSON
- representation produced by to_json().
-
- Args:
- s: string, JSON from to_json().
-
- Returns:
- An instance of the subclass of MediaUpload that was serialized with
- to_json().
- """
- data = simplejson.loads(s)
- # Find and call the right classmethod from_json() to restore the object.
- module = data['_module']
- m = __import__(module, fromlist=module.split('.')[:-1])
- kls = getattr(m, data['_class'])
- from_json = getattr(kls, 'from_json')
- return from_json(s)
-
-
-class MediaFileUpload(MediaUpload):
- """A MediaUpload for a file.
-
- Construct a MediaFileUpload and pass as the media_body parameter of the
- method. For example, if we had a service that allowed uploading images:
-
-
- media = MediaFileUpload('smiley.png', mimetype='image/png', chunksize=1000,
- resumable=True)
- service.objects().insert(
- bucket=buckets['items'][0]['id'],
- name='smiley.png',
- media_body=media).execute()
- """
-
- def __init__(self, filename, mimetype=None, chunksize=256*1024, resumable=False):
- """Constructor.
-
- Args:
- filename: string, Name of the file.
- mimetype: string, Mime-type of the file. If None then a mime-type will be
- guessed from the file extension.
- chunksize: int, File will be uploaded in chunks of this many bytes. Only
- used if resumable=True.
- resumable: bool, True if this is a resumable upload. False means upload
- in a single request.
- """
- self._filename = filename
- self._size = os.path.getsize(filename)
- self._fd = None
- if mimetype is None:
- (mimetype, encoding) = mimetypes.guess_type(filename)
- self._mimetype = mimetype
- self._chunksize = chunksize
- self._resumable = resumable
-
- def mimetype(self):
- return self._mimetype
-
- def size(self):
- return self._size
-
- def chunksize(self):
- return self._chunksize
-
- def resumable(self):
- return self._resumable
-
- def getbytes(self, begin, length):
- """Get bytes from the media.
-
- Args:
- begin: int, offset from beginning of file.
- length: int, number of bytes to read, starting at begin.
-
- Returns:
- A string of bytes read. May be shorted than length if EOF was reached
- first.
- """
- if self._fd is None:
- self._fd = open(self._filename, 'rb')
- self._fd.seek(begin)
- return self._fd.read(length)
-
- def to_json(self):
- """Creating a JSON representation of an instance of Credentials.
-
- Returns:
- string, a JSON representation of this instance, suitable to pass to
- from_json().
- """
- return self._to_json(['_fd'])
-
- @staticmethod
- def from_json(s):
- d = simplejson.loads(s)
- return MediaFileUpload(
- d['_filename'], d['_mimetype'], d['_chunksize'], d['_resumable'])
-
-
-class HttpRequest(object):
- """Encapsulates a single HTTP request."""
-
- def __init__(self, http, postproc, uri,
- method='GET',
- body=None,
- headers=None,
- methodId=None,
- resumable=None):
- """Constructor for an HttpRequest.
-
- Args:
- http: httplib2.Http, the transport object to use to make a request
- postproc: callable, called on the HTTP response and content to transform
- it into a data object before returning, or raising an exception
- on an error.
- uri: string, the absolute URI to send the request to
- method: string, the HTTP method to use
- body: string, the request body of the HTTP request,
- headers: dict, the HTTP request headers
- methodId: string, a unique identifier for the API method being called.
- resumable: MediaUpload, None if this is not a resumbale request.
- """
- self.uri = uri
- self.method = method
- self.body = body
- self.headers = headers or {}
- self.methodId = methodId
- self.http = http
- self.postproc = postproc
- self.resumable = resumable
-
- # Pull the multipart boundary out of the content-type header.
- major, minor, params = mimeparse.parse_mime_type(
- headers.get('content-type', 'application/json'))
-
- # The size of the non-media part of the request.
- self.body_size = len(self.body or '')
-
- # The resumable URI to send chunks to.
- self.resumable_uri = None
-
- # The bytes that have been uploaded.
- self.resumable_progress = 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)
-
- 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'] = str(self.body_size)
-
- resp, content = http.request(self.uri, self.method,
- body=self.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.")
-
- data = self.resumable.getbytes(self.resumable_progress,
- self.resumable.chunksize())
-
- headers = {
- 'Content-Range': 'bytes %d-%d/%d' % (
- self.resumable_progress, self.resumable_progress + len(data) - 1,
- self.resumable.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 'location' in resp:
- self.resumable_uri = resp['location']
- else:
- raise HttpError(resp, content, self.uri)
-
- return (MediaUploadProgress(self.resumable_progress, self.resumable.size()),
- None)
-
- def to_json(self):
- """Returns a JSON representation of the HttpRequest."""
- d = copy.copy(self.__dict__)
- if d['resumable'] is not None:
- d['resumable'] = self.resumable.to_json()
- del d['http']
- del d['postproc']
- return simplejson.dumps(d)
-
- @staticmethod
- def from_json(s, http, postproc):
- """Returns an HttpRequest populated with info from a JSON object."""
- d = simplejson.loads(s)
- if d['resumable'] is not None:
- d['resumable'] = MediaUpload.new_from_json(d['resumable'])
- return HttpRequest(
- http,
- postproc,
- uri=d['uri'],
- method=d['method'],
- body=d['body'],
- headers=d['headers'],
- methodId=d['methodId'],
- resumable=d['resumable'])
-
-
-class BatchHttpRequest(object):
- """Batches multiple HttpRequest objects into a single HTTP request."""
-
- def __init__(self, callback=None, batch_uri=None):
- """Constructor for a BatchHttpRequest.
-
- Args:
- callback: callable, A callback to be called for each response, of the
- form callback(id, response). The first parameter is the request id, and
- the second is the deserialized response object.
- batch_uri: string, URI to send batch requests to.
- """
- if batch_uri is None:
- batch_uri = 'https://www.googleapis.com/batch'
- self._batch_uri = batch_uri
-
- # Global callback to be called for each individual response in the batch.
- self._callback = callback
-
- # A map from id to (request, callback) pairs.
- self._requests = {}
-
- # List of request ids, in the order in which they were added.
- self._order = []
-
- # The last auto generated id.
- self._last_auto_id = 0
-
- # Unique ID on which to base the Content-ID headers.
- self._base_id = None
-
- def _id_to_header(self, id_):
- """Convert an id to a Content-ID header value.
-
- Args:
- id_: string, identifier of individual request.
-
- Returns:
- A Content-ID header with the id_ encoded into it. A UUID is prepended to
- the value because Content-ID headers are supposed to be universally
- unique.
- """
- if self._base_id is None:
- self._base_id = uuid.uuid4()
-
- return '<%s+%s>' % (self._base_id, urllib.quote(id_))
-
- def _header_to_id(self, header):
- """Convert a Content-ID header value to an id.
-
- Presumes the Content-ID header conforms to the format that _id_to_header()
- returns.
-
- Args:
- header: string, Content-ID header value.
-
- Returns:
- The extracted id value.
-
- Raises:
- BatchError if the header is not in the expected format.
- """
- if header[0] != '<' or header[-1] != '>':
- raise BatchError("Invalid value for Content-ID: %s" % header)
- if '+' not in header:
- raise BatchError("Invalid value for Content-ID: %s" % header)
- base, id_ = header[1:-1].rsplit('+', 1)
-
- return urllib.unquote(id_)
-
- def _serialize_request(self, request):
- """Convert an HttpRequest object into a string.
-
- Args:
- request: HttpRequest, the request to serialize.
-
- Returns:
- The request as a string in application/http format.
- """
- # Construct status line
- parsed = urlparse.urlparse(request.uri)
- request_line = urlparse.urlunparse(
- (None, None, parsed.path, parsed.params, parsed.query, None)
- )
- status_line = request.method + ' ' + request_line + ' HTTP/1.1\n'
- major, minor = request.headers.get('content-type', 'application/json').split('/')
- msg = MIMENonMultipart(major, minor)
- headers = request.headers.copy()
-
- # MIMENonMultipart adds its own Content-Type header.
- if 'content-type' in headers:
- del headers['content-type']
-
- for key, value in headers.iteritems():
- msg[key] = value
- msg['Host'] = parsed.netloc
- msg.set_unixfrom(None)
-
- if request.body is not None:
- msg.set_payload(request.body)
- msg['content-length'] = str(len(request.body))
-
- body = msg.as_string(False)
- # Strip off the \n\n that the MIME lib tacks onto the end of the payload.
- if request.body is None:
- body = body[:-2]
-
- return status_line.encode('utf-8') + body
-
- def _deserialize_response(self, payload):
- """Convert string into httplib2 response and content.
-
- Args:
- payload: string, headers and body as a string.
-
- Returns:
- A pair (resp, content) like would be returned from httplib2.request.
- """
- # Strip off the status line
- status_line, payload = payload.split('\n', 1)
- protocol, status, reason = status_line.split(' ', 2)
-
- # Parse the rest of the response
- parser = FeedParser()
- parser.feed(payload)
- msg = parser.close()
- msg['status'] = status
-
- # Create httplib2.Response from the parsed headers.
- resp = httplib2.Response(msg)
- resp.reason = reason
- resp.version = int(protocol.split('/', 1)[1].replace('.', ''))
-
- content = payload.split('\r\n\r\n', 1)[1]
-
- return resp, content
-
- def _new_id(self):
- """Create a new id.
-
- Auto incrementing number that avoids conflicts with ids already used.
-
- Returns:
- string, a new unique id.
- """
- self._last_auto_id += 1
- while str(self._last_auto_id) in self._requests:
- self._last_auto_id += 1
- return str(self._last_auto_id)
-
- def add(self, request, callback=None, request_id=None):
- """Add a new request.
-
- Every callback added will be paired with a unique id, the request_id. That
- unique id will be passed back to the callback when the response comes back
- from the server. The default behavior is to have the library generate it's
- own unique id. If the caller passes in a request_id then they must ensure
- uniqueness for each request_id, and if they are not an exception is
- raised. Callers should either supply all request_ids or nevery supply a
- request id, to avoid such an error.
-
- Args:
- request: HttpRequest, Request to add to the batch.
- callback: callable, A callback to be called for this response, of the
- form callback(id, response). The first parameter is the request id, and
- the second is the deserialized response object.
- request_id: string, A unique id for the request. The id will be passed to
- the callback with the response.
-
- Returns:
- None
-
- Raises:
- BatchError if a resumable request is added to a batch.
- KeyError is the request_id is not unique.
- """
- if request_id is None:
- request_id = self._new_id()
- if request.resumable is not None:
- raise BatchError("Resumable requests cannot be used in a batch request.")
- if request_id in self._requests:
- raise KeyError("A request with this ID already exists: %s" % request_id)
- self._requests[request_id] = (request, callback)
- self._order.append(request_id)
-
- 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.
- apiclient.errors.BatchError if the response is the wrong format.
- """
- 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']
- for_parser = header + content
-
- parser = FeedParser()
- parser.feed(for_parser)
- respRoot = parser.close()
-
- if not respRoot.is_multipart():
- raise BatchError("Response not in multipart/mixed format.", resp,
- content)
-
- 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)
-
-
-class HttpRequestMock(object):
- """Mock of HttpRequest.
-
- Do not construct directly, instead use RequestMockBuilder.
- """
-
- def __init__(self, resp, content, postproc):
- """Constructor for HttpRequestMock
-
- Args:
- resp: httplib2.Response, the response to emulate coming from the request
- content: string, the response body
- postproc: callable, the post processing function usually supplied by
- the model class. See model.JsonModel.response() as an example.
- """
- self.resp = resp
- self.content = content
- self.postproc = postproc
- if resp is None:
- self.resp = httplib2.Response({'status': 200, 'reason': 'OK'})
- if 'reason' in self.resp:
- self.resp.reason = self.resp['reason']
-
- def execute(self, http=None):
- """Execute the request.
-
- Same behavior as HttpRequest.execute(), but the response is
- mocked and not really from an HTTP request/response.
- """
- return self.postproc(self.resp, self.content)
-
-
-class RequestMockBuilder(object):
- """A simple mock of HttpRequest
-
- Pass in a dictionary to the constructor that maps request methodIds to
- tuples of (httplib2.Response, content, opt_expected_body) that should be
- returned when that method is called. None may also be passed in for the
- httplib2.Response, in which case a 200 OK response will be generated.
- If an opt_expected_body (str or dict) is provided, it will be compared to
- the body and UnexpectedBodyError will be raised on inequality.
-
- Example:
- response = '{"data": {"id": "tag:google.c...'
- requestBuilder = RequestMockBuilder(
- {
- 'plus.activities.get': (None, response),
- }
- )
- apiclient.discovery.build("plus", "v1", requestBuilder=requestBuilder)
-
- Methods that you do not supply a response for will return a
- 200 OK with an empty string as the response content or raise an excpetion
- if check_unexpected is set to True. The methodId is taken from the rpcName
- in the discovery document.
-
- For more details see the project wiki.
- """
-
- def __init__(self, responses, check_unexpected=False):
- """Constructor for RequestMockBuilder
-
- The constructed object should be a callable object
- that can replace the class HttpResponse.
-
- responses - A dictionary that maps methodIds into tuples
- of (httplib2.Response, content). The methodId
- comes from the 'rpcName' field in the discovery
- document.
- check_unexpected - A boolean setting whether or not UnexpectedMethodError
- should be raised on unsupplied method.
- """
- self.responses = responses
- self.check_unexpected = check_unexpected
-
- def __call__(self, http, postproc, uri, method='GET', body=None,
- headers=None, methodId=None, resumable=None):
- """Implements the callable interface that discovery.build() expects
- of requestBuilder, which is to build an object compatible with
- HttpRequest.execute(). See that method for the description of the
- parameters and the expected response.
- """
- if methodId in self.responses:
- response = self.responses[methodId]
- resp, content = response[:2]
- if len(response) > 2:
- # Test the body against the supplied expected_body.
- expected_body = response[2]
- if bool(expected_body) != bool(body):
- # Not expecting a body and provided one
- # or expecting a body and not provided one.
- raise UnexpectedBodyError(expected_body, body)
- if isinstance(expected_body, str):
- expected_body = simplejson.loads(expected_body)
- body = simplejson.loads(body)
- if body != expected_body:
- raise UnexpectedBodyError(expected_body, body)
- return HttpRequestMock(resp, content, postproc)
- elif self.check_unexpected:
- raise UnexpectedMethodError(methodId)
- else:
- model = JsonModel(False)
- return HttpRequestMock(None, '{}', model.response)
-
-
-class HttpMock(object):
- """Mock of httplib2.Http"""
-
- def __init__(self, filename, headers=None):
- """
- Args:
- filename: string, absolute filename to read response from
- headers: dict, header to return with response
- """
- if headers is None:
- headers = {'status': '200 OK'}
- f = file(filename, 'r')
- self.data = f.read()
- f.close()
- self.headers = headers
-
- def request(self, uri,
- method='GET',
- body=None,
- headers=None,
- redirections=1,
- connection_type=None):
- return httplib2.Response(self.headers), self.data
-
-
-class HttpMockSequence(object):
- """Mock of httplib2.Http
-
- Mocks a sequence of calls to request returning different responses for each
- call. Create an instance initialized with the desired response headers
- and content and then use as if an httplib2.Http instance.
-
- http = HttpMockSequence([
- ({'status': '401'}, ''),
- ({'status': '200'}, '{"access_token":"1/3w","expires_in":3600}'),
- ({'status': '200'}, 'echo_request_headers'),
- ])
- resp, content = http.request("http://examples.com")
-
- There are special values you can pass in for content to trigger
- behavours that are helpful in testing.
-
- 'echo_request_headers' means return the request headers in the response body
- 'echo_request_headers_as_json' means return the request headers in
- the response body
- 'echo_request_body' means return the request body in the response body
- 'echo_request_uri' means return the request uri in the response body
- """
-
- def __init__(self, iterable):
- """
- Args:
- iterable: iterable, a sequence of pairs of (headers, body)
- """
- self._iterable = iterable
-
- def request(self, uri,
- method='GET',
- body=None,
- headers=None,
- redirections=1,
- connection_type=None):
- resp, content = self._iterable.pop(0)
- if content == 'echo_request_headers':
- content = headers
- elif content == 'echo_request_headers_as_json':
- content = simplejson.dumps(headers)
- elif content == 'echo_request_body':
- content = body
- elif content == 'echo_request_uri':
- content = uri
- return httplib2.Response(resp), content
-
-
-def set_user_agent(http, user_agent):
- """Set the user-agent on every request.
-
- Args:
- http - An instance of httplib2.Http
- or something that acts like it.
- user_agent: string, the value for the user-agent header.
-
- Returns:
- A modified instance of http that was passed in.
-
- Example:
-
- h = httplib2.Http()
- h = set_user_agent(h, "my-app-name/6.0")
-
- Most of the time the user-agent will be set doing auth, this is for the rare
- cases where you are accessing an unauthenticated endpoint.
- """
- request_orig = http.request
-
- # The closure that will replace 'httplib2.Http.request'.
- def new_request(uri, method='GET', body=None, headers=None,
- redirections=httplib2.DEFAULT_MAX_REDIRECTS,
- connection_type=None):
- """Modify the request headers to add the user-agent."""
- if headers is None:
- headers = {}
- if 'user-agent' in headers:
- headers['user-agent'] = user_agent + ' ' + headers['user-agent']
- else:
- headers['user-agent'] = user_agent
- resp, content = request_orig(uri, method, body, headers,
- redirections, connection_type)
- return resp, content
-
- http.request = new_request
- return http
-
-
-def tunnel_patch(http):
- """Tunnel PATCH requests over POST.
- Args:
- http - An instance of httplib2.Http
- or something that acts like it.
-
- Returns:
- A modified instance of http that was passed in.
-
- Example:
-
- h = httplib2.Http()
- h = tunnel_patch(h, "my-app-name/6.0")
-
- Useful if you are running on a platform that doesn't support PATCH.
- Apply this last if you are using OAuth 1.0, as changing the method
- will result in a different signature.
- """
- request_orig = http.request
-
- # The closure that will replace 'httplib2.Http.request'.
- def new_request(uri, method='GET', body=None, headers=None,
- redirections=httplib2.DEFAULT_MAX_REDIRECTS,
- connection_type=None):
- """Modify the request headers to add the user-agent."""
- if headers is None:
- headers = {}
- if method == 'PATCH':
- if 'oauth_token' in headers.get('authorization', ''):
- logging.warning(
- 'OAuth 1.0 request made with Credentials after tunnel_patch.')
- headers['x-http-method-override'] = "PATCH"
- method = 'POST'
- resp, content = request_orig(uri, method, body, headers,
- redirections, connection_type)
- return resp, content
-
- http.request = new_request
- return http

Powered by Google App Engine
This is Rietveld 408576698