private async Task SendHeartbeatAsync(IOnPremiseConnectionContext connectionContext, CancellationToken token) { if (connectionContext == null) { throw new ArgumentNullException(nameof(connectionContext)); } if (connectionContext.NextHeartbeat > DateTime.UtcNow) { return; } connectionContext.NextHeartbeat = DateTime.UtcNow.Add(_heartbeatInterval); try { _logger?.Verbose("Sending {PingMethod}. connection-id={ConnectionId}", connectionContext.SupportsHeartbeat ? "Heartbeat" : "Ping (as heartbeat)", connectionContext.ConnectionId); var requestId = Guid.NewGuid().ToString(); var request = new OnPremiseConnectorRequest() { HttpMethod = connectionContext.SupportsHeartbeat ? "HEARTBEAT" : "PING", Url = String.Empty, RequestStarted = DateTime.UtcNow, OriginId = _backendCommunication.OriginId, RequestId = requestId, AcknowledgmentMode = AcknowledgmentMode.Auto, HttpHeaders = connectionContext.SupportsConfiguration ? null : new Dictionary <string, string> { ["X-TTRELAY-HEARTBEATINTERVAL"] = _heartbeatInterval.TotalSeconds.ToString(CultureInfo.InvariantCulture) }, }; // wait for the response of the Heartbeat / Ping var task = _backendCommunication.GetResponseAsync(requestId, _configuration.ActiveConnectionTimeout); // heartbeats do NOT go through the message dispatcher as we want to heartbeat the connections directly await connectionContext.RequestAction(request, token).ConfigureAwait(false); var response = await task.ConfigureAwait(false); if (response != null) { await _backendCommunication.RenewLastActivityAsync(connectionContext.ConnectionId).ConfigureAwait(false); } } catch (Exception ex) { _logger?.Error(ex, "Error during sending heartbeat to a client. link-id={LinkId}, connection-id={ConnectionId}, connector-version={ConnectorVersion}", connectionContext.LinkId, connectionContext.ConnectionId, connectionContext.ConnectorVersion); } }
public async Task <IHttpActionResult> PingAsync(Guid id) { var requestId = Guid.NewGuid().ToString(); var onPremiseConnectorRequest = new OnPremiseConnectorRequest { HttpMethod = "PING", Url = "", RequestStarted = DateTime.UtcNow, OriginId = _backendCommunication.OriginId, RequestId = requestId }; await _backendCommunication.SendOnPremiseConnectorRequest(id.ToString(), onPremiseConnectorRequest); var onPremiseTargetReponse = await _backendCommunication.GetResponseAsync(requestId); onPremiseConnectorRequest.RequestFinished = DateTime.UtcNow; _requestLogger.LogRequest(onPremiseConnectorRequest, onPremiseTargetReponse, HttpStatusCode.OK, id, _backendCommunication.OriginId, "invalid/Ping.local/"); return(Ok()); }
public async Task <IHttpActionResult> SendPing(Guid id) { var requestId = Guid.NewGuid().ToString(); var request = new OnPremiseConnectorRequest() { HttpMethod = "PING", Url = String.Empty, RequestStarted = DateTime.UtcNow, OriginId = _backendCommunication.OriginId, RequestId = requestId }; var task = _backendCommunication.GetResponseAsync(requestId); _backendCommunication.SendOnPremiseConnectorRequest(id, request); var response = await task.ConfigureAwait(false); request.RequestFinished = DateTime.UtcNow; _requestLogger.LogRequest(request, response, id, _backendCommunication.OriginId, "DEBUG/PING/", response?.StatusCode); return((response != null) ? (IHttpActionResult)Ok() : new StatusCodeResult(HttpStatusCode.GatewayTimeout, Request)); }
public async Task <HttpResponseMessage> Relay(string path) { _logger.Trace("Relaying http {0} {1}", path, ControllerContext.Request.Method); if (path == null) { _logger.Info("Path is not set."); return(NotFound()); } var pathInformation = _pathSplitter.Split(path); var link = _linkRepository.GetLink(pathInformation.UserName); if (link == null) { _logger.Info("Link for requested path {0} not found", path); return(NotFound()); } if (link.IsDisabled) { _logger.Info("{0}: Link {1} is disabled", link.Id, link.SymbolicName); return(NotFound()); } if (string.IsNullOrWhiteSpace(pathInformation.PathWithoutUserName)) { _logger.Info("{0}: Path without username is not found. Wrong path information: {1}", link.Id, path); return(NotFound()); } if (link.AllowLocalClientRequestsOnly && !Request.IsLocal()) { _logger.Info("{0}: Link {1} only allows local requests.", link.Id, link.SymbolicName); return(NotFound()); } _logger.Trace("{0}: Building on premise connector request. Origin Id: {1}, Path: {2}", link.Id, _backendCommunication.OriginId, path); var onPremiseConnectorRequest = (OnPremiseConnectorRequest) await _onPremiseRequestBuilder.BuildFrom(Request, _backendCommunication.OriginId, pathInformation.PathWithoutUserName); _logger.Trace("{0}: Sending on premise connector request.", link.Id); await _backendCommunication.SendOnPremiseConnectorRequest(link.Id.ToString(), onPremiseConnectorRequest); _logger.Trace("{0}: Waiting for response. Request Id", onPremiseConnectorRequest.RequestId); var onPremiseTargetReponse = await _backendCommunication.GetResponseAsync(onPremiseConnectorRequest.RequestId); if (onPremiseTargetReponse != null) { _logger.Trace("{0}: Response received from {1}", link.Id, onPremiseTargetReponse.RequestId); } else { _logger.Trace("{0}: On Premise Timeout", link.Id); } var response = _httpResponseMessageBuilder.BuildFrom(onPremiseTargetReponse, link); onPremiseConnectorRequest.RequestFinished = DateTime.UtcNow; var currentTraceConfigurationId = _traceManager.GetCurrentTraceConfigurationId(link.Id); if (currentTraceConfigurationId != null) { _traceManager.Trace(onPremiseConnectorRequest, onPremiseTargetReponse, currentTraceConfigurationId.Value); } _requestLogger.LogRequest(onPremiseConnectorRequest, onPremiseTargetReponse, response.StatusCode, link.Id, _backendCommunication.OriginId, path); return(response); }
public async Task <HttpResponseMessage> Relay(string fullPathToOnPremiseEndpoint) { _logger?.Debug("Relaying request. method={RequestMethod}, path={RequestPath}", ControllerContext.Request.Method, fullPathToOnPremiseEndpoint); if (fullPathToOnPremiseEndpoint == null) { _logger?.Information("Path to on premise endpoint is not set"); return(NotFound()); } var pathInformation = _pathSplitter.Split(fullPathToOnPremiseEndpoint); var link = _linkRepository.GetLink(pathInformation.UserName); if (!CanRequestBeHandled(fullPathToOnPremiseEndpoint, pathInformation, link)) { _logger?.Information("Request cannot be handled"); return(NotFound()); } var request = await _onPremiseRequestBuilder.BuildFromHttpRequest(Request, _backendCommunication.OriginId, pathInformation.PathWithoutUserName).ConfigureAwait(false); var statusCode = HttpStatusCode.GatewayTimeout; IOnPremiseConnectorResponse response = null; try { request = _interceptorManager.HandleRequest(request, Request, User, out var message); if (message != null) { _logger?.Verbose("Interceptor caused direct answering of request. request-id={RequestId}, status-code={ResponseStatusCode}", request.RequestId, message.StatusCode); statusCode = message.StatusCode; if (request.AlwaysSendToOnPremiseConnector) { _logger?.Verbose("Interceptor caused always sending of request. request-id={RequestId}", request.RequestId); SendOnPremiseConnectorRequest(link.Id, request); } return(message); } var task = _backendCommunication.GetResponseAsync(request.RequestId); SendOnPremiseConnectorRequest(link.Id, request); _logger?.Verbose("Waiting for response. request-id={RequestId}, link-id={LinkId}", request.RequestId, link.Id); response = await task.ConfigureAwait(false); if (response != null) { _logger?.Verbose("Response received. request-id={RequestId}, link-id={LinkId}", request.RequestId, link.Id); FetchResponseBodyForIntercepting((OnPremiseConnectorResponse)response); statusCode = response.StatusCode; } else { _logger?.Verbose("No response received because of on-premise timeout. request-id={RequestId}, link-id={LinkId}", request.RequestId, link.Id); } return(_interceptorManager.HandleResponse(request, Request, User, response, link.ForwardOnPremiseTargetErrorResponse)); } finally { FinishRequest(request as OnPremiseConnectorRequest, response, link.Id, fullPathToOnPremiseEndpoint, statusCode); } }