source: TFP-WebServer/SpaceWizards.HttpListener/src/System/Net/Managed/HttpRequestStream.Managed.cs

Last change on this file was 377, checked in by alloc, 2 years ago

Made SpaceWizards.HttpListener compilable against .NET 4.8 with preprocessor define UNITY_NETFRAMEWORK

File size: 7.2 KB
Line 
1// Licensed to the .NET Foundation under one or more agreements.
2// The .NET Foundation licenses this file to you under the MIT license.
3
4//
5// System.Net.RequestStream
6//
7// Author:
8// Gonzalo Paniagua Javier (gonzalo@novell.com)
9//
10// Copyright (c) 2005 Novell, Inc. (http://www.novell.com)
11//
12// Permission is hereby granted, free of charge, to any person obtaining
13// a copy of this software and associated documentation files (the
14// "Software"), to deal in the Software without restriction, including
15// without limitation the rights to use, copy, modify, merge, publish,
16// distribute, sublicense, and/or sell copies of the Software, and to
17// permit persons to whom the Software is furnished to do so, subject to
18// the following conditions:
19//
20// The above copyright notice and this permission notice shall be
21// included in all copies or substantial portions of the Software.
22//
23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30//
31
32// ReSharper disable RedundantUsingDirective
33// ReSharper disable RedundantExtendsListEntry
34// ReSharper disable RedundantCast
35
36using System;
37using System.Diagnostics;
38using System.IO;
39using System.Net;
40using System.Net.Sockets;
41using System.Runtime.ExceptionServices;
42using System.Runtime.InteropServices;
43using System.Threading;
44using System.Threading.Tasks;
45
46namespace SpaceWizards.HttpListener
47{
48 internal partial class HttpRequestStream : Stream
49 {
50 private byte[] _buffer;
51 private int _offset;
52 private int _length;
53 private long _remainingBody;
54 protected bool _closed;
55 private Stream _stream;
56
57 internal HttpRequestStream(Stream stream, byte[] buffer, int offset, int length)
58 : this(stream, buffer, offset, length, -1)
59 {
60 }
61
62 internal HttpRequestStream(Stream stream, byte[] buffer, int offset, int length, long contentlength)
63 {
64 _stream = stream;
65 _buffer = buffer;
66 _offset = offset;
67 _length = length;
68 _remainingBody = contentlength;
69 }
70
71 // Returns 0 if we can keep reading from the base stream,
72 // > 0 if we read something from the buffer.
73 // -1 if we had a content length set and we finished reading that many bytes.
74 private int FillFromBuffer(byte[] buffer, int offset, int count)
75 {
76 if (_remainingBody == 0)
77 return -1;
78
79 if (_length == 0)
80 return 0;
81
82 int size = Math.Min(_length, count);
83 if (_remainingBody > 0)
84 size = (int)Math.Min(size, _remainingBody);
85
86 if (_offset > _buffer.Length - size)
87 {
88 size = Math.Min(size, _buffer.Length - _offset);
89 }
90 if (size == 0)
91 return 0;
92
93 Buffer.BlockCopy(_buffer, _offset, buffer, offset, size);
94 _offset += size;
95 _length -= size;
96 if (_remainingBody > 0)
97 _remainingBody -= size;
98 return size;
99 }
100
101 protected virtual int ReadCore(byte[] buffer, int offset, int size)
102 {
103 // Call FillFromBuffer to check for buffer boundaries even when remaining_body is 0
104 int nread = FillFromBuffer(buffer, offset, size);
105 if (nread == -1)
106 { // No more bytes available (Content-Length)
107 return 0;
108 }
109 else if (nread > 0)
110 {
111 return nread;
112 }
113
114 if (_remainingBody > 0)
115 {
116 size = (int)Math.Min(_remainingBody, (long)size);
117 }
118
119 nread = _stream.Read(buffer, offset, size);
120
121 if (_remainingBody > 0)
122 {
123 if (nread == 0)
124 {
125 throw new HttpListenerException((int)HttpStatusCode.BadRequest);
126 }
127
128 Debug.Assert(nread <= _remainingBody);
129 _remainingBody -= nread;
130 }
131
132 return nread;
133 }
134
135 protected virtual IAsyncResult BeginReadCore(byte[] buffer, int offset, int size, AsyncCallback? cback, object? state)
136 {
137 if (size == 0 || _closed)
138 {
139 HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this);
140 ares._callback = cback;
141 ares._state = state;
142 ares.Complete();
143 return ares;
144 }
145
146 int nread = FillFromBuffer(buffer, offset, size);
147 if (nread > 0 || nread == -1)
148 {
149 HttpStreamAsyncResult ares = new HttpStreamAsyncResult(this);
150 ares._buffer = buffer;
151 ares._offset = offset;
152 ares._count = size;
153 ares._callback = cback;
154 ares._state = state;
155 ares._synchRead = Math.Max(0, nread);
156 ares.Complete();
157 return ares;
158 }
159
160 // Avoid reading past the end of the request to allow
161 // for HTTP pipelining
162 if (_remainingBody >= 0 && size > _remainingBody)
163 {
164 size = (int)Math.Min(_remainingBody, (long)size);
165 }
166
167 return _stream.BeginRead(buffer, offset, size, cback, state);
168 }
169
170 public override int EndRead(IAsyncResult asyncResult)
171 {
172 if (asyncResult == null)
173 throw new ArgumentNullException(nameof(asyncResult));
174
175 if (asyncResult is HttpStreamAsyncResult r)
176 {
177 if (!ReferenceEquals(this, r._parent))
178 {
179 throw new ArgumentException(SR.net_io_invalidasyncresult, nameof(asyncResult));
180 }
181 if (r._endCalled)
182 {
183 throw new InvalidOperationException(SR.Format(SR.net_io_invalidendcall, nameof(EndRead)));
184 }
185 r._endCalled = true;
186
187 if (!asyncResult.IsCompleted)
188 {
189 asyncResult.AsyncWaitHandle.WaitOne();
190 }
191
192 return r._synchRead;
193 }
194
195 if (_closed)
196 return 0;
197
198 int nread = 0;
199 try
200 {
201 nread = _stream.EndRead(asyncResult);
202 }
203 catch (IOException e) when (e.InnerException is ArgumentException || e.InnerException is InvalidOperationException)
204 {
205 ExceptionDispatchInfo.Throw(e.InnerException);
206 }
207
208 if (_remainingBody > 0)
209 {
210 if (nread == 0)
211 {
212 throw new HttpListenerException((int)HttpStatusCode.BadRequest);
213 }
214
215 Debug.Assert(nread <= _remainingBody);
216 _remainingBody -= nread;
217 }
218
219 return nread;
220 }
221 }
222}
Note: See TracBrowser for help on using the repository browser.