2019-02-14 09:14:50 +01:00
|
|
|
|
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>();
|
|
|
|
|
|
2019-10-11 12:37:16 +02:00
|
|
|
|
public bool Valid { get; private set; } = false;
|
|
|
|
|
|
2019-02-14 09:14:50 +01:00
|
|
|
|
public HttpReader(Stream stream)
|
|
|
|
|
{
|
|
|
|
|
Stream = stream;
|
|
|
|
|
}
|
|
|
|
|
public HttpReader(Stream stream,IPEndPoint remoteEndpoint)
|
|
|
|
|
{
|
|
|
|
|
Stream = stream;
|
|
|
|
|
RemoteEndpoint = remoteEndpoint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void Read()
|
|
|
|
|
{
|
|
|
|
|
ReadRequestHead();
|
|
|
|
|
|
2019-10-11 12:37:16 +02:00
|
|
|
|
if (blen == 0)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-02-14 09:14:50 +01:00
|
|
|
|
Method = ReadToken();
|
|
|
|
|
SkipWhiteSpace();
|
|
|
|
|
URL = ReadToken();
|
|
|
|
|
SkipWhiteSpace();
|
|
|
|
|
Protocol = ReadToken();
|
|
|
|
|
ReadLine();
|
|
|
|
|
|
|
|
|
|
ReadHeaders();
|
2019-10-11 12:37:16 +02:00
|
|
|
|
|
|
|
|
|
Valid = true;
|
2019-02-14 09:14:50 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|