2019-09-11 09:29:05 +02:00
|
|
|
|
using System;
|
|
|
|
|
using System.Net.Sockets;
|
|
|
|
|
using ln.types.threads;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using ln.types;
|
|
|
|
|
using ln.logging;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
namespace ln.http
|
|
|
|
|
{
|
|
|
|
|
public delegate void HTTPServerConnectionEvent(HTTPServerConnection connection);
|
|
|
|
|
|
|
|
|
|
public class HTTPServerConnection : PoolJob
|
|
|
|
|
{
|
|
|
|
|
public static ThreadLocal<HTTPServerConnection> Current { get; } = new ThreadLocal<HTTPServerConnection>();
|
|
|
|
|
static HashSet<HTTPServerConnection> currentConnections = new HashSet<HTTPServerConnection>();
|
|
|
|
|
public static HTTPServerConnection[] CurrentConnections => currentConnections.ToArray();
|
|
|
|
|
|
|
|
|
|
public HTTPServer HTTPServer { get; }
|
|
|
|
|
public TcpClient TcpClient { get; }
|
|
|
|
|
|
|
|
|
|
public HttpRequest CurrentRequest { get; protected set; }
|
|
|
|
|
|
|
|
|
|
public event HTTPServerConnectionEvent AbortRequested;
|
|
|
|
|
|
|
|
|
|
public HTTPServerConnection(HTTPServer httpServer,TcpClient tcpClient)
|
|
|
|
|
{
|
|
|
|
|
HTTPServer = httpServer;
|
|
|
|
|
TcpClient = tcpClient;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public virtual HttpResponse GetResponse(HttpRequest httpRequest,HttpApplication httpApplication) => httpApplication.GetResponse(httpRequest);
|
|
|
|
|
|
|
|
|
|
public virtual void Abort()
|
|
|
|
|
{
|
|
|
|
|
if (AbortRequested != null)
|
|
|
|
|
AbortRequested(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public override void RunJob()
|
|
|
|
|
{
|
|
|
|
|
HTTPServerConnection saveCurrent = Current.Value;
|
|
|
|
|
Current.Value = this;
|
2019-10-11 12:37:16 +02:00
|
|
|
|
lock (currentConnections)
|
|
|
|
|
currentConnections.Add(this);
|
2019-09-11 09:29:05 +02:00
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
setState("reading http request");
|
|
|
|
|
|
|
|
|
|
HttpReader httpReader = new HttpReader(TcpClient.GetStream());
|
|
|
|
|
httpReader.Read();
|
|
|
|
|
|
2019-10-11 12:37:16 +02:00
|
|
|
|
if (!httpReader.Valid)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-09-11 09:29:05 +02:00
|
|
|
|
HttpResponse response = null;
|
|
|
|
|
|
|
|
|
|
using (CurrentRequest = new HttpRequest(httpReader, (IPEndPoint)TcpClient.Client.LocalEndPoint))
|
|
|
|
|
{
|
|
|
|
|
CurrentRequest.ApplySession(HTTPServer.SessionCache);
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
HttpApplication application = HTTPServer.GetHttpApplication(new URI(CurrentRequest.BaseURI.ToString()));
|
|
|
|
|
|
|
|
|
|
application.Authenticate(CurrentRequest);
|
|
|
|
|
application.Authorize(CurrentRequest);
|
|
|
|
|
|
|
|
|
|
setState("handling http request");
|
|
|
|
|
|
|
|
|
|
response = GetResponse(CurrentRequest, application);
|
|
|
|
|
}
|
|
|
|
|
catch (Exception e)
|
|
|
|
|
{
|
|
|
|
|
setState("handling exception");
|
|
|
|
|
|
|
|
|
|
response = new HttpResponse(CurrentRequest, "text/plain");
|
|
|
|
|
response.StatusCode = 500;
|
|
|
|
|
response.ContentWriter.WriteLine("Exception caught: {0}", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
setState("sending response");
|
|
|
|
|
|
|
|
|
|
if (response == null)
|
|
|
|
|
{
|
|
|
|
|
Logging.Log(LogLevel.DEBUG, "Request {0} returned no Response", CurrentRequest);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!response.HasCustomContentStream)
|
|
|
|
|
{
|
|
|
|
|
response.ContentWriter.Flush();
|
|
|
|
|
MemoryStream cstream = (MemoryStream)response.ContentStream;
|
|
|
|
|
cstream.Position = 0;
|
|
|
|
|
|
|
|
|
|
response.SetHeader("content-length", cstream.Length.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (CurrentRequest.Session != null)
|
|
|
|
|
HTTPServer?.SessionCache?.ApplySessionID(response, CurrentRequest.Session);
|
|
|
|
|
|
|
|
|
|
response.AddCookie("LN_SEEN", DateTime.Now.ToString());
|
|
|
|
|
|
|
|
|
|
SendResponse(TcpClient.GetStream(), response);
|
|
|
|
|
TcpClient.Close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
finally
|
|
|
|
|
{
|
|
|
|
|
Current.Value = saveCurrent;
|
2019-10-11 12:37:16 +02:00
|
|
|
|
lock (currentConnections)
|
|
|
|
|
currentConnections.Remove(this);
|
2019-09-11 09:29:05 +02:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void SendResponse(Stream stream, HttpResponse response)
|
|
|
|
|
{
|
|
|
|
|
StreamWriter streamWriter = new StreamWriter(stream);
|
|
|
|
|
streamWriter.NewLine = "\r\n";
|
|
|
|
|
|
|
|
|
|
streamWriter.WriteLine("{0} {1} {2}", response.HttpRequest.Protocol, response.StatusCode, response.StatusMessage);
|
|
|
|
|
foreach (String headerName in response.GetHeaderNames())
|
|
|
|
|
{
|
|
|
|
|
streamWriter.WriteLine("{0}: {1}", headerName, response.GetHeader(headerName));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (HttpCookie httpCookie in response.Cookies)
|
|
|
|
|
{
|
|
|
|
|
streamWriter.WriteLine("Set-Cookie: {0}", httpCookie.ToString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
streamWriter.WriteLine();
|
|
|
|
|
streamWriter.Flush();
|
|
|
|
|
|
|
|
|
|
response.ContentStream.CopyTo(stream);
|
|
|
|
|
response.ContentStream.Close();
|
|
|
|
|
response.ContentStream.Dispose();
|
|
|
|
|
|
|
|
|
|
streamWriter.Flush();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|