using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.IO;
using System.Text.RegularExpressions;
namespace ServerLib
{
///
/// HTTP请求定义
///
public class HttpRequest : BaseHeader
{
///
/// URL参数
///
public Object Params { get; private set; }
///
/// HTTP请求方式
///
public string Method { get; private set; }
///
/// HTTP(S)地址
///
public string URL { get; set; }
///
/// HTTP协议版本
///
public string ProtocolVersion { get; set; }
///
/// 定义缓冲区
///
private const int MAX_SIZE = 1024 * 1024 * 2;
private byte[] bytes = new byte[MAX_SIZE];
public ILogger Logger { get; set; }
private Stream handler;
public HttpRequest(Stream stream)
{
this.handler = stream;
var data = GetRequestData(handler);
var rows = Regex.Split(data, Environment.NewLine);
//Request URL & Method & Version
var first = Regex.Split(rows[0], @"(\s+)")
.Where(e => e.Trim() != string.Empty)
.ToArray();
if (first.Length > 0) this.Method = first[0];
if (first.Length > 1) this.URL = Uri.UnescapeDataString(first[1]);
if (first.Length > 2) this.ProtocolVersion = first[2];
//Request Headers
this.Headers = GetRequestHeaders(rows);
//Request Body
Body = GetRequestBody(rows);
var contentLength = GetHeader(RequestHeaders.ContentLength);
if (int.TryParse(contentLength, out var length) && Body.Length != length)
{
do
{
length = stream.Read(bytes, 0, MAX_SIZE - 1);
Body += Encoding.UTF8.GetString(bytes, 0, length);
} while (Body.Length != length);
}
//Request "GET"
if (this.Method == "GET")
{
var isUrlencoded = this.URL.Contains('?');
if (isUrlencoded) this.Params = GetRequestParameters(URL.Split('?')[1]);
}
//Request "POST"
if (this.Method == "POST")
{
var contentType = GetHeader(RequestHeaders.ContentType);
if (contentType == @"application/x-www-form-urlencoded")
this.Params = GetRequestParameters(this.Body);
else if (contentType.Contains("application/json")) //application/json;charset=UTF-8
this.Params = (this.Body);
}
}
public Stream GetRequestStream()
{
return this.handler;
}
public string GetHeader(RequestHeaders header)
{
return GetHeaderByKey(header);
}
public string GetHeader(string fieldName)
{
return GetHeaderByKey(fieldName);
}
public void SetHeader(RequestHeaders header, string value)
{
SetHeaderByKey(header, value);
}
public void SetHeader(string fieldName, string value)
{
SetHeaderByKey(fieldName, value);
}
private string GetRequestData(Stream stream)
{
var length = 0;
var data = string.Empty;
do
{
length = stream.Read(bytes, 0, MAX_SIZE - 1);
data += Encoding.UTF8.GetString(bytes, 0, length);
} while (length > 0 && !data.Contains("\r\n\r\n"));
return data;
}
private string GetRequestBody(IEnumerable rows)
{
var target = rows.Select((v, i) => new { Value = v, Index = i })
.FirstOrDefault(e => e.Value.Trim() == string.Empty);
if (target == null) return null;
var range = Enumerable.Range(target.Index + 1, rows.Count() - target.Index - 1);
return string.Join(Environment.NewLine, range.Select(e => rows.ElementAt(e)).ToArray());
}
private Dictionary GetRequestHeaders(IEnumerable rows)
{
if (rows == null || rows.Count() <= 0) return null;
var target = rows.Select((v, i) => new { Value = v, Index = i })
.FirstOrDefault(e => e.Value.Trim() == string.Empty);
var length = target == null ? rows.Count() - 1 : target.Index;
if (length <= 1) return null;
var range = Enumerable.Range(1, length - 1);
return range.Select(e => rows.ElementAt(e)).ToDictionary(e => e.Split(':')[0], e => e.Split(':')[1].Trim());
}
private Dictionary GetRequestParameters(string row)
{
if (string.IsNullOrEmpty(row)) return null;
var kvs = Regex.Split(row, "&");
if (kvs == null || kvs.Count() <= 0) return null;
return kvs.ToDictionary(e => Regex.Split(e, "=")[0], e =>
{
var p = Regex.Split(e, "=");
return p.Length > 1 ? p[1] : "";
});
}
}
}