private async Task HandleHeartbeatRequestAsync(RequestContext ctx, IOnPremiseTargetRequest request) { _logger?.Debug("Received heartbeat from RelayServer. request-id={RequestId}", request.RequestId); if (LastHeartbeat == DateTime.MinValue) { if (request.HttpHeaders != null) { request.HttpHeaders.TryGetValue("X-TTRELAY-HEARTBEATINTERVAL", out var heartbeatHeaderValue); if (Int32.TryParse(heartbeatHeaderValue, out var heartbeatInterval)) { _logger?.Information("Heartbeat interval set to {HeartbeatInterval} seconds", heartbeatInterval); HeartbeatInterval = TimeSpan.FromSeconds(heartbeatInterval); } } } LastHeartbeat = DateTime.UtcNow; var response = BuildDefaultResponse(request.OriginId, request.RequestId); try { // No cancellation token here, to not cancel sending of an already fetched response await PostResponseAsync(ctx, response, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { _logger?.Error(ex, "Error during posting heartbeat response to relay. request-id={RequestId}", request.RequestId); } }
private async Task AcknowledgeRequestAsync(IOnPremiseTargetRequest request) { if (request.AcknowledgmentMode == AcknowledgmentMode.Auto) { _logger?.Debug("Automatically acknowledged by RelayServer. request-id={RequestId}", request.RequestId); return; } if (String.IsNullOrEmpty(request.AcknowledgeId)) { _logger?.Debug("No acknowledgment possible. request-id={RequestId}, acknowledgment-mode={AcknowledgmentMode}", request.RequestId, request.AcknowledgmentMode); return; } switch (request.AcknowledgmentMode) { case AcknowledgmentMode.Default: _logger?.Debug("Sending acknowledge to RelayServer. request-id={RequestId}, origin-id={OriginId}, acknowledge-id={AcknowledgeId}", request.RequestId, request.AcknowledgeOriginId, request.AcknowledgeId); await SendAcknowledgmentAsync(request.AcknowledgeOriginId, request.AcknowledgeId).ConfigureAwait(false); break; case AcknowledgmentMode.Manual: _logger?.Debug("Manual acknowledgment needed. request-id={RequestId}, origin-id={OriginId}, acknowledge-id={AcknowledgeId}", request.RequestId, request.AcknowledgeOriginId, request.AcknowledgeId); break; default: _logger?.Warning("Unknown acknowledgment mode found. request-id={RequestId}, acknowledgment-mode={AcknowledgmentMode}, acknowledge-id={AcknowledgeId}", request.RequestId, request.AcknowledgmentMode, request.AcknowledgeId); break; } }
private async Task AcknowledgeRequest(IOnPremiseTargetRequest request) { if (request.AcknowledgmentMode == AcknowledgmentMode.Auto) { _logger?.Debug("Automatically acknowledged by RelayServer. request-id={RequestId}", request.RequestId); return; } if (String.IsNullOrEmpty(request.AcknowledgeId)) { _logger?.Debug("No acknowledgment possible. request-id={RequestId}, acknowledgment-mode={AcknowledgmentMode}", request.RequestId, request.AcknowledgmentMode); return; } switch (request.AcknowledgmentMode) { case AcknowledgmentMode.Default: _logger?.Debug("Sending acknowledge to RelayServer. request-id={RequestId}, origin-id={OriginId}, acknowledge-id={AcknowledgeId}", request.RequestId, request.AcknowledgeOriginId, request.AcknowledgeId); await GetToRelay($"/request/acknowledge?oid={request.AcknowledgeOriginId}&aid={request.AcknowledgeId}&cid={ConnectionId}", CancellationToken.None).ConfigureAwait(false); // TODO no cancellation token here? break; case AcknowledgmentMode.Manual: _logger?.Debug("Manual acknowledgment needed. request-id={RequestId}, origin-id={OriginId}, acknowledge-id={AcknowledgeId}", request.RequestId, request.AcknowledgeOriginId, request.AcknowledgeId); break; default: _logger?.Warning("Unknown acknowledgment mode found. request-id={RequestId}, acknowledgment-mode={AcknowledgmentMode}, acknowledge-id={AcknowledgeId}", request.RequestId, request.AcknowledgmentMode, request.AcknowledgeId); break; } }
public InterceptedRequest(IOnPremiseTargetRequest request) { RequestId = request.RequestId; OriginId = request.OriginId; AcknowledgeId = request.AcknowledgeId; HttpMethod = request.HttpMethod; Url = request.Url; HttpHeaders = request.HttpHeaders; Stream = request.Stream; AcknowledgmentMode = request.AcknowledgmentMode; AcknowledgeOriginId = request.AcknowledgeOriginId; }
private async Task HandlePingRequestAsync(IOnPremiseTargetRequest request) { _logger.Info("Received ping from server"); await PostToRelayAsync(() => new StringContent(JsonConvert.SerializeObject(new OnPremiseTargetReponse { RequestStarted = DateTime.UtcNow, RequestFinished = DateTime.UtcNow, StatusCode = HttpStatusCode.OK, OriginId = request.OriginId, RequestId = request.RequestId }), Encoding.UTF8, "application/json")); }
private async Task HandlePingRequestAsync(RequestContext ctx, IOnPremiseTargetRequest request) { _logger?.Debug("Received ping from RelayServer. request-id={RequestId}", request.RequestId); var response = BuildDefaultResponse(request.OriginId, request.RequestId); try { // No cancellation token here, to not cancel sending of an already fetched response await PostResponseAsync(ctx, response, CancellationToken.None).ConfigureAwait(false); } catch (Exception ex) { _logger?.Error(ex, "Error during posting ping response to relay. request-id={RequestId}", request.RequestId); } }
private async Task <InterceptedResponse> GetResponseFromLocalTargetAsync(IOnPremiseTargetConnector connector, string url, IOnPremiseTargetRequest onPremiseTargetRequest, string relayedRequestHeader) { var request = new InterceptedRequest(onPremiseTargetRequest); try { var requestInterceptor = _onPremiseInterceptorFactory.CreateOnPremiseRequestInterceptor(); requestInterceptor?.HandleRequest(request); } catch (Exception ex) { _logger?.Error(ex, "Error during intercepting the request. request-id={RequestId}", request.RequestId); } var onPremiseTargetResponse = await connector.GetResponseFromLocalTargetAsync(url, request, relayedRequestHeader).ConfigureAwait(false); var response = new InterceptedResponse(onPremiseTargetResponse); try { var responseInterceptor = _onPremiseInterceptorFactory.CreateOnPremiseResponseInterceptor(); responseInterceptor?.HandleResponse(request, response); } catch (Exception ex) { _logger?.Error(ex, "Error during intercepting the response. request-id={RequestId}", request.RequestId); } return(response); }
public async Task <IOnPremiseTargetReponse> GetResponseAsync(string url, IOnPremiseTargetRequest onPremiseTargetRequest) { _logger.Debug("Requesting response from On-Premise Target..."); _logger.Trace("Requesting response from On-Premise Target. url={0}, request-id={1}, origin-id", url, onPremiseTargetRequest.RequestId, onPremiseTargetRequest.OriginId); var onPremiseTargetReponse = new OnPremiseTargetReponse { RequestId = onPremiseTargetRequest.RequestId, OriginId = onPremiseTargetRequest.OriginId, RequestStarted = DateTime.UtcNow }; var webRequest = await CreateOnPremiseTargetWebRequestAsync(url, onPremiseTargetRequest); HttpWebResponse webResponse = null; try { try { webResponse = (HttpWebResponse)await webRequest.GetResponseAsync(); } catch (WebException wex) { _logger.Trace("Error requesting response. request-id={0}", wex, onPremiseTargetRequest.RequestId); if (wex.Status == WebExceptionStatus.ProtocolError) { webResponse = (HttpWebResponse)wex.Response; } } if (webResponse == null) { _logger.Warn("Gateway timeout!"); _logger.Trace("Gateway timeout. request-id={0}", onPremiseTargetRequest.RequestId); onPremiseTargetReponse.StatusCode = HttpStatusCode.GatewayTimeout; onPremiseTargetReponse.HttpHeaders = new Dictionary <string, string> { { "X-TTRELAY-TIMEOUT", "On-Premise Target" } }; } else { onPremiseTargetReponse.StatusCode = webResponse.StatusCode; using (var stream = new MemoryStream()) { onPremiseTargetReponse.HttpHeaders = webResponse.Headers.AllKeys.ToDictionary(n => n, n => webResponse.Headers.Get(n), StringComparer.OrdinalIgnoreCase); using (var responseStream = webResponse.GetResponseStream() ?? Stream.Null) { await responseStream.CopyToAsync(stream); } onPremiseTargetReponse.Body = stream.ToArray(); } } onPremiseTargetReponse.RequestFinished = DateTime.UtcNow; _logger.Trace("Got response. status-code={0}, request-id={1}", onPremiseTargetReponse.StatusCode, onPremiseTargetReponse.RequestId); return(onPremiseTargetReponse); } finally { webResponse?.Dispose(); } }
private async Task <HttpWebRequest> CreateOnPremiseTargetWebRequestAsync(string url, IOnPremiseTargetRequest onPremiseTargetRequest) { _logger.Trace("Creating web request"); var webRequest = WebRequest.CreateHttp(new Uri(BaseUri, url)); webRequest.Method = onPremiseTargetRequest.HttpMethod; webRequest.Timeout = _requestTimeout * 1000; foreach (var httpHeader in onPremiseTargetRequest.HttpHeaders) { _logger.Trace(" adding header: header={0}, value={1}", httpHeader.Key, httpHeader.Value); Action <HttpWebRequest, string> restrictedHeader; if (_requestHeaderTransformations.TryGetValue(httpHeader.Key, out restrictedHeader)) { restrictedHeader?.Invoke(webRequest, httpHeader.Value); } else { webRequest.Headers.Add(httpHeader.Key, httpHeader.Value); } } if (onPremiseTargetRequest.Body != null) { _logger.Trace(" adding request body, length={0}", onPremiseTargetRequest.Body.Length); var requestStream = await webRequest.GetRequestStreamAsync(); await requestStream.WriteAsync(onPremiseTargetRequest.Body, 0, onPremiseTargetRequest.Body.Length); await requestStream.FlushAsync(); } return(webRequest); }
public async Task <IOnPremiseTargetResponse> GetResponseFromLocalTargetAsync(string url, IOnPremiseTargetRequest request, string relayedRequestHeader) { if (url == null) { throw new ArgumentNullException(nameof(url)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } _logger?.Verbose("Requesting response from on-premise in-proc target. request-id={RequestId}, url={RequestUrl}, origin-id={OriginId}", request.RequestId, url, request.OriginId); var response = new OnPremiseTargetResponse() { RequestId = request.RequestId, OriginId = request.OriginId, RequestStarted = DateTime.UtcNow, HttpHeaders = new Dictionary <string, string>(), }; try { var handler = CreateHandler(); try { using (var cts = new CancellationTokenSource(_requestTimeout)) { await handler.ProcessRequest(request, response, cts.Token).ConfigureAwait(false); if (cts.IsCancellationRequested) { _logger?.Warning("Gateway timeout. request-id={RequestId}", request.RequestId); response.StatusCode = HttpStatusCode.GatewayTimeout; response.HttpHeaders = new Dictionary <string, string> { ["X-TTRELAY-TIMEOUT"] = "On-Premise Target" }; } } } catch (Exception ex) { _logger?.Debug(ex, "Error requesting response from in-proc target. request-id={RequestId}", request.RequestId); response.StatusCode = HttpStatusCode.InternalServerError; response.HttpHeaders = new Dictionary <string, string> { ["Content-Type"] = "text/plain" }; response.Stream = new MemoryStream(Encoding.UTF8.GetBytes(ex.ToString())); } finally { // ReSharper disable once SuspiciousTypeConversion.Global (handler as IDisposable)?.Dispose(); } } catch (Exception ex) { _logger?.Warning(ex, "Error creating in-proc handler. request-id={RequestId}", request.RequestId); response.StatusCode = HttpStatusCode.InternalServerError; response.HttpHeaders = new Dictionary <string, string> { ["Content-Type"] = "text/plain" }; response.Stream = new MemoryStream(Encoding.UTF8.GetBytes(ex.ToString())); } response.RequestFinished = DateTime.UtcNow; _logger?.Verbose("Got in-proc response. request-id={RequestId}, status-code={ResponseStatusCode}", response.RequestId, response.StatusCode); return(response); }
private async Task <HttpResponseMessage> SendLocalRequestAsync(String url, IOnPremiseTargetRequest request, String relayedRequestHeader, CancellationToken token) { var requestMessage = _requestMessageBuilder.CreateLocalTargetRequestMessage(_baseUri, url, request, relayedRequestHeader); return(await _httpClient.SendAsync(requestMessage, token).ConfigureAwait(false)); }
private async Task <HttpResponseMessage> SendLocalRequestWithTimeoutAsync(String url, IOnPremiseTargetRequest request, String relayedRequestHeader) { // Only create CTS when really required (i.e. Timeout not Zero or infinite) if (_requestTimeout > TimeSpan.Zero && _requestTimeout != TimeSpan.MaxValue) { using (var cts = new CancellationTokenSource(_requestTimeout)) { return(await SendLocalRequestAsync(url, request, relayedRequestHeader, cts.Token).ConfigureAwait(false)); } } return(await SendLocalRequestAsync(url, request, relayedRequestHeader, CancellationToken.None).ConfigureAwait(false)); }
public async Task <IOnPremiseTargetResponse> GetResponseFromLocalTargetAsync(string url, IOnPremiseTargetRequest request, string relayedRequestHeader) { if (url == null) { throw new ArgumentNullException(nameof(url)); } if (request == null) { throw new ArgumentNullException(nameof(request)); } _logger?.Verbose("Requesting response from on-premise web target. request-id={RequestId}, url={RequestUrl}, origin-id={OriginId}", request.RequestId, url, request.OriginId); var response = new OnPremiseTargetResponse() { RequestId = request.RequestId, OriginId = request.OriginId, RequestStarted = DateTime.UtcNow, }; try { var message = await SendLocalRequestWithTimeoutAsync(url, request, relayedRequestHeader).ConfigureAwait(false); response.StatusCode = message.StatusCode; response.HttpHeaders = message.Headers.Union(message.Content.Headers).ToDictionary(kvp => kvp.Key, kvp => String.Join(" ", kvp.Value)); response.Stream = await message.Content.ReadAsStreamAsync().ConfigureAwait(false); response.HttpResponseMessage = message; } catch (Exception ex) { _logger?.Error(ex, "Error requesting response from local target. request-id={RequestId}", request.RequestId); response.StatusCode = HttpStatusCode.GatewayTimeout; response.HttpHeaders = new Dictionary <string, string> { ["X-TTRELAY-TIMEOUT"] = "On-Premise Target" }; } response.RequestFinished = DateTime.UtcNow; _logger?.Verbose("Got web response. request-id={RequestId}, status-code={ResponseStatusCode}", response.RequestId, response.StatusCode); return(response); }