using System; namespace NetCoreServer { /// /// HTTPS session is used to receive/send HTTP requests/responses from the connected HTTPS client. /// /// Thread-safe. public class HttpsSession : SslSession { public HttpsSession(HttpsServer server) : base(server) { Cache = server.Cache; Request = new HttpRequest(); Response = new HttpResponse(); } /// /// Get the static content cache /// public FileCache Cache { get; } /// /// Get the HTTP request /// protected HttpRequest Request { get; } /// /// Get the HTTP response /// public HttpResponse Response { get; } #region Send response / Send response body /// /// Send the current HTTP response (synchronous) /// /// Size of sent data public long SendResponse() => SendResponse(Response); /// /// Send the HTTP response (synchronous) /// /// HTTP response /// Size of sent data public long SendResponse(HttpResponse response) => Send(response.Cache.Data, response.Cache.Offset, response.Cache.Size); /// /// Send the HTTP response body (synchronous) /// /// HTTP response body /// Size of sent data public long SendResponseBody(string body) => Send(body); /// /// Send the HTTP response body (synchronous) /// /// HTTP response body as a span of characters /// Size of sent data public long SendResponseBody(ReadOnlySpan body) => Send(body); /// /// Send the HTTP response body (synchronous) /// /// HTTP response body buffer /// Size of sent data public long SendResponseBody(byte[] buffer) => Send(buffer); /// /// Send the HTTP response body (synchronous) /// /// HTTP response body buffer /// HTTP response body buffer offset /// HTTP response body size /// Size of sent data public long SendResponseBody(byte[] buffer, long offset, long size) => Send(buffer, offset, size); /// /// Send the HTTP response body (synchronous) /// /// HTTP response body buffer as a span of bytes /// Size of sent data public long SendResponseBody(ReadOnlySpan buffer) => Send(buffer); /// /// Send the current HTTP response (asynchronous) /// /// 'true' if the current HTTP response was successfully sent, 'false' if the session is not connected public bool SendResponseAsync() => SendResponseAsync(Response); /// /// Send the HTTP response (asynchronous) /// /// HTTP response /// 'true' if the current HTTP response was successfully sent, 'false' if the session is not connected public bool SendResponseAsync(HttpResponse response) => SendAsync(response.Cache.Data, response.Cache.Offset, response.Cache.Size); /// /// Send the HTTP response body (asynchronous) /// /// HTTP response body /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected public bool SendResponseBodyAsync(string body) => SendAsync(body); /// /// Send the HTTP response body (asynchronous) /// /// HTTP response body as a span of characters /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected public bool SendResponseBodyAsync(ReadOnlySpan body) => SendAsync(body); /// /// Send the HTTP response body (asynchronous) /// /// HTTP response body buffer /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected public bool SendResponseBodyAsync(byte[] buffer) => SendAsync(buffer); /// /// Send the HTTP response body (asynchronous) /// /// HTTP response body buffer /// HTTP response body buffer offset /// HTTP response body size /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected public bool SendResponseBodyAsync(byte[] buffer, long offset, long size) => SendAsync(buffer, offset, size); /// /// Send the HTTP response body (asynchronous) /// /// HTTP response body buffer as a span of bytes /// 'true' if the HTTP response body was successfully sent, 'false' if the session is not connected public bool SendResponseBodyAsync(ReadOnlySpan buffer) => SendAsync(buffer); #endregion #region Session handlers protected override void OnReceived(byte[] buffer, long offset, long size) { // Receive HTTP request header if (Request.IsPendingHeader()) { if (Request.ReceiveHeader(buffer, (int)offset, (int)size)) OnReceivedRequestHeader(Request); size = 0; } // Check for HTTP request error if (Request.IsErrorSet) { OnReceivedRequestError(Request, "Invalid HTTP request!"); Request.Clear(); Disconnect(); return; } // Receive HTTP request body if (Request.ReceiveBody(buffer, (int)offset, (int)size)) { OnReceivedRequestInternal(Request); Request.Clear(); return; } // Check for HTTP request error if (Request.IsErrorSet) { OnReceivedRequestError(Request, "Invalid HTTP request!"); Request.Clear(); Disconnect(); return; } } protected override void OnDisconnected() { // Receive HTTP request body if (Request.IsPendingBody()) { OnReceivedRequestInternal(Request); Request.Clear(); return; } } /// /// Handle HTTP request header received notification /// /// Notification is called when HTTP request header was received from the client. /// HTTP request protected virtual void OnReceivedRequestHeader(HttpRequest request) {} /// /// Handle HTTP request received notification /// /// Notification is called when HTTP request was received from the client. /// HTTP request protected virtual void OnReceivedRequest(HttpRequest request) {} /// /// Handle HTTP cached request received notification /// /// /// Notification is called when HTTP request was received /// from the client and the corresponding cached content /// was found. /// /// Default behavior is just send cached response content /// to the client. /// /// HTTP request /// Cached response content protected virtual void OnReceivedCachedRequest(HttpRequest request, byte[] content) { SendAsync(content); } /// /// Handle HTTP request error notification /// /// Notification is called when HTTP request error was received from the client. /// HTTP request /// HTTP request error protected virtual void OnReceivedRequestError(HttpRequest request, string error) {} #endregion private void OnReceivedRequestInternal(HttpRequest request) { // Try to get the cached response if (request.Method == "GET") { var index = request.Url.IndexOf('?'); var response = Cache.Find((index < 0) ? request.Url : request.Url.Substring(0, index)); if (response.Item1) { // Process the request with the cached response OnReceivedCachedRequest(request, response.Item2); return; } } // Process the request OnReceivedRequest(request); } } }