ln.http/HttpReader.cs

314 lines
9.0 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Net;
using ln.types.net;
using ln.http.message;
using ln.http.io;
using ln.http.message.parser;
namespace ln.http
{
public class HttpReader
{
delegate bool ReadCondition(int b);
public Stream Stream { get; }
private byte[] buffer = new byte[8192];
private int hlen;
private int blen;
private int bptr;
public Endpoint RemoteEndpoint { 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 Dictionary<string, string> Headers { get; } = new Dictionary<string, string>();
public bool Valid { get; private set; } = false;
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);
if (requestTokens.Length != 3)
throw new FormatException("request line malformed");
Method = requestTokens[0];
URL = requestTokens[1];
Protocol = requestTokens[2];
Headers = HTTP.ReadHeader(reader);
Valid = true;
}
public int ReadByte()
{
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 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++;
}
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();
return stringBuilder.ToString();
}
public void SkipWhiteSpace()
{
while (Char.IsWhiteSpace((char)ReadByte())) { };
Reverse();
}
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++;
}
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 void ReadHeaders()
//{
// while (bptr < hlen)
// {
// String name = ReadHeaderName();
// String value = ReadHeaderValue();
// 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;
}
/*
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];
}
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;
}
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 });
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);
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);
}
}
}
return headers;
}
public byte[] ReadRequestBody(byte[] buffer)
{
return null;
}
*/
}
}