Completed
Branch master (477316)
by Michael
08:56
created

thrift.transport.THttpClient.THttpClient.flush()   B

Complexity

Conditions 7

Size

Total Lines 35
Code Lines 22

Duplication

Lines 35
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 22
dl 35
loc 35
rs 7.952
c 0
b 0
f 0
cc 7
nop 1
1
#
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
#
19
20
import http.client
21
import os
22
import socket
23
import sys
24
import urllib.request, urllib.parse, urllib.error
25
import urllib.parse
26
import warnings
27
28
from io import StringIO
29
30
from .TTransport import *
31
32
33
class THttpClient(TTransportBase):
34
  """Http implementation of TTransport base."""
35
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
42
    Only the second supports https.
43
    """
44
    if port is not None:
45
      warnings.warn(
46
        "Please use the THttpClient('http://host:port/path') syntax",
47
        DeprecationWarning,
48
        stacklevel=2)
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 = urllib.parse.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 http.client.HTTP_PORT
60
      elif self.scheme == 'https':
61
        self.port = parsed.port or http.client.HTTPS_PORT
62
      self.host = parsed.hostname
63
      self.path = parsed.path
64
      if parsed.query:
65
        self.path += '?%s' % parsed.query
66
    self.__wbuf = StringIO()
67
    self.__http = None
68
    self.__timeout = None
69
    self.__custom_headers = None
70
71
  def open(self):
72
    if self.scheme == 'http':
73
      self.__http = http.client.HTTP(self.host, self.port)
74
    else:
75
      self.__http = http.client.HTTPS(self.host, self.port)
76
77
  def close(self):
78
    self.__http.close()
79
    self.__http = None
80
81
  def isOpen(self):
82
    return self.__http is not None
83
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:
91
      self.__timeout = ms / 1000.0
92
93
  def setCustomHeaders(self, headers):
94
    self.__custom_headers = headers
95
96
  def read(self, sz):
97
    return self.__http.file.read(sz)
98
99
  def write(self, buf):
100
    self.__wbuf.write(buf)
101
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
111
  def flush(self):
112
    if self.isOpen():
113
      self.close()
114
    self.open()
115
116
    # Pull data out of buffer
117
    data = self.__wbuf.getvalue()
118
    self.__wbuf = StringIO()
119
120
    # HTTP request
121
    self.__http.putrequest('POST', self.path)
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)))
127
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.parse.quote(script))
133
      self.__http.putheader('User-Agent', user_agent)
134
135
    if self.__custom_headers:
136
        for key, val in self.__custom_headers.items():
137
            self.__http.putheader(key, val)
138
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()
146
147
  # Decorate if we know how to timeout
148
  if hasattr(socket, 'getdefaulttimeout'):
149
    flush = __withTimeout(flush)
150