def request(self, operation, url, data=None, headers=None, url_params=None): if isinstance(url, (str, unicode)): if url.startswith('http:') and self.ssl: # Force all requests to be https if self.ssl is True. url = atom_url.parse_url('https:' + url[5:]) elif not url.startswith('http') and self.ssl: url = atom_url.parse_url('https://%s%s' % (self.server, url)) elif not url.startswith('http'): url = atom_url.parse_url('http://%s%s' % (self.server, url)) else: url = atom_url.parse_url(url) if url_params: for name, value in url_params.iteritems(): url.params[name] = value all_headers = self.additional_headers.copy() if headers: all_headers.update(headers) # If the list of headers does not include a Content-Length, attempt to # calculate it based on the data object. if data and 'Content-Length' not in all_headers: content_length = CalculateDataLength(data) if content_length: all_headers['Content-Length'] = str(content_length) # Find an Authorization token for this URL if one is available. if self.override_token: auth_token = self.override_token else: auth_token = self.token_store.find_token(url) return auth_token.perform_request(self.http_client, operation, url, data=data, headers=all_headers)
def find_token(self, url): """Selects an Authorization header token which can be used for the URL. Args: url: str or atom_url.Url or a list containing the same. The URL which is going to be requested. All tokens are examined to see if any scopes begin match the beginning of the URL. The first match found is returned. Returns: The token object which should execute the HTTP request. If there was no token for the url (the url did not begin with any of the token scopes available), then the atom_http_interface.GenericToken will be returned because the GenericToken calls through to the http client without adding an Authorization header. """ if url is None: return None if isinstance(url, (str, unicode)): url = atom_url.parse_url(url) if url in self._tokens: token = self._tokens[url] if token.valid_for_scope(url): return token else: del self._tokens[url] for scope, token in self._tokens.iteritems(): if token.valid_for_scope(url): return token return atom_http_interface.GenericToken()
def ProcessUrl(service, url, for_proxy=False): """Processes a passed URL. If the URL does not begin with https?, then the default value for server is used This method is deprecated, use atom_url.parse_url instead. """ if not isinstance(url, atom_url.Url): url = atom_url.parse_url(url) server = url.host ssl = False port = 80 if not server: if hasattr(service, 'server'): server = service.server else: server = service if not url.protocol and hasattr(service, 'ssl'): ssl = service.ssl if hasattr(service, 'port'): port = service.port else: if url.protocol == 'https': ssl = True elif url.protocol == 'http': ssl = False if url.port: port = int(url.port) elif port == 80 and ssl: port = 443 return (server, port, ssl, url.get_request_uri())
def valid_for_scope(self, url): """Tells the caller if the token authorizes access to the desired URL. """ if isinstance(url, (str, unicode)): url = atom_url.parse_url(url) for scope in self.scopes: if scope == atom_token_store.SCOPE_ALL: return True if isinstance(scope, (str, unicode)): scope = atom_url.parse_url(scope) if scope == url: return True # Check the host and the path, but ignore the port and protocol. elif scope.host == url.host and not scope.path: return True elif scope.host == url.host and scope.path and not url.path: continue elif scope.host == url.host and url.path.startswith(scope.path): return True return False
def _prepare_connection(self, url, headers): if not isinstance(url, atom_url.Url): if isinstance(url, types.StringTypes): url = atom_url.parse_url(url) else: raise atom_http_interface.UnparsableUrlObject('Unable to parse url ' 'parameter because it was not a string or atom_url.Url') if url.protocol == 'https': if not url.port: return httplib.HTTPSConnection(url.host) return httplib.HTTPSConnection(url.host, int(url.port)) else: if not url.port: return httplib.HTTPConnection(url.host) return httplib.HTTPConnection(url.host, int(url.port))
def _prepare_connection(self, url, headers): if not isinstance(url, atom_url.Url): if isinstance(url, types.StringTypes): url = atom_url.parse_url(url) else: raise atom_http_interface.UnparsableUrlObject( 'Unable to parse url ' 'parameter because it was not a string or atom_url.Url') if url.protocol == 'https': if not url.port: return httplib.HTTPSConnection(url.host) return httplib.HTTPSConnection(url.host, int(url.port)) else: if not url.port: return httplib.HTTPConnection(url.host) return httplib.HTTPConnection(url.host, int(url.port))
def request(self, operation, url, data=None, headers=None): """Performs an HTTP call to the server, supports GET, POST, PUT, and DELETE. Usage example, perform and HTTP GET on http://www.google.com/: import atom.http client = atom.http.HttpClient() http_response = client.request('GET', 'http://www.google.com/') Args: operation: str The HTTP operation to be performed. This is usually one of 'GET', 'POST', 'PUT', or 'DELETE' data: filestream, list of parts, or other object which can be converted to a string. Should be set to None when performing a GET or DELETE. If data is a file-like object which can be read, this method will read a chunk of 100K bytes at a time and send them. If the data is a list of parts to be sent, each part will be evaluated and sent. url: The full URL to which the request should be sent. Can be a string or atom_url.Url. headers: dict of strings. HTTP headers which should be sent in the request. """ all_headers = self.headers.copy() if headers: all_headers.update(headers) # If the list of headers does not include a Content-Length, attempt to # calculate it based on the data object. if data and 'Content-Length' not in all_headers: if isinstance(data, types.StringTypes): all_headers['Content-Length'] = str(len(data)) else: raise atom_http_interface.ContentLengthRequired('Unable to calculate ' 'the length of the data parameter. Specify a value for ' 'Content-Length') # Set the content type to the default value if none was set. if 'Content-Type' not in all_headers: all_headers['Content-Type'] = DEFAULT_CONTENT_TYPE if self.v2_http_client is not None: http_request = atom_http_core.HttpRequest(method=operation) atom_http_core.Uri.parse_uri(str(url)).modify_request(http_request) http_request.headers = all_headers if data: http_request._body_parts.append(data) return self.v2_http_client.request(http_request=http_request) if not isinstance(url, atom_url.Url): if isinstance(url, types.StringTypes): url = atom_url.parse_url(url) else: raise atom_http_interface.UnparsableUrlObject('Unable to parse url ' 'parameter because it was not a string or atom_url.Url') connection = self._prepare_connection(url, all_headers) if self.debug: connection.debuglevel = 1 connection.putrequest(operation, self._get_access_url(url), skip_host=True) if url.port is not None: connection.putheader('Host', '%s:%s' % (url.host, url.port)) else: connection.putheader('Host', url.host) # Overcome a bug in Python 2.4 and 2.5 # httplib.HTTPConnection.putrequest adding # HTTP request header 'Host: www.google.com:443' instead of # 'Host: www.google.com', and thus resulting the error message # 'Token invalid - AuthSub token has wrong scope' in the HTTP response. if (url.protocol == 'https' and int(url.port or 443) == 443 and hasattr(connection, '_buffer') and isinstance(connection._buffer, list)): header_line = 'Host: %s:443' % url.host replacement_header_line = 'Host: %s' % url.host try: connection._buffer[connection._buffer.index(header_line)] = ( replacement_header_line) except ValueError: # header_line missing from connection._buffer pass # Send the HTTP headers. for header_name in all_headers: connection.putheader(header_name, all_headers[header_name]) connection.endheaders() # If there is data, send it in the request. if data: if isinstance(data, list): for data_part in data: _send_data_part(data_part, connection) else: _send_data_part(data, connection) # Return the HTTP Response from the server. return connection.getresponse()
def request(self, operation, url, data=None, headers=None): """Performs an HTTP call to the server, supports GET, POST, PUT, and DELETE. Usage example, perform and HTTP GET on http://www.google.com/: import atom.http client = atom.http.HttpClient() http_response = client.request('GET', 'http://www.google.com/') Args: operation: str The HTTP operation to be performed. This is usually one of 'GET', 'POST', 'PUT', or 'DELETE' data: filestream, list of parts, or other object which can be converted to a string. Should be set to None when performing a GET or DELETE. If data is a file-like object which can be read, this method will read a chunk of 100K bytes at a time and send them. If the data is a list of parts to be sent, each part will be evaluated and sent. url: The full URL to which the request should be sent. Can be a string or atom_url.Url. headers: dict of strings. HTTP headers which should be sent in the request. """ all_headers = self.headers.copy() if headers: all_headers.update(headers) # If the list of headers does not include a Content-Length, attempt to # calculate it based on the data object. if data and 'Content-Length' not in all_headers: if isinstance(data, types.StringTypes): all_headers['Content-Length'] = str(len(data)) else: raise atom_http_interface.ContentLengthRequired( 'Unable to calculate ' 'the length of the data parameter. Specify a value for ' 'Content-Length') # Set the content type to the default value if none was set. if 'Content-Type' not in all_headers: all_headers['Content-Type'] = DEFAULT_CONTENT_TYPE if self.v2_http_client is not None: http_request = atom_http_core.HttpRequest(method=operation) atom_http_core.Uri.parse_uri(str(url)).modify_request(http_request) http_request.headers = all_headers if data: http_request._body_parts.append(data) return self.v2_http_client.request(http_request=http_request) if not isinstance(url, atom_url.Url): if isinstance(url, types.StringTypes): url = atom_url.parse_url(url) else: raise atom_http_interface.UnparsableUrlObject( 'Unable to parse url ' 'parameter because it was not a string or atom_url.Url') connection = self._prepare_connection(url, all_headers) if self.debug: connection.debuglevel = 1 connection.putrequest(operation, self._get_access_url(url), skip_host=True) if url.port is not None: connection.putheader('Host', '%s:%s' % (url.host, url.port)) else: connection.putheader('Host', url.host) # Overcome a bug in Python 2.4 and 2.5 # httplib.HTTPConnection.putrequest adding # HTTP request header 'Host: www.google.com:443' instead of # 'Host: www.google.com', and thus resulting the error message # 'Token invalid - AuthSub token has wrong scope' in the HTTP response. if (url.protocol == 'https' and int(url.port or 443) == 443 and hasattr(connection, '_buffer') and isinstance(connection._buffer, list)): header_line = 'Host: %s:443' % url.host replacement_header_line = 'Host: %s' % url.host try: connection._buffer[connection._buffer.index(header_line)] = ( replacement_header_line) except ValueError: # header_line missing from connection._buffer pass # Send the HTTP headers. for header_name in all_headers: connection.putheader(header_name, all_headers[header_name]) connection.endheaders() # If there is data, send it in the request. if data: if isinstance(data, list): for data_part in data: _send_data_part(data_part, connection) else: _send_data_part(data, connection) # Return the HTTP Response from the server. return connection.getresponse()