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

Implement request parsing #452

Merged
merged 21 commits into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
9aa7fd9
Introduce RequestHeader and try_parse_request[_fd].
khuey May 25, 2020
63308d9
Filter out request fields already parsed into the header.
khuey May 25, 2020
b065d62
Fix xproto::Gravity special casing to work with imports.
khuey May 26, 2020
8540c4e
Generate try_parse methods for Aux structs.
khuey May 26, 2020
733a784
Add a "conversion" from Infallible to ParseError.
khuey May 26, 2020
71b4237
Implement parsing for request fields.
khuey May 26, 2020
20081e3
Dispense with odd_length, which we don't care about at all.
khuey May 26, 2020
4007467
Check padding remaining after request parsing.
khuey May 26, 2020
4bce7d6
Add a few tests for request parsing.
khuey May 27, 2020
8892230
When checking the final padding don't index the slice directly which …
khuey May 27, 2020
93e38a8
Make clippy happy.
khuey May 27, 2020
6a7a2f5
Fix request parsing tests to do endian conversion.
khuey May 27, 2020
191e4f7
Fix odd_length handling.
khuey May 27, 2020
d4ecc46
Silence clippy warning.
khuey May 27, 2020
52f0f6f
Fix bad opcode test to be entirely correct except for a bad opcode.
khuey May 27, 2020
1e6fc09
Consolidate list parsing generation code.
khuey May 27, 2020
6ae0b81
Save a line on bool parsings.
khuey May 27, 2020
4dd8f67
Stop doing request length validation and get rid of the validate_requ…
khuey May 27, 2020
e7e1f12
More clippy fixes.
khuey May 27, 2020
26a6d34
Tweak comment as requested.
khuey May 27, 2020
3906f0f
Add a helper function for parsing request headers.
khuey May 27, 2020
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
282 changes: 228 additions & 54 deletions generator/src/generator/namespace.rs

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ impl std::fmt::Display for ParseError {
}
}

impl From<std::convert::Infallible> for ParseError {
fn from(_: std::convert::Infallible) -> Self {
unreachable!()
}
}
Comment on lines +21 to +25
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is it actually used?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. A quick test build says "this is unused".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used in xinput. It could probably be eliminated with some more special casing in the code generator.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to actually enable the necessary features in my test build. 🤦
New try says:

error[E0271]: type mismatch resolving `<u8 as std::convert::TryFrom<u8>>::Error == errors::ParseError`
    --> src/protocol/xinput.rs:8798:29
     |
8798 |         let format = format.try_into()?;
     |                             ^^^^^^^^ expected enum `std::convert::Infallible`, found enum `errors::ParseError`

error[E0271]: type mismatch resolving `<u8 as std::convert::TryFrom<u8>>::Error == errors::ParseError`
     --> src/protocol/xinput.rs:13546:29
      |
13546 |         let format = format.try_into()?;
      |                             ^^^^^^^^ expected enum `std::convert::Infallible`, found enum `errors::ParseError`

error: aborting due to 2 previous errors

This is inside ChangeDevicePropertyRequest and XIChangePropertyRequest In both cases, a format u8 is converted to u8.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah we could probably try harder to avoid that u8 -> u8 conversion if we wanted to.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that this try_into comes from emit_field_post_parse, which would normally convert it into an enum. But here it is "converted" into an u8 because it is a deducible field.

In emit_struct_type, this is avoided with:

if !field
    .name()
    .map(|field_name| deducible_fields.contains_key(field_name))
    .unwrap_or(false)
{
    self.emit_field_post_parse(field, out);
}


/// An error that occurred while connecting to an X11 server
#[derive(Debug)]
pub enum ConnectError {
Expand Down
8 changes: 7 additions & 1 deletion src/protocol/bigreq.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::io::IoSlice;
#[allow(unused_imports)]
use crate::utils::RawFdContainer;
#[allow(unused_imports)]
use crate::x11_utils::{Serialize, TryParse};
use crate::x11_utils::{check_exhausted, validate_request_pieces, RequestHeader, Serialize, TryParse};
use crate::connection::{BufWithFds, PiecewiseBuf, RequestConnection};
#[allow(unused_imports)]
use crate::cookie::{Cookie, CookieWithFds, VoidCookie};
Expand Down Expand Up @@ -59,6 +59,12 @@ impl EnableRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(ENABLE_REQUEST))?;
Ok(EnableRequest
)
}
}
pub fn enable<Conn>(conn: &Conn) -> Result<Cookie<'_, Conn, EnableReply>, ConnectionError>
where
Expand Down
123 changes: 122 additions & 1 deletion src/protocol/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::io::IoSlice;
#[allow(unused_imports)]
use crate::utils::RawFdContainer;
#[allow(unused_imports)]
use crate::x11_utils::{Serialize, TryParse};
use crate::x11_utils::{check_exhausted, validate_request_pieces, RequestHeader, Serialize, TryParse};
use crate::connection::{BufWithFds, PiecewiseBuf, RequestConnection};
#[allow(unused_imports)]
use crate::cookie::{Cookie, CookieWithFds, VoidCookie};
Expand Down Expand Up @@ -144,6 +144,19 @@ impl QueryVersionRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(QUERY_VERSION_REQUEST))?;
let (client_major_version, remaining) = u32::try_parse(value)?;
let (client_minor_version, remaining) = u32::try_parse(remaining)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
khuey marked this conversation as resolved.
Show resolved Hide resolved
check_exhausted(remaining)?;
Ok(QueryVersionRequest {
client_major_version,
client_minor_version,
})
}
}
pub fn query_version<Conn>(conn: &Conn, client_major_version: u32, client_minor_version: u32) -> Result<Cookie<'_, Conn, QueryVersionReply>, ConnectionError>
where
Expand Down Expand Up @@ -224,6 +237,21 @@ impl RedirectWindowRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(REDIRECT_WINDOW_REQUEST))?;
let (window, remaining) = xproto::Window::try_parse(value)?;
let (update, remaining) = u8::try_parse(remaining)?;
let update = update.try_into()?;
let remaining = remaining.get(3..).ok_or(ParseError::ParseError)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(RedirectWindowRequest {
window,
update,
})
}
}
pub fn redirect_window<Conn>(conn: &Conn, window: xproto::Window, update: Redirect) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -276,6 +304,21 @@ impl RedirectSubwindowsRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(REDIRECT_SUBWINDOWS_REQUEST))?;
let (window, remaining) = xproto::Window::try_parse(value)?;
let (update, remaining) = u8::try_parse(remaining)?;
let update = update.try_into()?;
let remaining = remaining.get(3..).ok_or(ParseError::ParseError)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(RedirectSubwindowsRequest {
window,
update,
})
}
}
pub fn redirect_subwindows<Conn>(conn: &Conn, window: xproto::Window, update: Redirect) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -328,6 +371,21 @@ impl UnredirectWindowRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(UNREDIRECT_WINDOW_REQUEST))?;
let (window, remaining) = xproto::Window::try_parse(value)?;
let (update, remaining) = u8::try_parse(remaining)?;
let update = update.try_into()?;
let remaining = remaining.get(3..).ok_or(ParseError::ParseError)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(UnredirectWindowRequest {
window,
update,
})
}
}
pub fn unredirect_window<Conn>(conn: &Conn, window: xproto::Window, update: Redirect) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -380,6 +438,21 @@ impl UnredirectSubwindowsRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(UNREDIRECT_SUBWINDOWS_REQUEST))?;
let (window, remaining) = xproto::Window::try_parse(value)?;
let (update, remaining) = u8::try_parse(remaining)?;
let update = update.try_into()?;
let remaining = remaining.get(3..).ok_or(ParseError::ParseError)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(UnredirectSubwindowsRequest {
window,
update,
})
}
}
pub fn unredirect_subwindows<Conn>(conn: &Conn, window: xproto::Window, update: Redirect) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -432,6 +505,19 @@ impl CreateRegionFromBorderClipRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(CREATE_REGION_FROM_BORDER_CLIP_REQUEST))?;
let (region, remaining) = xfixes::Region::try_parse(value)?;
let (window, remaining) = xproto::Window::try_parse(remaining)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(CreateRegionFromBorderClipRequest {
region,
window,
})
}
}
pub fn create_region_from_border_clip<Conn>(conn: &Conn, region: xfixes::Region, window: xproto::Window) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -484,6 +570,19 @@ impl NameWindowPixmapRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(NAME_WINDOW_PIXMAP_REQUEST))?;
let (window, remaining) = xproto::Window::try_parse(value)?;
let (pixmap, remaining) = xproto::Pixmap::try_parse(remaining)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(NameWindowPixmapRequest {
window,
pixmap,
})
}
}
pub fn name_window_pixmap<Conn>(conn: &Conn, window: xproto::Window, pixmap: xproto::Pixmap) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -530,6 +629,17 @@ impl GetOverlayWindowRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(GET_OVERLAY_WINDOW_REQUEST))?;
let (window, remaining) = xproto::Window::try_parse(value)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(GetOverlayWindowRequest {
window,
})
}
}
pub fn get_overlay_window<Conn>(conn: &Conn, window: xproto::Window) -> Result<Cookie<'_, Conn, GetOverlayWindowReply>, ConnectionError>
where
Expand Down Expand Up @@ -601,6 +711,17 @@ impl ReleaseOverlayWindowRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(RELEASE_OVERLAY_WINDOW_REQUEST))?;
let (window, remaining) = xproto::Window::try_parse(value)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(ReleaseOverlayWindowRequest {
window,
})
}
}
pub fn release_overlay_window<Conn>(conn: &Conn, window: xproto::Window) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down
71 changes: 70 additions & 1 deletion src/protocol/damage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::io::IoSlice;
#[allow(unused_imports)]
use crate::utils::RawFdContainer;
#[allow(unused_imports)]
use crate::x11_utils::{Serialize, TryParse};
use crate::x11_utils::{check_exhausted, validate_request_pieces, RequestHeader, Serialize, TryParse};
use crate::connection::{BufWithFds, PiecewiseBuf, RequestConnection};
#[allow(unused_imports)]
use crate::cookie::{Cookie, CookieWithFds, VoidCookie};
Expand Down Expand Up @@ -215,6 +215,19 @@ impl QueryVersionRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(QUERY_VERSION_REQUEST))?;
let (client_major_version, remaining) = u32::try_parse(value)?;
let (client_minor_version, remaining) = u32::try_parse(remaining)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(QueryVersionRequest {
client_major_version,
client_minor_version,
})
}
}
pub fn query_version<Conn>(conn: &Conn, client_major_version: u32, client_minor_version: u32) -> Result<Cookie<'_, Conn, QueryVersionReply>, ConnectionError>
where
Expand Down Expand Up @@ -301,6 +314,23 @@ impl CreateRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(CREATE_REQUEST))?;
let (damage, remaining) = Damage::try_parse(value)?;
let (drawable, remaining) = xproto::Drawable::try_parse(remaining)?;
let (level, remaining) = u8::try_parse(remaining)?;
let level = level.try_into()?;
let remaining = remaining.get(3..).ok_or(ParseError::ParseError)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(CreateRequest {
damage,
drawable,
level,
})
}
}
pub fn create<Conn>(conn: &Conn, damage: Damage, drawable: xproto::Drawable, level: ReportLevel) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -348,6 +378,17 @@ impl DestroyRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(DESTROY_REQUEST))?;
let (damage, remaining) = Damage::try_parse(value)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(DestroyRequest {
damage,
})
}
}
pub fn destroy<Conn>(conn: &Conn, damage: Damage) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -405,6 +446,21 @@ impl SubtractRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(SUBTRACT_REQUEST))?;
let (damage, remaining) = Damage::try_parse(value)?;
let (repair, remaining) = xfixes::Region::try_parse(remaining)?;
let (parts, remaining) = xfixes::Region::try_parse(remaining)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(SubtractRequest {
damage,
repair,
parts,
})
}
}
pub fn subtract<Conn, A, B>(conn: &Conn, damage: Damage, repair: A, parts: B) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down Expand Up @@ -462,6 +518,19 @@ impl AddRequest {
request0[2..4].copy_from_slice(&length.to_ne_bytes());
Ok((vec![request0.into()], vec![]))
}
/// Parse this request given its header, its body, and any fds that go along with it
pub fn try_parse_request(header: RequestHeader, value: &[u8]) -> Result<Self, ParseError> {
validate_request_pieces(header, value, None, Some(ADD_REQUEST))?;
let (drawable, remaining) = xproto::Drawable::try_parse(value)?;
let (region, remaining) = xfixes::Region::try_parse(remaining)?;
let remaining = remaining.get(..(4 - (remaining.len() % 4)) % 4)
.ok_or(ParseError::ParseError)?;
check_exhausted(remaining)?;
Ok(AddRequest {
drawable,
region,
})
}
}
pub fn add<Conn>(conn: &Conn, drawable: xproto::Drawable, region: xfixes::Region) -> Result<VoidCookie<'_, Conn>, ConnectionError>
where
Expand Down
Loading