// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-#if NET_2_0
+
+#if SECURITY_DEP
+
using System.IO;
using System.Net.Sockets;
using System.Text;
using System.Runtime.InteropServices;
namespace System.Net {
// FIXME: Does this buffer the response until Close?
+ // Update: we send a single packet for the first non-chunked Write
// What happens when we set content-length to X and write X-1 bytes then close?
// what if we don't set content-length at all?
- class ResponseStream : NetworkStream
+ class ResponseStream : Stream
{
HttpListenerResponse response;
bool ignore_errors;
bool disposed;
bool trailer_sent;
+ Stream stream;
- internal ResponseStream (Socket sock, HttpListenerResponse response, bool ignore_errors) :
- base (sock, false)
+ internal ResponseStream (Stream stream, HttpListenerResponse response, bool ignore_errors)
{
this.response = response;
this.ignore_errors = ignore_errors;
+ this.stream = stream;
}
public override bool CanRead {
{
if (disposed == false) {
disposed = true;
- if (response.HeadersSent == false)
- response.SendHeaders (true);
-
- if (response.SendChunked && !trailer_sent) {
- WriteChunkSize (0, true);
+ byte [] bytes = null;
+ MemoryStream ms = GetHeaders (true);
+ bool chunked = response.SendChunked;
+ if (ms != null) {
+ long start = ms.Position;
+ if (chunked && !trailer_sent) {
+ bytes = GetChunkSizeBytes (0, true);
+ ms.Position = ms.Length;
+ ms.Write (bytes, 0, bytes.Length);
+ }
+ InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start));
+ trailer_sent = true;
+ } else if (chunked && !trailer_sent) {
+ bytes = GetChunkSizeBytes (0, true);
+ InternalWrite (bytes, 0, bytes.Length);
trailer_sent = true;
}
response.Close ();
}
}
+ MemoryStream GetHeaders (bool closing)
+ {
+ // SendHeaders works on shared headers
+ lock (response.headers_lock) {
+ if (response.HeadersSent)
+ return null;
+ MemoryStream ms = new MemoryStream ();
+ response.SendHeaders (closing, ms);
+ return ms;
+ }
+ }
+
public override void Flush ()
{
}
static byte [] crlf = new byte [] { 13, 10 };
- void WriteChunkSize (int size, bool final)
+ static byte [] GetChunkSizeBytes (int size, bool final)
{
string str = String.Format ("{0:x}\r\n{1}", size, final ? "\r\n" : "");
- byte [] b = Encoding.ASCII.GetBytes (str);
- base.Write (b, 0, b.Length);
+ return Encoding.ASCII.GetBytes (str);
}
internal void InternalWrite (byte [] buffer, int offset, int count)
{
if (ignore_errors) {
try {
- base.Write (buffer, offset, count);
+ stream.Write (buffer, offset, count);
} catch { }
} else {
- base.Write (buffer, offset, count);
+ stream.Write (buffer, offset, count);
}
}
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (response.HeadersSent == false)
- response.SendHeaders (false);
-
+ byte [] bytes = null;
+ MemoryStream ms = GetHeaders (false);
bool chunked = response.SendChunked;
- try {
- if (chunked)
- WriteChunkSize (count, false);
- } catch { }
- InternalWrite (buffer, offset, count);
- try {
- if (chunked)
- base.Write (crlf, 0, 2);
- } catch { }
+ if (ms != null) {
+ long start = ms.Position; // After the possible preamble for the encoding
+ ms.Position = ms.Length;
+ if (chunked) {
+ bytes = GetChunkSizeBytes (count, false);
+ ms.Write (bytes, 0, bytes.Length);
+ }
+
+ int new_count = Math.Min (count, 16384 - (int) ms.Position + (int) start);
+ ms.Write (buffer, offset, new_count);
+ count -= new_count;
+ offset += new_count;
+ InternalWrite (ms.GetBuffer (), (int) start, (int) (ms.Length - start));
+ ms.SetLength (0);
+ ms.Capacity = 0; // 'dispose' the buffer in ms.
+ } else if (chunked) {
+ bytes = GetChunkSizeBytes (count, false);
+ InternalWrite (bytes, 0, bytes.Length);
+ }
+
+ if (count > 0)
+ InternalWrite (buffer, offset, count);
+ if (chunked)
+ InternalWrite (crlf, 0, 2);
}
public override IAsyncResult BeginWrite (byte [] buffer, int offset, int count,
if (disposed)
throw new ObjectDisposedException (GetType ().ToString ());
- if (response.HeadersSent == false)
- response.SendHeaders (false);
+ byte [] bytes = null;
+ MemoryStream ms = GetHeaders (false);
+ bool chunked = response.SendChunked;
+ if (ms != null) {
+ long start = ms.Position;
+ ms.Position = ms.Length;
+ if (chunked) {
+ bytes = GetChunkSizeBytes (count, false);
+ ms.Write (bytes, 0, bytes.Length);
+ }
+ ms.Write (buffer, offset, count);
+ buffer = ms.GetBuffer ();
+ offset = (int) start;
+ count = (int) (ms.Position - start);
+ } else if (chunked) {
+ bytes = GetChunkSizeBytes (count, false);
+ InternalWrite (bytes, 0, bytes.Length);
+ }
- try {
- if (response.SendChunked)
- WriteChunkSize (count, false);
- } catch { }
- return base.BeginWrite (buffer, offset, count, cback, state);
+ return stream.BeginWrite (buffer, offset, count, cback, state);
}
public override void EndWrite (IAsyncResult ares)
if (ignore_errors) {
try {
- base.EndWrite (ares);
+ stream.EndWrite (ares);
if (response.SendChunked)
- base.Write (crlf, 0, 2);
+ stream.Write (crlf, 0, 2);
} catch { }
} else {
- base.EndWrite (ares);
+ stream.EndWrite (ares);
if (response.SendChunked)
- base.Write (crlf, 0, 2);
+ stream.Write (crlf, 0, 2);
}
}