def test__add_query_parameter(self): self.assertEqual(util._add_query_parameter('/action', 'a', None), '/action') self.assertEqual(util._add_query_parameter('/action', 'a', 'b'), '/action?a=b') self.assertEqual(util._add_query_parameter('/action?a=b', 'a', 'c'), '/action?a=c') # Order is non-deterministic. self.assertIn(util._add_query_parameter('/action?a=b', 'c', 'd'), ['/action?a=b&c=d', '/action?c=d&a=b']) self.assertEqual(util._add_query_parameter('/action', 'a', ' ='), '/action?a=+%3D')
def callback_handler(self, request): from django import http import logging logging.info('callback_handler') self.request = request error = request.GET.get('error') if error: errormsg = request.GET.get('error') return http.HttpResponse('The authorization request failed: %s' % errormsg) else: user = users.get_current_user() self._create_flow(self) credentials = self.flow.step2_exchange( {'code': str(request.GET.get('code', ''))}) self._storage_class(self._credentials_class, None, self._credentials_property_name, user=user).put(credentials) redirect_uri = _parse_state_value(str(request.GET.get('state')), user) if self._token_response_param and credentials.token_response: resp_json = simplejson.dumps(credentials.token_response) redirect_uri = util._add_query_parameter( redirect_uri, self._token_response_param, resp_json) import logging logging.info(redirect_uri) return http.HttpResponseRedirect(redirect_uri)
def get(self): error = self.request.get('error') if error: errormsg = self.request.get('error_description', error) self.response.out.write( 'The authorization request failed: %s' % _safe_html(errormsg)) else: user = users.get_current_user() decorator._create_flow(self) credentials = decorator.flow.step2_exchange( self.request.params) decorator._storage_class( decorator._credentials_class, None, decorator._credentials_property_name, user=user).put(credentials) redirect_uri = _parse_state_value( str(self.request.get('state')), user) if decorator._token_response_param and credentials.token_response: resp_json = json.dumps(credentials.token_response) redirect_uri = util._add_query_parameter( redirect_uri, decorator._token_response_param, resp_json) self.redirect(redirect_uri)
def get(http_request, path, root=METADATA_ROOT, recursive=None): """Fetch a resource from the metadata server. Args: path: A string indicating the resource to retrieve. For example, 'instance/service-accounts/defualt' http_request: A callable that matches the method signature of httplib2.Http.request. Used to make the request to the metadataserver. root: A string indicating the full path to the metadata server root. recursive: A boolean indicating whether to do a recursive query of metadata. See https://cloud.google.com/compute/docs/metadata#aggcontents Returns: A dictionary if the metadata server returns JSON, otherwise a string. Raises: httplib2.Httplib2Error if an error corrured while retrieving metadata. """ url = urlparse.urljoin(root, path) url = util._add_query_parameter(url, 'recursive', recursive) response, content = http_request(url, headers=METADATA_HEADERS) if response.status == http_client.OK: decoded = _helpers._from_bytes(content) if response['content-type'] == 'application/json': return json.loads(decoded) else: return decoded else: raise httplib2.HttpLib2Error( 'Failed to retrieve {0} from the Google Compute Engine' 'metadata service. Response:\n{1}'.format(url, response))
def get(self): error = self.request.get('error') if error: errormsg = self.request.get('error_description', error) self.response.out.write( 'The authorization request failed: %s' % _safe_html(errormsg)) else: user = users.get_current_user() decorator._create_flow(self) credentials = decorator.flow.step2_exchange( self.request.params) decorator._storage_class( decorator._credentials_class, None, decorator._credentials_property_name, user=user).put(credentials) redirect_uri = _parse_state_value( str(self.request.get('state')), user) if (decorator._token_response_param and credentials.token_response): resp_json = json.dumps(credentials.token_response) redirect_uri = util._add_query_parameter( redirect_uri, decorator._token_response_param, resp_json) self.redirect(redirect_uri)
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. http: httplib2.Http, An instance of httplib2.Http or something that acts like it that HTTP requests will be made through. 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']) logger.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, uri=requested_url) try: service = simplejson.loads(content) except ValueError, e: logger.error('Failed to parse as JSON: ' + content) raise InvalidJsonError()
def methodNext(self, previous_request, previous_response): """Retrieves the next page of results. Args: previous_request: The request for the previous page. (required) previous_response: The response from the request for the previous page. (required) Returns: A request object that you can call 'execute()' on to request the next page. Returns None if there are no more items in the collection. """ # Retrieve nextPageToken from previous_response # Use as pageToken in previous_request to create new request. nextPageToken = previous_response.get(nextPageTokenName, None) if not nextPageToken: return None request = copy.copy(previous_request) if isPageTokenParameter: # Replace pageToken value in URI request.uri = _add_query_parameter(request.uri, pageTokenName, nextPageToken) logger.info('Next page request URL: %s %s' % (methodName, request.uri)) else: # Replace pageToken value in request body model = self._model body = model.deserialize(request.body) body[pageTokenName] = nextPageToken request.body = model.serialize(body) logger.info('Next page request body: %s %s' % (methodName, body)) return request
def get(self): error = self.request.get('error') if error: errormsg = self.request.get('error_description', error) self.response.out.write( 'The authorization request failed: {0!s}'.format( _safe_html(errormsg))) else: user = users.get_current_user() decorator._create_flow(self) credentials = decorator.flow.step2_exchange( self.request.params) StorageByKeyName(CredentialsModel, user.user_id(), 'credentials').put(credentials) redirect_uri = _parse_state_value( str(self.request.get('state')), user) if decorator._token_response_param and credentials.token_response: resp_json = simplejson.dumps( credentials.token_response) redirect_uri = util._add_query_parameter( redirect_uri, decorator._token_response_param, resp_json) self.redirect(redirect_uri)
def methodNext(self, previous_request, previous_response): """Retrieves the next page of results. Args: previous_request: The request for the previous page. (required) previous_response: The response from the request for the previous page. (required) Returns: A request object that you can call 'execute()' on to request the next page. Returns None if there are no more items in the collection. """ # Retrieve nextPageToken from previous_response # Use as pageToken in previous_request to create new request. nextPageToken = previous_response.get(nextPageTokenName, None) if not nextPageToken: return None request = copy.copy(previous_request) if isPageTokenParameter: # Replace pageToken value in URI request.uri = _add_query_parameter( request.uri, pageTokenName, nextPageToken) logger.info('Next page request URL: %s %s' % (methodName, request.uri)) else: # Replace pageToken value in request body model = self._model body = model.deserialize(request.body) body[pageTokenName] = nextPageToken request.body = model.serialize(body) logger.info('Next page request body: %s %s' % (methodName, body)) return request
def test__add_query_parameter(self): self.assertEqual( util._add_query_parameter('/action', 'a', None), '/action') self.assertEqual( util._add_query_parameter('/action', 'a', 'b'), '/action?a=b') self.assertEqual( util._add_query_parameter('/action?a=b', 'a', 'c'), '/action?a=c') # Order is non-deterministic. self.assertIn( util._add_query_parameter('/action?a=b', 'c', 'd'), ['/action?a=b&c=d', '/action?c=d&a=b']) self.assertEqual( util._add_query_parameter('/action', 'a', ' ='), '/action?a=+%3D')
def _retrieve_discovery_doc(url, http, cache_discovery, cache=None): """Retrieves the discovery_doc from cache or the internet. Args: url: string, the URL of the discovery document. http: httplib2.Http, An instance of httplib2.Http or something that acts like it through which HTTP requests will be made. cache_discovery: Boolean, whether or not to cache the discovery doc. cache: googleapiclient.discovery_cache.base.Cache, an optional cache object for the discovery documents. Returns: A unicode string representation of the discovery document. """ if cache_discovery: from . import discovery_cache from .discovery_cache import base if cache is None: cache = discovery_cache.autodetect() if cache: content = cache.get(url) if content: return content actual_url = url # 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: actual_url = _add_query_parameter(url, 'userIp', os.environ['REMOTE_ADDR']) logger.info('URL being requested: GET %s', actual_url) resp, content = http.request(actual_url) if resp.status == 404: raise UnknownApiNameOrVersion("name: %s version: %s" % (serviceName, version)) if resp.status >= 400: raise HttpError(resp, content, uri=actual_url) try: content = content.decode('utf-8') except AttributeError: pass try: service = json.loads(content) except ValueError as e: logger.error('Failed to parse as JSON: ' + content) raise InvalidJsonError() if cache_discovery and cache: cache.set(url, content) return content
def _dummy_zoo_request(self): with open(os.path.join(DATA_DIR, 'zoo.json'), 'rU') as fh: zoo_contents = fh.read() zoo_uri = uritemplate.expand(DISCOVERY_URI, {'api': 'zoo', 'apiVersion': 'v1'}) if 'REMOTE_ADDR' in os.environ: zoo_uri = util._add_query_parameter(zoo_uri, 'userIp', os.environ['REMOTE_ADDR']) http = httplib2.Http() original_request = http.request def wrapped_request(uri, method='GET', *args, **kwargs): if uri == zoo_uri: return httplib2.Response({'status': '200'}), zoo_contents return original_request(uri, method=method, *args, **kwargs) http.request = wrapped_request return http
def _dummy_zoo_request(self): with open(os.path.join(DATA_DIR, "zoo.json"), "rU") as fh: zoo_contents = fh.read() zoo_uri = uritemplate.expand(DISCOVERY_URI, {"api": "zoo", "apiVersion": "v1"}) if "REMOTE_ADDR" in os.environ: zoo_uri = util._add_query_parameter(zoo_uri, "userIp", os.environ["REMOTE_ADDR"]) http = httplib2.Http() original_request = http.request def wrapped_request(uri, method="GET", *args, **kwargs): if uri == zoo_uri: return httplib2.Response({"status": "200"}), zoo_contents return original_request(uri, method=method, *args, **kwargs) http.request = wrapped_request return http
def get(path, http_request=None, root=METADATA_ROOT, recursive=None): """Fetch a resource from the metadata server. Args: path: A string indicating the resource to retrieve. For example, 'instance/service-accounts/defualt' http_request: A callable that matches the method signature of httplib2.Http.request. Used to make the request to the metadataserver. root: A string indicating the full path to the metadata server root. recursive: A boolean indicating whether to do a recursive query of metadata. See https://cloud.google.com/compute/docs/metadata#aggcontents Returns: A dictionary if the metadata server returns JSON, otherwise a string. Raises: httplib2.Httplib2Error if an error corrured while retrieving metadata. """ if not http_request: http_request = httplib2.Http().request url = urlparse.urljoin(root, path) url = util._add_query_parameter(url, 'recursive', recursive) response, content = http_request( url, headers=METADATA_HEADERS ) if response.status == http_client.OK: decoded = _from_bytes(content) if response['content-type'] == 'application/json': return json.loads(decoded) else: return decoded else: raise httplib2.HttpLib2Error( 'Failed to retrieve {0} from the Google Compute Engine' 'metadata service. Response:\n{1}'.format(url, response))
def get(self): error = self.request.get('error') if error: errormsg = self.request.get('error_description', error) self.response.out.write( 'The authorization request failed: %s' % _safe_html(errormsg)) else: user = users.get_current_user() decorator._create_flow(self) credentials = decorator.flow.step2_exchange(self.request.params) StorageByKeyName( CredentialsModel, user.user_id(), 'credentials').put(credentials) redirect_uri = _parse_state_value(str(self.request.get('state')), user) if decorator._token_response_param and credentials.token_response: resp_json = simplejson.dumps(credentials.token_response) redirect_uri = util._add_query_parameter( redirect_uri, decorator._token_response_param, resp_json) self.redirect(redirect_uri)
def callback_handler(self, request): from django import http import logging logging.info('callback_handler') self.request = request error = request.GET.get('error') if error: errormsg = request.GET.get('error') return http.HttpResponse('The authorization request failed: %s' % errormsg) else: user = users.get_current_user() self._create_flow(self) credentials = self.flow.step2_exchange({'code' : str(request.GET.get('code', ''))}) self._storage_class(self._credentials_class, None, self._credentials_property_name, user=user).put(credentials) redirect_uri = _parse_state_value(str(request.GET.get('state')), user) if self._token_response_param and credentials.token_response: resp_json = simplejson.dumps(credentials.token_response) redirect_uri = util._add_query_parameter(redirect_uri, self._token_response_param, resp_json) import logging logging.info(redirect_uri) return http.HttpResponseRedirect(redirect_uri)
def method(self, **kwargs): # Don't bother with doc string, it will be over-written by createMethod. for name in kwargs.iterkeys(): if name not in parameters.argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) # Remove args that have a value of None. keys = kwargs.keys() for name in keys: if kwargs[name] is None: del kwargs[name] for name in parameters.required_params: if name not in kwargs: raise TypeError('Missing required parameter "%s"' % name) for name, regex in parameters.pattern_params.iteritems(): if name in kwargs: if isinstance(kwargs[name], basestring): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, pvalue, regex)) for name, enums in parameters.enum_params.iteritems(): if name in kwargs: # We need to handle the case of a repeated enum # name differently, since we want to handle both # arg='value' and arg=['value1', 'value2'] if (name in parameters.repeated_params and not isinstance(kwargs[name], basestring)): values = kwargs[name] else: values = [kwargs[name]] for value in values: if value not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, value, str(enums))) actual_query_params = {} actual_path_params = {} for key, value in kwargs.iteritems(): to_type = parameters.param_types.get(key, 'string') # For repeated parameters we cast each member of the list. if key in parameters.repeated_params and type(value) == type([]): cast_value = [_cast(x, to_type) for x in value] else: cast_value = _cast(value, to_type) if key in parameters.query_params: actual_query_params[parameters.argmap[key]] = cast_value if key in parameters.path_params: actual_path_params[parameters.argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) if self._developerKey: actual_query_params['key'] = self._developerKey model = self._model if methodName.endswith('_media'): model = MediaModel() elif 'response' not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = '' if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, basestring): (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, mimetype=media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError('media_filename must be str or MediaUpload.') # Check the maxSize if maxSize > 0 and media_upload.size() > maxSize: raise MediaUploadSizeError("Media larger than: %s" % maxSize) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = urlparse.urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): url = _add_query_parameter(url, 'uploadType', 'resumable') if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers['content-type'] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) url = _add_query_parameter(url, 'uploadType', 'media') else: # This is a multipart/related upload. msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split('/')) msg['Content-Transfer-Encoding'] = 'binary' payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) body = msgRoot.as_string() multipart_boundary = msgRoot.get_boundary() headers['content-type'] = ('multipart/related; ' 'boundary="%s"') % multipart_boundary url = _add_query_parameter(url, 'uploadType', 'multipart') logger.info('URL being requested: %s %s' % (httpMethod,url)) return self._requestBuilder(self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable)
def method(self, **kwargs): # Don't bother with doc string, it will be over-written by createMethod. for name in six.iterkeys(kwargs): if name not in parameters.argmap: raise TypeError('Got an unexpected keyword argument "{0!s}"'.format(name)) # Remove args that have a value of None. keys = list(kwargs.keys()) for name in keys: if kwargs[name] is None: del kwargs[name] for name in parameters.required_params: if name not in kwargs: raise TypeError('Missing required parameter "{0!s}"'.format(name)) for name, regex in six.iteritems(parameters.pattern_params): if name in kwargs: if isinstance(kwargs[name], six.string_types): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "{0!s}" value "{1!s}" does not match the pattern "{2!s}"'.format( name, pvalue, regex ) ) for name, enums in six.iteritems(parameters.enum_params): if name in kwargs: # We need to handle the case of a repeated enum # name differently, since we want to handle both # arg='value' and arg=['value1', 'value2'] if name in parameters.repeated_params and not isinstance(kwargs[name], six.string_types): values = kwargs[name] else: values = [kwargs[name]] for value in values: if value not in enums: raise TypeError( 'Parameter "{0!s}" value "{1!s}" is not an allowed value in "{2!s}"'.format( name, value, str(enums) ) ) actual_query_params = {} actual_path_params = {} for key, value in six.iteritems(kwargs): to_type = parameters.param_types.get(key, "string") # For repeated parameters we cast each member of the list. if key in parameters.repeated_params and type(value) == type([]): cast_value = [_cast(x, to_type) for x in value] else: cast_value = _cast(value, to_type) if key in parameters.query_params: actual_query_params[parameters.argmap[key]] = cast_value if key in parameters.path_params: actual_path_params[parameters.argmap[key]] = cast_value body_value = kwargs.get("body", None) media_filename = kwargs.get("media_body", None) if self._developerKey: actual_query_params["key"] = self._developerKey model = self._model if methodName.endswith("_media"): model = MediaModel() elif "response" not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = "" if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, six.string_types): (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ",".join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, mimetype=media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError("media_filename must be str or MediaUpload.") # Check the maxSize if media_upload.size() is not None and media_upload.size() > maxSize > 0: raise MediaUploadSizeError("Media larger than: {0!s}".format(maxSize)) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): url = _add_query_parameter(url, "uploadType", "resumable") if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers["content-type"] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) url = _add_query_parameter(url, "uploadType", "media") else: # This is a multipart/related upload. msgRoot = MIMEMultipart("related") # msgRoot should not write out it's own headers setattr(msgRoot, "_write_headers", lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers["content-type"].split("/")) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split("/")) msg["Content-Transfer-Encoding"] = "binary" payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) # encode the body: note that we can't use `as_string`, because # it plays games with `From ` lines. fp = BytesIO() g = _BytesGenerator(fp, mangle_from_=False) g.flatten(msgRoot, unixfrom=False) body = fp.getvalue() multipart_boundary = msgRoot.get_boundary() headers["content-type"] = ("multipart/related; " 'boundary="%s"') % multipart_boundary url = _add_query_parameter(url, "uploadType", "multipart") logger.info("URL being requested: {0!s} {1!s}".format(httpMethod, url)) return self._requestBuilder( self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable, )
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. http: httplib2.Http, An instance of httplib2.Http or something that acts like it that HTTP requests will be made through. 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: googleapiclient.Model, converts to and from the wire format. requestBuilder: googleapiclient.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']) logger.info('URL being requested: GET %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, uri=requested_url) try: service = simplejson.loads(content) except ValueError, e: logger.error('Failed to parse as JSON: ' + content) raise InvalidJsonError()
def method(self, **kwargs): # Don't bother with doc string, it will be over-written by createMethod. for name in kwargs.iterkeys(): if name not in parameters.argmap: raise TypeError('Got an unexpected keyword argument "%s"' % name) # Remove args that have a value of None. keys = kwargs.keys() for name in keys: if kwargs[name] is None: del kwargs[name] for name in parameters.required_params: if name not in kwargs: raise TypeError('Missing required parameter "%s"' % name) for name, regex in parameters.pattern_params.iteritems(): if name in kwargs: if isinstance(kwargs[name], basestring): pvalues = [kwargs[name]] else: pvalues = kwargs[name] for pvalue in pvalues: if re.match(regex, pvalue) is None: raise TypeError( 'Parameter "%s" value "%s" does not match the pattern "%s"' % (name, pvalue, regex)) for name, enums in parameters.enum_params.iteritems(): if name in kwargs: # We need to handle the case of a repeated enum # name differently, since we want to handle both # arg='value' and arg=['value1', 'value2'] if (name in parameters.repeated_params and not isinstance(kwargs[name], basestring)): values = kwargs[name] else: values = [kwargs[name]] for value in values: if value not in enums: raise TypeError( 'Parameter "%s" value "%s" is not an allowed value in "%s"' % (name, value, str(enums))) actual_query_params = {} actual_path_params = {} for key, value in kwargs.iteritems(): to_type = parameters.param_types.get(key, 'string') # For repeated parameters we cast each member of the list. if key in parameters.repeated_params and type(value) == type([]): cast_value = [_cast(x, to_type) for x in value] else: cast_value = _cast(value, to_type) if key in parameters.query_params: actual_query_params[parameters.argmap[key]] = cast_value if key in parameters.path_params: actual_path_params[parameters.argmap[key]] = cast_value body_value = kwargs.get('body', None) media_filename = kwargs.get('media_body', None) if self._developerKey: actual_query_params['key'] = self._developerKey model = self._model if methodName.endswith('_media'): model = MediaModel() elif 'response' not in methodDesc: model = RawModel() headers = {} headers, params, query, body = model.request(headers, actual_path_params, actual_query_params, body_value) expanded_url = uritemplate.expand(pathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) resumable = None multipart_boundary = '' if media_filename: # Ensure we end up with a valid MediaUpload object. if isinstance(media_filename, basestring): (media_mime_type, encoding) = mimetypes.guess_type(media_filename) if media_mime_type is None: raise UnknownFileType(media_filename) if not mimeparse.best_match([media_mime_type], ','.join(accept)): raise UnacceptableMimeTypeError(media_mime_type) media_upload = MediaFileUpload(media_filename, mimetype=media_mime_type) elif isinstance(media_filename, MediaUpload): media_upload = media_filename else: raise TypeError('media_filename must be str or MediaUpload.') # Check the maxSize if maxSize > 0 and media_upload.size() > maxSize: raise MediaUploadSizeError("Media larger than: %s" % maxSize) # Use the media path uri for media uploads expanded_url = uritemplate.expand(mediaPathUrl, params) url = _urljoin(self._baseUrl, expanded_url + query) if media_upload.resumable(): url = _add_query_parameter(url, 'uploadType', 'resumable') if media_upload.resumable(): # This is all we need to do for resumable, if the body exists it gets # sent in the first request, otherwise an empty body is sent. resumable = media_upload else: # A non-resumable upload if body is None: # This is a simple media upload headers['content-type'] = media_upload.mimetype() body = media_upload.getbytes(0, media_upload.size()) url = _add_query_parameter(url, 'uploadType', 'media') else: # This is a multipart/related upload. msgRoot = MIMEMultipart('related') # msgRoot should not write out it's own headers setattr(msgRoot, '_write_headers', lambda self: None) # attach the body as one part msg = MIMENonMultipart(*headers['content-type'].split('/')) msg.set_payload(body) msgRoot.attach(msg) # attach the media as the second part msg = MIMENonMultipart(*media_upload.mimetype().split('/')) msg['Content-Transfer-Encoding'] = 'binary' payload = media_upload.getbytes(0, media_upload.size()) msg.set_payload(payload) msgRoot.attach(msg) # encode the body: note that we can't use `as_string`, because # it plays games with `From ` lines. fp = StringIO.StringIO() g = Generator(fp, mangle_from_=False) g.flatten(msgRoot, unixfrom=False) body = fp.getvalue() multipart_boundary = msgRoot.get_boundary() headers['content-type'] = ( 'multipart/related; ' 'boundary="%s"') % multipart_boundary url = _add_query_parameter(url, 'uploadType', 'multipart') logger.info('URL being requested: %s %s' % (httpMethod, url)) return self._requestBuilder(self._http, model.response, url, method=httpMethod, body=body, headers=headers, methodId=methodId, resumable=resumable)