Skip to content

Commit e268ac0

Browse files
authored
Add support for HTTP/1.0 responses without 'Content-Lenght' header (#403)
1 parent 68421a7 commit e268ac0

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

nanoFramework.System.Net.Http/Http/StreamContent.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,21 +96,18 @@ protected override void SerializeToStream(Stream stream)
9696
}
9797
}
9898

99-
while (totalRead < contentLength)
99+
bool isDone = false;
100+
while ((totalRead < contentLength) && !isDone)
100101
{
101102
read = _content.Read(buffer, 0, buffer.Length);
103+
isDone = (_content is IKnowWhenDone knowWhenDone && knowWhenDone.IsDone);
102104

103-
if (_content is IKnowWhenDone knowWhenDone && knowWhenDone.IsDone)
104-
{
105-
//happens when a chunked response is at the end
106-
break;
107-
}
108-
else if (read == 0)
105+
if (!isDone && (read == 0))
109106
{
110107
// need to let the native layer get more data
111108
Thread.Sleep(10);
112109
}
113-
else
110+
else if (read > 0)
114111
{
115112
totalRead += read;
116113
stream.Write(buffer, 0, read);

nanoFramework.System.Net.Http/Http/System.Net._InputNetworkStreamWrapper.cs

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,7 +323,12 @@ public int ReadInternal(byte[] buffer, int offset, int size)
323323
// then we read into internal buffer.
324324
if (size < read_buffer_size)
325325
{
326-
if (0 == RefillInternalBuffer()) return 0;
326+
if (0 == RefillInternalBuffer())
327+
{
328+
// Handle the 'HTTP/1.0' case
329+
IsDone = IsHttp1_0Completed();
330+
return 0;
331+
}
327332

328333
dataBuffered = m_dataEnd - m_dataStart;
329334
if (dataBuffered > 0)
@@ -341,7 +346,15 @@ public int ReadInternal(byte[] buffer, int offset, int size)
341346
}
342347
else // Do not replentish internal buffer. Read rest of data directly
343348
{
344-
retVal += m_Stream.Read(buffer, offset, size);
349+
int bytesRead = m_Stream.Read(buffer, offset, size);
350+
retVal += bytesRead;
351+
352+
// Handle the 'HTTP/1.0' case
353+
if ((bytesRead == 0) && IsHttp1_0Completed())
354+
{
355+
IsDone = true;
356+
return retVal;
357+
}
345358
}
346359
}
347360

@@ -357,6 +370,20 @@ public int ReadInternal(byte[] buffer, int offset, int size)
357370
return retVal;
358371
}
359372

373+
/// <summary>
374+
/// Returns true if we are in 'HTTP/1.0' mode and the connection has been closed, which marks the end of the body.
375+
/// </summary>
376+
/// <remarks>
377+
/// In 'HTTP/1.0' mode, where the content length is not transmitted in the response header and the server closes the connection to mark the end of the body.
378+
/// (see: RFC9112, §6.3, point 8, https://www.rfc-editor.org/rfc/rfc9112#name-message-body-length)
379+
/// </remarks>
380+
private bool IsHttp1_0Completed()
381+
{
382+
return
383+
(m_BytesLeftInResponse == -1) && !m_EnableChunkedDecoding && // We are in HTTP/1.0 mode
384+
m_Socket.Poll(1, SelectMode.SelectRead) && (m_Socket.Available == 0); // The socket is disconnected
385+
}
386+
360387
/// <summary>
361388
/// Impletments Write for the stream.
362389
/// Since we do not have write buffering, all we do is delegate to the m_Stream.

0 commit comments

Comments
 (0)