ln.http/HttpReader.cs

298 lines
8.4 KiB
C#

using System;
using System.IO;
using System.Text;
using System.Collections.Generic;
using System.Net;
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 IPEndPoint RemoteEndpoint { 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 HttpReader(Stream stream)
{
Stream = stream;
}
public HttpReader(Stream stream,IPEndPoint remoteEndpoint)
{
Stream = stream;
RemoteEndpoint = remoteEndpoint;
}
public void Read()
{
ReadRequestHead();
Method = ReadToken();
SkipWhiteSpace();
URL = ReadToken();
SkipWhiteSpace();
Protocol = ReadToken();
ReadLine();
ReadHeaders();
}
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
{
blen += Stream.Read(buffer, blen, buffer.Length - blen);
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;
}
*/
}
}