diff --git a/vlib/net/address.c.v b/vlib/net/address.c.v index 3f8c5cf600664a..bc861850cfc6f5 100644 --- a/vlib/net/address.c.v +++ b/vlib/net/address.c.v @@ -163,17 +163,20 @@ pub fn resolve_addrs_fuzzy(addr string, @type SocketType) ![]Addr { // resolve_ipaddrs converts the given `addr`, `family` and `typ` to a list of addresses pub fn resolve_ipaddrs(addr string, family AddrFamily, typ SocketType) ![]Addr { - address, port := split_address(addr)! + mut address, port := split_address(addr)! - if addr[0] == `:` { + if address.starts_with('[') && address.ends_with(']') { + address = address[1..address.len - 1] + } + + // This is to allow a ":8080" shorthand notation similar to HTTPie + // [URL shortcuts for localhost](https://httpie.io/docs/cli/url-shortcuts-for-localhost) + // and (net.Dial)(https://pkg.go.dev/net#Dial) in Go. + if address == '' { match family { - .ip6 { - return [new_ip6(port, net.addr_ip6_any)] - } - .ip, .unspec { - return [new_ip(port, net.addr_ip_any)] - } - else {} + .ip6 { return [new_ip6(port, addr_ip6_any)] } + .ip, .unspec { return [new_ip(port, addr_ip_any)] } + .unix { error('unix address must not be empty') } } } diff --git a/vlib/net/http/server_test.v b/vlib/net/http/server_test.v index 098e3260513e1c..11c1eb5559f292 100644 --- a/vlib/net/http/server_test.v +++ b/vlib/net/http/server_test.v @@ -127,21 +127,21 @@ fn test_server_custom_handler() { } t := spawn server.listen_and_serve() server.wait_till_running()! - x := http.fetch(url: 'http://${server.addr}/endpoint?abc=xyz', data: 'my data')! + x := http.fetch(url: 'http://127.0.0.1:${cport}/endpoint?abc=xyz', data: 'my data')! assert x.body == 'my data, /endpoint?abc=xyz' assert x.status_code == 200 assert x.status_msg == 'OK' assert x.http_version == '1.1' - y := http.fetch(url: 'http://${server.addr}/another/endpoint', data: 'abcde')! + y := http.fetch(url: 'http://127.0.0.1:${cport}/another/endpoint', data: 'abcde')! assert y.body == 'abcde, /another/endpoint' assert y.status_code == 200 assert x.status_msg == 'OK' assert y.status() == .ok assert y.http_version == '1.1' // - http.fetch(url: 'http://${server.addr}/something/else')! + http.fetch(url: 'http://127.0.0.1:${cport}/something/else')! // - big_url := 'http://${server.addr}/redirect_to_big' + big_url := 'http://127.0.0.1:${cport}/redirect_to_big' mut progress_calls := &ProgressCalls{} z := http.fetch( url: big_url @@ -174,7 +174,7 @@ fn test_server_custom_handler() { assert progress_calls.chunks[0].bytestr().starts_with('HTTP/1.1 301 Moved permanently') assert progress_calls.chunks[1].bytestr().starts_with('HTTP/1.1 200 OK') assert progress_calls.chunks.last().bytestr().contains('xyz def') - assert progress_calls.redirected_to == ['http://${server.addr}/big'] + assert progress_calls.redirected_to == ['http://127.0.0.1:${cport}/big'] // server.stop() t.wait() @@ -232,7 +232,8 @@ fn test_my_counting_handler_on_random_port() { on_running: fn (mut server http.Server) { spawn fn (mut server http.Server) { log.warn('server started') - url := 'http://${server.addr}/count' + _, server_port := net.split_address(server.addr) or { panic(err) } + url := 'http://127.0.0.1:${server_port}/count' log.info('fetching from url: ${url}') for _ in 0 .. 5 { x := http.fetch(url: url, data: 'my data') or { panic(err) } diff --git a/vlib/net/tcp.c.v b/vlib/net/tcp.c.v index 8943fc8a75e484..a108104e0a4d68 100644 --- a/vlib/net/tcp.c.v +++ b/vlib/net/tcp.c.v @@ -21,15 +21,6 @@ mut: pub fn dial_tcp(oaddress string) !&TcpConn { mut address := oaddress - $if windows { - // resolving 0.0.0.0 to localhost, works on linux and macos, but not on windows, so try to emulate it: - if address.starts_with(':::') { - address = address.replace_once(':::', 'localhost:') - } - if address.starts_with('0.0.0.0:') { - address = address.replace_once('0.0.0.0:', 'localhost:') - } - } addrs := resolve_addrs_fuzzy(address, .tcp) or { return error('${err.msg()}; could not resolve address ${address} in dial_tcp') } diff --git a/vlib/net/tcp_test.v b/vlib/net/tcp_test.v index f0141aeb160586..6f4b5238396b83 100644 --- a/vlib/net/tcp_test.v +++ b/vlib/net/tcp_test.v @@ -1,20 +1,17 @@ -// vtest flaky: true -// vtest retry: 8 import net -import os const test_port = 45123 -fn handle_conn(mut c net.TcpConn) { +fn handle_conn(mut c net.TcpConn) ! { for { mut buf := []u8{len: 100, init: 0} read := c.read(mut buf) or { - println('Server: connection dropped') - return + eprintln('Server: connection dropped') + return err } c.write(buf[..read]) or { - println('Server: connection dropped') - return + eprintln('Server: connection dropped') + return err } } } @@ -24,40 +21,45 @@ fn one_shot_echo_server(mut l net.TcpListener, ch_started chan int) ! { ch_started <- 1 mut new_conn := l.accept() or { return error('could not accept') } eprintln(' > new_conn: ${new_conn}') - handle_conn(mut new_conn) - new_conn.close() or {} + handle_conn(mut new_conn)! + new_conn.close()! } fn echo(address string) ! { mut c := net.dial_tcp(address)! - defer { - c.close() or {} - } - println('local: ' + c.addr()!.str()) - println(' peer: ' + c.peer_addr()!.str()) + eprintln('local: ' + c.addr()!.str()) + eprintln(' peer: ' + c.peer_addr()!.str()) data := 'Hello from vlib/net!' c.write_string(data)! mut buf := []u8{len: 4096} - read := c.read(mut buf) or { panic(err) } + read := c.read(mut buf)! assert read == data.len for i := 0; i < read; i++ { assert buf[i] == data[i] } - println('Got "${buf.bytestr()}"') + c.close()! } fn test_tcp_ip6() { eprintln('\n>>> ${@FN}') - address := 'localhost:${test_port}' - mut l := net.listen_tcp(.ip6, ':${test_port}') or { panic(err) } + address := ':${test_port}' + mut l := net.listen_tcp(.ip6, address)! dump(l) start_echo_server(mut l) - echo(address) or { panic(err) } - l.close() or {} - // ensure there is at least one new socket created before the next test - l = net.listen_tcp(.ip6, ':${test_port + 1}') or { panic(err) } + echo(address)! + l.close()! +} + +fn test_tcp_ip6_localhost() { + eprintln('\n>>> ${@FN}') + address := '[::1]:${test_port}' + mut l := net.listen_tcp(.ip6, address)! + dump(l) + start_echo_server(mut l) + echo(address)! + l.close()! } fn start_echo_server(mut l net.TcpListener) { @@ -68,31 +70,31 @@ fn start_echo_server(mut l net.TcpListener) { fn test_tcp_ip() { eprintln('\n>>> ${@FN}') - address := 'localhost:${test_port}' - mut l := net.listen_tcp(.ip, address) or { panic(err) } + address := ':${test_port}' + mut l := net.listen_tcp(.ip, address)! dump(l) start_echo_server(mut l) - echo(address) or { panic(err) } - l.close() or {} + echo(address)! + l.close()! } -fn test_tcp_unix() { +fn test_tcp_ip_localhost() { eprintln('\n>>> ${@FN}') - // TODO(emily): - // whilst windows supposedly supports unix sockets - // this doesnt work (wsaeopnotsupp at the call to bind()) - $if !windows { - address := os.real_path('tcp-test.sock') - // address := 'tcp-test.sock' - println('${address}') + address := '127.0.0.1:${test_port}' + mut l := net.listen_tcp(.ip, address)! + dump(l) + start_echo_server(mut l) + echo(address)! + l.close()! +} - mut l := net.listen_tcp(.unix, address) or { panic(err) } - start_echo_server(mut l) - echo(address) or { panic(err) } - l.close() or {} +fn test_tcp_unix() { + eprintln('\n>>> ${@FN}') + address := 'tcp-test.sock' + eprintln('${address}') - os.rm(address) or { panic('failed to remove socket file') } - } + mut l := net.listen_tcp(.unix, address) or { return } + assert false } fn testsuite_end() {