##// END OF EJS Templates
httpclient: import ca33b88d143c from py-nonblocking-http (issue2932)
Augie Fackler -
r14990:494b26ad stable
parent child Browse files
Show More
@@ -1,134 +1,127 b''
1 # Copyright 2010, Google Inc.
1 # Copyright 2010, Google Inc.
2 # All rights reserved.
2 # All rights reserved.
3 #
3 #
4 # Redistribution and use in source and binary forms, with or without
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
5 # modification, are permitted provided that the following conditions are
6 # met:
6 # met:
7 #
7 #
8 # * Redistributions of source code must retain the above copyright
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
12 # in the documentation and/or other materials provided with the
13 # distribution.
13 # distribution.
14 # * Neither the name of Google Inc. nor the names of its
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
16 # this software without specific prior written permission.
17
17
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 """Abstraction to simplify socket use for Python < 2.6
29 """Abstraction to simplify socket use for Python < 2.6
30
30
31 This will attempt to use the ssl module and the new
31 This will attempt to use the ssl module and the new
32 socket.create_connection method, but fall back to the old
32 socket.create_connection method, but fall back to the old
33 methods if those are unavailable.
33 methods if those are unavailable.
34 """
34 """
35 import logging
35 import logging
36 import socket
36 import socket
37
37
38 logger = logging.getLogger(__name__)
38 logger = logging.getLogger(__name__)
39
39
40 try:
40 try:
41 import ssl
41 import ssl
42 ssl.wrap_socket # make demandimporters load the module
42 ssl.wrap_socket # make demandimporters load the module
43 have_ssl = True
43 have_ssl = True
44 except ImportError:
44 except ImportError:
45 import httplib
45 import httplib
46 import urllib2
46 import urllib2
47 have_ssl = getattr(urllib2, 'HTTPSHandler', False)
47 have_ssl = getattr(urllib2, 'HTTPSHandler', False)
48 ssl = False
48 ssl = False
49
49
50
50
51 try:
51 try:
52 create_connection = socket.create_connection
52 create_connection = socket.create_connection
53 except AttributeError:
53 except AttributeError:
54 def create_connection(address):
54 def create_connection(address):
55 host, port = address
55 host, port = address
56 msg = "getaddrinfo returns an empty list"
56 msg = "getaddrinfo returns an empty list"
57 sock = None
57 sock = None
58 for res in socket.getaddrinfo(host, port, 0,
58 for res in socket.getaddrinfo(host, port, 0,
59 socket.SOCK_STREAM):
59 socket.SOCK_STREAM):
60 af, socktype, proto, _canonname, sa = res
60 af, socktype, proto, _canonname, sa = res
61 try:
61 try:
62 sock = socket.socket(af, socktype, proto)
62 sock = socket.socket(af, socktype, proto)
63 logger.info("connect: (%s, %s)", host, port)
63 logger.info("connect: (%s, %s)", host, port)
64 sock.connect(sa)
64 sock.connect(sa)
65 except socket.error, msg:
65 except socket.error, msg:
66 logger.info('connect fail: %s %s', host, port)
66 logger.info('connect fail: %s %s', host, port)
67 if sock:
67 if sock:
68 sock.close()
68 sock.close()
69 sock = None
69 sock = None
70 continue
70 continue
71 break
71 break
72 if not sock:
72 if not sock:
73 raise socket.error, msg
73 raise socket.error, msg
74 return sock
74 return sock
75
75
76 if ssl:
76 if ssl:
77 wrap_socket = ssl.wrap_socket
77 wrap_socket = ssl.wrap_socket
78 CERT_NONE = ssl.CERT_NONE
78 CERT_NONE = ssl.CERT_NONE
79 CERT_OPTIONAL = ssl.CERT_OPTIONAL
79 CERT_OPTIONAL = ssl.CERT_OPTIONAL
80 CERT_REQUIRED = ssl.CERT_REQUIRED
80 CERT_REQUIRED = ssl.CERT_REQUIRED
81 PROTOCOL_SSLv2 = ssl.PROTOCOL_SSLv2
82 PROTOCOL_SSLv3 = ssl.PROTOCOL_SSLv3
83 PROTOCOL_SSLv23 = ssl.PROTOCOL_SSLv23
84 PROTOCOL_TLSv1 = ssl.PROTOCOL_TLSv1
85 else:
81 else:
86 class FakeSocket(httplib.FakeSocket):
82 class FakeSocket(httplib.FakeSocket):
87 """Socket wrapper that supports SSL.
83 """Socket wrapper that supports SSL.
88 """
84 """
89 # backport the behavior from Python 2.6, which is to busy wait
85 # backport the behavior from Python 2.6, which is to busy wait
90 # on the socket instead of anything nice. Sigh.
86 # on the socket instead of anything nice. Sigh.
91 # See http://bugs.python.org/issue3890 for more info.
87 # See http://bugs.python.org/issue3890 for more info.
92 def recv(self, buflen=1024, flags=0):
88 def recv(self, buflen=1024, flags=0):
93 """ssl-aware wrapper around socket.recv
89 """ssl-aware wrapper around socket.recv
94 """
90 """
95 if flags != 0:
91 if flags != 0:
96 raise ValueError(
92 raise ValueError(
97 "non-zero flags not allowed in calls to recv() on %s" %
93 "non-zero flags not allowed in calls to recv() on %s" %
98 self.__class__)
94 self.__class__)
99 while True:
95 while True:
100 try:
96 try:
101 return self._ssl.read(buflen)
97 return self._ssl.read(buflen)
102 except socket.sslerror, x:
98 except socket.sslerror, x:
103 if x.args[0] == socket.SSL_ERROR_WANT_READ:
99 if x.args[0] == socket.SSL_ERROR_WANT_READ:
104 continue
100 continue
105 else:
101 else:
106 raise x
102 raise x
107
103
108 PROTOCOL_SSLv2 = 0
104 _PROTOCOL_SSLv23 = 2
109 PROTOCOL_SSLv3 = 1
110 PROTOCOL_SSLv23 = 2
111 PROTOCOL_TLSv1 = 3
112
105
113 CERT_NONE = 0
106 CERT_NONE = 0
114 CERT_OPTIONAL = 1
107 CERT_OPTIONAL = 1
115 CERT_REQUIRED = 2
108 CERT_REQUIRED = 2
116
109
117 def wrap_socket(sock, keyfile=None, certfile=None,
110 def wrap_socket(sock, keyfile=None, certfile=None,
118 server_side=False, cert_reqs=CERT_NONE,
111 server_side=False, cert_reqs=CERT_NONE,
119 ssl_version=PROTOCOL_SSLv23, ca_certs=None,
112 ssl_version=_PROTOCOL_SSLv23, ca_certs=None,
120 do_handshake_on_connect=True,
113 do_handshake_on_connect=True,
121 suppress_ragged_eofs=True):
114 suppress_ragged_eofs=True):
122 if cert_reqs != CERT_NONE and ca_certs:
115 if cert_reqs != CERT_NONE and ca_certs:
123 raise CertificateValidationUnsupported(
116 raise CertificateValidationUnsupported(
124 'SSL certificate validation requires the ssl module'
117 'SSL certificate validation requires the ssl module'
125 '(included in Python 2.6 and later.)')
118 '(included in Python 2.6 and later.)')
126 sslob = socket.ssl(sock)
119 sslob = socket.ssl(sock)
127 # borrow httplib's workaround for no ssl.wrap_socket
120 # borrow httplib's workaround for no ssl.wrap_socket
128 sock = FakeSocket(sock, sslob)
121 sock = FakeSocket(sock, sslob)
129 return sock
122 return sock
130
123
131
124
132 class CertificateValidationUnsupported(Exception):
125 class CertificateValidationUnsupported(Exception):
133 """Exception raised when cert validation is requested but unavailable."""
126 """Exception raised when cert validation is requested but unavailable."""
134 # no-check-code
127 # no-check-code
@@ -1,195 +1,195 b''
1 # Copyright 2010, Google Inc.
1 # Copyright 2010, Google Inc.
2 # All rights reserved.
2 # All rights reserved.
3 #
3 #
4 # Redistribution and use in source and binary forms, with or without
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
5 # modification, are permitted provided that the following conditions are
6 # met:
6 # met:
7 #
7 #
8 # * Redistributions of source code must retain the above copyright
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
12 # in the documentation and/or other materials provided with the
13 # distribution.
13 # distribution.
14 # * Neither the name of Google Inc. nor the names of its
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
16 # this software without specific prior written permission.
17
17
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 import difflib
29 import difflib
30 import socket
30 import socket
31
31
32 import http
32 import http
33
33
34
34
35 class MockSocket(object):
35 class MockSocket(object):
36 """Mock non-blocking socket object.
36 """Mock non-blocking socket object.
37
37
38 This is ONLY capable of mocking a nonblocking socket.
38 This is ONLY capable of mocking a nonblocking socket.
39
39
40 Attributes:
40 Attributes:
41 early_data: data to always send as soon as end of headers is seen
41 early_data: data to always send as soon as end of headers is seen
42 data: a list of strings to return on recv(), with the
42 data: a list of strings to return on recv(), with the
43 assumption that the socket would block between each
43 assumption that the socket would block between each
44 string in the list.
44 string in the list.
45 read_wait_sentinel: data that must be written to the socket before
45 read_wait_sentinel: data that must be written to the socket before
46 beginning the response.
46 beginning the response.
47 close_on_empty: If true, close the socket when it runs out of data
47 close_on_empty: If true, close the socket when it runs out of data
48 for the client.
48 for the client.
49 """
49 """
50 def __init__(self, af, socktype, proto):
50 def __init__(self, af, socktype, proto):
51 self.af = af
51 self.af = af
52 self.socktype = socktype
52 self.socktype = socktype
53 self.proto = proto
53 self.proto = proto
54
54
55 self.early_data = []
55 self.early_data = []
56 self.data = []
56 self.data = []
57 self.remote_closed = self.closed = False
57 self.remote_closed = self.closed = False
58 self.close_on_empty = False
58 self.close_on_empty = False
59 self.sent = ''
59 self.sent = ''
60 self.read_wait_sentinel = http._END_HEADERS
60 self.read_wait_sentinel = http._END_HEADERS
61
61
62 def close(self):
62 def close(self):
63 self.closed = True
63 self.closed = True
64
64
65 def connect(self, sa):
65 def connect(self, sa):
66 self.sa = sa
66 self.sa = sa
67
67
68 def setblocking(self, timeout):
68 def setblocking(self, timeout):
69 assert timeout == 0
69 assert timeout == 0
70
70
71 def recv(self, amt=-1):
71 def recv(self, amt=-1):
72 if self.early_data:
72 if self.early_data:
73 datalist = self.early_data
73 datalist = self.early_data
74 elif not self.data:
74 elif not self.data:
75 return ''
75 return ''
76 else:
76 else:
77 datalist = self.data
77 datalist = self.data
78 if amt == -1:
78 if amt == -1:
79 return datalist.pop(0)
79 return datalist.pop(0)
80 data = datalist.pop(0)
80 data = datalist.pop(0)
81 if len(data) > amt:
81 if len(data) > amt:
82 datalist.insert(0, data[amt:])
82 datalist.insert(0, data[amt:])
83 if not self.data and not self.early_data and self.close_on_empty:
83 if not self.data and not self.early_data and self.close_on_empty:
84 self.remote_closed = True
84 self.remote_closed = True
85 return data[:amt]
85 return data[:amt]
86
86
87 @property
87 @property
88 def ready_for_read(self):
88 def ready_for_read(self):
89 return ((self.early_data and http._END_HEADERS in self.sent)
89 return ((self.early_data and http._END_HEADERS in self.sent)
90 or (self.read_wait_sentinel in self.sent and self.data)
90 or (self.read_wait_sentinel in self.sent and self.data)
91 or self.closed or self.remote_closed)
91 or self.closed or self.remote_closed)
92
92
93 def send(self, data):
93 def send(self, data):
94 # this is a horrible mock, but nothing needs us to raise the
94 # this is a horrible mock, but nothing needs us to raise the
95 # correct exception yet
95 # correct exception yet
96 assert not self.closed, 'attempted to write to a closed socket'
96 assert not self.closed, 'attempted to write to a closed socket'
97 assert not self.remote_closed, ('attempted to write to a'
97 assert not self.remote_closed, ('attempted to write to a'
98 ' socket closed by the server')
98 ' socket closed by the server')
99 if len(data) > 8192:
99 if len(data) > 8192:
100 data = data[:8192]
100 data = data[:8192]
101 self.sent += data
101 self.sent += data
102 return len(data)
102 return len(data)
103
103
104
104
105 def mockselect(r, w, x, timeout=0):
105 def mockselect(r, w, x, timeout=0):
106 """Simple mock for select()
106 """Simple mock for select()
107 """
107 """
108 readable = filter(lambda s: s.ready_for_read, r)
108 readable = filter(lambda s: s.ready_for_read, r)
109 return readable, w[:], []
109 return readable, w[:], []
110
110
111
111
112 class MockSSLSocket(object):
112 class MockSSLSocket(object):
113 def __init__(self, sock):
113 def __init__(self, sock):
114 self._sock = sock
114 self._sock = sock
115 self._fail_recv = True
115 self._fail_recv = True
116
116
117 def __getattr__(self, key):
117 def __getattr__(self, key):
118 return getattr(self._sock, key)
118 return getattr(self._sock, key)
119
119
120 def __setattr__(self, key, value):
120 def __setattr__(self, key, value):
121 if key not in ('_sock', '_fail_recv'):
121 if key not in ('_sock', '_fail_recv'):
122 return setattr(self._sock, key, value)
122 return setattr(self._sock, key, value)
123 return object.__setattr__(self, key, value)
123 return object.__setattr__(self, key, value)
124
124
125 def recv(self, amt=-1):
125 def recv(self, amt=-1):
126 try:
126 try:
127 if self._fail_recv:
127 if self._fail_recv:
128 raise socket.sslerror(socket.SSL_ERROR_WANT_READ)
128 raise socket.sslerror(socket.SSL_ERROR_WANT_READ)
129 return self._sock.recv(amt=amt)
129 return self._sock.recv(amt=amt)
130 finally:
130 finally:
131 self._fail_recv = not self._fail_recv
131 self._fail_recv = not self._fail_recv
132
132
133
133
134 def mocksslwrap(sock, keyfile=None, certfile=None,
134 def mocksslwrap(sock, keyfile=None, certfile=None,
135 server_side=False, cert_reqs=http.socketutil.CERT_NONE,
135 server_side=False, cert_reqs=http.socketutil.CERT_NONE,
136 ssl_version=http.socketutil.PROTOCOL_SSLv23, ca_certs=None,
136 ssl_version=None, ca_certs=None,
137 do_handshake_on_connect=True,
137 do_handshake_on_connect=True,
138 suppress_ragged_eofs=True):
138 suppress_ragged_eofs=True):
139 return MockSSLSocket(sock)
139 return MockSSLSocket(sock)
140
140
141
141
142 def mockgetaddrinfo(host, port, unused, streamtype):
142 def mockgetaddrinfo(host, port, unused, streamtype):
143 assert unused == 0
143 assert unused == 0
144 assert streamtype == socket.SOCK_STREAM
144 assert streamtype == socket.SOCK_STREAM
145 if host.count('.') != 3:
145 if host.count('.') != 3:
146 host = '127.0.0.42'
146 host = '127.0.0.42'
147 return [(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, '',
147 return [(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP, '',
148 (host, port))]
148 (host, port))]
149
149
150
150
151 class HttpTestBase(object):
151 class HttpTestBase(object):
152 def setUp(self):
152 def setUp(self):
153 self.orig_socket = socket.socket
153 self.orig_socket = socket.socket
154 socket.socket = MockSocket
154 socket.socket = MockSocket
155
155
156 self.orig_getaddrinfo = socket.getaddrinfo
156 self.orig_getaddrinfo = socket.getaddrinfo
157 socket.getaddrinfo = mockgetaddrinfo
157 socket.getaddrinfo = mockgetaddrinfo
158
158
159 self.orig_select = http.select.select
159 self.orig_select = http.select.select
160 http.select.select = mockselect
160 http.select.select = mockselect
161
161
162 self.orig_sslwrap = http.socketutil.wrap_socket
162 self.orig_sslwrap = http.socketutil.wrap_socket
163 http.socketutil.wrap_socket = mocksslwrap
163 http.socketutil.wrap_socket = mocksslwrap
164
164
165 def tearDown(self):
165 def tearDown(self):
166 socket.socket = self.orig_socket
166 socket.socket = self.orig_socket
167 http.select.select = self.orig_select
167 http.select.select = self.orig_select
168 http.socketutil.wrap_socket = self.orig_sslwrap
168 http.socketutil.wrap_socket = self.orig_sslwrap
169 socket.getaddrinfo = self.orig_getaddrinfo
169 socket.getaddrinfo = self.orig_getaddrinfo
170
170
171 def assertStringEqual(self, l, r):
171 def assertStringEqual(self, l, r):
172 try:
172 try:
173 self.assertEqual(l, r, ('failed string equality check, '
173 self.assertEqual(l, r, ('failed string equality check, '
174 'see stdout for details'))
174 'see stdout for details'))
175 except:
175 except:
176 add_nl = lambda li: map(lambda x: x + '\n', li)
176 add_nl = lambda li: map(lambda x: x + '\n', li)
177 print 'failed expectation:'
177 print 'failed expectation:'
178 print ''.join(difflib.unified_diff(
178 print ''.join(difflib.unified_diff(
179 add_nl(l.splitlines()), add_nl(r.splitlines()),
179 add_nl(l.splitlines()), add_nl(r.splitlines()),
180 fromfile='expected', tofile='got'))
180 fromfile='expected', tofile='got'))
181 raise
181 raise
182
182
183 def doPost(self, con, expect_body, body_to_send='This is some POST data'):
183 def doPost(self, con, expect_body, body_to_send='This is some POST data'):
184 con.request('POST', '/', body=body_to_send,
184 con.request('POST', '/', body=body_to_send,
185 expect_continue=True)
185 expect_continue=True)
186 expected_req = ('POST / HTTP/1.1\r\n'
186 expected_req = ('POST / HTTP/1.1\r\n'
187 'Host: 1.2.3.4\r\n'
187 'Host: 1.2.3.4\r\n'
188 'content-length: %d\r\n'
188 'content-length: %d\r\n'
189 'Expect: 100-Continue\r\n'
189 'Expect: 100-Continue\r\n'
190 'accept-encoding: identity\r\n\r\n' %
190 'accept-encoding: identity\r\n\r\n' %
191 len(body_to_send))
191 len(body_to_send))
192 if expect_body:
192 if expect_body:
193 expected_req += body_to_send
193 expected_req += body_to_send
194 return expected_req
194 return expected_req
195 # no-check-code
195 # no-check-code
General Comments 0
You need to be logged in to leave comments. Login now