From 59a592f4c43a1a7a1814951ecc5f41896cabd05d Mon Sep 17 00:00:00 2001 From: a_m0d Date: Thu, 1 Nov 2012 23:29:46 -0400 Subject: [PATCH 1/3] Add end_of_file handling to TcpBufferedSocket. This fixes #3891. Also removed debug!(...) statement from socket destructor which causes a crash when the logging level is set to debug. --- src/libstd/net_tcp.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 942d52a3ad6b7..a2c3c77eba32f 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -48,11 +48,13 @@ pub fn TcpSocket(socket_data: @TcpSocketData) -> TcpSocket { */ struct TcpSocketBuf { data: @TcpBufferedSocketData, + mut end_of_stream: bool, } pub fn TcpSocketBuf(data: @TcpBufferedSocketData) -> TcpSocketBuf { TcpSocketBuf { - data: data + data: data, + end_of_stream: false } } @@ -782,6 +784,7 @@ impl TcpSocketBuf: io::Reader { let err_data = read_result.get_err(); if err_data.err_name == ~"EOF" { + self.end_of_stream = true; break; } else { debug!("ERROR sock_buf as io::reader.read err %? %?", @@ -808,13 +811,21 @@ impl TcpSocketBuf: io::Reader { } fn read_byte() -> int { let mut bytes = ~[0]; - if self.read(bytes, 1u) == 0 { fail } else { bytes[0] as int } + if self.read(bytes, 1u) == 0 { + if self.end_of_stream { + -1 + } else { + fail + } + } else { + bytes[0] as int + } } fn unread_byte(amt: int) { self.data.buf.unshift(amt as u8); } fn eof() -> bool { - false // noop + self.end_of_stream } fn seek(dist: int, seek: io::SeekStyle) { log(debug, fmt!("tcp_socket_buf seek stub %? %?", dist, seek)); @@ -871,7 +882,8 @@ fn tear_down_socket_data(socket_data: @TcpSocketData) unsafe { uv::ll::close(stream_handle_ptr, tcp_socket_dtor_close_cb); }; core::comm::recv(closed_po); - log(debug, fmt!("about to free socket_data at %?", socket_data)); + //the line below will most likely crash + //log(debug, fmt!("about to free socket_data at %?", socket_data)); rustrt::rust_uv_current_kernel_free(stream_handle_ptr as *libc::c_void); log(debug, ~"exiting dtor for tcp_socket"); From d42cf97bcc6110be8a8b2ec02669230b265332dd Mon Sep 17 00:00:00 2001 From: a_m0d Date: Tue, 6 Nov 2012 19:16:01 -0500 Subject: [PATCH 2/3] Fix trailing whitespace issues --- src/libstd/net_tcp.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index a2c3c77eba32f..0131c482f58da 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -813,12 +813,12 @@ impl TcpSocketBuf: io::Reader { let mut bytes = ~[0]; if self.read(bytes, 1u) == 0 { if self.end_of_stream { - -1 + -1 } else { fail } - } else { - bytes[0] as int + } else { + bytes[0] as int } } fn unread_byte(amt: int) { From 062ac8cb97fef80a370ef884c468c66c4c9d30e3 Mon Sep 17 00:00:00 2001 From: a_m0d Date: Wed, 7 Nov 2012 23:49:01 -0500 Subject: [PATCH 3/3] Fix whitespace issues from previous commits. Also added test for #3891. --- src/libstd/net_tcp.rs | 50 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/src/libstd/net_tcp.rs b/src/libstd/net_tcp.rs index 0131c482f58da..ea77949a45964 100644 --- a/src/libstd/net_tcp.rs +++ b/src/libstd/net_tcp.rs @@ -811,7 +811,7 @@ impl TcpSocketBuf: io::Reader { } fn read_byte() -> int { let mut bytes = ~[0]; - if self.read(bytes, 1u) == 0 { + if self.read(bytes, 1u) == 0 { if self.end_of_stream { -1 } else { @@ -1280,7 +1280,10 @@ mod test { fn test_gl_tcp_ipv4_server_client_reader_writer() { impl_gl_tcp_ipv4_server_client_reader_writer(); } - + #[test] + fn test_tcp_socket_impl_reader_handles_eof() { + impl_tcp_socket_impl_reader_handles_eof(); + } } #[cfg(target_arch="x86")] mod impl32 { @@ -1553,6 +1556,49 @@ mod test { */ } + fn impl_tcp_socket_impl_reader_handles_eof() { + use io::{Reader,ReaderUtil}; + let hl_loop = uv::global_loop::get(); + let server_ip = ~"127.0.0.1"; + let server_port = 10041u; + let expected_req = ~"GET /"; + let expected_resp = ~"A string\nwith multiple lines\n"; + + let server_result_po = core::comm::Port::<~str>(); + let server_result_ch = core::comm::Chan(&server_result_po); + + let cont_po = core::comm::Port::<()>(); + let cont_ch = core::comm::Chan(&cont_po); + // server + do task::spawn_sched(task::ManualThreads(1u)) { + let actual_req = do comm::listen |server_ch| { + run_tcp_test_server( + server_ip, + server_port, + expected_resp, + server_ch, + cont_ch, + hl_loop) + }; + server_result_ch.send(actual_req); + }; + core::comm::recv(cont_po); + // client + log(debug, ~"server started, firing up client.."); + let server_addr = ip::v4::parse_addr(server_ip); + let conn_result = connect(server_addr, server_port, hl_loop); + if result::is_err(&conn_result) { + assert false; + } + let sock_buf = @socket_buf(result::unwrap(move conn_result)); + buf_write(sock_buf, expected_req); + + let buf_reader = sock_buf as Reader; + let actual_response = str::from_bytes(buf_reader.read_whole_stream()); + log(debug, fmt!("Actual response: %s", actual_response)); + assert expected_resp == actual_response; + } + fn buf_write(w: &W, val: &str) { log(debug, fmt!("BUF_WRITE: val len %?", str::len(val))); do str::byte_slice(val) |b_slice| {