diff --git a/crates/model-connector/src/envelope.rs b/crates/model-connector/src/envelope.rs index f8d4a22..5400eac 100644 --- a/crates/model-connector/src/envelope.rs +++ b/crates/model-connector/src/envelope.rs @@ -65,20 +65,20 @@ pub fn frame_bytes_for_payload(ciphertext_len: usize) -> usize { /// the inverse of [`frame_bytes_for_payload`]. `None` when the frame cannot /// carry even an empty envelope. pub fn payload_bytes_for_frame(max_frame_bytes: usize) -> Option { - if frame_bytes_for_payload(0) > max_frame_bytes { - return None; - } - // frame_bytes_for_payload is increasing; the answer is at most half the frame. - let (mut low, mut high) = (0, max_frame_bytes / 2); - while low < high { - let mid = low + (high - low).div_ceil(2); - if frame_bytes_for_payload(mid) <= max_frame_bytes { - low = mid; - } else { - high = mid - 1; - } - } - Some(low) + // frame_bytes_for_payload(0) is the shell plus a one-byte array header. + let fixed = frame_bytes_for_payload(0) - 1; + let room = max_frame_bytes.checked_sub(fixed)?; + // Each array header width bounds the payloads it can describe; the + // widest payload any width admits is the answer. + let by_header = |header: usize, cap: usize| room.checked_sub(header).map(|r| (r / 2).min(cap)); + [ + by_header(5, usize::MAX), + by_header(3, 65_535), + by_header(1, 15), + ] + .into_iter() + .flatten() + .max() } pub fn encrypt_invocation( diff --git a/crates/model-connector/src/serve.rs b/crates/model-connector/src/serve.rs index 0ea0766..9e3c9ff 100644 --- a/crates/model-connector/src/serve.rs +++ b/crates/model-connector/src/serve.rs @@ -52,14 +52,6 @@ impl ServeLimits { /// An admitted payload therefore always fits, and `complete` is given the /// same frame bound to fit every result in. fn validate(&self, admissions: &[CallerAdmission]) -> Result<(), ServeError> { - let smallest = frame_bytes_for_payload(MIN_PAYLOAD_BYTES); - if self.max_frame_bytes > 0 && self.max_frame_bytes < smallest { - return Err(ServeError::FrameBound { - max_frame_bytes: self.max_frame_bytes, - payload_bytes: MIN_PAYLOAD_BYTES, - needed_frame_bytes: smallest, - }); - } if self.max_frame_bytes == 0 || self.max_frame_bytes > u32::MAX as usize || self.max_connections == 0 @@ -68,6 +60,14 @@ impl ServeLimits { { return Err(ServeError::InvalidConfig("serve limits")); } + let smallest = frame_bytes_for_payload(MIN_PAYLOAD_BYTES); + if self.max_frame_bytes < smallest { + return Err(ServeError::FrameBound { + max_frame_bytes: self.max_frame_bytes, + payload_bytes: MIN_PAYLOAD_BYTES, + needed_frame_bytes: smallest, + }); + } if admissions.is_empty() { return Err(ServeError::InvalidConfig("callers")); }