92 lines
3.5 KiB
C#
92 lines
3.5 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Net;
|
|
using System.Text;
|
|
|
|
namespace ln.http;
|
|
|
|
public class Http1XConnection : HttpConnection
|
|
{
|
|
bool _keepAlive;
|
|
|
|
public Http1XConnection(Listener listener, IPEndPoint remoteEndpoint, Stream connectionStream, string method, Uri uri, HttpVersion httpVersion)
|
|
: base(listener, remoteEndpoint, connectionStream, method, uri, httpVersion)
|
|
{
|
|
if (httpVersion == HttpVersion.HTTP11)
|
|
_keepAlive = true;
|
|
}
|
|
|
|
public override void Run()
|
|
{
|
|
string _method = Method;
|
|
Uri _requestUri = RequestUri;
|
|
HttpVersion _httpVersion = HttpVersion;
|
|
HeaderContainer headerContainer = new HeaderContainer();
|
|
|
|
while (ConnectionStream.CanRead && ConnectionStream.CanWrite)
|
|
{
|
|
headerContainer.Clear();
|
|
headerContainer.Read(ConnectionStream);
|
|
|
|
if (
|
|
headerContainer.TryGetHeader("connection", out Header connectionHeader)
|
|
)
|
|
{
|
|
switch (connectionHeader.Value)
|
|
{
|
|
case "close":
|
|
_keepAlive = false;
|
|
break;
|
|
case "keep-alive":
|
|
_keepAlive = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
HttpRequestStream requestStream = null;
|
|
if (headerContainer.TryGetInteger("content-length", out int contentLength))
|
|
requestStream = new HttpRequestStream(ConnectionStream, contentLength);
|
|
|
|
HttpRequestContext requestContext = new HttpRequestContext(Listener, this, ConnectionStream, new HttpRequest(_method, _requestUri, _httpVersion, false, headerContainer, requestStream));
|
|
Listener.Dispatch(requestContext);
|
|
|
|
if (!ConnectionStream.CanWrite && !ConnectionStream.CanRead)
|
|
break;
|
|
|
|
SendResponse(requestContext);
|
|
ConnectionStream.Flush();
|
|
|
|
string responseConnectionHeader = requestContext.Response.GetHeader("connection");
|
|
_keepAlive = responseConnectionHeader switch
|
|
{
|
|
"close" => false,
|
|
"keep-alive" => true,
|
|
_ => _keepAlive
|
|
};
|
|
|
|
requestContext.Dispose();
|
|
|
|
if (!_keepAlive)
|
|
break;
|
|
|
|
if (!HttpConnection.ReadRequestLine(ConnectionStream, out _method, out _requestUri, out _httpVersion))
|
|
break;
|
|
}
|
|
}
|
|
|
|
public override void SendResponse(HttpRequestContext requestContext)
|
|
{
|
|
foreach (var httpCookie in requestContext.Response.Cookies)
|
|
requestContext.Response.Headers.Add("Set-Cookie", httpCookie.ToString());
|
|
|
|
string statusLine = $"{HttpVersionSupport.ToString(requestContext.Request.HttpVersion)} {(int)requestContext.Response.HttpStatusCode} {requestContext.Response.HttpStatusCode.ToString()}\r\n";
|
|
byte[] statusLineBytes = Encoding.ASCII.GetBytes(statusLine);
|
|
requestContext.ConnectionStream.Write(statusLineBytes, 0, statusLineBytes.Length);
|
|
if (!requestContext.Response.Headers.Contains("content-type"))
|
|
requestContext.Response.Headers.Set("content-type", requestContext.Response.HttpContent?.ContentType);
|
|
requestContext.Response.Headers.Set("content-length", requestContext.Response.HttpContent?.Length.ToString() ?? "0");
|
|
requestContext.Response.Headers.CopyTo(requestContext.ConnectionStream);
|
|
requestContext.Response.HttpContent?.CopyTo(requestContext.ConnectionStream);
|
|
}
|
|
|
|
} |