Comments (2)
I think there are two separate issues here:
- Stream ID accounting is buggy, which causes the connection to go into protocol error and go away.
- Go away handling is also buggy, which causes the panic.
More on stream id accounting bug, in h2::proto::streams::recv
:
/// Update state reflecting a new, remotely opened stream
///
/// Returns the stream state if successful. `None` if refused
pub fn open(
&mut self,
id: StreamId,
counts: &mut Counts<P>,
) -> Result<Option<StreamId>, RecvError> {
assert!(self.refused.is_none());
self.ensure_can_open(id)?;
let next_id = self.next_stream_id()?;
if id < next_id {
return Err(RecvError::Connection(ProtocolError));
}
self.next_stream_id = id.next_id();
if !counts.can_inc_num_recv_streams() {
self.refused = Some(id);
return Ok(None);
}
Ok(Some(id))
}
/// Transition the stream state based on receiving headers
///
/// The caller ensures that the frame represents headers and not trailers.
pub fn recv_headers(
&mut self,
frame: frame::Headers,
stream: &mut store::Ptr<B, P>,
counts: &mut Counts<P>,
) -> Result<(), RecvError> {
trace!("opening stream; init_window={}", self.init_window_sz);
let is_initial = stream.state.recv_open(frame.is_end_stream())?;
if is_initial {
let id = frame.stream_id();
let next_id = self.next_stream_id()?;
if id >= next_id {
self.next_stream_id = id.next_id();
} else {
error!("invalid id: {:?} < {:?}", id, next_id);
return Err(RecvError::Connection(ProtocolError));
}
...
Both open
and recv_headers
attempt to update self.next_stream_id
, which causes newly received headers to be interpreted as invalid.
In h2::proto::streams::streams::Streams::recv_headers
, we see that both Recv::open
and Recv::recv_headers
are called as a stream is initialized:
/// Process inbound headers
pub fn recv_headers(&mut self, frame: frame::Headers) -> Result<(), RecvError> {
let id = frame.stream_id();
let mut me = self.inner.lock().unwrap();
let me = &mut *me;
let key = match me.store.find_entry(id) {
Entry::Occupied(e) => e.key(),
Entry::Vacant(e) => match me.actions.recv.open(id, &mut me.counts)? {
Some(stream_id) => {
let stream = Stream::new(
stream_id,
me.actions.send.init_window_sz(),
me.actions.recv.init_window_sz(),
);
e.insert(stream)
},
None => return Ok(()),
},
};
let stream = me.store.resolve(key);
let actions = &mut me.actions;
me.counts.transition(stream, |counts, stream| {
trace!(
"recv_headers; stream={:?}; state={:?}",
stream.id,
stream.state
);
let res = if stream.state.is_recv_headers() {
actions.recv.recv_headers(frame, stream, counts)
} else ...
So, it seems that at least one of the following should be changed:
open
should not update the next stream idrecv_headers
should not check the next stream id- the
is_initial
checkin recv_headers is wrong
I think this also means we must not be testing the Streams::recv_headers call path.
from h2.
d0bb3cb implements a serverside test that illustrates this problem.
from h2.
Related Issues (20)
- Server hangs when there is delay between headers and body HOT 2
- GitHub security advisory - vulnerable to denial of service HOT 1
- Server doesn't send flow control WINDOW_UPDATE frames HOT 2
- Panicking following 0.3.17 HOT 1
- Unable to send response. HOT 3
- assertion failed: self.num_remote_reset_streams > 0 HOT 1
- How to set frame priority / Weight ? HOT 4
- Request processing always times out, HOT 1
- Handling of RFC7540 8.1.2.5 HOT 5
- Panic due to the max headers capacity HOT 1
- `h2spec 2.6.0` tests are failling against `h2` HOT 3
- Settings frames are not applied correctly HOT 12
- Sending data frame results in transmission of more tcp segments than needed HOT 11
- Make tracing an optional feature
- Modifying the `akamai` example to send to `www.google.com` and adding a `host` header and errors HOT 2
- `max_send_buffer_size` documentation states default is 400 MB. It is 400 KB. HOT 2
- Remove tokio I/O traits from dependencies HOT 4
- http2 error: stream error received: unspecific protocol error detected HOT 4
- custom SETTINGS settings
- Proposal: change the default value of `initial_max_send_streams` to 100 HOT 7
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from h2.