| Mark Slee | 89e2bb8 | 2007-03-01 00:20:36 +0000 | [diff] [blame] | 1 | # | 
| David Reiss | ea2cba8 | 2009-03-30 21:35:00 +0000 | [diff] [blame] | 2 | # Licensed to the Apache Software Foundation (ASF) under one | 
 | 3 | # or more contributor license agreements. See the NOTICE file | 
 | 4 | # distributed with this work for additional information | 
 | 5 | # regarding copyright ownership. The ASF licenses this file | 
 | 6 | # to you under the Apache License, Version 2.0 (the | 
 | 7 | # "License"); you may not use this file except in compliance | 
 | 8 | # with the License. You may obtain a copy of the License at | 
 | 9 | # | 
 | 10 | #   http://www.apache.org/licenses/LICENSE-2.0 | 
 | 11 | # | 
 | 12 | # Unless required by applicable law or agreed to in writing, | 
 | 13 | # software distributed under the License is distributed on an | 
 | 14 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | 
 | 15 | # KIND, either express or implied. See the License for the | 
 | 16 | # specific language governing permissions and limitations | 
 | 17 | # under the License. | 
 | 18 | # | 
| Mark Slee | 89e2bb8 | 2007-03-01 00:20:36 +0000 | [diff] [blame] | 19 |  | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 20 | import httplib | 
| Roger Meier | 3f5a264 | 2012-04-13 14:20:08 +0000 | [diff] [blame] | 21 | import os | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 22 | import socket | 
| Roger Meier | 3f5a264 | 2012-04-13 14:20:08 +0000 | [diff] [blame] | 23 | import sys | 
 | 24 | import urllib | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 25 | import urlparse | 
 | 26 | import warnings | 
 | 27 |  | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 28 | from cStringIO import StringIO | 
 | 29 |  | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 30 | from TTransport import * | 
 | 31 |  | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 32 |  | 
 | 33 | class THttpClient(TTransportBase): | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 34 |   """Http implementation of TTransport base.""" | 
 | 35 |  | 
| David Reiss | 2aa2890 | 2009-03-26 06:22:18 +0000 | [diff] [blame] | 36 |   def __init__(self, uri_or_host, port=None, path=None): | 
 | 37 |     """THttpClient supports two different types constructor parameters. | 
 | 38 |  | 
 | 39 |     THttpClient(host, port, path) - deprecated | 
 | 40 |     THttpClient(uri) | 
 | 41 |  | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 42 |     Only the second supports https. | 
 | 43 |     """ | 
| David Reiss | 2aa2890 | 2009-03-26 06:22:18 +0000 | [diff] [blame] | 44 |     if port is not None: | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 45 |       warnings.warn( | 
 | 46 |         "Please use the THttpClient('http://host:port/path') syntax", | 
 | 47 |         DeprecationWarning, | 
 | 48 |         stacklevel=2) | 
| David Reiss | 2aa2890 | 2009-03-26 06:22:18 +0000 | [diff] [blame] | 49 |       self.host = uri_or_host | 
 | 50 |       self.port = port | 
 | 51 |       assert path | 
 | 52 |       self.path = path | 
 | 53 |       self.scheme = 'http' | 
 | 54 |     else: | 
 | 55 |       parsed = urlparse.urlparse(uri_or_host) | 
 | 56 |       self.scheme = parsed.scheme | 
 | 57 |       assert self.scheme in ('http', 'https') | 
 | 58 |       if self.scheme == 'http': | 
 | 59 |         self.port = parsed.port or httplib.HTTP_PORT | 
 | 60 |       elif self.scheme == 'https': | 
 | 61 |         self.port = parsed.port or httplib.HTTPS_PORT | 
 | 62 |       self.host = parsed.hostname | 
 | 63 |       self.path = parsed.path | 
| Bryan Duxbury | 727d67d | 2010-09-02 01:00:19 +0000 | [diff] [blame] | 64 |       if parsed.query: | 
 | 65 |         self.path += '?%s' % parsed.query | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 66 |     self.__wbuf = StringIO() | 
 | 67 |     self.__http = None | 
| David Reiss | ff3d249 | 2010-03-09 05:19:16 +0000 | [diff] [blame] | 68 |     self.__timeout = None | 
| Roger Meier | fa392e9 | 2012-04-11 22:15:15 +0000 | [diff] [blame] | 69 |     self.__custom_headers = None | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 70 |  | 
 | 71 |   def open(self): | 
| David Reiss | 2aa2890 | 2009-03-26 06:22:18 +0000 | [diff] [blame] | 72 |     if self.scheme == 'http': | 
 | 73 |       self.__http = httplib.HTTP(self.host, self.port) | 
 | 74 |     else: | 
 | 75 |       self.__http = httplib.HTTPS(self.host, self.port) | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 76 |  | 
 | 77 |   def close(self): | 
 | 78 |     self.__http.close() | 
 | 79 |     self.__http = None | 
| David Reiss | 0c90f6f | 2008-02-06 22:18:40 +0000 | [diff] [blame] | 80 |  | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 81 |   def isOpen(self): | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 82 |     return self.__http is not None | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 83 |  | 
| David Reiss | ff3d249 | 2010-03-09 05:19:16 +0000 | [diff] [blame] | 84 |   def setTimeout(self, ms): | 
 | 85 |     if not hasattr(socket, 'getdefaulttimeout'): | 
 | 86 |       raise NotImplementedError | 
 | 87 |  | 
 | 88 |     if ms is None: | 
 | 89 |       self.__timeout = None | 
 | 90 |     else: | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 91 |       self.__timeout = ms / 1000.0 | 
| David Reiss | ff3d249 | 2010-03-09 05:19:16 +0000 | [diff] [blame] | 92 |  | 
| Roger Meier | fa392e9 | 2012-04-11 22:15:15 +0000 | [diff] [blame] | 93 |   def setCustomHeaders(self, headers): | 
 | 94 |     self.__custom_headers = headers | 
 | 95 |  | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 96 |   def read(self, sz): | 
 | 97 |     return self.__http.file.read(sz) | 
 | 98 |  | 
 | 99 |   def write(self, buf): | 
 | 100 |     self.__wbuf.write(buf) | 
 | 101 |  | 
| David Reiss | ff3d249 | 2010-03-09 05:19:16 +0000 | [diff] [blame] | 102 |   def __withTimeout(f): | 
 | 103 |     def _f(*args, **kwargs): | 
 | 104 |       orig_timeout = socket.getdefaulttimeout() | 
 | 105 |       socket.setdefaulttimeout(args[0].__timeout) | 
 | 106 |       result = f(*args, **kwargs) | 
 | 107 |       socket.setdefaulttimeout(orig_timeout) | 
 | 108 |       return result | 
 | 109 |     return _f | 
 | 110 |  | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 111 |   def flush(self): | 
| David Reiss | 7c1f6f8 | 2009-03-24 20:10:24 +0000 | [diff] [blame] | 112 |     if self.isOpen(): | 
 | 113 |       self.close() | 
| Bryan Duxbury | 6972041 | 2012-01-03 17:32:30 +0000 | [diff] [blame] | 114 |     self.open() | 
| David Reiss | 7c1f6f8 | 2009-03-24 20:10:24 +0000 | [diff] [blame] | 115 |  | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 116 |     # Pull data out of buffer | 
 | 117 |     data = self.__wbuf.getvalue() | 
 | 118 |     self.__wbuf = StringIO() | 
 | 119 |  | 
 | 120 |     # HTTP request | 
| David Reiss | 2aa2890 | 2009-03-26 06:22:18 +0000 | [diff] [blame] | 121 |     self.__http.putrequest('POST', self.path) | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 122 |  | 
 | 123 |     # Write headers | 
 | 124 |     self.__http.putheader('Host', self.host) | 
 | 125 |     self.__http.putheader('Content-Type', 'application/x-thrift') | 
 | 126 |     self.__http.putheader('Content-Length', str(len(data))) | 
| Roger Meier | fa392e9 | 2012-04-11 22:15:15 +0000 | [diff] [blame] | 127 |  | 
| Roger Meier | 3f5a264 | 2012-04-13 14:20:08 +0000 | [diff] [blame] | 128 |     if not self.__custom_headers or 'User-Agent' not in self.__custom_headers: | 
 | 129 |       user_agent = 'Python/THttpClient' | 
 | 130 |       script = os.path.basename(sys.argv[0]) | 
 | 131 |       if script: | 
 | 132 |         user_agent = '%s (%s)' % (user_agent, urllib.quote(script)) | 
 | 133 |       self.__http.putheader('User-Agent', user_agent) | 
 | 134 |  | 
| Roger Meier | fa392e9 | 2012-04-11 22:15:15 +0000 | [diff] [blame] | 135 |     if self.__custom_headers: | 
 | 136 |         for key, val in self.__custom_headers.iteritems(): | 
 | 137 |             self.__http.putheader(key, val) | 
 | 138 |  | 
| Mark Slee | bd8b991 | 2007-02-27 20:17:00 +0000 | [diff] [blame] | 139 |     self.__http.endheaders() | 
 | 140 |  | 
 | 141 |     # Write payload | 
 | 142 |     self.__http.send(data) | 
 | 143 |  | 
 | 144 |     # Get reply to flush the request | 
 | 145 |     self.code, self.message, self.headers = self.__http.getreply() | 
| David Reiss | ff3d249 | 2010-03-09 05:19:16 +0000 | [diff] [blame] | 146 |  | 
 | 147 |   # Decorate if we know how to timeout | 
 | 148 |   if hasattr(socket, 'getdefaulttimeout'): | 
 | 149 |     flush = __withTimeout(flush) |