@@ -2187,11 +2187,12 @@ def test_getting_header_defaultint(self):
2187
2187
class TunnelTests (TestCase ):
2188
2188
def setUp (self ):
2189
2189
response_text = (
2190
- 'HTTP/1.0 200 OK\r \n \r \n ' # Reply to CONNECT
2190
+ 'HTTP/1.1 200 OK\r \n \r \n ' # Reply to CONNECT
2191
2191
'HTTP/1.1 200 OK\r \n ' # Reply to HEAD
2192
2192
'Content-Length: 42\r \n \r \n '
2193
2193
)
2194
2194
self .host = 'proxy.com'
2195
+ self .port = client .HTTP_PORT
2195
2196
self .conn = client .HTTPConnection (self .host )
2196
2197
self .conn ._create_connection = self ._create_connection (response_text )
2197
2198
@@ -2203,15 +2204,45 @@ def create_connection(address, timeout=None, source_address=None):
2203
2204
return FakeSocket (response_text , host = address [0 ], port = address [1 ])
2204
2205
return create_connection
2205
2206
2206
- def test_set_tunnel_host_port_headers (self ):
2207
+ def test_set_tunnel_host_port_headers_add_host_missing (self ):
2207
2208
tunnel_host = 'destination.com'
2208
2209
tunnel_port = 8888
2209
2210
tunnel_headers = {'User-Agent' : 'Mozilla/5.0 (compatible, MSIE 11)' }
2211
+ tunnel_headers_after = tunnel_headers .copy ()
2212
+ tunnel_headers_after ['Host' ] = '%s:%d' % (tunnel_host , tunnel_port )
2210
2213
self .conn .set_tunnel (tunnel_host , port = tunnel_port ,
2211
2214
headers = tunnel_headers )
2212
2215
self .conn .request ('HEAD' , '/' , '' )
2213
2216
self .assertEqual (self .conn .sock .host , self .host )
2214
- self .assertEqual (self .conn .sock .port , client .HTTP_PORT )
2217
+ self .assertEqual (self .conn .sock .port , self .port )
2218
+ self .assertEqual (self .conn ._tunnel_host , tunnel_host )
2219
+ self .assertEqual (self .conn ._tunnel_port , tunnel_port )
2220
+ self .assertEqual (self .conn ._tunnel_headers , tunnel_headers_after )
2221
+
2222
+ def test_set_tunnel_host_port_headers_set_host_identical (self ):
2223
+ tunnel_host = 'destination.com'
2224
+ tunnel_port = 8888
2225
+ tunnel_headers = {'User-Agent' : 'Mozilla/5.0 (compatible, MSIE 11)' ,
2226
+ 'Host' : '%s:%d' % (tunnel_host , tunnel_port )}
2227
+ self .conn .set_tunnel (tunnel_host , port = tunnel_port ,
2228
+ headers = tunnel_headers )
2229
+ self .conn .request ('HEAD' , '/' , '' )
2230
+ self .assertEqual (self .conn .sock .host , self .host )
2231
+ self .assertEqual (self .conn .sock .port , self .port )
2232
+ self .assertEqual (self .conn ._tunnel_host , tunnel_host )
2233
+ self .assertEqual (self .conn ._tunnel_port , tunnel_port )
2234
+ self .assertEqual (self .conn ._tunnel_headers , tunnel_headers )
2235
+
2236
+ def test_set_tunnel_host_port_headers_set_host_different (self ):
2237
+ tunnel_host = 'destination.com'
2238
+ tunnel_port = 8888
2239
+ tunnel_headers = {'User-Agent' : 'Mozilla/5.0 (compatible, MSIE 11)' ,
2240
+ 'Host' : '%s:%d' % ('example.com' , 4200 )}
2241
+ self .conn .set_tunnel (tunnel_host , port = tunnel_port ,
2242
+ headers = tunnel_headers )
2243
+ self .conn .request ('HEAD' , '/' , '' )
2244
+ self .assertEqual (self .conn .sock .host , self .host )
2245
+ self .assertEqual (self .conn .sock .port , self .port )
2215
2246
self .assertEqual (self .conn ._tunnel_host , tunnel_host )
2216
2247
self .assertEqual (self .conn ._tunnel_port , tunnel_port )
2217
2248
self .assertEqual (self .conn ._tunnel_headers , tunnel_headers )
@@ -2223,17 +2254,96 @@ def test_disallow_set_tunnel_after_connect(self):
2223
2254
'destination.com' )
2224
2255
2225
2256
def test_connect_with_tunnel (self ):
2226
- self .conn .set_tunnel ('destination.com' )
2257
+ d = {
2258
+ b'host' : b'destination.com' ,
2259
+ b'port' : client .HTTP_PORT ,
2260
+ }
2261
+ self .conn .set_tunnel (d [b'host' ].decode ('ascii' ))
2262
+ self .conn .request ('HEAD' , '/' , '' )
2263
+ self .assertEqual (self .conn .sock .host , self .host )
2264
+ self .assertEqual (self .conn .sock .port , self .port )
2265
+ self .assertIn (b'CONNECT %(host)s:%(port)d HTTP/1.1\r \n '
2266
+ b'Host: %(host)s:%(port)d\r \n \r \n ' % d ,
2267
+ self .conn .sock .data )
2268
+ self .assertIn (b'HEAD / HTTP/1.1\r \n Host: %(host)s\r \n ' % d ,
2269
+ self .conn .sock .data )
2270
+
2271
+ def test_connect_with_tunnel_with_default_port (self ):
2272
+ d = {
2273
+ b'host' : b'destination.com' ,
2274
+ b'port' : client .HTTP_PORT ,
2275
+ }
2276
+ self .conn .set_tunnel (d [b'host' ].decode ('ascii' ), port = d [b'port' ])
2277
+ self .conn .request ('HEAD' , '/' , '' )
2278
+ self .assertEqual (self .conn .sock .host , self .host )
2279
+ self .assertEqual (self .conn .sock .port , self .port )
2280
+ self .assertIn (b'CONNECT %(host)s:%(port)d HTTP/1.1\r \n '
2281
+ b'Host: %(host)s:%(port)d\r \n \r \n ' % d ,
2282
+ self .conn .sock .data )
2283
+ self .assertIn (b'HEAD / HTTP/1.1\r \n Host: %(host)s\r \n ' % d ,
2284
+ self .conn .sock .data )
2285
+
2286
+ def test_connect_with_tunnel_with_nonstandard_port (self ):
2287
+ d = {
2288
+ b'host' : b'destination.com' ,
2289
+ b'port' : 8888 ,
2290
+ }
2291
+ self .conn .set_tunnel (d [b'host' ].decode ('ascii' ), port = d [b'port' ])
2292
+ self .conn .request ('HEAD' , '/' , '' )
2293
+ self .assertEqual (self .conn .sock .host , self .host )
2294
+ self .assertEqual (self .conn .sock .port , self .port )
2295
+ self .assertIn (b'CONNECT %(host)s:%(port)d HTTP/1.1\r \n '
2296
+ b'Host: %(host)s:%(port)d\r \n \r \n ' % d ,
2297
+ self .conn .sock .data )
2298
+ self .assertIn (b'HEAD / HTTP/1.1\r \n Host: %(host)s:%(port)d\r \n ' % d ,
2299
+ self .conn .sock .data )
2300
+
2301
+ # This request is not RFC-valid, but it's been possible with the library
2302
+ # for years, so don't break it unexpectedly... This also tests
2303
+ # case-insensitivity when injecting Host: headers if they're missing.
2304
+ def test_connect_with_tunnel_with_different_host_header (self ):
2305
+ d = {
2306
+ b'host' : b'destination.com' ,
2307
+ b'tunnel_host_header' : b'example.com:9876' ,
2308
+ b'port' : client .HTTP_PORT ,
2309
+ }
2310
+ self .conn .set_tunnel (
2311
+ d [b'host' ].decode ('ascii' ),
2312
+ headers = {'HOST' : d [b'tunnel_host_header' ].decode ('ascii' )})
2313
+ self .conn .request ('HEAD' , '/' , '' )
2314
+ self .assertEqual (self .conn .sock .host , self .host )
2315
+ self .assertEqual (self .conn .sock .port , self .port )
2316
+ self .assertIn (b'CONNECT %(host)s:%(port)d HTTP/1.1\r \n '
2317
+ b'HOST: %(tunnel_host_header)s\r \n \r \n ' % d ,
2318
+ self .conn .sock .data )
2319
+ self .assertIn (b'HEAD / HTTP/1.1\r \n Host: %(host)s\r \n ' % d ,
2320
+ self .conn .sock .data )
2321
+
2322
+ def test_connect_with_tunnel_different_host (self ):
2323
+ d = {
2324
+ b'host' : b'destination.com' ,
2325
+ b'port' : client .HTTP_PORT ,
2326
+ }
2327
+ self .conn .set_tunnel (d [b'host' ].decode ('ascii' ))
2328
+ self .conn .request ('HEAD' , '/' , '' )
2329
+ self .assertEqual (self .conn .sock .host , self .host )
2330
+ self .assertEqual (self .conn .sock .port , self .port )
2331
+ self .assertIn (b'CONNECT %(host)s:%(port)d HTTP/1.1\r \n '
2332
+ b'Host: %(host)s:%(port)d\r \n \r \n ' % d ,
2333
+ self .conn .sock .data )
2334
+ self .assertIn (b'HEAD / HTTP/1.1\r \n Host: %(host)s\r \n ' % d ,
2335
+ self .conn .sock .data )
2336
+
2337
+ def test_connect_with_tunnel_idna (self ):
2338
+ dest = '\u03b4 \u03c0 \u03b8 .gr'
2339
+ dest_port = b'%s:%d' % (dest .encode ('idna' ), client .HTTP_PORT )
2340
+ expected = b'CONNECT %s HTTP/1.1\r \n Host: %s\r \n \r \n ' % (
2341
+ dest_port , dest_port )
2342
+ self .conn .set_tunnel (dest )
2227
2343
self .conn .request ('HEAD' , '/' , '' )
2228
2344
self .assertEqual (self .conn .sock .host , self .host )
2229
2345
self .assertEqual (self .conn .sock .port , client .HTTP_PORT )
2230
- self .assertIn (b'CONNECT destination.com' , self .conn .sock .data )
2231
- # issue22095
2232
- self .assertNotIn (b'Host: destination.com:None' , self .conn .sock .data )
2233
- self .assertIn (b'Host: destination.com' , self .conn .sock .data )
2234
-
2235
- # This test should be removed when CONNECT gets the HTTP/1.1 blessing
2236
- self .assertNotIn (b'Host: proxy.com' , self .conn .sock .data )
2346
+ self .assertIn (expected , self .conn .sock .data )
2237
2347
2238
2348
def test_tunnel_connect_single_send_connection_setup (self ):
2239
2349
"""Regresstion test for https://bugs.python.org/issue43332."""
@@ -2253,12 +2363,19 @@ def test_tunnel_connect_single_send_connection_setup(self):
2253
2363
msg = f'unexpected proxy data sent { proxy_setup_data_sent !r} ' )
2254
2364
2255
2365
def test_connect_put_request (self ):
2256
- self .conn .set_tunnel ('destination.com' )
2366
+ d = {
2367
+ b'host' : b'destination.com' ,
2368
+ b'port' : client .HTTP_PORT ,
2369
+ }
2370
+ self .conn .set_tunnel (d [b'host' ].decode ('ascii' ))
2257
2371
self .conn .request ('PUT' , '/' , '' )
2258
2372
self .assertEqual (self .conn .sock .host , self .host )
2259
- self .assertEqual (self .conn .sock .port , client .HTTP_PORT )
2260
- self .assertIn (b'CONNECT destination.com' , self .conn .sock .data )
2261
- self .assertIn (b'Host: destination.com' , self .conn .sock .data )
2373
+ self .assertEqual (self .conn .sock .port , self .port )
2374
+ self .assertIn (b'CONNECT %(host)s:%(port)d HTTP/1.1\r \n '
2375
+ b'Host: %(host)s:%(port)d\r \n \r \n ' % d ,
2376
+ self .conn .sock .data )
2377
+ self .assertIn (b'PUT / HTTP/1.1\r \n Host: %(host)s\r \n ' % d ,
2378
+ self .conn .sock .data )
2262
2379
2263
2380
def test_tunnel_debuglog (self ):
2264
2381
expected_header = 'X-Dummy: 1'
0 commit comments