33
44using System . IO ;
55using System . Net . Http . Headers ;
6+ using System . Threading ;
7+ using System . Threading . Tasks ;
68using System . Web . Http ;
79
810namespace System . Net . Http . Internal
911{
1012 /// <summary>
11- /// Stream which only exposes a read-only only range view of an
13+ /// Stream which only exposes a read-only only range view of an
1214 /// inner stream.
1315 /// </summary>
1416 internal class ByteRangeStream : DelegatingStream
1517 {
1618 // The offset stream position at which the range starts.
1719 private readonly long _lowerbounds ;
1820
19- // The total number of bytes within the range.
21+ // The total number of bytes within the range.
2022 private readonly long _totalCount ;
2123
2224 // The current number of bytes read into the range
@@ -92,6 +94,23 @@ public override bool CanWrite
9294 get { return false ; }
9395 }
9496
97+ public override long Position
98+ {
99+ get
100+ {
101+ return _currentCount ;
102+ }
103+ set
104+ {
105+ if ( value < 0 )
106+ {
107+ throw Error . ArgumentMustBeGreaterThanOrEqualTo ( "value" , value , 0L ) ;
108+ }
109+
110+ _currentCount = value ;
111+ }
112+ }
113+
95114 public override IAsyncResult BeginRead ( byte [ ] buffer , int offset , int count , AsyncCallback callback , object state )
96115 {
97116 return base . BeginRead ( buffer , offset , PrepareStreamForRangeRead ( count ) , callback , state ) ;
@@ -102,16 +121,47 @@ public override int Read(byte[] buffer, int offset, int count)
102121 return base . Read ( buffer , offset , PrepareStreamForRangeRead ( count ) ) ;
103122 }
104123
124+ public override Task < int > ReadAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
125+ {
126+ return base . ReadAsync ( buffer , offset , PrepareStreamForRangeRead ( count ) , cancellationToken ) ;
127+ }
128+
105129 public override int ReadByte ( )
106130 {
107131 int effectiveCount = PrepareStreamForRangeRead ( 1 ) ;
108132 if ( effectiveCount <= 0 )
109133 {
110134 return - 1 ;
111135 }
136+
112137 return base . ReadByte ( ) ;
113138 }
114139
140+ public override long Seek ( long offset , SeekOrigin origin )
141+ {
142+ switch ( origin )
143+ {
144+ case SeekOrigin . Begin :
145+ _currentCount = offset ;
146+ break ;
147+ case SeekOrigin . Current :
148+ _currentCount = _currentCount + offset ;
149+ break ;
150+ case SeekOrigin . End :
151+ _currentCount = _totalCount + offset ;
152+ break ;
153+ default :
154+ throw Error . InvalidEnumArgument ( "origin" , ( int ) origin , typeof ( SeekOrigin ) ) ;
155+ }
156+
157+ if ( _currentCount < 0L )
158+ {
159+ throw new IOException ( Properties . Resources . ByteRangeStreamInvalidOffset ) ;
160+ }
161+
162+ return _currentCount ;
163+ }
164+
115165 public override void SetLength ( long value )
116166 {
117167 throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
@@ -132,33 +182,49 @@ public override void EndWrite(IAsyncResult asyncResult)
132182 throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
133183 }
134184
185+ public override Task WriteAsync ( byte [ ] buffer , int offset , int count , CancellationToken cancellationToken )
186+ {
187+ throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
188+ }
189+
135190 public override void WriteByte ( byte value )
136191 {
137192 throw Error . NotSupported ( Properties . Resources . ByteRangeStreamReadOnly ) ;
138193 }
139194
140195 /// <summary>
141- /// Gets the
196+ /// Gets the correct count for the next read operation.
142197 /// </summary>
143198 /// <param name="count">The count requested to be read by the caller.</param>
144199 /// <returns>The remaining bytes to read within the range defined for this stream.</returns>
145200 private int PrepareStreamForRangeRead ( int count )
146201 {
147- long effectiveCount = Math . Min ( count , _totalCount - _currentCount ) ;
148- if ( effectiveCount > 0 )
202+ // A negative count causes base.Raad* methods to throw an ArgumentOutOfRangeException.
203+ if ( count <= 0 )
149204 {
150- // Check if we should update the stream position
151- long position = InnerStream . Position ;
152- if ( _lowerbounds + _currentCount != position )
153- {
154- InnerStream . Position = _lowerbounds + _currentCount ;
155- }
205+ return count ;
206+ }
156207
157- // Update current number of bytes read
158- _currentCount += effectiveCount ;
208+ // Reading past the end simply does nothing.
209+ if ( _currentCount >= _totalCount )
210+ {
211+ return 0 ;
159212 }
160213
161- // Effective count can never be bigger than int
214+ long effectiveCount = Math . Min ( count , _totalCount - _currentCount ) ;
215+
216+ // Check if we should update the inner stream's position.
217+ var newPosition = _lowerbounds + _currentCount ;
218+ var position = InnerStream . Position ;
219+ if ( newPosition != position )
220+ {
221+ InnerStream . Position = newPosition ;
222+ }
223+
224+ // Update current number of bytes read.
225+ _currentCount += effectiveCount ;
226+
227+ // Effective count can never be bigger than int.
162228 return ( int ) effectiveCount ;
163229 }
164230 }
0 commit comments