Skip to content

Commit b51d2e9

Browse files
authored
Added support for chunked transfer encoding in HTTP response (#232)
1 parent d746f7a commit b51d2e9

3 files changed

Lines changed: 85 additions & 7 deletions

File tree

nanoFramework.System.Net.Http/Http/System.Net.HttpListenerResponse.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ private void PrepareHeaders()
145145
m_httpResponseHeaders.AddWithoutValidate(HttpKnownHeaderNames.Location, m_redirectLocation);
146146
m_ResponseStatusCode = (int)HttpStatusCode.Redirect;
147147
}
148+
149+
if (m_sendChunked)
150+
{
151+
m_httpResponseHeaders.AddWithoutValidate(HttpKnownHeaderNames.TransferEncoding, "chunked");
152+
}
148153
}
149154

150155
/// <summary>
@@ -187,7 +192,7 @@ private void SendHeaders()
187192
Encoding encoder = Encoding.UTF8;
188193

189194
byte[] statusLine = encoder.GetBytes(ComposeHTTPResponse());
190-
m_clientStream.Write(statusLine, 0, statusLine.Length);
195+
m_clientStream.m_Stream.Write(statusLine, 0, statusLine.Length);
191196

192197
// Prepares/Updates WEB header collection.
193198
PrepareHeaders();
@@ -196,7 +201,7 @@ private void SendHeaders()
196201
byte[] pHeaders = m_httpResponseHeaders.ToByteArray();
197202

198203
// Sends the headers
199-
m_clientStream.Write(pHeaders, 0, pHeaders.Length);
204+
m_clientStream.m_Stream.Write(pHeaders, 0, pHeaders.Length);
200205

201206
m_WasResponseSent = true;
202207
}
@@ -334,6 +339,7 @@ public bool SendChunked
334339
{
335340
ThrowIfResponseSent();
336341
m_sendChunked = value;
342+
m_clientStream.m_enableChunkedEncoding = value;
337343
}
338344
}
339345

@@ -443,7 +449,7 @@ void IDisposable.Dispose()
443449
// Iterates over list of client connections and remove its stream from it.
444450
m_Listener.RemoveClientStream(m_clientStream);
445451

446-
m_clientStream.Flush();
452+
m_clientStream.m_Stream.Flush();
447453

448454
// If KeepAlive is true,
449455
if (m_KeepAlive)

nanoFramework.System.Net.Http/Http/System.Net._OutputNetworkStreamWrapper.cs

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ namespace System.Net
88
{
99
using System.IO;
1010
using System.Net.Sockets;
11+
using System.Text;
1112

1213
/// <summary>
1314
/// The OutputNetworkStreamWrapper is used to re-implement calls to NetworkStream.Write
@@ -29,6 +30,11 @@ internal class OutputNetworkStreamWrapper : Stream
2930
/// </summary>
3031
internal NetworkStream m_Stream;
3132

33+
/// <summary>
34+
/// If true causes all written data to be encoded as chunks
35+
/// </summary>
36+
internal bool m_enableChunkedEncoding = false;
37+
3238
/// <summary>
3339
/// Type definition of delegate for sending of HTTP headers.
3440
/// </summary>
@@ -40,6 +46,11 @@ internal class OutputNetworkStreamWrapper : Stream
4046
/// </summary>
4147
private SendHeadersDelegate m_headersSend;
4248

49+
/// <summary>
50+
/// EOL marker in chunked encoding
51+
/// </summary>
52+
private readonly byte[] EOLMarker = { 0xd, 0xa };
53+
4354
/// <summary>
4455
/// Just passes parameters to the base.
4556
/// Socket is not owned by base NetworkStream
@@ -118,6 +129,35 @@ public override int WriteTimeout
118129
set { m_Stream.WriteTimeout = value; }
119130
}
120131

132+
/// <summary>
133+
/// Writes to stream size of chunk and marks start of the chunk
134+
/// </summary>
135+
private void WriteChunkStart(int size)
136+
{
137+
byte[] chunkLengthBytes = Encoding.UTF8.GetBytes($"{size:X}");
138+
m_Stream.Write(chunkLengthBytes, 0, chunkLengthBytes.Length);
139+
m_Stream.Write(EOLMarker, 0, EOLMarker.Length);
140+
}
141+
142+
/// <summary>
143+
/// Writes to stream marker - finish of the chunk
144+
/// </summary>
145+
private void WriteChunkEnd()
146+
{
147+
m_Stream.Write(EOLMarker, 0, EOLMarker.Length);
148+
}
149+
150+
/// <summary>
151+
/// Writes to stream marker - finish of all chunks
152+
/// </summary>
153+
private void WriteChunkFinish()
154+
{
155+
byte[] zero = { 0x30 };
156+
m_Stream.Write(zero, 0, 1);
157+
m_Stream.Write(EOLMarker, 0, EOLMarker.Length);
158+
m_Stream.Write(EOLMarker, 0, EOLMarker.Length);
159+
}
160+
121161
/// <summary>
122162
/// Closes the stream. Verifies that HTTP response is sent before closing.
123163
/// </summary>
@@ -144,7 +184,12 @@ public override void Flush()
144184
// Calls HttpListenerResponse.SendHeaders. HttpListenerResponse.SendHeaders sets m_headersSend to null.
145185
m_headersSend();
146186
}
147-
187+
188+
if (m_enableChunkedEncoding)
189+
{
190+
WriteChunkFinish();
191+
}
192+
148193
// Need to check for null before using here
149194
m_Stream?.Flush();
150195
}
@@ -194,9 +239,26 @@ public override void SetLength(long value)
194239
/// <param name="value">Byte value to write.</param>
195240
public override void WriteByte(byte value)
196241
{
242+
if (m_headersSend != null)
243+
{
244+
// Calls HttpListenerResponse.SendHeaders. HttpListenerResponse.SendHeaders sets m_headersSend to null.
245+
m_headersSend();
246+
}
247+
248+
if (m_enableChunkedEncoding)
249+
{
250+
WriteChunkStart(1);
251+
}
252+
197253
m_Stream.WriteByte(value);
254+
255+
if (m_enableChunkedEncoding)
256+
{
257+
WriteChunkEnd();
258+
}
198259
}
199260

261+
200262
/// <summary>
201263
/// Re-implements writing of data to network stream.
202264
/// The only functionality - on first write it sends HTTP headers.
@@ -213,7 +275,17 @@ public override void Write(byte[] buffer, int offset, int size)
213275
m_headersSend();
214276
}
215277

216-
m_Stream.Write(buffer, offset, size);
278+
if (m_enableChunkedEncoding)
279+
{
280+
WriteChunkStart(size);
281+
}
282+
283+
m_Stream.Write(buffer, 0, size);
284+
285+
if (m_enableChunkedEncoding)
286+
{
287+
WriteChunkEnd();
288+
}
217289
}
218290
}
219291
}

version.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
3-
"version": "1.3.5-preview.{height}",
3+
"version": "1.3.6-preview.{height}",
44
"assemblyVersion": {
55
"precision": "revision"
66
},
@@ -22,4 +22,4 @@
2222
"versionIncrement": "build",
2323
"firstUnstableTag": "preview"
2424
}
25-
}
25+
}

0 commit comments

Comments
 (0)