Rework HTTPRequest connection handling, use HTTP.Parse(..), obsolete HTTPReader

master
Harald Wolff 2020-02-04 21:40:39 +01:00
parent 2542f9a5e1
commit eda733fcbd
3 changed files with 343 additions and 282 deletions

View File

@ -10,304 +10,311 @@ using ln.http.message.parser;
namespace ln.http
{
public class HttpReader
{
delegate bool ReadCondition(int b);
//public class HttpReader
//{
// delegate bool ReadCondition(int b);
public Stream Stream { get; }
// public Stream Stream { get; }
private byte[] buffer = new byte[8192];
private int hlen;
private int blen;
private int bptr;
// private byte[] buffer = new byte[8192];
// private int hlen;
// private int blen;
// private int bptr;
public Endpoint RemoteEndpoint { get; private set; }
// public Endpoint RemoteEndpoint { get; private set; }
public HeaderContainer Headers { get; private set; }
// public HeaderContainer Headers { get; private set; }
public String Method { get; private set; }
public String URL { get; private set; }
public String Protocol { get; private set; }
// public String Method { get; private set; }
// public String URL { get; private set; }
// public String Protocol { get; private set; }
//public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>();
// //public Dictionary<string, string> Headers { get; } = new Dictionary<string, string>();
public bool Valid { get; private set; } = false;
// public bool Valid { get; private set; } = false;
public HttpReader(Stream stream)
{
Stream = stream;
}
public HttpReader(Stream stream,Endpoint remoteEndpoint)
{
Stream = stream;
RemoteEndpoint = remoteEndpoint;
}
// public HttpReader(Stream stream)
// {
// Stream = stream;
// }
// public HttpReader(Stream stream,Endpoint remoteEndpoint)
// {
// Stream = stream;
// RemoteEndpoint = remoteEndpoint;
// }
public void Read()
{
UnbufferedStreamReader reader = new UnbufferedStreamReader(Stream);
string requestLine = reader.ReadLine();
string[] requestTokens = requestLine.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
// public void Read()
// {
// UnbufferedStreamReader reader = new UnbufferedStreamReader(Stream);
// string requestLine = reader.ReadLine();
// string[] requestTokens = requestLine.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
if (requestTokens.Length != 3)
throw new FormatException("request line malformed");
// if (requestTokens.Length != 3)
// throw new FormatException("request line malformed");
Method = requestTokens[0];
URL = requestTokens[1];
Protocol = requestTokens[2];
// Method = requestTokens[0];
// URL = requestTokens[1];
// Protocol = requestTokens[2];
Headers = HTTP.ReadHeader(reader);
// Headers = HTTP.ReadHeader(reader);
Valid = true;
}
// Valid = true;
// }
public int ReadByte()
{
if (bptr >= blen)
return -1;
return buffer[bptr++];
}
// public int ReadByte()
// {
// if (bptr >= blen)
// return -1;
// return buffer[bptr++];
// }
public int Current
{
get
{
if (bptr >= blen)
return -1;
return buffer[bptr];
}
}
// public int Current
// {
// get
// {
// if (bptr >= blen)
// return -1;
// return buffer[bptr];
// }
// }
public void Reverse()
{
if ((bptr > 0) && (bptr < blen))
bptr--;
}
// public void Reverse()
// {
// if ((bptr > 0) && (bptr < blen))
// bptr--;
// }
public void ReadRequestHead()
{
bptr = 0;
do
{
int rlen = Stream.Read(buffer, blen, buffer.Length - blen);
if (rlen == 0)
throw new IOException();
// public void ReadRequestHead()
// {
// bptr = 0;
// do
// {
// int rlen = Stream.Read(buffer, blen, buffer.Length - blen);
// if (rlen == 0)
// throw new IOException();
blen += rlen;
while (bptr <= (blen - 4))
{
if (
(buffer[bptr + 0] == '\r') &&
(buffer[bptr + 1] == '\n') &&
(buffer[bptr + 2] == '\r') &&
(buffer[bptr + 3] == '\n')
)
{
hlen = bptr;
bptr = 0;
return;
}
bptr++;
}
// blen += rlen;
// while (bptr <= (blen - 4))
// {
// if (
// (buffer[bptr + 0] == '\r') &&
// (buffer[bptr + 1] == '\n') &&
// (buffer[bptr + 2] == '\r') &&
// (buffer[bptr + 3] == '\n')
// )
// {
// hlen = bptr;
// bptr = 0;
// return;
// }
// bptr++;
// }
byte[] nbuffer = new byte[buffer.Length << 1];
Array.Copy(buffer, nbuffer, buffer.Length);
buffer = nbuffer;
} while (blen >= buffer.Length);
bptr = 0;
}
// byte[] nbuffer = new byte[buffer.Length << 1];
// Array.Copy(buffer, nbuffer, buffer.Length);
// buffer = nbuffer;
// } while (blen >= buffer.Length);
// bptr = 0;
// }
private String ReadConditional(ReadCondition readCondition,bool reverse = true)
{
StringBuilder stringBuilder = new StringBuilder();
int b = ReadByte();
while ((b != -1) && (readCondition(b)) )
{
stringBuilder.Append((char)b);
b = ReadByte();
}
if (reverse)
Reverse();
// private String ReadConditional(ReadCondition readCondition,bool reverse = true)
// {
// StringBuilder stringBuilder = new StringBuilder();
// int b = ReadByte();
// while ((b != -1) && (readCondition(b)) )
// {
// stringBuilder.Append((char)b);
// b = ReadByte();
// }
// if (reverse)
// Reverse();
return stringBuilder.ToString();
}
// return stringBuilder.ToString();
// }
public void SkipWhiteSpace()
{
while (Char.IsWhiteSpace((char)ReadByte())) { };
Reverse();
}
// public void SkipWhiteSpace()
// {
// while (Char.IsWhiteSpace((char)ReadByte())) { };
// Reverse();
// }
public String ReadToken()
{
return ReadConditional((b) => !Char.IsWhiteSpace((char)b));
}
// public String ReadToken()
// {
// return ReadConditional((b) => !Char.IsWhiteSpace((char)b));
// }
public String ReadLine()
{
int p = bptr;
while (p < blen - 1)
{
if ((buffer[p] == '\r') && (buffer[p + 1] == '\n'))
{
break;
}
p++;
}
// public String ReadLine()
// {
// int p = bptr;
// while (p < blen - 1)
// {
// if ((buffer[p] == '\r') && (buffer[p + 1] == '\n'))
// {
// break;
// }
// p++;
// }
string result = Encoding.ASCII.GetString(buffer, bptr, p - bptr);
bptr = p + 2;
return result;
}
// string result = Encoding.ASCII.GetString(buffer, bptr, p - bptr);
// bptr = p + 2;
// return result;
// }
public String ReadHeaderName()
{
return ReadConditional((b) => b != ':', false).ToUpper();
}
public String ReadHeaderValue()
{
String value = ReadLine();
while (Char.IsWhiteSpace((char)Current))
{
value = value + ReadLine();
}
return value.Trim();
}
// public String ReadHeaderName()
// {
// return ReadConditional((b) => b != ':', false).ToUpper();
// }
// public String ReadHeaderValue()
// {
// String value = ReadLine();
// while (Char.IsWhiteSpace((char)Current))
// {
// value = value + ReadLine();
// }
// return value.Trim();
// }
//public void ReadHeaders()
//{
// while (bptr < hlen)
// {
// String name = ReadHeaderName();
// String value = ReadHeaderValue();
// //public void ReadHeaders()
// //{
// // while (bptr < hlen)
// // {
// // String name = ReadHeaderName();
// // String value = ReadHeaderValue();
// Headers.Add(name, value);
// }
//}
// // Headers.Add(name, value);
// // }
// //}
public int ReadRequestBody(byte[] dst,int offset,int length)
{
int nRead = 0;
if (bptr < blen)
{
int len = Math.Min(length, blen - bptr);
Array.Copy(buffer, bptr, dst, offset, len);
bptr += len;
length -= len;
offset += len;
nRead += len;
}
if (length > 0)
{
nRead += Stream.Read(dst, offset, length);
}
return nRead;
}
// public int ReadRequestBody(byte[] dst,int offset,int length)
// {
// //int nRead = 0;
// //if (bptr < blen)
// //{
// // int len = Math.Min(length, blen - bptr);
// // Array.Copy(buffer, bptr, dst, offset, len);
// // bptr += len;
// // length -= len;
// // offset += len;
// // nRead += len;
// //}
// int nRead = 0;
// while (length > 0)
// {
// int nr = Stream.Read(dst, offset, length);
// if (nr > 0)
// {
// nRead += nr;
// length -= nr;
// offset += nr;
// }
// }
// return nRead;
// }
/*
byte[] buffer;
int blen = 0;
int bptr = 0;
// /*
// byte[] buffer;
// int blen = 0;
// int bptr = 0;
public HttpReader(Stream stream)
{
Stream = stream;
buffer = new byte[1024];
}
public HttpReader(Stream stream, int buffersize)
{
Stream = stream;
buffer = new byte[buffersize];
}
// public HttpReader(Stream stream)
// {
// Stream = stream;
// buffer = new byte[1024];
// }
// public HttpReader(Stream stream, int buffersize)
// {
// Stream = stream;
// buffer = new byte[buffersize];
// }
private int read()
{
if (bptr >= blen)
{
bptr = 0;
blen = Stream.Read(buffer, 0, buffer.Length);
if (blen <= 0)
throw new EndOfStreamException();
}
return buffer[bptr++];
}
// private int read()
// {
// if (bptr >= blen)
// {
// bptr = 0;
// blen = Stream.Read(buffer, 0, buffer.Length);
// if (blen <= 0)
// throw new EndOfStreamException();
// }
// return buffer[bptr++];
// }
private int ReadTo(byte[] b,int offset,byte[] mark)
{
int pm = 0;
int p = offset;
while (p < b.Length)
{
b[p] = (byte)read();
if (b[p] == mark[pm])
{
pm++;
if (pm >= mark.Length)
{
p++;
break;
}
}
else
{
pm = 0;
}
p++;
}
return p;
}
// private int ReadTo(byte[] b,int offset,byte[] mark)
// {
// int pm = 0;
// int p = offset;
// while (p < b.Length)
// {
// b[p] = (byte)read();
// if (b[p] == mark[pm])
// {
// pm++;
// if (pm >= mark.Length)
// {
// p++;
// break;
// }
// }
// else
// {
// pm = 0;
// }
// p++;
// }
// return p;
// }
public String ReadRequestLine(int maxSize = 1024)
{
byte[] b = new byte[maxSize];
int l = ReadTo(b, 0, new byte[] { 0x0d, 0x0a });
return Encoding.ASCII.GetString(b, 0, l);
}
// public String ReadRequestLine(int maxSize = 1024)
// {
// byte[] b = new byte[maxSize];
// int l = ReadTo(b, 0, new byte[] { 0x0d, 0x0a });
// return Encoding.ASCII.GetString(b, 0, l);
// }
public Dictionary<string,string> ReadHTTPHeaders()
{
byte[] b = new byte[8192];
int hlen = ReadTo(b, 0, new byte[] { 0x0d, 0x0a, 0x0d, 0x0a });
// public Dictionary<string,string> ReadHTTPHeaders()
// {
// byte[] b = new byte[8192];
// int hlen = ReadTo(b, 0, new byte[] { 0x0d, 0x0a, 0x0d, 0x0a });
Dictionary<string, string> headers = new Dictionary<string, string>();
// Dictionary<string, string> headers = new Dictionary<string, string>();
string rawHeaders = Encoding.ASCII.GetString(b, 0, hlen);
String[] rawLines = rawHeaders.Split(new String[] { "\r\n" }, StringSplitOptions.None);
// string rawHeaders = Encoding.ASCII.GetString(b, 0, hlen);
// String[] rawLines = rawHeaders.Split(new String[] { "\r\n" }, StringSplitOptions.None);
for (int n = rawLines.Length-1; n >= 0 ; n--)
{
if ((rawLines[n].Length > 0) && (Char.IsWhiteSpace(rawLines[n][0])))
{
rawLines[n - 1] = rawLines[n - 1] + rawLines[n];
rawLines[n] = null;
}
}
// for (int n = rawLines.Length-1; n >= 0 ; n--)
// {
// if ((rawLines[n].Length > 0) && (Char.IsWhiteSpace(rawLines[n][0])))
// {
// rawLines[n - 1] = rawLines[n - 1] + rawLines[n];
// rawLines[n] = null;
// }
// }
foreach (String rawLine in rawLines)
{
if (rawLine != null)
{
int colon = rawLine.IndexOf(':');
if (colon > 0)
{
String name = rawLine.Substring(0, colon).Trim().ToUpper();
String value = rawLine.Substring(colon + 1).Trim();
headers.Add(name, value);
}
}
}
// foreach (String rawLine in rawLines)
// {
// if (rawLine != null)
// {
// int colon = rawLine.IndexOf(':');
// if (colon > 0)
// {
// String name = rawLine.Substring(0, colon).Trim().ToUpper();
// String value = rawLine.Substring(colon + 1).Trim();
// headers.Add(name, value);
// }
// }
// }
return headers;
}
// return headers;
// }
public byte[] ReadRequestBody(byte[] buffer)
{
return null;
}
*/
}
// public byte[] ReadRequestBody(byte[] buffer)
// {
// return null;
// }
// */
//}
}

View File

@ -7,6 +7,8 @@ using ln.types.net;
using System.Threading;
using ln.http.session;
using ln.http.message;
using ln.http.io;
using ln.http.message.parser;
namespace ln.http
{
@ -42,7 +44,16 @@ namespace ln.http
public HeaderContainer RequestHeaders => requestHeaders;
public MemoryStream ContentStream { get; }
MemoryStream contentStream;
public MemoryStream ContentStream
{
get
{
if (contentStream == null)
ReadRequestBody();
return contentStream;
}
}
public TextReader ContentReader
{
get
@ -53,45 +64,89 @@ namespace ln.http
}
}
public Stream GetConnectionStream()
{
return connectionStream;
}
StreamReader contentReader;
int requestBodyLength;
byte[] requestBody;
Stream connectionStream;
StreamReader contentReader;
public HttpRequest(HTTPServer httpServer, HttpReader httpReader, Endpoint localEndpoint)
Stream connectionStream;
UnbufferedStreamReader connectionReader;
public Stream GetConnectionStream() => connectionStream;
public HttpRequest(HTTPServer httpServer, Stream clientStream, Endpoint localEndpoint, Endpoint remoteEndpoint)
{
HTTPServer = httpServer;
connectionStream = httpReader.Stream;
connectionStream = clientStream;
connectionReader = new UnbufferedStreamReader(connectionStream);
LocalEndpoint = localEndpoint;
RemoteEndpoint = httpReader.RemoteEndpoint;
Method = httpReader.Method;
Protocol = httpReader.Protocol;
RequestURL = httpReader.URL;
RemoteEndpoint = remoteEndpoint;
//requestHeaders = new Dictionary<string, string>(httpReader.Headers);
requestHeaders = httpReader.Headers;
ReadRequestLine();
requestHeaders = HTTP.ReadHeader(connectionReader);
requestCookies = new Dictionary<string, string>();
requestParameters = new Dictionary<string, string>();
Setup();
requestBodyLength = int.Parse(GetRequestHeader("content-length", "0"));
}
int clength = int.Parse(GetRequestHeader("content-length", "0"));
requestBody = new byte[clength];
void ReadRequestLine()
{
string requestLine = connectionReader.ReadLine();
string[] requestTokens = requestLine.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
if (clength > 0)
if (requestTokens.Length != 3)
throw new BadRequestException();
Method = requestTokens[0];
RequestURL = requestTokens[1];
Protocol = requestTokens[2];
}
public void ReadRequestBody()
{
requestBody = new byte[requestBodyLength];
if (requestBodyLength > 0)
{
int nread = httpReader.ReadRequestBody(requestBody, 0, clength);
if (nread != clength)
throw new HttpException(500, "failed to read request content");
int nRead = 0;
int length = requestBodyLength;
while (length > 0)
{
int nr = connectionStream.Read(requestBody, nRead, length);
if (nr > 0)
{
nRead += nr;
length -= nr;
}
}
}
ContentStream = new MemoryStream(requestBody);
contentStream = new MemoryStream(requestBody);
}
public void FinishRequest()
{
if ((requestBodyLength > 0) && (requestBody == null))
{
int nRead = 0;
int length = requestBodyLength;
byte[] discard = new byte[8192];
while (length > 0)
{
int nr = connectionStream.Read(discard,0,length > discard.Length ? discard.Length : length);
if (nr > 0)
{
nRead += nr;
length -= nr;
}
}
}
}
public void MakeCurrent() => current.Value = this;

View File

@ -33,10 +33,7 @@ namespace ln.http.connections
{
try
{
HttpReader httpReader = new HttpReader(GetStream());
httpReader.Read();
return new HttpRequest(httpServer, httpReader, Listener.LocalEndpoint);
return new HttpRequest(httpServer, GetStream(), Listener.LocalEndpoint, new Endpoint(RemoteHost, RemotePort));
} catch (IOException)
{
return null;
@ -58,6 +55,8 @@ namespace ln.http.connections
public static void SendResponse(Stream stream, HttpResponse response)
{
response.HttpRequest.FinishRequest();
response.SetHeader("Content-Length", response.ContentStream.Length.ToString());
StreamWriter streamWriter = new StreamWriter(stream);