void TrackSession(HttpSession session) { sessionTable[session.Id] = session; var sessionCount = sessionTable.Count; int currentMax; while ((currentMax = maxConnectedSessions) < sessionCount) { if (Interlocked.CompareExchange(ref maxConnectedSessions, sessionCount, currentMax) != currentMax) { continue; } } }
bool HandleWebsocketUpgrade(HttpSession session, int routeTableIndex, int endpointIndex, WebSocketUpgradeResponse response, out int responseBytesWritten) { responseBytesWritten = session.WriteWebSocketUpgradeResponse(response); var acceptUpgradeResponse = response as WebSocketUpgradeResponse.AcceptUpgradeResponse; if (acceptUpgradeResponse == null) { return false; } else { long id = Interlocked.Increment(ref acceptedWebSocketSessions); var webSocketSession = new WebSocketSession(id, session.TcpClient, session.Stream, bytesReceived => router.Metrics.CountRequestBytesIn(routeTableIndex, endpointIndex, bytesReceived), bytesSent => router.Metrics.CountResponseBytesOut(routeTableIndex, endpointIndex, bytesSent), () => UntrackWebSocketSession(id)); TrackWebSocketSession(webSocketSession); try { acceptUpgradeResponse.OnAccepted(webSocketSession); //TODO: Task.Run this? return true; } catch (Exception e) { UntrackWebSocketSession(id); logger.Error("Error calling WebSocketUpgradeResponse.OnAccepted callback - {0}", e.ToString()); return false; } } }
async Task<int> AcceptWebSocketUpgrade(HttpSession session, int routeTableIndex, int endpointIndex, WebSocketUpgradeResponse.AcceptUpgradeResponse response) { var bytesWritten = await response.WriteToAsync(session.Stream, 0, sessionReadTimeout).ConfigureAwait(false); var id = Interlocked.Increment(ref acceptedWebSocketSessions); var webSocketSession = new WebSocketSession(id, session.TcpClient, session.Stream, bytesReceived => router.Metrics.CountRequestBytesIn(routeTableIndex, endpointIndex, bytesReceived), bytesSent => router.Metrics.CountResponseBytesOut(routeTableIndex, endpointIndex, bytesSent), () => UntrackWebSocketSession(id), sessionReadBufferSize, (int)sessionReadTimeout.TotalMilliseconds, (int)sessionWriteTimeout.TotalMilliseconds); TrackWebSocketSession(webSocketSession); try { response.OnAccepted(webSocketSession); //TODO: Task.Run this? return bytesWritten; } catch (Exception) { UntrackWebSocketSession(id); throw; } }
async Task HandleSession(HttpSession session) { var closeSessionOnReturn = true; try { var continueSession = true; while (continueSession && !session.IsDisconnected()) { try { TrackSessionRead(session.Id); if (await session.ReadToBufferAsync().ConfigureAwait(false) == 0) // 0 => client clean disconnect { break; } } finally { UntrackSessionRead(session.Id); } int requestBytesParsed, responseBytesWritten; HttpRequest request; while (continueSession && session.TryParseNextRequestFromBuffer(out requestBytesParsed, out request)) { Router.HandleResult result = await router.HandleRequest(request, DateTime.UtcNow).ConfigureAwait(false); HttpResponse response = result.HttpResponse; var webSocketUpgradeResponse = response as WebSocketUpgradeResponse; if (webSocketUpgradeResponse == null) { responseBytesWritten = session.WriteResponse(response, request.IsKeepAlive); continueSession = request.IsKeepAlive && session.KeepAlivesRemaining > 0; } else { var isUpgraded = HandleWebsocketUpgrade(session, result.MatchedRouteTableIndex, result.MatchedEndpointIndex, webSocketUpgradeResponse, out responseBytesWritten); continueSession = false; closeSessionOnReturn = !isUpgraded; } if (result.MatchedRouteTableIndex >= 0 && result.MatchedEndpointIndex >= 0) { router.Metrics.CountBytes(result.MatchedRouteTableIndex, result.MatchedEndpointIndex, requestBytesParsed, responseBytesWritten); } } } } catch (RequestException e) { logger.Warn("Error parsing or bad request - {0}", e.Message); } catch (SessionStreamException) { // forced disconnect, socket errors } catch (Exception e) { //TODO: count session-fatal errors (not captured as route table 500s) logger.Fatal("Internal server error handling session - {0}", e.ToString()); } finally { UntrackSession(session.Id); if (closeSessionOnReturn) { session.CloseQuiety(); } } }
async Task HandleSession(HttpSession session) { var closeSessionOnReturn = true; try { var continueRequestLoop = true; while (continueRequestLoop && !session.IsDisconnected()) // request loop { try { TrackSessionRead(session.Id); if (await session.ReadToBufferAsync().ConfigureAwait(false) == 0) // 0 => client clean disconnect { break; } } finally { UntrackSessionRead(session.Id); } int requestBytesParsed, responseBytesWritten; HttpRequest request; while (continueRequestLoop && session.TryParseNextRequestFromBuffer(out requestBytesParsed, out request)) { Router.HandleResult result = await router.HandleRequest(request, DateTime.UtcNow).ConfigureAwait(false); HttpResponse response = result.HttpResponse; if (response is WebSocketUpgradeResponse) { continueRequestLoop = false; var acceptUpgrade = response as WebSocketUpgradeResponse.AcceptUpgradeResponse; if (acceptUpgrade == null) { var rejectUpgrade = (WebSocketUpgradeResponse.RejectUpgradeResponse)response; responseBytesWritten = await rejectUpgrade.WriteToAsync(session.Stream, 0, sessionReadTimeout).ConfigureAwait(false); } else { responseBytesWritten = await AcceptWebSocketUpgrade(session, result.MatchedRouteTableIndex, result.MatchedEndpointIndex, acceptUpgrade).ConfigureAwait(false); closeSessionOnReturn = false; } } else { responseBytesWritten = await response.WriteToAsync(session.Stream, request.IsKeepAlive ? session.KeepAlivesRemaining : 0, sessionReadTimeout).ConfigureAwait(false); continueRequestLoop = request.IsKeepAlive && session.KeepAlivesRemaining > 0; } if (result.MatchedRouteTableIndex >= 0 && result.MatchedEndpointIndex >= 0) { router.Metrics.CountBytes(result.MatchedRouteTableIndex, result.MatchedEndpointIndex, requestBytesParsed, responseBytesWritten); } } } } catch (RequestException e) { sessionExceptionCounters.Count(e.GetType()); logger.Warn("Error parsing or bad request - {0}", e.Message); } catch (SessionStreamException e) { sessionExceptionCounters.Count(e.GetType()); } catch (Exception e) { sessionExceptionCounters.Count(e.GetType()); logger.Fatal("Error handling session - {0}", e.ToString()); } finally { UntrackSession(session.Id); if (closeSessionOnReturn) { session.CloseQuiety(); } } }