blob: 293d9304c48c134cb01f978871b56f199c138e8f [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
21import socket
22import urlparse
23import warnings
24
Mark Sleebd8b9912007-02-27 20:17:00 +000025from cStringIO import StringIO
26
Bryan Duxbury69720412012-01-03 17:32:30 +000027from TTransport import *
28
Mark Sleebd8b9912007-02-27 20:17:00 +000029
30class THttpClient(TTransportBase):
Mark Sleebd8b9912007-02-27 20:17:00 +000031 """Http implementation of TTransport base."""
32
David Reiss2aa28902009-03-26 06:22:18 +000033 def __init__(self, uri_or_host, port=None, path=None):
34 """THttpClient supports two different types constructor parameters.
35
36 THttpClient(host, port, path) - deprecated
37 THttpClient(uri)
38
Bryan Duxbury69720412012-01-03 17:32:30 +000039 Only the second supports https.
40 """
David Reiss2aa28902009-03-26 06:22:18 +000041 if port is not None:
Bryan Duxbury69720412012-01-03 17:32:30 +000042 warnings.warn(
43 "Please use the THttpClient('http://host:port/path') syntax",
44 DeprecationWarning,
45 stacklevel=2)
David Reiss2aa28902009-03-26 06:22:18 +000046 self.host = uri_or_host
47 self.port = port
48 assert path
49 self.path = path
50 self.scheme = 'http'
51 else:
52 parsed = urlparse.urlparse(uri_or_host)
53 self.scheme = parsed.scheme
54 assert self.scheme in ('http', 'https')
55 if self.scheme == 'http':
56 self.port = parsed.port or httplib.HTTP_PORT
57 elif self.scheme == 'https':
58 self.port = parsed.port or httplib.HTTPS_PORT
59 self.host = parsed.hostname
60 self.path = parsed.path
Bryan Duxbury727d67d2010-09-02 01:00:19 +000061 if parsed.query:
62 self.path += '?%s' % parsed.query
Mark Sleebd8b9912007-02-27 20:17:00 +000063 self.__wbuf = StringIO()
64 self.__http = None
David Reissff3d2492010-03-09 05:19:16 +000065 self.__timeout = None
Roger Meierfa392e92012-04-11 22:15:15 +000066 self.__custom_headers = None
Mark Sleebd8b9912007-02-27 20:17:00 +000067
68 def open(self):
David Reiss2aa28902009-03-26 06:22:18 +000069 if self.scheme == 'http':
70 self.__http = httplib.HTTP(self.host, self.port)
71 else:
72 self.__http = httplib.HTTPS(self.host, self.port)
Mark Sleebd8b9912007-02-27 20:17:00 +000073
74 def close(self):
75 self.__http.close()
76 self.__http = None
David Reiss0c90f6f2008-02-06 22:18:40 +000077
Mark Sleebd8b9912007-02-27 20:17:00 +000078 def isOpen(self):
Bryan Duxbury69720412012-01-03 17:32:30 +000079 return self.__http is not None
Mark Sleebd8b9912007-02-27 20:17:00 +000080
David Reissff3d2492010-03-09 05:19:16 +000081 def setTimeout(self, ms):
82 if not hasattr(socket, 'getdefaulttimeout'):
83 raise NotImplementedError
84
85 if ms is None:
86 self.__timeout = None
87 else:
Bryan Duxbury69720412012-01-03 17:32:30 +000088 self.__timeout = ms / 1000.0
David Reissff3d2492010-03-09 05:19:16 +000089
Roger Meierfa392e92012-04-11 22:15:15 +000090 def setCustomHeaders(self, headers):
91 self.__custom_headers = headers
92
Mark Sleebd8b9912007-02-27 20:17:00 +000093 def read(self, sz):
94 return self.__http.file.read(sz)
95
96 def write(self, buf):
97 self.__wbuf.write(buf)
98
David Reissff3d2492010-03-09 05:19:16 +000099 def __withTimeout(f):
100 def _f(*args, **kwargs):
101 orig_timeout = socket.getdefaulttimeout()
102 socket.setdefaulttimeout(args[0].__timeout)
103 result = f(*args, **kwargs)
104 socket.setdefaulttimeout(orig_timeout)
105 return result
106 return _f
107
Mark Sleebd8b9912007-02-27 20:17:00 +0000108 def flush(self):
David Reiss7c1f6f82009-03-24 20:10:24 +0000109 if self.isOpen():
110 self.close()
Bryan Duxbury69720412012-01-03 17:32:30 +0000111 self.open()
David Reiss7c1f6f82009-03-24 20:10:24 +0000112
Mark Sleebd8b9912007-02-27 20:17:00 +0000113 # Pull data out of buffer
114 data = self.__wbuf.getvalue()
115 self.__wbuf = StringIO()
116
117 # HTTP request
David Reiss2aa28902009-03-26 06:22:18 +0000118 self.__http.putrequest('POST', self.path)
Mark Sleebd8b9912007-02-27 20:17:00 +0000119
120 # Write headers
121 self.__http.putheader('Host', self.host)
122 self.__http.putheader('Content-Type', 'application/x-thrift')
123 self.__http.putheader('Content-Length', str(len(data)))
Roger Meierfa392e92012-04-11 22:15:15 +0000124
125 if self.__custom_headers:
126 for key, val in self.__custom_headers.iteritems():
127 self.__http.putheader(key, val)
128
Mark Sleebd8b9912007-02-27 20:17:00 +0000129 self.__http.endheaders()
130
131 # Write payload
132 self.__http.send(data)
133
134 # Get reply to flush the request
135 self.code, self.message, self.headers = self.__http.getreply()
David Reissff3d2492010-03-09 05:19:16 +0000136
137 # Decorate if we know how to timeout
138 if hasattr(socket, 'getdefaulttimeout'):
139 flush = __withTimeout(flush)