11use core:: fmt;
2+ use core:: str;
23
3- use anyhow:: { anyhow, bail, Result } ;
4+ use anyhow:: { anyhow, bail, Context as _ , Result } ;
45use tokio:: io:: { AsyncBufRead , AsyncBufReadExt as _, AsyncRead , AsyncReadExt as _, BufReader } ;
56
67use crate :: alloc:: prelude:: * ;
78use crate :: languageserver:: envelope;
89
9- /// An input frame.
10- #[ derive( Debug ) ]
11- pub ( super ) struct Frame < ' a > {
12- pub ( super ) content : & ' a [ u8 ] ,
10+ enum State {
11+ /// Initial state, before header has been received.
12+ Initial ,
13+ /// Reading state, when a header has been received.
14+ Reading ( usize ) ,
1315}
1416
1517/// Input connection.
1618pub ( super ) struct Input < I > {
17- buf : rust_alloc:: vec:: Vec < u8 > ,
1819 reader : BufReader < I > ,
20+ state : State ,
1921}
2022
2123impl < I > Input < I >
@@ -25,28 +27,46 @@ where
2527 /// Create a new input connection.
2628 pub ( super ) fn new ( reader : I ) -> Self {
2729 Self {
28- buf : rust_alloc:: vec:: Vec :: new ( ) ,
2930 reader : BufReader :: new ( reader) ,
31+ state : State :: Initial ,
3032 }
3133 }
3234
3335 /// Get the next input frame.
34- pub ( super ) async fn next ( & mut self ) -> Result < Option < Frame < ' _ > > > {
35- let headers = match Headers :: read ( & mut self . buf , & mut self . reader ) . await ? {
36- Some ( headers) => headers,
37- None => return Ok ( None ) ,
38- } ;
36+ pub ( super ) async fn next ( & mut self , buf : & mut rust_alloc:: vec:: Vec < u8 > ) -> Result < bool > {
37+ loop {
38+ match self . state {
39+ State :: Initial => {
40+ let Some ( headers) = Headers :: read ( buf, & mut self . reader ) . await ? else {
41+ return Ok ( false ) ;
42+ } ;
3943
40- tracing:: trace!( " headers: {:?}" , headers) ;
44+ tracing:: trace!( ? headers, "Received headers" ) ;
4145
42- let length = match headers. content_length {
43- Some ( length) => length as usize ,
44- None => bail ! ( "missing content-length" ) ,
45- } ;
46+ let len = match headers. content_length {
47+ Some ( length) => length as usize ,
48+ None => bail ! ( "Missing content-length in header" ) ,
49+ } ;
50+
51+ buf. resize ( len, 0u8 ) ;
52+ self . state = State :: Reading ( 0 ) ;
53+ }
54+ State :: Reading ( ref mut at) => {
55+ let n = self . reader . read ( & mut buf[ * at..] ) . await ?;
4656
47- self . buf . resize ( length, 0u8 ) ;
48- self . reader . read_exact ( & mut self . buf [ ..] ) . await ?;
49- Ok ( Some ( Frame { content : & self . buf } ) )
57+ * at += n;
58+
59+ if * at == buf. len ( ) {
60+ self . state = State :: Initial ;
61+ return Ok ( true ) ;
62+ }
63+
64+ if n == 0 {
65+ return Ok ( false ) ;
66+ }
67+ }
68+ }
69+ }
5070 }
5171}
5272
@@ -195,12 +215,12 @@ impl Outbound {
195215 }
196216}
197217
198- #[ derive( Debug ) ]
218+ #[ derive( Debug , Clone , Copy ) ]
199219pub ( super ) enum ContentType {
200220 JsonRPC ,
201221}
202222
203- #[ derive( Default , Debug ) ]
223+ #[ derive( Default , Debug , Clone , Copy ) ]
204224pub ( super ) struct Headers {
205225 pub ( super ) content_length : Option < u32 > ,
206226 pub ( super ) content_type : Option < ContentType > ,
@@ -216,10 +236,9 @@ impl Headers {
216236 S : ?Sized + Unpin + AsyncBufRead ,
217237 {
218238 let mut headers = Headers :: default ( ) ;
239+ let mut any = false ;
219240
220241 loop {
221- buf. clear ( ) ;
222-
223242 let len = match reader. read_until ( b'\n' , buf) . await {
224243 Ok ( len) => len,
225244 Err ( error) => return Err ( error. into ( ) ) ,
@@ -229,11 +248,11 @@ impl Headers {
229248 return Ok ( None ) ;
230249 }
231250
232- debug_assert ! ( len == buf. len( ) ) ;
233- let buf = & buf[ ..len] ;
251+ debug_assert_eq ! ( len, buf. len( ) ) ;
234252
235- let buf = std:: str:: from_utf8 ( buf) ?;
236- let line = buf. trim ( ) ;
253+ let line = buf. get ( ..len) . unwrap_or_default ( ) ;
254+ let line = str:: from_utf8 ( line) . context ( "decoding line" ) ?;
255+ let line = line. trim ( ) ;
237256
238257 if line. is_empty ( ) {
239258 break ;
@@ -245,28 +264,40 @@ impl Headers {
245264
246265 let key = key. trim ( ) ;
247266 let value = value. trim ( ) ;
248- let key = key. to_lowercase ( ) ;
249267
250- match key. as_str ( ) {
251- "content-type" => match value {
252- "application/vscode-jsonrpc; charset=utf-8" => {
253- headers. content_type = Some ( ContentType :: JsonRPC ) ;
268+ ' done: {
269+ if key. eq_ignore_ascii_case ( "content-type" ) {
270+ match value {
271+ "application/vscode-jsonrpc; charset=utf-8" => {
272+ headers. content_type = Some ( ContentType :: JsonRPC ) ;
273+ }
274+ value => {
275+ return Err ( anyhow ! ( "Unsupported content-type `{value}`" ) ) ;
276+ }
254277 }
255- value => {
256- return Err ( anyhow ! ( "bad value: {:?}" , value) ) ;
257- }
258- } ,
259- "content-length" => {
278+
279+ any = true ;
280+ break ' done;
281+ }
282+
283+ if key. eq_ignore_ascii_case ( "content-length" ) {
260284 let value = value
261285 . parse :: < u32 > ( )
262286 . map_err ( |e| anyhow ! ( "bad content-length: {}: {}" , value, e) ) ?;
263287
264288 headers. content_length = Some ( value) ;
265- }
266- key => {
267- return Err ( anyhow ! ( "header not supported: {:?}" , key) ) ;
268- }
289+ any = true ;
290+ break ' done;
291+ } ;
292+
293+ bail ! ( "Unsupported header `{key}`" ) ;
269294 }
295+
296+ buf. clear ( ) ;
297+ }
298+
299+ if !any {
300+ return Ok ( None ) ;
270301 }
271302
272303 Ok ( Some ( headers) )
0 commit comments