claude_codex/providers/cursor/
connect.rs1use bytes::{Bytes, BytesMut};
2
3pub const FLAG_GZIP: u8 = 0x01;
5pub const FLAG_END: u8 = 0x02;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct ConnectFrame {
10 pub flags: u8,
11 pub payload: Bytes,
12}
13
14pub fn encode_connect_frame(payload: impl AsRef<[u8]>, flags: u8) -> Bytes {
17 let payload = payload.as_ref();
18 let mut out = BytesMut::with_capacity(5 + payload.len());
19 out.extend_from_slice(&[flags]);
20 out.extend_from_slice(&(payload.len() as u32).to_be_bytes());
21 out.extend_from_slice(payload);
22 out.freeze()
23}
24
25#[derive(Default)]
35pub struct ConnectFrameDecoder {
36 buffer: BytesMut,
37}
38
39impl ConnectFrameDecoder {
40 pub fn new() -> Self {
41 Self::default()
42 }
43
44 pub fn push(&mut self, chunk: impl AsRef<[u8]>) -> Result<Vec<ConnectFrame>, ConnectError> {
49 self.buffer.extend_from_slice(chunk.as_ref());
50 self.drain(64 * 1024 * 1024) }
52
53 pub fn push_with_limit(
55 &mut self,
56 chunk: impl AsRef<[u8]>,
57 max_payload: usize,
58 ) -> Result<Vec<ConnectFrame>, ConnectError> {
59 self.buffer.extend_from_slice(chunk.as_ref());
60 self.drain(max_payload)
61 }
62
63 fn drain(&mut self, max_payload: usize) -> Result<Vec<ConnectFrame>, ConnectError> {
64 let mut out = Vec::new();
65 loop {
66 if self.buffer.len() < 5 {
67 break;
68 }
69 let len = u32::from_be_bytes([
70 self.buffer[1],
71 self.buffer[2],
72 self.buffer[3],
73 self.buffer[4],
74 ]) as usize;
75
76 if len > max_payload {
77 return Err(ConnectError::PayloadTooLarge {
78 length: len,
79 max: max_payload,
80 });
81 }
82
83 if self.buffer.len() < 5 + len {
84 break;
85 }
86
87 let mut raw = self.buffer.split_to(5 + len);
88 out.push(ConnectFrame {
89 flags: raw[0],
90 payload: raw.split_off(5).freeze(),
91 });
92 }
93 Ok(out)
94 }
95
96 pub fn buffered(&self) -> usize {
98 self.buffer.len()
99 }
100}
101
102pub fn decode_gzip_frame(payload: &[u8]) -> Result<Vec<u8>, std::io::Error> {
105 use std::io::Read;
106 let mut decoder = flate2::read::GzDecoder::new(payload);
107 let mut out = Vec::new();
108 decoder.read_to_end(&mut out)?;
109 Ok(out)
110}
111
112pub fn parse_connect_error(payload: &[u8]) -> Option<ConnectEndError> {
116 if payload.is_empty() {
117 return None;
118 }
119 let parsed: serde_json::Value = serde_json::from_slice(payload).ok()?;
120 let error = parsed.get("error")?;
121 let code = error.get("code")?.as_str()?;
122 let message = error.get("message")?.as_str().unwrap_or("Connect error");
123 let status = match code {
124 "resource_exhausted" => 429,
125 _ => 502,
126 };
127 Some(ConnectEndError {
128 code: code.to_string(),
129 message: message.to_string(),
130 detail: parsed.to_string(),
131 status,
132 })
133}
134
135#[derive(Debug, Clone)]
136pub struct ConnectEndError {
137 pub code: String,
138 pub message: String,
139 pub detail: String,
140 pub status: u16,
141}
142
143impl std::fmt::Display for ConnectEndError {
144 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
145 write!(
146 f,
147 "Connect error {}: {} ({})",
148 self.status, self.message, self.code
149 )
150 }
151}
152
153impl std::error::Error for ConnectEndError {}
154
155#[derive(Debug, Clone)]
156pub enum ConnectError {
157 PayloadTooLarge { length: usize, max: usize },
158}
159
160impl std::fmt::Display for ConnectError {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 match self {
163 ConnectError::PayloadTooLarge { length, max } => {
164 write!(f, "Connect frame payload {length} exceeds max {max}")
165 }
166 }
167 }
168}
169
170impl std::error::Error for ConnectError {}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175
176 #[test]
177 fn encode_roundtrip() {
178 let frame = encode_connect_frame(b"hello", 0);
179 let mut decoder = ConnectFrameDecoder::new();
180 let frames = decoder.push(&frame).unwrap();
181 assert_eq!(frames.len(), 1);
182 assert_eq!(frames[0].flags, 0);
183 assert_eq!(&frames[0].payload[..], b"hello");
184 }
185
186 #[test]
187 fn encode_with_gzip_flag() {
188 let frame = encode_connect_frame(b"gzip-data", FLAG_GZIP);
189 let mut decoder = ConnectFrameDecoder::new();
190 let frames = decoder.push(&frame).unwrap();
191 assert_eq!(frames.len(), 1);
192 assert_eq!(frames[0].flags, FLAG_GZIP);
193 }
194
195 #[test]
196 fn encode_with_end_flag() {
197 let frame = encode_connect_frame(b"", FLAG_END);
198 let mut decoder = ConnectFrameDecoder::new();
199 let frames = decoder.push(&frame).unwrap();
200 assert_eq!(frames.len(), 1);
201 assert_eq!(frames[0].flags, FLAG_END);
202 assert!(frames[0].payload.is_empty());
203 }
204
205 #[test]
206 fn encode_with_gzip_and_end_flags() {
207 let payload = b"end-data";
208 let frame = encode_connect_frame(payload, FLAG_GZIP | FLAG_END);
209 let mut decoder = ConnectFrameDecoder::new();
210 let frames = decoder.push(&frame).unwrap();
211 assert_eq!(frames.len(), 1);
212 assert_eq!(frames[0].flags, FLAG_GZIP | FLAG_END);
213 assert_eq!(&frames[0].payload[..], payload);
214 }
215
216 #[test]
217 fn multiple_frames_in_single_chunk() {
218 let f1 = encode_connect_frame(b"first", 0);
219 let f2 = encode_connect_frame(b"second", 0);
220 let mut combined = BytesMut::new();
221 combined.extend_from_slice(&f1);
222 combined.extend_from_slice(&f2);
223
224 let mut decoder = ConnectFrameDecoder::new();
225 let frames = decoder.push(combined).unwrap();
226 assert_eq!(frames.len(), 2);
227 assert_eq!(&frames[0].payload[..], b"first");
228 assert_eq!(&frames[1].payload[..], b"second");
229 }
230
231 #[test]
232 fn split_chunks_are_assembled() {
233 let frame = encode_connect_frame(b"split-test", 0);
234 let (a, b) = frame.split_at(3);
235
236 let mut decoder = ConnectFrameDecoder::new();
237 let frames = decoder.push(a).unwrap();
238 assert!(frames.is_empty());
239
240 let frames = decoder.push(b).unwrap();
241 assert_eq!(frames.len(), 1);
242 assert_eq!(&frames[0].payload[..], b"split-test");
243 }
244
245 #[test]
246 fn split_at_header_boundary() {
247 let frame = encode_connect_frame(b"split-at-5", 0);
248 let (a, b) = frame.split_at(1);
250
251 let mut decoder = ConnectFrameDecoder::new();
252 let frames = decoder.push(a).unwrap();
253 assert!(frames.is_empty());
254
255 let frames = decoder.push(b).unwrap();
256 assert_eq!(frames.len(), 1);
257 assert_eq!(&frames[0].payload[..], b"split-at-5");
258 }
259
260 #[test]
261 fn oversized_length_is_rejected() {
262 let mut decoder = ConnectFrameDecoder::new();
263 let oversized = encode_connect_frame(vec![0u8; 100], 0);
265 let result = decoder.push_with_limit(&oversized, 10);
266 assert!(result.is_err());
267 match result.unwrap_err() {
268 ConnectError::PayloadTooLarge { length, max } => {
269 assert_eq!(length, 100);
270 assert_eq!(max, 10);
271 }
272 }
273 }
274
275 #[test]
276 fn empty_chunk_produces_no_frames() {
277 let mut decoder = ConnectFrameDecoder::new();
278 let frames = decoder.push(b"").unwrap();
279 assert!(frames.is_empty());
280 }
281
282 #[test]
283 fn buf_returns_buffered_bytes() {
284 let mut decoder = ConnectFrameDecoder::new();
285 decoder.push(b"\x00\x00").unwrap();
287 assert_eq!(decoder.buffered(), 2);
288 }
289
290 #[test]
291 fn clean_end_frame_empty_payload() {
292 let frame = encode_connect_frame(b"", FLAG_END);
293 let mut decoder = ConnectFrameDecoder::new();
294 let frames = decoder.push(frame).unwrap();
295 assert_eq!(frames.len(), 1);
296 assert_eq!(frames[0].flags, FLAG_END);
297 assert!(frames[0].payload.is_empty());
298 assert!(parse_connect_error(&frames[0].payload).is_none());
300 }
301
302 #[test]
303 fn connect_json_error_parsing() {
304 let json_err = serde_json::json!({
305 "error": {
306 "code": "resource_exhausted",
307 "message": "quota exceeded",
308 "details": []
309 }
310 });
311 let payload = serde_json::to_vec(&json_err).unwrap();
312 let frame = encode_connect_frame(&payload, FLAG_END);
313 let mut decoder = ConnectFrameDecoder::new();
314 let frames = decoder.push(frame).unwrap();
315 assert_eq!(frames.len(), 1);
316
317 let err = parse_connect_error(&frames[0].payload).unwrap();
318 assert_eq!(err.code, "resource_exhausted");
319 assert_eq!(err.status, 429);
320 assert_eq!(err.message, "quota exceeded");
321 }
322
323 #[test]
324 fn connect_json_unavailable_error() {
325 let json_err = serde_json::json!({
326 "error": {
327 "code": "unavailable",
328 "message": "service unavailable"
329 }
330 });
331 let payload = serde_json::to_vec(&json_err).unwrap();
332 let err = parse_connect_error(&payload).unwrap();
333 assert_eq!(err.code, "unavailable");
334 assert_eq!(err.status, 502);
335 }
336
337 #[test]
338 fn frame_fixture_matches_reference_layout() {
339 let frame = encode_connect_frame(b"abc", 0);
342 assert_eq!(hex::encode(frame), "0000000003616263");
343 }
344
345 #[test]
346 fn frame_fixture_with_flags() {
347 let frame = encode_connect_frame(b"xyz", 0x01);
349 assert_eq!(hex::encode(frame), "010000000378797a");
350 }
351
352 #[test]
353 fn gzip_frame_decompress() {
354 let payload = b"hello gzip";
355 let mut compressed = Vec::new();
356 {
357 use std::io::Write;
358 let mut encoder =
359 flate2::write::GzEncoder::new(&mut compressed, flate2::Compression::fast());
360 encoder.write_all(payload).unwrap();
361 encoder.finish().unwrap();
362 }
363
364 let frame = encode_connect_frame(&compressed, FLAG_GZIP);
365 let mut decoder = ConnectFrameDecoder::new();
366 let frames = decoder.push(frame).unwrap();
367 assert_eq!(frames.len(), 1);
368 assert_eq!(frames[0].flags, FLAG_GZIP);
369
370 let decompressed = decode_gzip_frame(&frames[0].payload).unwrap();
371 assert_eq!(decompressed, b"hello gzip");
372 }
373}