client/*: Treat protocol name as str and not [u8] (#6967)

* client/*: Treat protocol name as str and not [u8]

Notification protocol names are in practice always valid utf8 strings.
Instead of treating them as such in the type system, thus far they were
casted to a [u8] at creation time.

With this commit protocol names are instead treated as valid utf8
strings throughout the codebase and passed as `Cow<'static, str>`
instead of `Cow<'static, [u8]>`. Among other things this eliminates the
need for string casting when logging.

* client/network: Don't allocate when protocol name is borrowed
This commit is contained in:
Max Inden
2020-08-28 17:34:25 +02:00
committed by GitHub
parent ff1e8150e1
commit 8fd343e39d
16 changed files with 87 additions and 76 deletions
@@ -50,7 +50,7 @@ const MAX_HANDSHAKE_SIZE: usize = 1024;
#[derive(Debug, Clone)]
pub struct NotificationsIn {
/// Protocol name to use when negotiating the substream.
protocol_name: Cow<'static, [u8]>,
protocol_name: Cow<'static, str>,
}
/// Upgrade that opens a substream, waits for the remote to accept by sending back a status
@@ -58,7 +58,7 @@ pub struct NotificationsIn {
#[derive(Debug, Clone)]
pub struct NotificationsOut {
/// Protocol name to use when negotiating the substream.
protocol_name: Cow<'static, [u8]>,
protocol_name: Cow<'static, str>,
/// Message to send when we start the handshake.
initial_message: Vec<u8>,
}
@@ -100,14 +100,14 @@ pub struct NotificationsOutSubstream<TSubstream> {
impl NotificationsIn {
/// Builds a new potential upgrade.
pub fn new(protocol_name: impl Into<Cow<'static, [u8]>>) -> Self {
pub fn new(protocol_name: impl Into<Cow<'static, str>>) -> Self {
NotificationsIn {
protocol_name: protocol_name.into(),
}
}
/// Returns the name of the protocol that we accept.
pub fn protocol_name(&self) -> &[u8] {
pub fn protocol_name(&self) -> &Cow<'static, str> {
&self.protocol_name
}
}
@@ -117,7 +117,11 @@ impl UpgradeInfo for NotificationsIn {
type InfoIter = iter::Once<Self::Info>;
fn protocol_info(&self) -> Self::InfoIter {
iter::once(self.protocol_name.clone())
let bytes: Cow<'static, [u8]> = match &self.protocol_name {
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
Cow::Owned(s) => Cow::Owned(s.as_bytes().to_vec())
};
iter::once(bytes)
}
}
@@ -244,7 +248,7 @@ where TSubstream: AsyncRead + AsyncWrite + Unpin,
impl NotificationsOut {
/// Builds a new potential upgrade.
pub fn new(protocol_name: impl Into<Cow<'static, [u8]>>, initial_message: impl Into<Vec<u8>>) -> Self {
pub fn new(protocol_name: impl Into<Cow<'static, str>>, initial_message: impl Into<Vec<u8>>) -> Self {
let initial_message = initial_message.into();
if initial_message.len() > MAX_HANDSHAKE_SIZE {
error!(target: "sub-libp2p", "Outbound networking handshake is above allowed protocol limit");
@@ -262,7 +266,11 @@ impl UpgradeInfo for NotificationsOut {
type InfoIter = iter::Once<Self::Info>;
fn protocol_info(&self) -> Self::InfoIter {
iter::once(self.protocol_name.clone())
let bytes: Cow<'static, [u8]> = match &self.protocol_name {
Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()),
Cow::Owned(s) => Cow::Owned(s.as_bytes().to_vec())
};
iter::once(bytes)
}
}
@@ -378,10 +386,11 @@ mod tests {
use async_std::net::{TcpListener, TcpStream};
use futures::{prelude::*, channel::oneshot};
use libp2p::core::upgrade;
use std::borrow::Cow;
#[test]
fn basic_works() {
const PROTO_NAME: &'static [u8] = b"/test/proto/1";
const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1");
let (listener_addr_tx, listener_addr_rx) = oneshot::channel();
let client = async_std::task::spawn(async move {
@@ -420,7 +429,7 @@ mod tests {
fn empty_handshake() {
// Check that everything still works when the handshake messages are empty.
const PROTO_NAME: &'static [u8] = b"/test/proto/1";
const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1");
let (listener_addr_tx, listener_addr_rx) = oneshot::channel();
let client = async_std::task::spawn(async move {
@@ -457,7 +466,7 @@ mod tests {
#[test]
fn refused() {
const PROTO_NAME: &'static [u8] = b"/test/proto/1";
const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1");
let (listener_addr_tx, listener_addr_rx) = oneshot::channel();
let client = async_std::task::spawn(async move {
@@ -495,7 +504,7 @@ mod tests {
#[test]
fn large_initial_message_refused() {
const PROTO_NAME: &'static [u8] = b"/test/proto/1";
const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1");
let (listener_addr_tx, listener_addr_rx) = oneshot::channel();
let client = async_std::task::spawn(async move {
@@ -526,7 +535,7 @@ mod tests {
#[test]
fn large_handshake_refused() {
const PROTO_NAME: &'static [u8] = b"/test/proto/1";
const PROTO_NAME: Cow<'static, str> = Cow::Borrowed("/test/proto/1");
let (listener_addr_tx, listener_addr_rx) = oneshot::channel();
let client = async_std::task::spawn(async move {