/// <inheritdoc />
        /// <summary>
        /// Routes a <paramref name="request" /> and <paramref name="response" /> to
        /// the appropriate controller
        /// </summary>
        /// <param name="request">The request to route</param>
        /// <param name="response">The response to route</param>
        /// <returns>
        /// Returns a task that completes once the request has been routed and handled
        /// </returns>
        public async Task Route(IHttpResourceRequest request, IHttpResourceResponse response)
        {
            var requestPath = request.Url.AbsolutePath;

            if (string.IsNullOrWhiteSpace(requestPath))
            {
                return;
            }

            var pathSegments           = requestPath.Split('/');
            var supportedResourceTypes = ResourceTypes.ToList();
            var resourceSegments       = pathSegments
                                         .SkipWhile(segment => !supportedResourceTypes.Contains(segment))
                                         .ToList();

            var resourceType = resourceSegments.FirstOrDefault();

            if (string.IsNullOrWhiteSpace(resourceType))
            {
                response.StatusCode = 400;
                return;
            }

            var controller = GetController(resourceType);

            if (string.IsNullOrWhiteSpace(resourceType))
            {
                response.StatusCode = 400;
                return;
            }

            var subPath = resourceSegments.Skip(1); // Skip resource type
            await controller.Process(request, response, subPath);
        }
示例#2
0
        public async Task Process(IHttpResourceRequest request, IHttpResourceResponse response,
            IEnumerable<string> subPath)
        {
            if (request == null) throw new ArgumentNullException("request");
            if (response == null) throw new ArgumentNullException("response");

            var topicSegments = subPath.ToList();
            if (!topicSegments.Any() && "get".Equals(request.HttpMethod, StringComparison.OrdinalIgnoreCase))
            {
                await GetTopics(request, response);
                return;
            }
            if (topicSegments.Any())
            {
                var topic = topicSegments.First();
                var nestedResource = topicSegments.Skip(1).FirstOrDefault();
                if ("subscriber".Equals(nestedResource, StringComparison.OrdinalIgnoreCase))
                {
                    var subscriberSubPath = topicSegments.Skip(2);
                    await PostOrDeleteSubscriber(request, response, topic, subscriberSubPath);
                    return;
                }
            }

            response.StatusCode = 400;
        }
示例#3
0
        /// <inheritdoc />
        public async Task Process(IHttpResourceRequest request, IHttpResourceResponse response,
                                  IEnumerable <string> subPath)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            if (!request.IsGet())
            {
                response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                response.AddHeader("Allow", "GET");
                return;
            }

            var metricsSegments = subPath.ToList();

            if (!metricsSegments.Any() && request.IsGet())
            {
                await GetMetrics(response);

                return;
            }

            response.StatusCode = 400;
        }
示例#4
0
        private async Task GetMetrics(IHttpResourceResponse response)
        {
            if (_metricsCollector == null)
            {
                // Message journaling is not enabled
                response.StatusCode = (int)HttpStatusCode.NotImplemented;
                return;
            }

            response.ContentType = "application/json";
            var encoding = response.ContentEncoding;

            if (encoding == null)
            {
                encoding = Encoding.UTF8;
                response.ContentEncoding = encoding;
            }

            var metrics         = _metricsCollector.Sample;
            var responseContent = _serializer.Serialize(metrics);
            var encodedContent  = encoding.GetBytes(responseContent);

            response.StatusCode = 200;
            await response.OutputStream.WriteAsync(encodedContent, 0, encodedContent.Length);
        }
示例#5
0
        /// <summary>
        /// Processes the specified <paramref name="request"/> and updates the supplied
        /// <paramref name="response"/>
        /// </summary>
        /// <param name="request">The HTTP resource request to process</param>
        /// <param name="response">The HTTP response to update</param>
        /// <param name="subPath">The portion of the request path that remains after the
        /// request was routed to this controller</param>
        /// <returns>Returns a task that completes when the request has been processed and the
        /// response has been updated</returns>
        public async Task Process(IHttpResourceRequest request, IHttpResourceResponse response,
                                  IEnumerable <string> subPath)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            var topicSegments = subPath.ToList();

            if (!topicSegments.Any() && request.IsGet())
            {
                await GetTopics(response);

                return;
            }

            if (topicSegments.Any())
            {
                var topic          = topicSegments.First();
                var nestedResource = topicSegments.Skip(1).FirstOrDefault();
                if ("subscriber".Equals(nestedResource, StringComparison.OrdinalIgnoreCase))
                {
                    await PostOrDeleteSubscriber(request, response, topic);

                    return;
                }
            }

            response.StatusCode = 400;
        }
 /// <summary>
 /// Initializes a new <see cref="HttpExceptionHandler"/> for the specified HTTP
 /// <paramref name="request"/> and <paramref name="response"/>
 /// </summary>
 /// <param name="request">The HTTP request being processed</param>
 /// <param name="response">The HTTP response being constructed</param>
 /// <param name="source">(Optional) The object in which the exception occurred</param>
 /// <param name="diagnosticService">(Optional) The service through which diagnostic events
 /// are reported and processed</param>
 /// <exception cref="ArgumentNullException">Thrown if <paramref name="request"/> or
 /// <paramref name="response"/> are <c>null</c></exception>
 public HttpExceptionHandler(IHttpResourceRequest request, IHttpResourceResponse response, IDiagnosticService diagnosticService, object source = null)
 {
     _request           = request ?? throw new ArgumentNullException(nameof(request));
     _response          = response ?? throw new ArgumentNullException(nameof(response));
     _diagnosticService = diagnosticService ?? DiagnosticService.DefaultInstance;
     _source            = source ?? this;
 }
示例#7
0
        private async Task PostOrDeleteSubscriber(IHttpResourceRequest request, IHttpResourceResponse response,
                                                  TopicName topic)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            var uri = request.QueryString["uri"];

            if (uri == null)
            {
                response.StatusCode        = 400;
                response.StatusDescription = "Subscriber URI is required";
                return;
            }

            var subscriber = new Uri(uri);

            if (!_topics.Contains(topic))
            {
                response.StatusCode        = 404;
                response.StatusDescription = "Topic not found";
                return;
            }

            var authorized = _authorizationService == null ||
                             await _authorizationService.IsAuthorizedToSubscribe(request.Principal, topic);

            if (!authorized)
            {
                response.StatusCode        = 401;
                response.StatusDescription = "Unauthorized";
                return;
            }

            if ("delete".Equals(request.HttpMethod, StringComparison.OrdinalIgnoreCase))
            {
                // TODO: Verify that the subscriber is the one deleting the subscription
                // Ideas: Issue another HTTP request back to the subscriber to verify?
                //        Require the subscriber to specify a subscription ID (GUID?)
                //        when subscribing and then supply the same ID when unsubscribing?
                await _subscriptionTrackingService.RemoveSubscription(topic, subscriber);
            }
            else
            {
                var ttlStr = request.QueryString["ttl"];
                var ttl    = string.IsNullOrWhiteSpace(ttlStr)
                    ? default(TimeSpan)
                    : TimeSpan.FromSeconds(int.Parse(ttlStr));

                await _subscriptionTrackingService.AddSubscription(topic, subscriber, ttl);
            }
            response.StatusCode = 200;
        }
示例#8
0
 public HttpExceptionHandler(IHttpResourceRequest request, IHttpResourceResponse response, ILog log = null)
 {
     if (request == null) throw new ArgumentNullException("request");
     if (response == null) throw new ArgumentNullException("response");
     _request = request;
     _response = response;
     _log = log ?? LogManager.GetLogger(LoggingCategories.Http);
 }
示例#9
0
 public async Task GetTopics(IHttpResourceRequest request, IHttpResourceResponse response)
 {
     var topicList = _topics.Select(t => t.ToString()).ToArray();
     var responseContent = _serializer.Serialize(topicList);
     var encoding = response.ContentEncoding;
     var encodedContent = encoding.GetBytes(responseContent);
     await response.OutputStream.WriteAsync(encodedContent, 0, encodedContent.Length);
     response.StatusCode = 200;
 }
示例#10
0
        public async Task Post(IHttpResourceRequest request, IHttpResourceResponse response)
        {
            if (request == null) throw new ArgumentNullException("request");
            if (response == null) throw new ArgumentNullException("response");

            var flattenedHeaders = request.Headers.AllKeys
                .ToDictionary(k => k, k => request.Headers[k]);

            var messageHeaders = new MessageHeaders(flattenedHeaders);
            var content = await request.ReadContentAsString();
            var message = new Message(messageHeaders, content);

            await _accept(message, request.Principal);
            response.StatusCode = 202;
        }
示例#11
0
        public async Task Process(IHttpResourceRequest request, IHttpResourceResponse response,
            IEnumerable<string> subPath)
        {
            if (request == null) throw new ArgumentNullException("request");
            if (response == null) throw new ArgumentNullException("response");

            if (!request.IsPost())
            {
                response.StatusCode = 405;
                response.AddHeader("Allow", "POST");
                return;
            }

            await Post(request, response);
        }
示例#12
0
        private async Task Post(IHttpResourceRequest request, IHttpResourceResponse response)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            var authorized = _authorizationService == null ||
                             await _authorizationService.IsAuthorizedToSendMessages(request.Principal);

            if (!authorized)
            {
                response.StatusCode        = 401;
                response.StatusDescription = "Unauthorized";
                return;
            }

            // The authorization header should have been processed by the HTTP host prior to this
            // point in order to initialize the principal on the request context.  This is
            // sensitive information and should not be copied into and thus exposed by the message
            // headers.
            var authorizationHeader = HttpRequestHeader.Authorization.ToString("G");
            var sensitiveHeaders    = new[] { authorizationHeader };

            var flattenedHeaders = request.Headers.AllKeys
                                   .Except(sensitiveHeaders, StringComparer.OrdinalIgnoreCase)
                                   .ToDictionary(k => k, k => request.Headers[k]);

            var messageHeaders = new MessageHeaders(flattenedHeaders)
            {
                Received = DateTime.UtcNow
            };

            var content = await request.ReadContentAsString();

            var message = new Message(messageHeaders, content);

            Thread.CurrentPrincipal = request.Principal;
            await _accept(message, request.Principal, default(CancellationToken));

            response.StatusCode = 202;
        }
示例#13
0
        private async Task GetTopics(IHttpResourceResponse response)
        {
            response.ContentType = "application/json";
            var encoding = response.ContentEncoding;

            if (encoding == null)
            {
                encoding = Encoding.UTF8;
                response.ContentEncoding = encoding;
            }

            var topicList       = _topics.Select(t => t.ToString()).ToArray();
            var responseContent = _serializer.Serialize(topicList);
            var encodedContent  = encoding.GetBytes(responseContent);

            response.StatusCode = 200;
            await response.OutputStream.WriteAsync(encodedContent, 0, encodedContent.Length);
        }
示例#14
0
        /// <inheritdoc />
        public async Task Process(IHttpResourceRequest request, IHttpResourceResponse response, IEnumerable <string> subPath)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            if (!request.IsPost())
            {
                response.StatusCode = 405;
                response.AddHeader("Allow", "POST");
                return;
            }

            await Post(request, response);
        }
示例#15
0
        /// <inheritdoc />
        public async Task Process(IHttpResourceRequest request, IHttpResourceResponse response, IEnumerable <string> subPath)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            if (!request.IsGet())
            {
                response.StatusCode = (int)HttpStatusCode.MethodNotAllowed;
                response.AddHeader("Allow", "GET");
                return;
            }



            await Get(request, response);
        }
示例#16
0
        public async Task PostOrDeleteSubscriber(IHttpResourceRequest request, IHttpResourceResponse response,
            TopicName topic, IEnumerable<string> subPath)
        {
            if (request == null) throw new ArgumentNullException("request");
            if (response == null) throw new ArgumentNullException("response");

            var uri = request.QueryString["uri"];
            if (uri == null)
            {
                response.StatusCode = 400;
                response.StatusDescription = "Subscriber URI is required";
                return;
            }

            var subscriber = new Uri(uri);
            if (!_topics.Contains(topic))
            {
                response.StatusCode = 404;
                response.StatusDescription = "Topic not found";
                return;
            }

            if ("delete".Equals(request.HttpMethod, StringComparison.OrdinalIgnoreCase))
            {
                await _subscriptionTrackingService.RemoveSubscription(topic, subscriber);
            }
            else
            {
                var ttlStr = request.QueryString["ttl"];
                var ttl = string.IsNullOrWhiteSpace(ttlStr)
                    ? default(TimeSpan)
                    : TimeSpan.FromSeconds(int.Parse(ttlStr));

                await _subscriptionTrackingService.AddSubscription(topic, subscriber, ttl);
            }
            response.StatusCode = 202;
        }
示例#17
0
        private async Task Get(IHttpResourceRequest request, IHttpResourceResponse response)
        {
            if (request == null)
            {
                throw new ArgumentNullException(nameof(request));
            }
            if (response == null)
            {
                throw new ArgumentNullException(nameof(response));
            }

            if (_messageJournal == null)
            {
                // Message journaling is not enabled
                response.StatusCode = (int)HttpStatusCode.NotImplemented;
                return;
            }

            var authorized = _authorizationService == null ||
                             await _authorizationService.IsAuthorizedToQueryJournal(request.Principal);

            if (!authorized)
            {
                response.StatusCode        = (int)HttpStatusCode.Unauthorized;
                response.StatusDescription = "Unauthorized";
                return;
            }

            var responseModel = new JournalGetResponseModel();
            var start         = await GetStartPosition(request, responseModel.Errors);

            var count  = GetCount(request, responseModel.Errors);
            var filter = ConfigureFilter(request, responseModel.Errors);

            if (responseModel.Errors.Any())
            {
                response.StatusCode = (int)HttpStatusCode.BadRequest;
            }
            else
            {
                var result = await _messageJournal.Read(start, count, filter);

                responseModel.Start        = start.ToString();
                responseModel.Next         = result.Next.ToString();
                responseModel.EndOfJournal = result.EndOfJournal;
                responseModel.Entries      = result.Entries.Select(entry => new MessageJournalEntryModel
                {
                    Position  = entry.Position.ToString(),
                    Category  = entry.Category,
                    Timestamp = entry.Timestamp,
                    Data      = new MessageJournalEntryDataModel
                    {
                        Headers = entry.Data.Headers.ToDictionary(h => (string)h.Key, h => h.Value),
                        Content = entry.Data.Content
                    }
                }).ToList();
                response.StatusCode = (int)HttpStatusCode.OK;
            }

            response.ContentType = "application/json";
            var encoding = response.ContentEncoding;

            if (encoding == null)
            {
                encoding = Encoding.UTF8;
                response.ContentEncoding = encoding;
            }

            var serializedContent = _serializer.Serialize(responseModel);
            var encodedContent    = encoding.GetBytes(serializedContent);

            response.StatusCode = 200;
            await response.OutputStream.WriteAsync(encodedContent, 0, encodedContent.Length);
        }