blob: ea80a1ae875865a297a7b14dad15757e3933284f [file] [log] [blame]
Mark Slee89e2bb82007-03-01 00:20:36 +00001#
David Reissea2cba82009-03-30 21:35:00 +00002# 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 Slee89e2bb82007-03-01 00:20:36 +000019
Bryan Duxbury69720412012-01-03 17:32:30 +000020import httplib
Roger Meier3f5a2642012-04-13 14:20:08 +000021import os
Bryan Duxbury69720412012-01-03 17:32:30 +000022import socket
Roger Meier3f5a2642012-04-13 14:20:08 +000023import sys
24import urllib
Bryan Duxbury69720412012-01-03 17:32:30 +000025import urlparse
26import warnings
27
Mark Sleebd8b9912007-02-27 20:17:00 +000028from cStringIO import StringIO
29
Bryan Duxbury69720412012-01-03 17:32:30 +000030from TTransport import *
31
Mark Sleebd8b9912007-02-27 20:17:00 +000032
33class THttpClient(TTransportBase):
Mark Sleebd8b9912007-02-27 20:17:00 +000034 """Http implementation of TTransport base."""
35
David Reiss2aa28902009-03-26 06:22:18 +000036 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 Duxbury69720412012-01-03 17:32:30 +000042 Only the second supports https.
43 """
David Reiss2aa28902009-03-26 06:22:18 +000044 if port is not None:
Bryan Duxbury69720412012-01-03 17:32:30 +000045 warnings.warn(
46 "Please use the THttpClient('http://host:port/path') syntax",
47 DeprecationWarning,
48 stacklevel=2)
David Reiss2aa28902009-03-26 06:22:18 +000049 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 Duxbury727d67d2010-09-02 01:00:19 +000064 if parsed.query:
65 self.path += '?%s' % parsed.query
Mark Sleebd8b9912007-02-27 20:17:00 +000066 self.__wbuf = StringIO()
67 self.__http = None
David Reissff3d2492010-03-09 05:19:16 +000068 self.__timeout = None
Roger Meierfa392e92012-04-11 22:15:15 +000069 self.__custom_headers = None
Mark Sleebd8b9912007-02-27 20:17:00 +000070
71 def open(self):
David Reiss2aa28902009-03-26 06:22:18 +000072 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 Sleebd8b9912007-02-27 20:17:00 +000076
77 def close(self):
78 self.__http.close()
79 self.__http = None
David Reiss0c90f6f2008-02-06 22:18:40 +000080
Mark Sleebd8b9912007-02-27 20:17:00 +000081 def isOpen(self):
Bryan Duxbury69720412012-01-03 17:32:30 +000082 return self.__http is not None
Mark Sleebd8b9912007-02-27 20:17:00 +000083
David Reissff3d2492010-03-09 05:19:16 +000084 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 Duxbury69720412012-01-03 17:32:30 +000091 self.__timeout = ms / 1000.0
David Reissff3d2492010-03-09 05:19:16 +000092
Roger Meierfa392e92012-04-11 22:15:15 +000093 def setCustomHeaders(self, headers):
94 self.__custom_headers = headers
95
Mark Sleebd8b9912007-02-27 20:17:00 +000096 def read(self, sz):
97 return self.__http.file.read(sz)
98
99 def write(self, buf):
100 self.__wbuf.write(buf)
101
David Reissff3d2492010-03-09 05:19:16 +0000102 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 Sleebd8b9912007-02-27 20:17:00 +0000111 def flush(self):
David Reiss7c1f6f82009-03-24 20:10:24 +0000112 if self.isOpen():
113 self.close()
Bryan Duxbury69720412012-01-03 17:32:30 +0000114 self.open()
David Reiss7c1f6f82009-03-24 20:10:24 +0000115
Mark Sleebd8b9912007-02-27 20:17:00 +0000116 # Pull data out of buffer
117 data = self.__wbuf.getvalue()
118 self.__wbuf = StringIO()
119
120 # HTTP request
David Reiss2aa28902009-03-26 06:22:18 +0000121 self.__http.putrequest('POST', self.path)
Mark Sleebd8b9912007-02-27 20:17:00 +0000122
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 Meierfa392e92012-04-11 22:15:15 +0000127
Roger Meier3f5a2642012-04-13 14:20:08 +0000128 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 Meierfa392e92012-04-11 22:15:15 +0000135 if self.__custom_headers:
136 for key, val in self.__custom_headers.iteritems():
137 self.__http.putheader(key, val)
138
Mark Sleebd8b9912007-02-27 20:17:00 +0000139 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 Reissff3d2492010-03-09 05:19:16 +0000146
147 # Decorate if we know how to timeout
148 if hasattr(socket, 'getdefaulttimeout'):
149 flush = __withTimeout(flush)