private bool RequestPathMatchesAttributePath(IHttpRequest request, ActivityHandlerAttribute attribute, string[] baseUrlParts)
        {
            if (request.Verb != attribute.Verb)
            {
                return(false);
            }

            string pattern = attribute.Path;
            string path    = request.Path;

            if (baseUrlParts.Length > 0)
            {
                pattern = $"/{string.Join("/", baseUrlParts)}{pattern}";
            }

            string[] pathParts = path.Split(new[] { '?' }, StringSplitOptions.RemoveEmptyEntries);

            string[] tokens = pattern.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
            string[] values = pathParts[0].Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);

            if (tokens.Length != values.Length)
            {
                return(false);
            }

            /*
             * if any non-tokenised path field doesn't match, bomb out
             * These two should match
             * /link/{orgId}/xyz/{userId}
             * /link/anything/xyz/blah?hello=world&etc=etc
             *
             * These two should not
             * /link/{orgId}/xyz/{userId}
             * /link/{orgId}/abc/{userId}
             */

            for (int i = 0; i < tokens.Length; i++)
            {
                bool replaceable = tokens[i].StartsWith("{") && tokens[i].EndsWith("}");
                if (!replaceable && tokens[i] != values[i])
                {
                    return(false);
                }
            }

            return(true);
        }
        private IActivityHandler GetRequestHandler(IHttpRequest request, out ActivityHandlerAttribute activityHandler)
        {
            var baseUrlParts = _configurationManager.Get("BaseUrl", "/").ToLowerInvariant().Split('/').Where(x => x != string.Empty).ToArray();

            activityHandler = null;
            bool Predicate(ActivityHandlerAttribute attr) => RequestPathMatchesAttributePath(request, attr, baseUrlParts);

            IDictionary <Type, ActivityHandlerAttribute[]> handlers = activityHandlers ??
                                                                      (activityHandlers =
                                                                           _container.GetAttributedTypes <ActivityHandlerAttribute>(
                                                                               typeof(IActivityHandler)));

            logger.Debug(nameof(RequestBroker) + "." + nameof(GetRequestHandler),
                         new LogItem("Event", "Got handlers"),
                         new LogItem("Handlers", string.Join(",", handlers.Select(kvp => kvp.Key.Name))));

            KeyValuePair <Type, ActivityHandlerAttribute[]> handlerInfo =
                handlers.FirstOrDefault(kvp => kvp.Value.Any(Predicate));

            logger.Debug(nameof(RequestBroker) + "." + nameof(GetRequestHandler),
                         new LogItem("HandlerInfo", handlerInfo.Key?.Name));

            if (handlerInfo.Key == null)
            {
                return(null);
            }

            ActivityHandlerAttribute attribute = handlerInfo.Value.First(Predicate);

            activityHandler = attribute;

            var path = attribute.Path;

            if (baseUrlParts.Length > 0)
            {
                path = $"/{string.Join("/",baseUrlParts)}{path}";
            }

            request.SetUriPattern(path);

            IActivityHandler instance = (IActivityHandler)_container.GetInstance(handlerInfo.Key);

            return(instance);
        }
        public IHttpResponse HandleRequest(IHttpRequest request, TokenState tokenState)
        {
            IHttpResponse response = _container.GetInstance <IHttpResponse>(true);

            if (tokenState == TokenState.Invalid || tokenState == TokenState.Expired || tokenState == TokenState.NotYetValid)
            {
                return(UnauthorisedResponse);
            }

            logger.Trace($"{nameof(RequestBroker)}.{nameof(HandleRequest)}", new LogItem("Event", "GetRequestHandler started"));
            Stopwatch timer = Stopwatch.StartNew();

            IActivityHandler handler = GetRequestHandler(request, out ActivityHandlerAttribute attribute);

            var handlerName = handler != null?handler.GetType().Name : "null";

            logger.Trace($"{nameof(RequestBroker)}.{nameof(HandleRequest)}", new LogItem("Event", "GetRequestHandler completed"), new LogItem("DurationMilliseconds", timer.Elapsed.TotalMilliseconds), new LogItem("FoundHandler", handlerName));

            if (handler == null)
            {
                switch (request.Verb)
                {
                case HttpVerb.Options:
                    handler   = _container.GetInstance <OptionsActivityHandler>();
                    attribute = new ActivityHandlerAttribute("", request.Verb, "")
                    {
                        SkipAuthorisation = true
                    };
                    break;

                default:
                    return(null);
                }
            }

            JwtSecurityToken token = request.SecurityToken;

            if (!activityAuthorisationManager.CheckAuthorisation(token, attribute))
            {
                var unauthorised = _container.GetInstance <IHttpResponse>(true);
                unauthorised.HttpStatusCode = HttpStatusCode.Unauthorized;
                return(unauthorised);
            }

            logger.Trace($"{nameof(RequestBroker)}.{nameof(HandleRequest)}", new LogItem("Event", "Handler Handle called"));
            timer.Restart();

            try
            {
                handler.Handle(request, response);
            }
            catch (Exception exception)
            {
                logger.Exception($"{nameof(RequestBroker)}.{nameof(HandleRequest)}", "Exception caught handling request", exception);

                response.SetStringContent(string.Empty);
                response.HttpStatusCode = HttpStatusCode.InternalServerError;
            }

            var elapsedMilliseconds = timer.Elapsed.TotalMilliseconds;

            logger.Trace($"{nameof(RequestBroker)}.{nameof(HandleRequest)}", new LogItem("Event", "Handler Handle completed"), new LogItem("DurationMilliseconds", elapsedMilliseconds));
            apiMetrics.RecordHandlerDuration(elapsedMilliseconds, handlerName, response.HttpStatusCode);

            return(response);
        }