diff --git a/HttpReader.cs b/HttpReader.cs index 050697a..72ce77b 100644 --- a/HttpReader.cs +++ b/HttpReader.cs @@ -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 Headers { get; } = new Dictionary(); + // //public Dictionary Headers { get; } = new Dictionary(); - 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 ReadHTTPHeaders() - { - byte[] b = new byte[8192]; - int hlen = ReadTo(b, 0, new byte[] { 0x0d, 0x0a, 0x0d, 0x0a }); + // public Dictionary ReadHTTPHeaders() + // { + // byte[] b = new byte[8192]; + // int hlen = ReadTo(b, 0, new byte[] { 0x0d, 0x0a, 0x0d, 0x0a }); - Dictionary headers = new Dictionary(); + // Dictionary headers = new Dictionary(); - 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; + // } + // */ + //} } diff --git a/HttpRequest.cs b/HttpRequest.cs index e4a5d2a..88ec6fc 100644 --- a/HttpRequest.cs +++ b/HttpRequest.cs @@ -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(httpReader.Headers); - requestHeaders = httpReader.Headers; + ReadRequestLine(); + + requestHeaders = HTTP.ReadHeader(connectionReader); requestCookies = new Dictionary(); requestParameters = new Dictionary(); 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; diff --git a/connections/Connection.cs b/connections/Connection.cs index 09d3066..ceedca3 100644 --- a/connections/Connection.cs +++ b/connections/Connection.cs @@ -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);