Add google appengine to repo
[frozenviper.git] / google_appengine / google / appengine / dist / httplib.py
blobc1bee3a03d7c7c992920097fb07c6fcde887a9ca
1 #!/usr/bin/env python
3 # Copyright 2007 Google Inc.
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 """Copyright 2008 Python Software Foundation, Ian Bicking, and Google."""
19 import mimetools
20 import StringIO
21 import sys
24 CONTINUE = 100
25 SWITCHING_PROTOCOLS = 101
26 PROCESSING = 102
27 OK = 200
28 CREATED = 201
29 ACCEPTED = 202
30 NON_AUTHORITATIVE_INFORMATION = 203
31 NO_CONTENT = 204
32 RESET_CONTENT = 205
33 PARTIAL_CONTENT = 206
34 MULTI_STATUS = 207
35 IM_USED = 226
36 MULTIPLE_CHOICES = 300
37 MOVED_PERMANENTLY = 301
38 FOUND = 302
39 SEE_OTHER = 303
40 NOT_MODIFIED = 304
41 USE_PROXY = 305
42 TEMPORARY_REDIRECT = 307
43 BAD_REQUEST = 400
44 UNAUTHORIZED = 401
45 PAYMENT_REQUIRED = 402
46 FORBIDDEN = 403
47 NOT_FOUND = 404
48 METHOD_NOT_ALLOWED = 405
49 NOT_ACCEPTABLE = 406
50 PROXY_AUTHENTICATION_REQUIRED = 407
51 REQUEST_TIMEOUT = 408
52 CONFLICT = 409
53 GONE = 410
54 LENGTH_REQUIRED = 411
55 PRECONDITION_FAILED = 412
56 REQUEST_ENTITY_TOO_LARGE = 413
57 REQUEST_URI_TOO_LONG = 414
58 UNSUPPORTED_MEDIA_TYPE = 415
59 REQUESTED_RANGE_NOT_SATISFIABLE = 416
60 EXPECTATION_FAILED = 417
61 UNPROCESSABLE_ENTITY = 422
62 LOCKED = 423
63 FAILED_DEPENDENCY = 424
64 UPGRADE_REQUIRED = 426
65 INTERNAL_SERVER_ERROR = 500
66 NOT_IMPLEMENTED = 501
67 BAD_GATEWAY = 502
68 SERVICE_UNAVAILABLE = 503
69 GATEWAY_TIMEOUT = 504
70 HTTP_VERSION_NOT_SUPPORTED = 505
71 INSUFFICIENT_STORAGE = 507
72 NOT_EXTENDED = 510
74 responses = {
75 100: 'Continue',
76 101: 'Switching Protocols',
78 200: 'OK',
79 201: 'Created',
80 202: 'Accepted',
81 203: 'Non-Authoritative Information',
82 204: 'No Content',
83 205: 'Reset Content',
84 206: 'Partial Content',
86 300: 'Multiple Choices',
87 301: 'Moved Permanently',
88 302: 'Found',
89 303: 'See Other',
90 304: 'Not Modified',
91 305: 'Use Proxy',
92 306: '(Unused)',
93 307: 'Temporary Redirect',
95 400: 'Bad Request',
96 401: 'Unauthorized',
97 402: 'Payment Required',
98 403: 'Forbidden',
99 404: 'Not Found',
100 405: 'Method Not Allowed',
101 406: 'Not Acceptable',
102 407: 'Proxy Authentication Required',
103 408: 'Request Timeout',
104 409: 'Conflict',
105 410: 'Gone',
106 411: 'Length Required',
107 412: 'Precondition Failed',
108 413: 'Request Entity Too Large',
109 414: 'Request-URI Too Long',
110 415: 'Unsupported Media Type',
111 416: 'Requested Range Not Satisfiable',
112 417: 'Expectation Failed',
114 500: 'Internal Server Error',
115 501: 'Not Implemented',
116 502: 'Bad Gateway',
117 503: 'Service Unavailable',
118 504: 'Gateway Timeout',
119 505: 'HTTP Version Not Supported',
122 HTTP_PORT = 80
123 HTTPS_PORT = 443
129 class HTTPConnection:
132 protocol = 'http'
133 default_port = HTTP_PORT
134 _allow_truncated = True
135 _follow_redirects = False
137 def __init__(self, host, port=None, strict=False, timeout=None):
138 from google.appengine.api import urlfetch
139 self._fetch = urlfetch.fetch
140 self._method_map = {
141 'GET': urlfetch.GET,
142 'POST': urlfetch.POST,
143 'HEAD': urlfetch.HEAD,
144 'PUT': urlfetch.PUT,
145 'DELETE': urlfetch.DELETE,
147 self.host = host
148 self.port = port
149 self._method = self._url = None
150 self._body = ''
151 self.headers = []
153 def connect(self):
154 pass
156 def request(self, method, url, body=None, headers=None):
157 self._method = method
158 self._url = url
159 try:
160 self._body = body.read()
161 except AttributeError:
162 self._body = body
163 if headers is None:
164 headers = []
165 elif hasattr(headers, 'items'):
166 headers = headers.items()
167 self.headers = headers
169 def putrequest(self, request, selector, skip_host=False, skip_accept_encoding=False):
170 self._method = request
171 self._url = selector
173 def putheader(self, header, *lines):
174 line = '\r\n\t'.join([str(line) for line in lines])
175 self.headers.append((header, line))
177 def endheaders(self):
178 pass
180 def set_debuglevel(self, level=None):
181 pass
183 def send(self, data):
184 self._body += data
186 def getresponse(self):
187 if self.port and self.port != self.default_port:
188 host = '%s:%s' % (self.host, self.port)
189 else:
190 host = self.host
191 if not self._url.startswith(self.protocol):
192 url = '%s://%s%s' % (self.protocol, host, self._url)
193 else:
194 url = self._url
195 headers = dict(self.headers)
197 try:
198 method = self._method_map[self._method.upper()]
199 except KeyError:
200 raise ValueError("%r is an unrecognized HTTP method" % self._method)
202 response = self._fetch(url, self._body, method, headers,
203 self._allow_truncated, self._follow_redirects)
204 return HTTPResponse(response)
206 def close(self):
207 pass
210 class HTTPSConnection(HTTPConnection):
212 protocol = 'https'
213 default_port = HTTPS_PORT
215 def __init__(self, host, port=None, key_file=None, cert_file=None,
216 strict=False, timeout=None):
217 if key_file is not None or cert_file is not None:
218 raise NotImplementedError(
219 "key_file and cert_file arguments are not implemented")
220 HTTPConnection.__init__(self, host, port=port, strict=strict,
221 timeout=timeout)
224 class HTTPResponse(object):
226 def __init__(self, fetch_response):
227 self._fetch_response = fetch_response
228 self.fp = StringIO.StringIO(fetch_response.content)
230 def __getattr__(self, attr):
231 return getattr(self.fp, attr)
233 def getheader(self, name, default=None):
234 return self._fetch_response.headers.get(name, default)
236 def getheaders(self):
237 return self._fetch_response.headers.items()
239 @property
240 def msg(self):
241 msg = mimetools.Message(StringIO.StringIO(''))
242 for name, value in self._fetch_response.headers.items():
243 msg[name] = str(value)
244 return msg
246 version = 11
248 @property
249 def status(self):
250 return self._fetch_response.status_code
252 @property
253 def reason(self):
254 return responses.get(self._fetch_response.status_code, 'Unknown')
257 class HTTP:
258 "Compatibility class with httplib.py from 1.5."
260 _http_vsn = 11
261 _http_vsn_str = 'HTTP/1.1'
263 debuglevel = 0
265 _connection_class = HTTPConnection
267 def __init__(self, host='', port=None, strict=None):
268 "Provide a default host, since the superclass requires one."
270 if port == 0:
271 port = None
273 self._setup(self._connection_class(host, port, strict))
275 def _setup(self, conn):
276 self._conn = conn
278 self.send = conn.send
279 self.putrequest = conn.putrequest
280 self.endheaders = conn.endheaders
281 self.set_debuglevel = conn.set_debuglevel
283 conn._http_vsn = self._http_vsn
284 conn._http_vsn_str = self._http_vsn_str
286 self.file = None
288 def connect(self, host=None, port=None):
289 "Accept arguments to set the host/port, since the superclass doesn't."
290 self.__init__(host, port)
292 def getfile(self):
293 "Provide a getfile, since the superclass' does not use this concept."
294 return self.file
296 def putheader(self, header, *values):
297 "The superclass allows only one value argument."
298 self._conn.putheader(header, '\r\n\t'.join([str(v) for v in values]))
300 def getreply(self):
301 """Compat definition since superclass does not define it.
303 Returns a tuple consisting of:
304 - server status code (e.g. '200' if all goes well)
305 - server "reason" corresponding to status code
306 - any RFC822 headers in the response from the server
308 response = self._conn.getresponse()
310 self.headers = response.msg
311 self.file = response.fp
312 return response.status, response.reason, response.msg
314 def close(self):
315 self._conn.close()
317 self.file = None
320 class HTTPS(HTTP):
321 """Compatibility with 1.5 httplib interface
323 Python 1.5.2 did not have an HTTPS class, but it defined an
324 interface for sending http requests that is also useful for
325 https.
328 _connection_class = HTTPSConnection
330 def __init__(self, host='', port=None, key_file=None, cert_file=None,
331 strict=None):
332 if key_file is not None or cert_file is not None:
333 raise NotImplementedError(
334 "key_file and cert_file arguments are not implemented")
337 if port == 0:
338 port = None
339 self._setup(self._connection_class(host, port, key_file,
340 cert_file, strict))
342 self.key_file = key_file
343 self.cert_file = cert_file
346 class HTTPException(Exception):
347 pass
349 class NotConnected(HTTPException):
350 pass
352 class InvalidURL(HTTPException):
353 pass
355 class UnknownProtocol(HTTPException):
356 def __init__(self, version):
357 self.version = version
358 HTTPException.__init__(self, version)
360 class UnknownTransferEncoding(HTTPException):
361 pass
363 class UnimplementedFileMode(HTTPException):
364 pass
366 class IncompleteRead(HTTPException):
367 def __init__(self, partial):
368 self.partial = partial
369 HTTPException.__init__(self, partial)
371 class ImproperConnectionState(HTTPException):
372 pass
374 class CannotSendRequest(ImproperConnectionState):
375 pass
377 class CannotSendHeader(ImproperConnectionState):
378 pass
380 class ResponseNotReady(ImproperConnectionState):
381 pass
383 class BadStatusLine(HTTPException):
384 def __init__(self, line):
385 self.line = line
386 HTTPException.__init__(self, line)
388 error = HTTPException