예제 #1
0
 public void Trace(IOnPremiseConnectorRequest request, IOnPremiseConnectorResponse response, IEnumerable <Guid> traceConfigurationIds)
 {
     foreach (var traceConfigurationId in traceConfigurationIds)
     {
         Trace(request, response, traceConfigurationId);
     }
 }
        public HttpResponseMessage BuildFromConnectorResponse(IOnPremiseConnectorResponse response, Link link, string requestId)
        {
            var message = new HttpResponseMessage();

            if (response == null)
            {
                _logger?.Verbose("Received no response. request-id={RequestId}", requestId);

                message.StatusCode = HttpStatusCode.GatewayTimeout;
                message.Content    = new ByteArrayContent(Array.Empty <byte>());
                message.Content.Headers.Add("X-TTRELAY-TIMEOUT", "On-Premise");
            }
            else
            {
                message.StatusCode = response.StatusCode;
                message.Content    = GetResponseContentForOnPremiseTargetResponse(response, link);

                if (response.HttpHeaders.TryGetValue("WWW-Authenticate", out var wwwAuthenticate))
                {
                    message.Headers.Add("WWW-Authenticate", wwwAuthenticate);
                }

                if (IsRedirectStatusCode(response.StatusCode) && response.HttpHeaders.TryGetValue("Location", out var location))
                {
                    message.Headers.Location = new Uri(location, UriKind.RelativeOrAbsolute);
                }
            }

            return(message);
        }
예제 #3
0
        public void LogRequest(IOnPremiseConnectorRequest request, IOnPremiseConnectorResponse response, Guid linkId, Guid originId, string relayPath, HttpStatusCode?statusCode)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }

            var pathInformation = _pathSplitter.Split(relayPath);

            _logRepository.LogRequest(new RequestLogEntry
            {
                LocalUrl                  = pathInformation.LocalUrl,
                HttpStatusCode            = statusCode ?? HttpStatusCode.InternalServerError,
                ContentBytesIn            = request.ContentLength,
                ContentBytesOut           = response?.ContentLength ?? 0,
                OnPremiseConnectorInDate  = request.RequestStarted,
                OnPremiseConnectorOutDate = request.RequestFinished,
                OnPremiseTargetInDate     = response?.RequestStarted,
                OnPremiseTargetOutDate    = response?.RequestFinished,
                OriginId                  = originId,
                OnPremiseTargetKey        = pathInformation.OnPremiseTargetKey,
                LinkId    = linkId,
                RequestId = request.RequestId,
            });
        }
        public void SendOnPremiseTargetResponse(Guid originId, IOnPremiseConnectorResponse response)
        {
            CheckDisposed();

            _logger?.Debug("Dispatching response. origin-id={OriginId}", originId);

            _messageDispatcher.DispatchResponse(originId, response);
        }
        public void DispatchResponse(Guid originId, IOnPremiseConnectorResponse response)
        {
            var content = Serialize(response, out var props);

            lock (_model)
            {
                _model.BasicPublish(_EXCHANGE_NAME, $"{_RESPONSE_QUEUE_PREFIX}{originId}", false, props, content);
            }
        }
 private void ForwardOnPremiseTargetResponse(IOnPremiseConnectorResponse response)
 {
     if (_requestCompletedCallbacks.TryRemove(response.RequestId, out var onPremiseConnectorCallback))
     {
         _logger?.Debug("Forwarding on-premise target response. request-id={RequestId}", response.RequestId);
         onPremiseConnectorCallback.Response.SetResult(response);
     }
     else
     {
         _logger?.Information("Response received but no request callback found for request {RequestId}", response.RequestId);
     }
 }
예제 #7
0
 public InterceptedResponse(IOnPremiseConnectorResponse other)
 {
     RequestId       = other.RequestId;
     OriginId        = other.OriginId;
     RequestStarted  = other.RequestStarted;
     RequestFinished = other.RequestFinished;
     StatusCode      = other.StatusCode;
     HttpHeaders     = other.HttpHeaders;
     Body            = other.Body;  // this is because of legacy on-premise connectors (v1)
     Stream          = other.Stream;
     ContentLength   = other.ContentLength;
 }
        public void DispatchResponse(Guid originId, IOnPremiseConnectorResponse response)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            CheckDisposed();
            _logger?.Debug("Dispatching response. origin-id={OriginId}, request-id={RequestId}, status-code={ResponseStatusCode}", originId, response.RequestId, response.StatusCode);

            GetResponseSubject(originId).OnNext(response);
        }
예제 #9
0
        private void FinishRequest(OnPremiseConnectorRequest request, IOnPremiseConnectorResponse response, LinkInformation link, string path, HttpStatusCode statusCode)
        {
            if (request == null)
            {
                return;
            }

            request.RequestFinished = DateTime.UtcNow;

            _logger?.Verbose("Finishing request. request-id={RequestId}, link-id={LinkId}, link-name={LinkName}, on-premise-duration={RemoteDuration}, global-duration={GlobalDuration}", request.RequestId, link.Id, link.SymbolicName, response?.RequestFinished - response?.RequestStarted, request.RequestFinished - request.RequestStarted);

            _traceManager.Trace(request, response, link.TraceConfigurationIds);
            _requestLogger.LogRequest(request, response, link.Id, _backendCommunication.OriginId, path, statusCode);
        }
예제 #10
0
        private void FinishRequest(IOnPremiseConnectorRequest request, IOnPremiseConnectorResponse response, Guid linkId, string path, HttpStatusCode statusCode)
        {
            request.RequestFinished = DateTime.UtcNow;

            _logger?.Verbose("Finishing request. request-id={RequestId}, link-id={LinkId}, on-premise-duration={RemoteDuration}, global-duration={GlobalDuration}", request.RequestId, linkId, response?.RequestFinished - response?.RequestStarted, request.RequestFinished - request.RequestStarted);

            // TODO this may be debounced for e.g. 5 minutes to skip querying on each request in future release
            var currentTraceConfigurationId = _traceManager.GetCurrentTraceConfigurationId(linkId);

            if (currentTraceConfigurationId != null)
            {
                _traceManager.Trace(request, response, currentTraceConfigurationId.Value);
            }

            _requestLogger.LogRequest(request, response, linkId, _backendCommunication.OriginId, path, statusCode);
        }
        public HttpContent GetResponseContentForOnPremiseTargetResponse(IOnPremiseConnectorResponse response, Link link)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            if (response.StatusCode >= HttpStatusCode.InternalServerError && !link.ForwardOnPremiseTargetErrorResponse)
            {
                return(null);
            }

            HttpContent content;

            if (response.ContentLength == 0)
            {
                _logger?.Verbose("Received empty body. request-id={RequestId}", response.RequestId);

                content = new ByteArrayContent(Array.Empty <byte>());
            }
            else if (response.Body != null)
            {
                // only legacy on-premise connectors (v1) use this property
                _logger?.Verbose("Received small legacy body with data. request-id={RequestId}, body-length={ResponseContentLength}", response.RequestId, response.Body.Length);

                content = new ByteArrayContent(response.Body);
            }
            else
            {
                _logger?.Verbose("Received body. request-id={RequestId}, content-length={ResponseContentLength}", response.RequestId, response.ContentLength);

                var stream = _postDataTemporaryStore.GetResponseStream(response.RequestId);
                if (stream == null)
                {
                    throw new InvalidOperationException();                     // TODO what now?
                }

                content = new StreamContent(stream, 0x10000);
            }

            AddContentHttpHeaders(content, response.HttpHeaders);

            return(content);
        }
        public HttpContent GetResponseContentForOnPremiseTargetResponse(IOnPremiseConnectorResponse response, bool forwardOnPremiseTargetErrorResponse)
        {
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            if (response.StatusCode >= HttpStatusCode.InternalServerError && !forwardOnPremiseTargetErrorResponse)
            {
                return(null);
            }

            HttpContent content;

            if (response.ContentLength == 0)
            {
                // No content
                content = new ByteArrayContent(Array.Empty <byte>());
            }
            else if (response.Body != null)
            {
                // Unmodified legacy response
                content = new ByteArrayContent(response.Body);
            }
            else
            {
                // Normal content stream
                var stream = response.Stream;
                if (stream == null)
                {
                    throw new InvalidOperationException();                     // TODO what now?
                }
                else if (stream.Position != 0 && stream.CanSeek)
                {
                    stream.Position = 0;
                }

                content = new StreamContent(stream, 0x10000);
            }

            AddContentHttpHeaders(content, response.HttpHeaders);

            return(content);
        }
예제 #13
0
        public void Trace(IOnPremiseConnectorRequest request, IOnPremiseConnectorResponse response, Guid traceConfigurationId)
        {
            try
            {
                if (!Directory.Exists(_configuration.TraceFileDirectory))
                {
                    Directory.CreateDirectory(_configuration.TraceFileDirectory);
                }

                var filenamePrefix = $"{Path.Combine(_configuration.TraceFileDirectory, traceConfigurationId.ToString())}-{DateTime.Now.Ticks}";
                _traceFileWriter.WriteHeaderFileAsync(filenamePrefix + _ON_PREMISE_CONNECTOR_HEADER_EXTENSION, request.HttpHeaders);
                _traceFileWriter.WriteContentFileAsync(filenamePrefix + _ON_PREMISE_CONNECTOR_CONTENT_EXTENSION, request.Body);

                _traceFileWriter.WriteHeaderFileAsync(filenamePrefix + _ON_PREMISE_TARGET_HEADER_EXTENSION, response.HttpHeaders);
                _traceFileWriter.WriteContentFileAsync(filenamePrefix + _ON_PREMISE_TARGET_CONTENT_EXTENSION, response.Body);
            }
            catch (Exception ex)
            {
                _logger?.Warning(ex, "Could not create trace");
            }
        }
예제 #14
0
        public HttpResponseMessage HandleResponse(IOnPremiseConnectorRequest request, HttpRequestMessage message, IPrincipal clientUser, IOnPremiseConnectorResponse response)
        {
            if (_responseInterceptor == null)
            {
                return(null);
            }

            _logger?.Verbose("Handling response. request-id={RequestId}", request.RequestId);

            try
            {
                var interceptedRequest = CreateInterceptedRequest(request, message, clientUser);

                var immediateResponse = response == null?_responseInterceptor.OnResponseFailed(interceptedRequest) : _responseInterceptor.OnResponseReceived(interceptedRequest, new InterceptedResponse(response));

                if (immediateResponse != null)
                {
                    immediateResponse.RequestMessage = message;
                }

                return(immediateResponse);
            }
            catch (Exception ex)
            {
                _logger?.Error(ex, "Error while executing the response interceptor. type-name={InterceptorType}, request-id={RequestId}", _requestInceptor?.GetType().Name, request.RequestId);
                return(null);
            }
        }
예제 #15
0
 public void DispatchResponse(Guid originId, IOnPremiseConnectorResponse response)
 {
     EnsureResponseChannel(originId.ToString()).Dispatch(response);
 }
예제 #16
0
        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);
            }
        }
예제 #17
0
 public void LogRequest(IOnPremiseConnectorRequest request, IOnPremiseConnectorResponse response, Guid linkId, Guid originId, String relayPath, HttpStatusCode?statusCode)
 {
     // Noop
 }
예제 #18
0
        public HttpResponseMessage HandleResponse(IOnPremiseConnectorRequest request, HttpRequestMessage message, IPrincipal clientUser, IOnPremiseConnectorResponse response, bool forwardOnPremiseTargetErrorResponse)
        {
            if (_responseInterceptor == null)
            {
                return(_httpResponseMessageBuilder.BuildFromConnectorResponse(response, forwardOnPremiseTargetErrorResponse, request.RequestId));
            }

            _logger.Verbose("Handling response. request-id={RequestId}", request.RequestId);

            try
            {
                var interceptedRequest = CreateInterceptedRequest(request, message, clientUser);

                HttpResponseMessage immediateResponse = null;
                if (response == null)
                {
                    immediateResponse = _responseInterceptor.OnResponseFailed(interceptedRequest);
                }
                else
                {
                    var interceptedResponse = new InterceptedResponse(_logger.ForContext <IInterceptedResponse>(), response);
                    immediateResponse = _responseInterceptor.OnResponseReceived(interceptedRequest, interceptedResponse);

                    if (immediateResponse == null)
                    {
                        return(_httpResponseMessageBuilder.BuildFromConnectorResponse(interceptedResponse, forwardOnPremiseTargetErrorResponse, request.RequestId));
                    }
                }

                if (immediateResponse != null)
                {
                    immediateResponse.RequestMessage = message;
                }

                return(immediateResponse ?? _httpResponseMessageBuilder.BuildFromConnectorResponse(null, forwardOnPremiseTargetErrorResponse, request.RequestId));
            }
            catch (Exception ex)
            {
                _logger.Error(ex, "Error while executing the response interceptor. type-name={InterceptorType}, request-id={RequestId}", _requestInterceptor?.GetType().Name, request.RequestId);
                return(null);
            }
        }