44// This is a shared source file included in both ModelContextProtocol.Core and the test project.
55// Do not reference symbols internal to the core project, as they won't be available in tests.
66
7+ #if NET
8+ using System . Buffers ;
9+ using System . Buffers . Text ;
10+ using System . Diagnostics . CodeAnalysis ;
11+
12+ #endif
713using System . Text ;
814
915namespace ModelContextProtocol . Server ;
@@ -39,6 +45,34 @@ public static bool TryParse(string eventId, out string sessionId, out string str
3945 streamId = string . Empty ;
4046 sequence = 0 ;
4147
48+ #if NET
49+ ReadOnlySpan < char > eventIdSpan = eventId . AsSpan ( ) ;
50+ Span < Range > partRanges = stackalloc Range [ 4 ] ;
51+ int rangeCount = eventIdSpan . Split ( partRanges , Separator ) ;
52+ if ( rangeCount != 3 )
53+ {
54+ return false ;
55+ }
56+
57+ try
58+ {
59+ ReadOnlySpan < char > sessionBase64 = eventIdSpan [ partRanges [ 0 ] ] ;
60+ ReadOnlySpan < char > streamBase64 = eventIdSpan [ partRanges [ 1 ] ] ;
61+ ReadOnlySpan < char > sequenceSpan = eventIdSpan [ partRanges [ 2 ] ] ;
62+
63+ if ( ! TryDecodeBase64ToString ( sessionBase64 , out sessionId ! ) ||
64+ ! TryDecodeBase64ToString ( streamBase64 , out streamId ! ) )
65+ {
66+ return false ;
67+ }
68+
69+ return long . TryParse ( sequenceSpan , out sequence ) ;
70+ }
71+ catch
72+ {
73+ return false ;
74+ }
75+ #else
4276 var parts = eventId . Split ( Separator ) ;
4377 if ( parts . Length != 3 )
4478 {
@@ -55,5 +89,30 @@ public static bool TryParse(string eventId, out string sessionId, out string str
5589 {
5690 return false ;
5791 }
92+ #endif
93+ }
94+
95+ #if NET
96+ private static bool TryDecodeBase64ToString ( ReadOnlySpan < char > base64Chars , [ NotNullWhen ( true ) ] out string ? result )
97+ {
98+ // Use a single buffer: base64 chars are ASCII (1:1 with UTF8 bytes),
99+ // and decoded data is always smaller than encoded, so we can decode in-place.
100+ int bufferLength = base64Chars . Length ;
101+ Span < byte > buffer = bufferLength <= 256
102+ ? stackalloc byte [ bufferLength ]
103+ : new byte [ bufferLength ] ;
104+
105+ Encoding . UTF8 . GetBytes ( base64Chars , buffer ) ;
106+
107+ OperationStatus status = Base64 . DecodeFromUtf8InPlace ( buffer , out int bytesWritten ) ;
108+ if ( status != OperationStatus . Done )
109+ {
110+ result = null ;
111+ return false ;
112+ }
113+
114+ result = Encoding . UTF8 . GetString ( buffer [ ..bytesWritten ] ) ;
115+ return true ;
58116 }
117+ #endif
59118}
0 commit comments