0
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2025-03-03 09:31:22 -05:00

stabilize net Addr (#3709)

Co-authored-by: xiaoxintang <15707971810@163.com>
This commit is contained in:
Bartek Iwańczuk 2020-01-18 21:49:55 +01:00 committed by GitHub
parent 34b99fec8e
commit 23e67eb515
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 86 deletions

View file

@ -1307,8 +1307,8 @@ declare namespace Deno {
interface Addr {
transport: Transport;
/** UNSTABLE: Address is unstable because inconsistent with ConnectOptions. */
address: string;
hostname: string;
port: number;
}
/** UNSTABLE: Maybe remove ShutdownMode entirely. */
@ -1342,21 +1342,19 @@ declare namespace Deno {
*/
close(): void;
/** Return the address of the `Listener`. */
addr(): Addr;
addr: Addr;
[Symbol.asyncIterator](): AsyncIterator<Conn>;
}
export interface Conn extends Reader, Writer, Closer {
/** UNSTABLE: return Addr?
*
/**
* The local address of the connection.
*/
localAddr: string;
/** UNSTABLE: return Addr?
*
localAddr: Addr;
/**
* The remote address of the connection.
*/
remoteAddr: string;
remoteAddr: Addr;
/** The resource ID of the connection. */
rid: number;
/** Shuts down (`shutdown(2)`) the reading side of the TCP connection. Most
@ -1426,7 +1424,7 @@ declare namespace Deno {
}
/**
* Dial connects to the address on the named transport.
* Connects to the address on the named transport.
*
* @param options
* @param options.port The port to connect to. (Required.)

View file

@ -8,11 +8,10 @@ export type Transport = "tcp";
// TODO support other types:
// export type Transport = "tcp" | "tcp4" | "tcp6" | "unix" | "unixpacket";
// TODO(ry) Replace 'address' with 'hostname' and 'port', similar to ConnectOptions
// and ListenOptions.
export interface Addr {
transport: Transport;
address: string;
hostname: string;
port: number;
}
/** A Listener is a generic transport listener for stream-oriented protocols. */
@ -26,7 +25,7 @@ export interface Listener extends AsyncIterator<Conn> {
close(): void;
/** Return the address of the `Listener`. */
addr(): Addr;
addr: Addr;
[Symbol.asyncIterator](): AsyncIterator<Conn>;
}
@ -54,8 +53,8 @@ export function shutdown(rid: number, how: ShutdownMode): void {
export class ConnImpl implements Conn {
constructor(
readonly rid: number,
readonly remoteAddr: string,
readonly localAddr: string
readonly remoteAddr: Addr,
readonly localAddr: Addr
) {}
write(p: Uint8Array): Promise<number> {
@ -88,8 +87,7 @@ export class ConnImpl implements Conn {
export class ListenerImpl implements Listener {
constructor(
readonly rid: number,
private transport: Transport,
private localAddr: string,
public addr: Addr,
private closing: boolean = false
) {}
@ -103,13 +101,6 @@ export class ListenerImpl implements Listener {
close(this.rid);
}
addr(): Addr {
return {
transport: this.transport,
address: this.localAddr
};
}
async next(): Promise<IteratorResult<Conn>> {
if (this.closing) {
return { value: undefined, done: true };
@ -134,9 +125,9 @@ export class ListenerImpl implements Listener {
export interface Conn extends Reader, Writer, Closer {
/** The local address of the connection. */
localAddr: string;
localAddr: Addr;
/** The remote address of the connection. */
remoteAddr: string;
remoteAddr: Addr;
/** The resource ID of the connection. */
rid: number;
/** Shuts down (`shutdown(2)`) the reading side of the TCP connection. Most
@ -175,12 +166,13 @@ export interface ListenOptions {
export function listen(options: ListenOptions): Listener {
const hostname = options.hostname || "0.0.0.0";
const transport = options.transport || "tcp";
const res = sendSync(dispatch.OP_LISTEN, {
hostname,
port: options.port,
transport
});
return new ListenerImpl(res.rid, transport, res.localAddr);
return new ListenerImpl(res.rid, res.localAddr);
}
export interface ConnectOptions {
@ -189,7 +181,9 @@ export interface ConnectOptions {
transport?: Transport;
}
/** Dial connects to the address on the named transport.
const connectDefaults = { hostname: "127.0.0.1", transport: "tcp" };
/** Connects to the address on the named transport.
*
* @param options
* @param options.port The port to connect to. (Required.)
@ -207,10 +201,7 @@ export interface ConnectOptions {
* connect({ hostname: "golang.org", port: 80, transport: "tcp" })
*/
export async function connect(options: ConnectOptions): Promise<Conn> {
const res = await sendAsync(dispatch.OP_CONNECT, {
hostname: options.hostname || "127.0.0.1",
port: options.port,
transport: options.transport || "tcp"
});
options = Object.assign(connectDefaults, options);
const res = await sendAsync(dispatch.OP_CONNECT, options);
return new ConnImpl(res.rid, res.remoteAddr!, res.localAddr!);
}

View file

@ -3,11 +3,9 @@ import { testPerm, assert, assertEquals } from "./test_util.ts";
testPerm({ net: true }, function netListenClose(): void {
const listener = Deno.listen({ hostname: "127.0.0.1", port: 4500 });
const addr = listener.addr();
assertEquals(addr.transport, "tcp");
// TODO(ry) Replace 'address' with 'hostname' and 'port', similar to
// ConnectOptions and ListenOptions.
assertEquals(addr.address, "127.0.0.1:4500");
assertEquals(listener.addr.transport, "tcp");
assertEquals(listener.addr.hostname, "127.0.0.1");
assertEquals(listener.addr.port, 4500);
listener.close();
});
@ -52,13 +50,15 @@ testPerm({ net: true }, async function netDialListen(): Promise<void> {
listener.accept().then(
async (conn): Promise<void> => {
assert(conn.remoteAddr != null);
assertEquals(conn.localAddr, "127.0.0.1:4500");
assertEquals(conn.localAddr.hostname, "127.0.0.1");
assertEquals(conn.localAddr.port, 4500);
await conn.write(new Uint8Array([1, 2, 3]));
conn.close();
}
);
const conn = await Deno.connect({ hostname: "127.0.0.1", port: 4500 });
assertEquals(conn.remoteAddr, "127.0.0.1:4500");
assertEquals(conn.remoteAddr.hostname, "127.0.0.1");
assertEquals(conn.remoteAddr.port, 4500);
assert(conn.localAddr != null);
const buf = new Uint8Array(1024);
const readResult = await conn.read(buf);

View file

@ -6,6 +6,7 @@ import { Listener, Transport, Conn, ConnImpl, ListenerImpl } from "./net.ts";
// TODO(ry) There are many configuration options to add...
// https://docs.rs/rustls/0.16.0/rustls/struct.ClientConfig.html
interface ConnectTLSOptions {
transport?: Transport;
port: number;
hostname?: string;
certFile?: string;
@ -59,5 +60,5 @@ export function listenTLS(options: ListenTLSOptions): Listener {
certFile: options.certFile,
keyFile: options.keyFile
});
return new TLSListenerImpl(res.rid, transport, res.localAddr);
return new TLSListenerImpl(res.rid, res.localAddr);
}

View file

@ -117,8 +117,16 @@ fn op_accept(
table.add("tcpStream", Box::new(StreamResource::TcpStream(tcp_stream)));
Ok(json!({
"rid": rid,
"localAddr": local_addr.to_string(),
"remoteAddr": remote_addr.to_string(),
"localAddr": {
"hostname": local_addr.ip().to_string(),
"port": local_addr.port(),
"transport": "tcp",
},
"remoteAddr": {
"hostname": remote_addr.ip().to_string(),
"port": remote_addr.port(),
"transport": "tcp",
}
}))
};
@ -152,8 +160,16 @@ fn op_connect(
table.add("tcpStream", Box::new(StreamResource::TcpStream(tcp_stream)));
Ok(json!({
"rid": rid,
"localAddr": local_addr.to_string(),
"remoteAddr": remote_addr.to_string(),
"localAddr": {
"hostname": local_addr.ip().to_string(),
"port": local_addr.port(),
"transport": args.transport,
},
"remoteAddr": {
"hostname": remote_addr.ip().to_string(),
"port": remote_addr.port(),
"transport": args.transport,
}
}))
};
@ -272,7 +288,6 @@ fn op_listen(
futures::executor::block_on(resolve_addr(&args.hostname, args.port))?;
let listener = futures::executor::block_on(TcpListener::bind(&addr))?;
let local_addr = listener.local_addr()?;
let local_addr_str = local_addr.to_string();
let listener_resource = TcpListenerResource {
listener,
waker: None,
@ -280,10 +295,19 @@ fn op_listen(
};
let mut table = state.lock_resource_table();
let rid = table.add("tcpListener", Box::new(listener_resource));
debug!("New listener {} {}", rid, local_addr_str);
debug!(
"New listener {} {}:{}",
rid,
local_addr.ip().to_string(),
local_addr.port()
);
Ok(JsonOp::Sync(json!({
"rid": rid,
"localAddr": local_addr_str,
"localAddr": {
"hostname": local_addr.ip().to_string(),
"port": local_addr.port(),
"transport": args.transport,
},
})))
}

View file

@ -53,6 +53,7 @@ pub fn init(i: &mut Isolate, s: &ThreadSafeState) {
#[derive(Deserialize)]
#[serde(rename_all = "camelCase")]
struct ConnectTLSArgs {
transport: String,
hostname: String,
port: u16,
cert_file: Option<String>,
@ -101,8 +102,16 @@ pub fn op_connect_tls(
);
Ok(json!({
"rid": rid,
"localAddr": local_addr.to_string(),
"remoteAddr": remote_addr.to_string(),
"localAddr": {
"hostname": local_addr.ip().to_string(),
"port": local_addr.port(),
"transport": args.transport,
},
"remoteAddr": {
"hostname": remote_addr.ip().to_string(),
"port": remote_addr.port(),
"transport": args.transport,
}
}))
};
@ -257,7 +266,6 @@ fn op_listen_tls(
futures::executor::block_on(resolve_addr(&args.hostname, args.port))?;
let listener = futures::executor::block_on(TcpListener::bind(&addr))?;
let local_addr = listener.local_addr()?;
let local_addr_str = local_addr.to_string();
let tls_listener_resource = TlsListenerResource {
listener,
tls_acceptor,
@ -269,7 +277,11 @@ fn op_listen_tls(
Ok(JsonOp::Sync(json!({
"rid": rid,
"localAddr": local_addr_str
"localAddr": {
"hostname": local_addr.ip().to_string(),
"port": local_addr.port(),
"transport": args.transport,
},
})))
}
@ -371,8 +383,16 @@ fn op_accept_tls(
};
Ok(json!({
"rid": rid,
"localAddr": local_addr.to_string(),
"remoteAddr": remote_addr.to_string(),
"localAddr": {
"transport": "tcp",
"hostname": local_addr.ip().to_string(),
"port": local_addr.port()
},
"remoteAddr": {
"transport": "tcp",
"hostname": remote_addr.ip().to_string(),
"port": remote_addr.port()
}
}))
};

View file

@ -41,6 +41,29 @@ const dec = new TextDecoder();
type Handler = () => void;
const mockConn = {
localAddr: {
transport: "tcp",
hostname: "",
port: 0
},
remoteAddr: {
transport: "tcp",
hostname: "",
port: 0
},
rid: -1,
closeRead: (): void => {},
closeWrite: (): void => {},
read: async (): Promise<number | Deno.EOF> => {
return 0;
},
write: async (): Promise<number> => {
return -1;
},
close: (): void => {}
};
const responseTests: ResponseTest[] = [
// Default response
{
@ -75,20 +98,7 @@ test(async function responseWrite(): Promise<void> {
const request = new ServerRequest();
request.w = bufw;
request.conn = {
localAddr: "",
remoteAddr: "",
rid: -1,
closeRead: (): void => {},
closeWrite: (): void => {},
read: async (): Promise<number | Deno.EOF> => {
return 0;
},
write: async (): Promise<number> => {
return -1;
},
close: (): void => {}
};
request.conn = mockConn as Deno.Conn;
await request.respond(testCase.response);
assertEquals(buf.toString(), testCase.raw);
@ -416,21 +426,6 @@ test(async function writeStringReaderResponse(): Promise<void> {
assertEquals(r.more, false);
});
const mockConn = {
localAddr: "",
remoteAddr: "",
rid: -1,
closeRead: (): void => {},
closeWrite: (): void => {},
read: async (): Promise<number | Deno.EOF> => {
return 0;
},
write: async (): Promise<number> => {
return -1;
},
close: (): void => {}
};
test(async function readRequestError(): Promise<void> {
const input = `GET / HTTP/1.1
malformedHeader
@ -438,7 +433,7 @@ malformedHeader
const reader = new BufReader(new StringReader(input));
let err;
try {
await readRequest(mockConn, reader);
await readRequest(mockConn as Deno.Conn, reader);
} catch (e) {
err = e;
}
@ -517,7 +512,7 @@ test(async function testReadRequestError(): Promise<void> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
let req: any;
try {
req = await readRequest(mockConn, reader);
req = await readRequest(mockConn as Deno.Conn, reader);
} catch (e) {
err = e;
}