33using System . IO ;
44using System . Text ;
55using System . Threading . Tasks ;
6- using Titanium . Web . Proxy . Extensions ;
76
87namespace Titanium . Web . Proxy . Helpers
98{
@@ -15,12 +14,30 @@ namespace Titanium.Web.Proxy.Helpers
1514 /// </summary>
1615 internal class CustomBinaryReader : IDisposable
1716 {
18- private readonly Stream stream ;
17+ private readonly CustomBufferedStream stream ;
18+ private readonly int bufferSize ;
1919 private readonly Encoding encoding ;
2020
21- internal CustomBinaryReader ( Stream stream )
21+ [ ThreadStatic ]
22+ private static byte [ ] staticBuffer ;
23+
24+ private byte [ ] buffer
25+ {
26+ get
27+ {
28+ if ( staticBuffer == null || staticBuffer . Length != bufferSize )
29+ {
30+ staticBuffer = new byte [ bufferSize ] ;
31+ }
32+
33+ return staticBuffer ;
34+ }
35+ }
36+
37+ internal CustomBinaryReader ( CustomBufferedStream stream , int bufferSize )
2238 {
2339 this . stream = stream ;
40+ this . bufferSize = bufferSize ;
2441
2542 //default to UTF-8
2643 encoding = Encoding . UTF8 ;
@@ -34,33 +51,41 @@ internal CustomBinaryReader(Stream stream)
3451 /// <returns></returns>
3552 internal async Task < string > ReadLineAsync ( )
3653 {
37- using ( var readBuffer = new MemoryStream ( ) )
54+ var lastChar = default ( byte ) ;
55+
56+ int bufferDataLength = 0 ;
57+
58+ // try to use the thread static buffer, usually it is enough
59+ var buffer = this . buffer ;
60+
61+ while ( stream . DataAvailable || await stream . FillBufferAsync ( ) )
3862 {
39- var lastChar = default ( char ) ;
40- var buffer = new byte [ 1 ] ;
41-
42- while ( ( await stream . ReadAsync ( buffer , 0 , 1 ) ) > 0 )
43- {
44- //if new line
45- if ( lastChar == '\r ' && buffer [ 0 ] == '\n ' )
46- {
47- var result = readBuffer . ToArray ( ) ;
48- return encoding . GetString ( result . SubArray ( 0 , result . Length - 1 ) ) ;
49- }
50- //end of stream
51- if ( buffer [ 0 ] == '\0 ' )
52- {
53- return encoding . GetString ( readBuffer . ToArray ( ) ) ;
54- }
55-
56- await readBuffer . WriteAsync ( buffer , 0 , 1 ) ;
57-
58- //store last char for new line comparison
59- lastChar = ( char ) buffer [ 0 ] ;
60- }
61-
62- return encoding . GetString ( readBuffer . ToArray ( ) ) ;
63+ var newChar = stream . ReadByteFromBuffer ( ) ;
64+ buffer [ bufferDataLength ] = newChar ;
65+
66+ //if new line
67+ if ( lastChar == '\r ' && newChar == '\n ' )
68+ {
69+ return encoding . GetString ( buffer , 0 , bufferDataLength - 1 ) ;
70+ }
71+ //end of stream
72+ if ( newChar == '\0 ' )
73+ {
74+ return encoding . GetString ( buffer , 0 , bufferDataLength ) ;
75+ }
76+
77+ bufferDataLength ++ ;
78+
79+ //store last char for new line comparison
80+ lastChar = newChar ;
81+
82+ if ( bufferDataLength == buffer . Length )
83+ {
84+ ResizeBuffer ( ref buffer , bufferDataLength * 2 ) ;
85+ }
6386 }
87+
88+ return encoding . GetString ( buffer , 0 , bufferDataLength ) ;
6489 }
6590
6691 /// <summary>
@@ -78,6 +103,17 @@ internal async Task<List<string>> ReadAllLinesAsync()
78103 return requestLines ;
79104 }
80105
106+ /// <summary>
107+ /// Read until the last new line, ignores the result
108+ /// </summary>
109+ /// <returns></returns>
110+ internal async Task ReadAndIgnoreAllLinesAsync ( )
111+ {
112+ while ( ! string . IsNullOrEmpty ( await ReadLineAsync ( ) ) )
113+ {
114+ }
115+ }
116+
81117 /// <summary>
82118 /// Read the specified number of raw bytes from the base stream
83119 /// </summary>
@@ -91,34 +127,51 @@ internal async Task<byte[]> ReadBytesAsync(int bufferSize, long totalBytesToRead
91127 if ( totalBytesToRead < bufferSize )
92128 bytesToRead = ( int ) totalBytesToRead ;
93129
94- var buffer = new byte [ bufferSize ] ;
130+ var buffer = this . buffer ;
131+ if ( bytesToRead > buffer . Length )
132+ {
133+ buffer = new byte [ bytesToRead ] ;
134+ }
95135
96- var bytesRead = 0 ;
136+ int bytesRead ;
97137 var totalBytesRead = 0 ;
98138
99- using ( var outStream = new MemoryStream ( ) )
139+ while ( ( bytesRead = await stream . ReadAsync ( buffer , totalBytesRead , bytesToRead ) ) > 0 )
100140 {
101- while ( ( bytesRead += await stream . ReadAsync ( buffer , 0 , bytesToRead ) ) > 0 )
102- {
103- await outStream . WriteAsync ( buffer , 0 , bytesRead ) ;
104- totalBytesRead += bytesRead ;
141+ totalBytesRead += bytesRead ;
142+
143+ if ( totalBytesRead == totalBytesToRead )
144+ break ;
105145
106- if ( totalBytesRead == totalBytesToRead )
107- break ;
146+ var remainingBytes = totalBytesToRead - totalBytesRead ;
147+ bytesToRead = Math . Min ( bufferSize , ( int ) remainingBytes ) ;
108148
109- bytesRead = 0 ;
110- var remainingBytes = ( totalBytesToRead - totalBytesRead ) ;
111- bytesToRead = remainingBytes > ( long ) bufferSize ? bufferSize : ( int ) remainingBytes ;
149+ if ( totalBytesRead + bytesToRead > buffer . Length )
150+ {
151+ ResizeBuffer ( ref buffer , Math . Min ( totalBytesToRead , buffer . Length * 2 ) ) ;
112152 }
153+ }
113154
114- return outStream . ToArray ( ) ;
155+ if ( totalBytesRead != buffer . Length )
156+ {
157+ //Normally this should not happen. Resize the buffer anyway
158+ var newBuffer = new byte [ totalBytesRead ] ;
159+ Buffer . BlockCopy ( buffer , 0 , newBuffer , 0 , totalBytesRead ) ;
160+ buffer = newBuffer ;
115161 }
116162
163+ return buffer ;
117164 }
118165
119166 public void Dispose ( )
120167 {
168+ }
121169
170+ private void ResizeBuffer ( ref byte [ ] buffer , long size )
171+ {
172+ var newBuffer = new byte [ size ] ;
173+ Buffer . BlockCopy ( buffer , 0 , newBuffer , 0 , buffer . Length ) ;
174+ buffer = newBuffer ;
122175 }
123176 }
124177}
0 commit comments