PageRenderTime 26ms CodeModel.GetById 12ms app.highlight 10ms RepoModel.GetById 1ms app.codeStats 0ms

/atom/http_interface.py

http://radioappz.googlecode.com/
Python | 158 lines | 131 code | 3 blank | 24 comment | 8 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
 17"""This module provides a common interface for all HTTP requests.
 18
 19  HttpResponse: Represents the server's response to an HTTP request. Provides
 20      an interface identical to httplib.HTTPResponse which is the response
 21      expected from higher level classes which use HttpClient.request.
 22
 23  GenericHttpClient: Provides an interface (superclass) for an object 
 24      responsible for making HTTP requests. Subclasses of this object are
 25      used in AtomService and GDataService to make requests to the server. By
 26      changing the http_client member object, the AtomService is able to make
 27      HTTP requests using different logic (for example, when running on 
 28      Google App Engine, the http_client makes requests using the App Engine
 29      urlfetch API). 
 30"""
 31
 32
 33__author__ = 'api.jscudder (Jeff Scudder)'
 34
 35
 36import StringIO
 37
 38
 39USER_AGENT = '%s GData-Python/2.0.9'
 40
 41
 42class Error(Exception):
 43  pass
 44
 45
 46class UnparsableUrlObject(Error):
 47  pass
 48
 49
 50class ContentLengthRequired(Error):
 51  pass
 52  
 53
 54class HttpResponse(object):
 55  def __init__(self, body=None, status=None, reason=None, headers=None):
 56    """Constructor for an HttpResponse object. 
 57
 58    HttpResponse represents the server's response to an HTTP request from
 59    the client. The HttpClient.request method returns a httplib.HTTPResponse
 60    object and this HttpResponse class is designed to mirror the interface
 61    exposed by httplib.HTTPResponse.
 62
 63    Args:
 64      body: A file like object, with a read() method. The body could also
 65          be a string, and the constructor will wrap it so that 
 66          HttpResponse.read(self) will return the full string.
 67      status: The HTTP status code as an int. Example: 200, 201, 404.
 68      reason: The HTTP status message which follows the code. Example: 
 69          OK, Created, Not Found
 70      headers: A dictionary containing the HTTP headers in the server's 
 71          response. A common header in the response is Content-Length.
 72    """
 73    if body:
 74      if hasattr(body, 'read'):
 75        self._body = body
 76      else:
 77        self._body = StringIO.StringIO(body)
 78    else:
 79      self._body = None
 80    if status is not None:
 81      self.status = int(status)
 82    else:
 83      self.status = None
 84    self.reason = reason
 85    self._headers = headers or {}
 86
 87  def getheader(self, name, default=None):
 88    if name in self._headers:
 89      return self._headers[name]
 90    else:
 91      return default
 92    
 93  def read(self, amt=None):
 94    if not amt:
 95      return self._body.read()
 96    else:
 97      return self._body.read(amt)
 98
 99
100class GenericHttpClient(object):
101  debug = False
102
103  def __init__(self, http_client, headers=None):
104    """
105    
106    Args:
107      http_client: An object which provides a request method to make an HTTP 
108          request. The request method in GenericHttpClient performs a 
109          call-through to the contained HTTP client object.
110      headers: A dictionary containing HTTP headers which should be included
111          in every HTTP request. Common persistent headers include 
112          'User-Agent'.
113    """
114    self.http_client = http_client
115    self.headers = headers or {}
116
117  def request(self, operation, url, data=None, headers=None):
118    all_headers = self.headers.copy()
119    if headers:
120      all_headers.update(headers)
121    return self.http_client.request(operation, url, data=data, 
122        headers=all_headers)
123
124  def get(self, url, headers=None):
125    return self.request('GET', url, headers=headers)
126
127  def post(self, url, data, headers=None):
128    return self.request('POST', url, data=data, headers=headers)
129
130  def put(self, url, data, headers=None):
131    return self.request('PUT', url, data=data, headers=headers)
132
133  def delete(self, url, headers=None):
134    return self.request('DELETE', url, headers=headers)
135
136
137class GenericToken(object):
138  """Represents an Authorization token to be added to HTTP requests.
139  
140  Some Authorization headers included calculated fields (digital
141  signatures for example) which are based on the parameters of the HTTP
142  request. Therefore the token is responsible for signing the request
143  and adding the Authorization header. 
144  """
145  def perform_request(self, http_client, operation, url, data=None, 
146                      headers=None):
147    """For the GenericToken, no Authorization token is set."""
148    return http_client.request(operation, url, data=data, headers=headers)
149
150  def valid_for_scope(self, url):
151    """Tells the caller if the token authorizes access to the desired URL.
152    
153    Since the generic token doesn't add an auth header, it is not valid for
154    any scope.
155    """
156    return False
157
158