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 |
|
|
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 |
|
|
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