/atom/http_interface.py

http://radioappz.googlecode.com/ · Python · 158 lines · 131 code · 3 blank · 24 comment · 6 complexity · d79e80c6e3f879599607f95e5bc22b22 MD5 · raw file

  1. #!/usr/bin/python
  2. #
  3. # Copyright (C) 2008 Google Inc.
  4. #
  5. # Licensed under the Apache License, Version 2.0 (the "License");
  6. # you may not use this file except in compliance with the License.
  7. # You may obtain a copy of the License at
  8. #
  9. # http://www.apache.org/licenses/LICENSE-2.0
  10. #
  11. # Unless required by applicable law or agreed to in writing, software
  12. # distributed under the License is distributed on an "AS IS" BASIS,
  13. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. """This module provides a common interface for all HTTP requests.
  17. HttpResponse: Represents the server's response to an HTTP request. Provides
  18. an interface identical to httplib.HTTPResponse which is the response
  19. expected from higher level classes which use HttpClient.request.
  20. GenericHttpClient: Provides an interface (superclass) for an object
  21. responsible for making HTTP requests. Subclasses of this object are
  22. used in AtomService and GDataService to make requests to the server. By
  23. changing the http_client member object, the AtomService is able to make
  24. HTTP requests using different logic (for example, when running on
  25. Google App Engine, the http_client makes requests using the App Engine
  26. urlfetch API).
  27. """
  28. __author__ = 'api.jscudder (Jeff Scudder)'
  29. import StringIO
  30. USER_AGENT = '%s GData-Python/2.0.9'
  31. class Error(Exception):
  32. pass
  33. class UnparsableUrlObject(Error):
  34. pass
  35. class ContentLengthRequired(Error):
  36. pass
  37. class HttpResponse(object):
  38. def __init__(self, body=None, status=None, reason=None, headers=None):
  39. """Constructor for an HttpResponse object.
  40. HttpResponse represents the server's response to an HTTP request from
  41. the client. The HttpClient.request method returns a httplib.HTTPResponse
  42. object and this HttpResponse class is designed to mirror the interface
  43. exposed by httplib.HTTPResponse.
  44. Args:
  45. body: A file like object, with a read() method. The body could also
  46. be a string, and the constructor will wrap it so that
  47. HttpResponse.read(self) will return the full string.
  48. status: The HTTP status code as an int. Example: 200, 201, 404.
  49. reason: The HTTP status message which follows the code. Example:
  50. OK, Created, Not Found
  51. headers: A dictionary containing the HTTP headers in the server's
  52. response. A common header in the response is Content-Length.
  53. """
  54. if body:
  55. if hasattr(body, 'read'):
  56. self._body = body
  57. else:
  58. self._body = StringIO.StringIO(body)
  59. else:
  60. self._body = None
  61. if status is not None:
  62. self.status = int(status)
  63. else:
  64. self.status = None
  65. self.reason = reason
  66. self._headers = headers or {}
  67. def getheader(self, name, default=None):
  68. if name in self._headers:
  69. return self._headers[name]
  70. else:
  71. return default
  72. def read(self, amt=None):
  73. if not amt:
  74. return self._body.read()
  75. else:
  76. return self._body.read(amt)
  77. class GenericHttpClient(object):
  78. debug = False
  79. def __init__(self, http_client, headers=None):
  80. """
  81. Args:
  82. http_client: An object which provides a request method to make an HTTP
  83. request. The request method in GenericHttpClient performs a
  84. call-through to the contained HTTP client object.
  85. headers: A dictionary containing HTTP headers which should be included
  86. in every HTTP request. Common persistent headers include
  87. 'User-Agent'.
  88. """
  89. self.http_client = http_client
  90. self.headers = headers or {}
  91. def request(self, operation, url, data=None, headers=None):
  92. all_headers = self.headers.copy()
  93. if headers:
  94. all_headers.update(headers)
  95. return self.http_client.request(operation, url, data=data,
  96. headers=all_headers)
  97. def get(self, url, headers=None):
  98. return self.request('GET', url, headers=headers)
  99. def post(self, url, data, headers=None):
  100. return self.request('POST', url, data=data, headers=headers)
  101. def put(self, url, data, headers=None):
  102. return self.request('PUT', url, data=data, headers=headers)
  103. def delete(self, url, headers=None):
  104. return self.request('DELETE', url, headers=headers)
  105. class GenericToken(object):
  106. """Represents an Authorization token to be added to HTTP requests.
  107. Some Authorization headers included calculated fields (digital
  108. signatures for example) which are based on the parameters of the HTTP
  109. request. Therefore the token is responsible for signing the request
  110. and adding the Authorization header.
  111. """
  112. def perform_request(self, http_client, operation, url, data=None,
  113. headers=None):
  114. """For the GenericToken, no Authorization token is set."""
  115. return http_client.request(operation, url, data=data, headers=headers)
  116. def valid_for_scope(self, url):
  117. """Tells the caller if the token authorizes access to the desired URL.
  118. Since the generic token doesn't add an auth header, it is not valid for
  119. any scope.
  120. """
  121. return False