Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

support custom settings #825

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ use crate::{FlowControl, PingPong, RecvStream, SendStream};

use bytes::{Buf, Bytes};
use http::{uri, HeaderMap, Method, Request, Response, Version};
use std::collections::BTreeSet;
use std::fmt;
use std::future::Future;
use std::pin::Pin;
Expand Down Expand Up @@ -343,6 +344,9 @@ pub struct Builder {
///
/// When this gets exceeded, we issue GOAWAYs.
local_max_error_reset_streams: Option<usize>,

/// Custom settings IDs to be tracked from the remote
allowed_custom_settings: BTreeSet<u16>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -557,6 +561,16 @@ where
pub fn current_max_recv_streams(&self) -> usize {
self.inner.current_max_recv_streams()
}

/// Returns the value of a custom setting specified in the [SETTINGS frame][1].
///
/// This method returns the currently acknowledged value received from the
/// remote.
///
/// [1]: https://httpwg.org/specs/rfc7540.html#rfc.section.6.5
pub fn custom_setting(&self, id: u16) -> Option<u32> {
self.inner.custom_setting(id)
}
}

impl<B> fmt::Debug for SendRequest<B>
Expand Down Expand Up @@ -663,6 +677,7 @@ impl Builder {
settings: Default::default(),
stream_id: 1.into(),
local_max_error_reset_streams: Some(proto::DEFAULT_LOCAL_RESET_COUNT_MAX),
allowed_custom_settings: BTreeSet::new(),
}
}

Expand Down Expand Up @@ -859,6 +874,26 @@ impl Builder {
self
}

/// Set a custom setting in the SETTINGS frame.
///
/// See [Section 6.5] in the HTTP/2 spec for more details.
///
/// [Section 6.5]: https://httpwg.org/specs/rfc7540.html#rfc.section.6.5
pub fn custom_setting(&mut self, id: u16, value: u32) -> &mut Self {
self.settings.set_custom_setting(id, Some(value));
self
}

/// By default, unknown settings recieved from the remote will be ignored.
///
/// See [Section 6.5] in the HTTP/2 spec for more details.
///
/// [Section 6.5]: https://httpwg.org/specs/rfc7540.html#rfc.section.6.5
pub fn allow_custom_setting(&mut self, id: u16) -> &mut Self {
self.allowed_custom_settings.insert(id);
self
}

/// Sets the initial maximum of locally initiated (send) streams.
///
/// The initial settings will be overwritten by the remote peer when
Expand Down Expand Up @@ -1335,6 +1370,7 @@ where
remote_reset_stream_max: builder.pending_accept_reset_stream_max,
local_error_reset_streams_max: builder.local_max_error_reset_streams,
settings: builder.settings.clone(),
allowed_custom_settings: builder.allowed_custom_settings,
},
);
let send_request = SendRequest {
Expand Down
28 changes: 27 additions & 1 deletion src/frame/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::fmt;

use crate::frame::{util, Error, Frame, FrameSize, Head, Kind, StreamId};
use bytes::{BufMut, BytesMut};
use std::collections::BTreeMap;

#[derive(Clone, Default, Eq, PartialEq)]
pub struct Settings {
Expand All @@ -14,6 +15,7 @@ pub struct Settings {
max_frame_size: Option<u32>,
max_header_list_size: Option<u32>,
enable_connect_protocol: Option<u32>,
custom: BTreeMap<u16, u32>,
}

/// An enum that lists all valid settings that can be sent in a SETTINGS
Expand All @@ -29,6 +31,7 @@ pub enum Setting {
MaxFrameSize(u32),
MaxHeaderListSize(u32),
EnableConnectProtocol(u32),
Custom(u16, u32),
}

#[derive(Copy, Clone, Eq, PartialEq, Default)]
Expand Down Expand Up @@ -125,6 +128,18 @@ impl Settings {
self.header_table_size = size;
}

pub fn set_custom_setting(&mut self, id: u16, val: Option<u32>) {
if let Some(val) = val {
self.custom.insert(id, val);
} else {
self.custom.remove(&id);
}
}

pub fn custom_setting(&self, id: u16) -> Option<u32> {
self.custom.get(&id).copied()
}

pub fn load(head: Head, payload: &[u8]) -> Result<Settings, Error> {
use self::Setting::*;

Expand Down Expand Up @@ -197,6 +212,9 @@ impl Settings {
return Err(Error::InvalidSettingValue);
}
},
Some(Custom(id, val)) => {
settings.custom.insert(id, val);
}
None => {}
}
}
Expand Down Expand Up @@ -256,6 +274,10 @@ impl Settings {
if let Some(v) = self.enable_connect_protocol {
f(EnableConnectProtocol(v));
}

for (id, v) in &self.custom {
f(Custom(*id, *v));
}
}
}

Expand Down Expand Up @@ -292,6 +314,9 @@ impl fmt::Debug for Settings {
Setting::EnableConnectProtocol(v) => {
builder.field("enable_connect_protocol", &v);
}
Setting::Custom(id, v) => {
builder.field(format!("0x{:04x}", id).as_str(), &v);
}
});

builder.finish()
Expand All @@ -315,7 +340,7 @@ impl Setting {
5 => Some(MaxFrameSize(val)),
6 => Some(MaxHeaderListSize(val)),
8 => Some(EnableConnectProtocol(val)),
_ => None,
id => Some(Custom(id, val)),
}
}

Expand Down Expand Up @@ -347,6 +372,7 @@ impl Setting {
MaxFrameSize(v) => (5, v),
MaxHeaderListSize(v) => (6, v),
EnableConnectProtocol(v) => (8, v),
Custom(id, v) => (id, v),
};

dst.put_u16(kind);
Expand Down
14 changes: 14 additions & 0 deletions src/proto/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::proto::*;

use bytes::Bytes;
use futures_core::Stream;
use std::collections::BTreeSet;
use std::io;
use std::marker::PhantomData;
use std::pin::Pin;
Expand Down Expand Up @@ -83,6 +84,7 @@ pub(crate) struct Config {
pub remote_reset_stream_max: usize,
pub local_error_reset_streams_max: Option<usize>,
pub settings: frame::Settings,
pub allowed_custom_settings: BTreeSet<u16>,
}

#[derive(Debug)]
Expand Down Expand Up @@ -123,6 +125,7 @@ where
.max_concurrent_streams()
.map(|max| max as usize),
local_max_error_reset_streams: config.local_error_reset_streams_max,
allowed_custom_settings: config.allowed_custom_settings.clone(),
}
}
let streams = Streams::new(streams_config(&config));
Expand Down Expand Up @@ -162,6 +165,13 @@ where
self.inner.settings.send_settings(settings)
}

/// Send a new SETTINGS frame with a custom setting.
pub(crate) fn set_custom_setting(&mut self, id: u16, value: u32) -> Result<(), UserError> {
let mut settings = frame::Settings::default();
settings.set_custom_setting(id, Some(value));
self.inner.settings.send_settings(settings)
}

/// Returns the maximum number of concurrent streams that may be initiated
/// by this peer.
pub(crate) fn max_send_streams(&self) -> usize {
Expand Down Expand Up @@ -362,6 +372,10 @@ where
fn clear_expired_reset_streams(&mut self) {
self.inner.streams.clear_expired_reset_streams();
}

pub(crate) fn custom_setting(&self, id: u16) -> Option<u32> {
self.inner.streams.custom_setting(id)
}
}

impl<P, B> ConnectionInner<P, B>
Expand Down
4 changes: 4 additions & 0 deletions src/proto/streams/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ use crate::frame::{StreamId, StreamIdOverflow};
use crate::proto::*;

use bytes::Bytes;
use std::collections::BTreeSet;
use std::time::Duration;

#[derive(Debug)]
Expand Down Expand Up @@ -72,4 +73,7 @@ pub struct Config {
///
/// When this gets exceeded, we issue GOAWAYs.
pub local_max_error_reset_streams: Option<usize>,

/// Custom settings IDs to be tracked from the remote
pub allowed_custom_settings: BTreeSet<u16>,
}
16 changes: 16 additions & 0 deletions src/proto/streams/send.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use bytes::Buf;
use tokio::io::AsyncWrite;

use std::cmp::Ordering;
use std::collections::{BTreeMap, BTreeSet};
use std::io;
use std::task::{Context, Poll, Waker};

Expand Down Expand Up @@ -38,6 +39,10 @@ pub(super) struct Send {

/// If extended connect protocol is enabled.
is_extended_connect_protocol_enabled: bool,

/// Custom settings
custom_settings: BTreeMap<u16, u32>,
allowed_custom_settings: BTreeSet<u16>,
}

/// A value to detect which public API has called `poll_reset`.
Expand All @@ -57,6 +62,8 @@ impl Send {
prioritize: Prioritize::new(config),
is_push_enabled: true,
is_extended_connect_protocol_enabled: false,
custom_settings: BTreeMap::new(),
allowed_custom_settings: config.allowed_custom_settings.clone(),
}
}

Expand Down Expand Up @@ -434,6 +441,11 @@ impl Send {
if let Some(val) = settings.is_extended_connect_protocol_enabled() {
self.is_extended_connect_protocol_enabled = val;
}
for id in &self.allowed_custom_settings {
if let Some(val) = settings.custom_setting(*id) {
self.custom_settings.insert(*id, val);
}
}

// Applies an update to the remote endpoint's initial window size.
//
Expand Down Expand Up @@ -582,4 +594,8 @@ impl Send {
pub(crate) fn is_extended_connect_protocol_enabled(&self) -> bool {
self.is_extended_connect_protocol_enabled
}

pub(crate) fn custom_setting(&self, id: u16) -> Option<u32> {
self.custom_settings.get(&id).copied()
}
}
4 changes: 4 additions & 0 deletions src/proto/streams/streams.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ where
let me = self.inner.lock().unwrap();
me.counts.max_recv_streams()
}

pub(crate) fn custom_setting(&self, id: u16) -> Option<u32> {
self.inner.lock().unwrap().actions.send.custom_setting(id)
}
}

impl<B> DynStreams<'_, B> {
Expand Down
52 changes: 51 additions & 1 deletion src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,7 @@ use crate::{FlowControl, PingPong, RecvStream, SendStream};

use bytes::{Buf, Bytes};
use http::{HeaderMap, Method, Request, Response};
use std::collections::BTreeSet;
use std::future::Future;
use std::pin::Pin;
use std::task::{Context, Poll};
Expand Down Expand Up @@ -258,6 +259,9 @@ pub struct Builder {
///
/// When this gets exceeded, we issue GOAWAYs.
local_max_error_reset_streams: Option<usize>,

/// Custom settings IDs to be tracked from the remote
allowed_custom_settings: BTreeSet<u16>,
}

/// Send a response back to the client
Expand Down Expand Up @@ -497,6 +501,21 @@ where
Ok(())
}

/// Set a custom setting in the SETTINGS frame.
///
/// See [Section 6.5] in the HTTP/2 spec for more details.
///
/// [Section 6.5]: https://httpwg.org/specs/rfc7540.html#rfc.section.6.5
///
/// # Errors
///
/// Returns an error if a previous call is still pending acknowledgement
/// from the remote endpoint.
pub fn set_custom_setting(&mut self, id: u16, value: u32) -> Result<(), crate::Error> {
self.connection.set_custom_setting(id, value)?;
Ok(())
}

/// Returns `Ready` when the underlying connection has closed.
///
/// If any new inbound streams are received during a call to `poll_closed`,
Expand Down Expand Up @@ -587,6 +606,16 @@ where
pub fn num_wired_streams(&self) -> usize {
self.connection.num_wired_streams()
}

/// Returns the value of a custom setting specified in the [SETTINGS frame][1].
///
/// This method returns the currently acknowledged value received from the
/// remote.
///
/// [1]: https://httpwg.org/specs/rfc7540.html#rfc.section.6.5
pub fn custom_setting(&self, id: u16) -> Option<u32> {
self.connection.custom_setting(id)
}
}

#[cfg(feature = "stream")]
Expand Down Expand Up @@ -650,8 +679,8 @@ impl Builder {
settings: Settings::default(),
initial_target_connection_window_size: None,
max_send_buffer_size: proto::DEFAULT_MAX_SEND_BUFFER_SIZE,

local_max_error_reset_streams: Some(proto::DEFAULT_LOCAL_RESET_COUNT_MAX),
allowed_custom_settings: BTreeSet::new(),
}
}

Expand Down Expand Up @@ -1023,6 +1052,26 @@ impl Builder {
self
}

/// Set a custom setting in the SETTINGS frame.
///
/// See [Section 6.5] in the HTTP/2 spec for more details.
///
/// [Section 6.5]: https://httpwg.org/specs/rfc7540.html#rfc.section.6.5
pub fn set_custom_setting(&mut self, id: u16, value: Option<u32>) -> &mut Self {
self.settings.set_custom_setting(id, value);
self
}

/// By default, unknown settings recieved from the remote will be ignored.
///
/// See [Section 6.5] in the HTTP/2 spec for more details.
///
/// [Section 6.5]: https://httpwg.org/specs/rfc7540.html#rfc.section.6.5
pub fn allow_custom_setting(&mut self, id: u16) -> &mut Self {
self.allowed_custom_settings.insert(id);
self
}

/// Creates a new configured HTTP/2 server backed by `io`.
///
/// It is expected that `io` already be in an appropriate state to commence
Expand Down Expand Up @@ -1385,6 +1434,7 @@ where
.builder
.local_max_error_reset_streams,
settings: self.builder.settings.clone(),
allowed_custom_settings: self.builder.allowed_custom_settings.clone(),
},
);

Expand Down