##// END OF EJS Templates
httpclient: import revision b8c3511a8cae from py-nonblocking-http...
Augie Fackler -
r14341:5c3de67e default
parent child Browse files
Show More
@@ -0,0 +1,94 b''
1 # Copyright 2011, Google Inc.
2 # All rights reserved.
3 #
4 # Redistribution and use in source and binary forms, with or without
5 # modification, are permitted provided that the following conditions are
6 # met:
7 #
8 # * Redistributions of source code must retain the above copyright
9 # notice, this list of conditions and the following disclaimer.
10 # * Redistributions in binary form must reproduce the above
11 # copyright notice, this list of conditions and the following disclaimer
12 # in the documentation and/or other materials provided with the
13 # distribution.
14 # * Neither the name of Google Inc. nor the names of its
15 # contributors may be used to endorse or promote products derived from
16 # this software without specific prior written permission.
17
18 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
29 import unittest
30
31 import http
32
33 # relative import to ease embedding the library
34 import util
35
36
37
38 class HttpSslTest(util.HttpTestBase, unittest.TestCase):
39 def testSslRereadRequired(self):
40 con = http.HTTPConnection('1.2.3.4:443')
41 con._connect()
42 # extend the list instead of assign because of how
43 # MockSSLSocket works.
44 con.sock.data.extend(['HTTP/1.1 200 OK\r\n',
45 'Server: BogusServer 1.0\r\n',
46 'MultiHeader: Value\r\n'
47 'MultiHeader: Other Value\r\n'
48 'MultiHeader: One More!\r\n'
49 'Content-Length: 10\r\n',
50 '\r\n'
51 '1234567890'
52 ])
53 con.request('GET', '/')
54
55 expected_req = ('GET / HTTP/1.1\r\n'
56 'Host: 1.2.3.4\r\n'
57 'accept-encoding: identity\r\n\r\n')
58
59 self.assertEqual(('1.2.3.4', 443), con.sock.sa)
60 self.assertEqual(expected_req, con.sock.sent)
61 resp = con.getresponse()
62 self.assertEqual('1234567890', resp.read())
63 self.assertEqual(['Value', 'Other Value', 'One More!'],
64 resp.headers.getheaders('multiheader'))
65 self.assertEqual(['BogusServer 1.0'],
66 resp.headers.getheaders('server'))
67
68 def testSslRereadInEarlyResponse(self):
69 con = http.HTTPConnection('1.2.3.4:443')
70 con._connect()
71 # extend the list instead of assign because of how
72 # MockSSLSocket works.
73 con.sock.early_data.extend(['HTTP/1.1 200 OK\r\n',
74 'Server: BogusServer 1.0\r\n',
75 'MultiHeader: Value\r\n'
76 'MultiHeader: Other Value\r\n'
77 'MultiHeader: One More!\r\n'
78 'Content-Length: 10\r\n',
79 '\r\n'
80 '1234567890'
81 ])
82
83 expected_req = self.doPost(con, False)
84 self.assertEqual(None, con.sock,
85 'Connection should have disowned socket')
86
87 resp = con.getresponse()
88 self.assertEqual(('1.2.3.4', 443), resp.sock.sa)
89 self.assertEqual(expected_req, resp.sock.sent)
90 self.assertEqual('1234567890', resp.read())
91 self.assertEqual(['Value', 'Other Value', 'One More!'],
92 resp.headers.getheaders('multiheader'))
93 self.assertEqual(['BogusServer 1.0'],
94 resp.headers.getheaders('server'))
@@ -165,7 +165,13 b' class HTTPResponse(object):'
165 165 logger.info('timed out with timeout of %s', self._timeout)
166 166 raise HTTPTimeoutException('timeout reading data')
167 167 logger.info('cl: %r body: %r', self._content_len, self._body)
168 data = self.sock.recv(INCOMING_BUFFER_SIZE)
168 try:
169 data = self.sock.recv(INCOMING_BUFFER_SIZE)
170 except socket.sslerror, e:
171 if e.args[0] != socket.SSL_ERROR_WANT_READ:
172 raise
173 logger.debug('SSL_WANT_READ in _select, should retry later')
174 return True
169 175 logger.debug('response read %d data during _select', len(data))
170 176 if not data:
171 177 if not self.headers:
@@ -545,7 +551,14 b' class HTTPConnection(object):'
545 551 # incoming data
546 552 if r:
547 553 try:
548 data = r[0].recv(INCOMING_BUFFER_SIZE)
554 try:
555 data = r[0].recv(INCOMING_BUFFER_SIZE)
556 except socket.sslerror, e:
557 if e.args[0] != socket.SSL_ERROR_WANT_READ:
558 raise
559 logger.debug(
560 'SSL_WANT_READ while sending data, retrying...')
561 continue
549 562 if not data:
550 563 logger.info('socket appears closed in read')
551 564 outgoing_headers = body = None
@@ -39,7 +39,7 b' class SimpleHttpTest(util.HttpTestBase, '
39 39 def _run_simple_test(self, host, server_data, expected_req, expected_data):
40 40 con = http.HTTPConnection(host)
41 41 con._connect()
42 con.sock.data = server_data
42 con.sock.data.extend(server_data)
43 43 con.request('GET', '/')
44 44
45 45 self.assertStringEqual(expected_req, con.sock.sent)
@@ -224,19 +224,6 b' dotencode'
224 224 'accept-encoding: identity\r\n\r\n'),
225 225 '1234567890')
226 226
227 def doPost(self, con, expect_body, body_to_send='This is some POST data'):
228 con.request('POST', '/', body=body_to_send,
229 expect_continue=True)
230 expected_req = ('POST / HTTP/1.1\r\n'
231 'Host: 1.2.3.4\r\n'
232 'content-length: %d\r\n'
233 'Expect: 100-Continue\r\n'
234 'accept-encoding: identity\r\n\r\n' %
235 len(body_to_send))
236 if expect_body:
237 expected_req += body_to_send
238 return expected_req
239
240 227 def testEarlyContinueResponse(self):
241 228 con = http.HTTPConnection('1.2.3.4:80')
242 229 con._connect()
@@ -97,12 +97,12 b' class ProxyHttpTest(util.HttpTestBase, u'
97 97 '\r\n'
98 98 '1234567890'])
99 99 con._connect()
100 con.sock.data = ['HTTP/1.1 200 OK\r\n',
101 'Server: BogusServer 1.0\r\n',
102 'Content-Length: 10\r\n',
103 '\r\n'
104 '1234567890'
105 ]
100 con.sock.data.extend(['HTTP/1.1 200 OK\r\n',
101 'Server: BogusServer 1.0\r\n',
102 'Content-Length: 10\r\n',
103 '\r\n'
104 '1234567890'
105 ])
106 106 con.request('GET', '/')
107 107
108 108 expected_req = ('CONNECT 1.2.3.4:443 HTTP/1.0\r\n'
@@ -109,12 +109,29 b' def mockselect(r, w, x, timeout=0):'
109 109 return readable, w[:], []
110 110
111 111
112 class MockSSLSocket(object):
113 def __init__(self, sock):
114 self._sock = sock
115 self._fail_recv = True
116
117 def __getattr__(self, key):
118 return getattr(self._sock, key)
119
120 def recv(self, amt=-1):
121 try:
122 if self._fail_recv:
123 raise socket.sslerror(socket.SSL_ERROR_WANT_READ)
124 return self._sock.recv(amt=amt)
125 finally:
126 self._fail_recv = not self._fail_recv
127
128
112 129 def mocksslwrap(sock, keyfile=None, certfile=None,
113 130 server_side=False, cert_reqs=http.socketutil.CERT_NONE,
114 131 ssl_version=http.socketutil.PROTOCOL_SSLv23, ca_certs=None,
115 132 do_handshake_on_connect=True,
116 133 suppress_ragged_eofs=True):
117 return sock
134 return MockSSLSocket(sock)
118 135
119 136
120 137 def mockgetaddrinfo(host, port, unused, streamtype):
@@ -157,4 +174,17 b' class HttpTestBase(object):'
157 174 add_nl(l.splitlines()), add_nl(r.splitlines()),
158 175 fromfile='expected', tofile='got'))
159 176 raise
177
178 def doPost(self, con, expect_body, body_to_send='This is some POST data'):
179 con.request('POST', '/', body=body_to_send,
180 expect_continue=True)
181 expected_req = ('POST / HTTP/1.1\r\n'
182 'Host: 1.2.3.4\r\n'
183 'content-length: %d\r\n'
184 'Expect: 100-Continue\r\n'
185 'accept-encoding: identity\r\n\r\n' %
186 len(body_to_send))
187 if expect_body:
188 expected_req += body_to_send
189 return expected_req
160 190 # no-check-code
General Comments 0
You need to be logged in to leave comments. Login now