88"""
99
1010import json
11+ import os
1112import socket
13+ import tempfile
1214import time
1315
1416import pytest
2325@pytest .fixture (scope = "module" )
2426def http_server (request ):
2527 """
26- Slightly modified version of the `` pytest_localserver.plugin.http_server` `
28+ Slightly modified version of the :func:` pytest_localserver.plugin.httpserver `
2729 fixture that will only start and stop the server application once for test
2830 performance reasons.
2931 """
@@ -33,18 +35,48 @@ def http_server(request):
3335 return server
3436
3537
38+ @pytest .fixture (scope = "module" )
39+ def http_server_uds (request ):
40+ """Like :func:`http_server` but will listen on a Unix domain socket instead
41+
42+ If the current platform does not support Unix domain sockets, the
43+ corresponding test will be skipped.
44+ """
45+ if not hasattr (socket , "AF_UNIX" ):
46+ pytest .skip ("Platform does not support Unix domain sockets" )
47+
48+ uds_path = tempfile .mktemp (".sock" )
49+ def remove_uds_path ():
50+ try :
51+ os .remove (uds_path )
52+ except FileNotFoundError :
53+ pass
54+ request .addfinalizer (remove_uds_path )
55+
56+ server = pytest_localserver .http .ContentServer ("unix://{0}" .format (uds_path ))
57+ server .start ()
58+ request .addfinalizer (server .stop )
59+ return server
60+
61+
3662@pytest .fixture
3763def http_client (http_server ):
3864 return ipfshttpclient .http .ClientSync (
3965 "/ip4/{0}/tcp/{1}/http" .format (* http_server .server_address ),
40- ipfshttpclient .DEFAULT_BASE
66+ ipfshttpclient .DEFAULT_BASE ,
67+ )
68+
69+
70+ @pytest .fixture
71+ def http_client_uds (http_server_uds ):
72+ return ipfshttpclient .http .ClientSync (
73+ "/unix/{0}" .format (http_server_uds .server_address .lstrip ("/" )),
74+ ipfshttpclient .DEFAULT_BASE ,
4175 )
4276
4377
4478def broken_http_server_app (environ , start_response ):
45- """
46- HTTP server application that will be slower to respond (0.5 seconds)
47- """
79+ """HTTP server application that will return a malformed response"""
4880 start_response ("0 What the heck?" , [])
4981
5082 yield b""
@@ -58,9 +90,7 @@ def broken_http_server(request):
5890
5991
6092def slow_http_server_app (environ , start_response ):
61- """
62- HTTP server application that will be slower to respond (0.5 seconds)
63- """
93+ """HTTP server application that will be slower to respond (0.5 seconds)"""
6494 start_response ("400 Bad Request" , [
6595 ("Content-Type" , "text/json" )
6696 ])
@@ -86,13 +116,28 @@ def test_successful_request(http_client, http_server):
86116 res = http_client .request ("/okay" )
87117 assert res == b"okay"
88118
119+ def test_successful_request_uds (http_client_uds , http_server_uds ):
120+ """Tests that a successful http request returns the proper message."""
121+ http_server_uds .serve_content ("okay" , 200 )
122+
123+ res = http_client_uds .request ("/okay" )
124+ assert res == b"okay"
125+ print (http_server_uds .requests [0 ].headers )
126+
89127def test_generic_failure (http_client , http_server ):
90128 """Tests that a failed http request raises an HTTPError."""
91129 http_server .serve_content ("fail" , 500 )
92130
93131 with pytest .raises (ipfshttpclient .exceptions .StatusError ):
94132 http_client .request ("/fail" )
95133
134+ def test_generic_failure_uds (http_client_uds , http_server_uds ):
135+ """Tests that a failed http request raises an HTTPError."""
136+ http_server_uds .serve_content ("fail" , 500 )
137+
138+ with pytest .raises (ipfshttpclient .exceptions .StatusError ):
139+ http_client_uds .request ("/fail" )
140+
96141def test_http_client_failure (http_client , http_server ):
97142 """Tests that an http client failure raises an ipfsHTTPClientError."""
98143 http_server .serve_content (json .dumps ({
@@ -366,26 +411,33 @@ def test_readable_stream_wrapper_read_single_bytes(mocker):
366411
367412@pytest .mark .parametrize ("args,expected" , [
368413 (("/dns/localhost/tcp/5001" , "api/v0" ),
369- ("http://localhost:5001/api/v0/" , socket .AF_UNSPEC , False )),
414+ ("http://localhost:5001/api/v0/" , None , socket .AF_UNSPEC , False )),
370415
371416 (("/dns/localhost/tcp/5001/http" , "api/v0" ),
372- ("http://localhost:5001/api/v0/" , socket .AF_UNSPEC , False )),
417+ ("http://localhost:5001/api/v0/" , None , socket .AF_UNSPEC , False )),
373418
374419 (("/dns4/localhost/tcp/5001/http" , "api/v0" ),
375- ("http://localhost:5001/api/v0/" , socket .AF_INET , False )),
420+ ("http://localhost:5001/api/v0/" , None , socket .AF_INET , False )),
376421
377422 (("/dns6/localhost/tcp/5001/http" , "api/v0/" ),
378- ("http://localhost:5001/api/v0/" , socket .AF_INET6 , False )),
423+ ("http://localhost:5001/api/v0/" , None , socket .AF_INET6 , False )),
379424
380425 (("/ip4/127.0.0.1/tcp/5001/https" , "api/v1/" ),
381- ("https://127.0.0.1:5001/api/v1/" , socket .AF_INET , True )),
426+ ("https://127.0.0.1:5001/api/v1/" , None , socket .AF_INET , True )),
382427
383428 (("/ip6/::1/tcp/5001/https" , "api/v1" ),
384- ("https://[::1]:5001/api/v1/" , socket .AF_INET6 , True )),
429+ ("https://[::1]:5001/api/v1/" , None , socket .AF_INET6 , True )),
385430
386431 (("/dns4/ietf.org/tcp/443/https" , "/base/" ),
387- ("https://ietf.org:443/base/" , socket .AF_INET , False )),
388- ])
432+ ("https://ietf.org:443/base/" , None , socket .AF_INET , False )),
433+ ] + ([ # Unix domain sockets aren't supported on all target platforms
434+ (("/unix/run/ipfs/ipfs.sock" , "api/v0" ),
435+ ("http://%2Frun%2Fipfs%2Fipfs.sock/api/v0/" , "/run/ipfs/ipfs.sock" , socket .AF_UNIX , False )),
436+ # Stupid, but standard behaviour: There is no way to append a target protocol item, after
437+ # a path protocol like /unix, so terminating it with /https ends up part of the /unix path
438+ (("/unix/run/ipfs/ipfs.sock/https" , "api/v0" ),
439+ ("http://%2Frun%2Fipfs%2Fipfs.sock%2Fhttps/api/v0/" , "/run/ipfs/ipfs.sock/https" , socket .AF_UNIX , False )),
440+ ] if hasattr (socket , "AF_UNIX" ) else []))
389441def test_multiaddr_to_url_data (args , expected ):
390442 assert ipfshttpclient .http_common .multiaddr_to_url_data (* args ) == expected
391443
@@ -395,12 +447,18 @@ def test_multiaddr_to_url_data(args, expected):
395447 ("/ip4/192.168.250.1/tcp/4001/p2p/QmVgNoP89mzpgEAAqK8owYoDEyB97MkcGvoWZir8otE9Uc" , "api/v1/" ),
396448 ("/ip4/::1/sctp/5001/https" , "api/v1/" ),
397449 ("/sctp/5001/http" , "api/v0" ),
450+ ("/unix" , "api/v0" ),
451+
452+ # Should work, but needs support in py-multiaddr first (tls protocol)
453+ ("/ip6/::1/tcp/5001/tls/http" , "api/v1" ),
398454
399- # Should work, but currently doesn't (no proxy support)
400- ("/dns/localhost/tcp/5001/socks5/dns/ietf.org/tcp/80/http" , "/base/" ),
401- ("/dns/proxy-servers.example/tcp/5001/https/dns/ietf.org/tcp/80/http" , "/base/" ),
455+ # Should work, but needs support in py-multiaddr first (proxying protocols)
456+ ("/dns/localhost/tcp/1080/socks5/dns/ietf.org/tcp/80/http" , "/base/" ),
457+ ("/dns/localhost/tcp/1080/socks5/ip6/2001:1234:5678:9ABC::1/tcp/80/http" , "/base/" ),
458+ ("/dns/localhost/tcp/80/http-tunnel/dns/mgnt.my-server.example/tcp/443/https" , "/srv/ipfs/api/v0" ),
459+ ("/dns/proxy-servers.example/tcp/443/tls/http-tunnel/dns/my-server.example/tcp/5001/http" , "/base/" ),
402460
403- # Maybe should also work, but currently doesn't (HTTP/3)
461+ # Maybe should also work eventually , but currently doesn't (HTTP/3)
404462 ("/dns/localhost/udp/5001/quic/http" , "/base" ),
405463])
406464def test_multiaddr_to_url_data_invalid (args ):
0 commit comments