Implemented simple Session tracking
parent
ce948567fc
commit
089ce02f0b
|
@ -6,6 +6,7 @@ using System.Threading;
|
|||
using ln.http.threads;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using ln.http.resources.session;
|
||||
|
||||
|
||||
namespace ln.http
|
||||
|
@ -25,8 +26,13 @@ namespace ln.http
|
|||
|
||||
Pool threadPool = new Pool();
|
||||
|
||||
public SessionCache SessionCache { get; set; }
|
||||
|
||||
|
||||
|
||||
public HTTPServer()
|
||||
{
|
||||
SessionCache = new SessionCache();
|
||||
}
|
||||
|
||||
public void AddEndpoint(IPEndPoint endpoint)
|
||||
|
@ -99,6 +105,8 @@ namespace ln.http
|
|||
HttpRequest httpRequest = new HttpRequest(httpReader, (IPEndPoint)tcpClient.Client.LocalEndPoint);
|
||||
HttpResponse response = null;
|
||||
|
||||
httpRequest.ApplySession(SessionCache);
|
||||
|
||||
try
|
||||
{
|
||||
HttpApplication application = DefaultApplication;
|
||||
|
@ -123,6 +131,14 @@ namespace ln.http
|
|||
response.SetHeader("content-length", cstream.Length.ToString());
|
||||
}
|
||||
|
||||
if (SessionCache != null)
|
||||
{
|
||||
SessionCache.ApplySessionID(response,httpRequest.Session);
|
||||
}
|
||||
|
||||
response.AddCookie("LN_SEEN", DateTime.Now.ToString());
|
||||
|
||||
|
||||
StreamWriter streamWriter = new StreamWriter(tcpClient.GetStream());
|
||||
|
||||
streamWriter.WriteLine("{0} {1} {2}", httpRequest.Protocol,response.StatusCode, response.StatusMessage);
|
||||
|
@ -131,6 +147,12 @@ namespace ln.http
|
|||
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();
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
namespace ln.http
|
||||
{
|
||||
public class HttpCookie
|
||||
{
|
||||
public String Name { get; set; }
|
||||
public String Value { get; set; }
|
||||
|
||||
public bool Secure { get; set; }
|
||||
public DateTime Expires { get; set; }
|
||||
public String Path { get; set; }
|
||||
public String Domain { get; set; }
|
||||
|
||||
public HttpCookie(String name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
public HttpCookie(String name,String value)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
stringBuilder.AppendFormat("{0}={1}", Name, Value);
|
||||
if (Secure)
|
||||
stringBuilder.Append(";SECURE");
|
||||
|
||||
if (Path != null)
|
||||
stringBuilder.AppendFormat(";Path={0}", Path);
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -6,12 +6,14 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using ln.http.exceptions;
|
||||
using ln.http.resources.session;
|
||||
|
||||
namespace ln.http
|
||||
{
|
||||
public class HttpRequest
|
||||
{
|
||||
Dictionary<String, String> requestHeaders;
|
||||
Dictionary<String, String> requestCookies;
|
||||
|
||||
public IPEndPoint RemoteEndpoint { get; private set; }
|
||||
public IPEndPoint LocalEndpoint { get; private set; }
|
||||
|
@ -28,6 +30,8 @@ namespace ln.http
|
|||
|
||||
public QueryStringParameters Query { get; private set; }
|
||||
|
||||
public Session Session { get; private set; }
|
||||
|
||||
public HttpRequest(HttpReader httpReader,IPEndPoint localEndpoint)
|
||||
{
|
||||
LocalEndpoint = localEndpoint;
|
||||
|
@ -37,6 +41,7 @@ namespace ln.http
|
|||
RequestURL = httpReader.URL;
|
||||
|
||||
requestHeaders = new Dictionary<string, string>(httpReader.Headers);
|
||||
requestCookies = new Dictionary<string, string>();
|
||||
|
||||
Setup();
|
||||
}
|
||||
|
@ -44,6 +49,7 @@ namespace ln.http
|
|||
private void Setup()
|
||||
{
|
||||
SetupResourceURI();
|
||||
SetupCookies();
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -70,6 +76,35 @@ namespace ln.http
|
|||
Query = new QueryStringParameters(URI.Query);
|
||||
}
|
||||
|
||||
private void SetupCookies()
|
||||
{
|
||||
string cookies = GetRequestHeader("COOKIE");
|
||||
foreach (String cookie in cookies.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
string[] c = cookie.Split(new char[] { '=' }, 2);
|
||||
string cn, cv;
|
||||
cn = c[0].Trim();
|
||||
if (c.Length > 1)
|
||||
cv = c[1].Trim();
|
||||
else
|
||||
cv = "";
|
||||
|
||||
if (!this.requestCookies.ContainsKey(cn))
|
||||
this.requestCookies.Add(cn, cv);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplySession(SessionCache sessionCache)
|
||||
{
|
||||
Session session = sessionCache.ApplySession(this);
|
||||
Session = session;
|
||||
if (Session == null)
|
||||
{
|
||||
requestHeaders.Add("X-LNH-Session-Failed", "true");
|
||||
Session = new Session();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
|
@ -93,6 +128,20 @@ namespace ln.http
|
|||
|
||||
public String[] RequestHeaderNames => requestHeaders.Keys.ToArray();
|
||||
|
||||
public String[] CookieNames => requestCookies.Keys.ToArray();
|
||||
public bool ContainsCookie(String name)
|
||||
{
|
||||
return this.requestCookies.ContainsKey(name);
|
||||
}
|
||||
public String GetCookie(String name)
|
||||
{
|
||||
return requestCookies[name];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public HttpResponse Redirect(string location,int status = 301)
|
||||
{
|
||||
HttpResponse httpResponse = new HttpResponse(this);
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace ln.http
|
|||
int statusCode;
|
||||
string statusMessage;
|
||||
Dictionary<string, List<String>> headers = new Dictionary<string, List<string>>();
|
||||
List<HttpCookie> cookies = new List<HttpCookie>();
|
||||
|
||||
public HttpResponse(HttpRequest httpRequest)
|
||||
{
|
||||
|
@ -84,6 +85,22 @@ namespace ln.http
|
|||
}
|
||||
|
||||
|
||||
public void AddCookie(string name,string value)
|
||||
{
|
||||
AddCookie(new HttpCookie(name, value));
|
||||
}
|
||||
public void AddCookie(HttpCookie httpCookie)
|
||||
{
|
||||
cookies.Add(httpCookie);
|
||||
}
|
||||
public void RemoveCookie(HttpCookie httpCookie)
|
||||
{
|
||||
cookies.Remove(httpCookie);
|
||||
}
|
||||
public HttpCookie[] Cookies => cookies.ToArray();
|
||||
|
||||
|
||||
|
||||
public int StatusCode
|
||||
{
|
||||
get
|
||||
|
|
|
@ -42,10 +42,14 @@
|
|||
<Compile Include="HttpStatusCodes.cs" />
|
||||
<Compile Include="QueryStringParameters.cs" />
|
||||
<Compile Include="HttpApplication.cs" />
|
||||
<Compile Include="HttpCookie.cs" />
|
||||
<Compile Include="session\Session.cs" />
|
||||
<Compile Include="session\SessionCache.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="exceptions\" />
|
||||
<Folder Include="threads\" />
|
||||
<Folder Include="session\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
|
@ -0,0 +1,33 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace ln.http.resources.session
|
||||
{
|
||||
public class Session
|
||||
{
|
||||
public Guid SessionID { get; private set; }
|
||||
public long SessionAge => DateTimeOffset.Now.ToUnixTimeSeconds() - LastTouch;
|
||||
public long LastTouch { get; private set; }
|
||||
|
||||
private readonly Dictionary<string, object> elements = new Dictionary<string, object>();
|
||||
|
||||
public Session()
|
||||
{
|
||||
SessionID = Guid.NewGuid();
|
||||
}
|
||||
|
||||
public object this[string name]
|
||||
{
|
||||
get => this.elements[name];
|
||||
set => this.elements[name] = value;
|
||||
}
|
||||
|
||||
public String[] ElementNames => this.elements.Keys.ToArray();
|
||||
|
||||
public void Touch()
|
||||
{
|
||||
LastTouch = DateTimeOffset.Now.ToUnixTimeSeconds();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
namespace ln.http.resources.session
|
||||
{
|
||||
public class SessionCache
|
||||
{
|
||||
Dictionary<Guid, Session> sessions = new Dictionary<Guid, Session>();
|
||||
|
||||
public SessionCache()
|
||||
{
|
||||
}
|
||||
|
||||
public bool Contains(Guid sessionID)
|
||||
{
|
||||
return this.sessions.ContainsKey(sessionID);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new Session instance
|
||||
*
|
||||
*/
|
||||
public virtual Session CreateSession()
|
||||
{
|
||||
return new Session();
|
||||
}
|
||||
|
||||
/*
|
||||
* Find and return SessionID from given HttpRequest
|
||||
*
|
||||
*/
|
||||
public virtual Guid FindSessionID(HttpRequest httpRequest)
|
||||
{
|
||||
if (httpRequest.ContainsCookie("SID_LN"))
|
||||
{
|
||||
return Guid.Parse(httpRequest.GetCookie("SID_LN"));
|
||||
}
|
||||
return Guid.Empty;
|
||||
}
|
||||
|
||||
/*
|
||||
* Apply SessionID of the given Session to the given Response
|
||||
*
|
||||
*/
|
||||
public virtual void ApplySessionID(HttpResponse httpResponse,Session session)
|
||||
{
|
||||
HttpCookie sessionCookie = new HttpCookie("SID_LN",session.SessionID.ToString());
|
||||
sessionCookie.Path = "/";
|
||||
httpResponse.AddCookie(sessionCookie);
|
||||
}
|
||||
|
||||
public Session ApplySession(HttpRequest httpRequest)
|
||||
{
|
||||
Guid sessionID = FindSessionID(httpRequest);
|
||||
if (!Guid.Empty.Equals(sessionID) && Contains(sessionID))
|
||||
{
|
||||
Session session = this.sessions[sessionID];
|
||||
session.Touch();
|
||||
return session;
|
||||
}
|
||||
else
|
||||
{
|
||||
Session session = CreateSession();
|
||||
this.sessions.Add(session.SessionID, session);
|
||||
return session;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue