/// <summary> /// Negotiates the response based on the given result and context. /// </summary> /// <param name="routeResult">The route result.</param> /// <param name="context">The context.</param> /// <returns>A <see cref="Response" />.</returns> public Response NegotiateResponse(dynamic routeResult, NancyContext context) { Response response; if (TryCastResultToResponse(routeResult, out response)) { context.WriteTraceLog(sb => sb.AppendLine("[DefaultResponseNegotiator] Processing as real response")); return(response); } context.WriteTraceLog(sb => sb.AppendLine("[DefaultResponseNegotiator] Processing as negotiation")); NegotiationContext negotiationContext = GetNegotiationContext(routeResult, context); var coercedAcceptHeaders = this.GetCoercedAcceptHeaders(context).ToArray(); context.WriteTraceLog(sb => GetAccepHeaderTraceLog(context, negotiationContext, coercedAcceptHeaders, sb)); var compatibleHeaders = this.GetCompatibleHeaders(coercedAcceptHeaders, negotiationContext, context).ToArray(); if (!compatibleHeaders.Any()) { context.WriteTraceLog(sb => sb.AppendLine("[DefaultResponseNegotiator] Unable to negotiate response - no headers compatible")); return(new NotAcceptableResponse()); } return(CreateResponse(compatibleHeaders, negotiationContext, context)); }
/// <summary> /// Creates a response from the compatible headers. /// </summary> /// <param name="compatibleHeaders">The compatible headers.</param> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="context">The context.</param> /// <returns>A <see cref="Response"/>.</returns> private Response CreateResponse(IList <CompatibleHeader> compatibleHeaders, NegotiationContext negotiationContext, NancyContext context) { var response = NegotiateResponse(compatibleHeaders, negotiationContext, context); if (response == null) { context.WriteTraceLog(sb => sb.AppendLine("[DefaultResponseNegotiator] Unable to negotiate response - no processors returned valid response")); response = new NotAcceptableResponse(); } response.WithHeader("Vary", "Accept"); this.AddLinkHeader(compatibleHeaders, response, context.Request.Url); SetStatusCode(negotiationContext, response); SetReasonPhrase(negotiationContext, response); AddCookies(negotiationContext, response); if (response is NotAcceptableResponse) { return(response); } AddContentTypeHeader(negotiationContext, response); AddNegotiatedHeaders(negotiationContext, response); return(response); }
/// <summary> /// Prioritizes the response processors and tries to negotiate a response. /// </summary> /// <param name="compatibleHeaders">The compatible headers.</param> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="context">The context.</param> /// <returns>Response.</returns> private static Response NegotiateResponse( IEnumerable <CompatibleHeader> compatibleHeaders, NegotiationContext negotiationContext, NancyContext context) { foreach (var compatibleHeader in compatibleHeaders) { var prioritizedProcessors = compatibleHeader.Processors .OrderByDescending(x => x.Item2.ModelResult) .ThenByDescending(x => x.Item2.RequestedContentTypeResult); foreach (var prioritizedProcessor in prioritizedProcessors) { var processorType = prioritizedProcessor.Item1.GetType(); context.WriteTraceLog(sb => sb.AppendFormat("[DefaultResponseNegotiator] Invoking processor: {0}\n", processorType)); var mediaRangeModel = negotiationContext.GetModelForMediaRange(compatibleHeader.MediaRange); var response = prioritizedProcessor.Item1.Process(compatibleHeader.MediaRange, mediaRangeModel, context); if (response != null) { return(response); } } } return(null); }
/// <summary> /// Adds the negotiated headers from the <see cref="NegotiationContext"/> to the <see cref="Response"/>. /// </summary> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="response">The response.</param> private static void AddNegotiatedHeaders(NegotiationContext negotiationContext, Response response) { foreach (var header in negotiationContext.Headers) { response.Headers[header.Key] = header.Value; } }
/// <summary> /// Sets the status code from the <see cref="NegotiationContext"/> on the <see cref="Response"/>. /// </summary> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="response">The response.</param> private static void SetStatusCode(NegotiationContext negotiationContext, Response response) { if (negotiationContext.StatusCode.HasValue) { response.StatusCode = negotiationContext.StatusCode.Value; } }
/// <summary> /// Sets the reason phrase from the <see cref="NegotiationContext"/> on the <see cref="Response"/>. /// </summary> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="response">The response.</param> private static void SetReasonPhrase(NegotiationContext negotiationContext, Response response) { if (negotiationContext.ReasonPhrase != null) { response.ReasonPhrase = negotiationContext.ReasonPhrase; } }
/// <summary> /// Adds the cookies from the <see cref="NegotiationContext"/> to the <see cref="Response"/>. /// </summary> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="response">The response.</param> private static void AddCookies(NegotiationContext negotiationContext, Response response) { foreach (var cookie in negotiationContext.Cookies) { response.Cookies.Add(cookie); } }
/// <summary> /// Adds the content type header from the <see cref="NegotiationContext"/> to the <see cref="Response"/>. /// </summary> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="response">The response.</param> private static void AddContentTypeHeader(NegotiationContext negotiationContext, Response response) { if (negotiationContext.Headers.ContainsKey("Content-Type")) { response.ContentType = negotiationContext.Headers["Content-Type"]; negotiationContext.Headers.Remove("Content-Type"); } }
/// <summary> /// Adds the content type header from the <see cref="NegotiationContext"/> to the <see cref="Response"/>. /// </summary> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="response">The response.</param> private static void AddContentTypeHeader(NegotiationContext negotiationContext, Response response) { string contentType; if (negotiationContext.Headers.TryGetValue("Content-Type", out contentType)) { response.ContentType = contentType; negotiationContext.Headers.Remove("Content-Type"); } }
private static IEnumerable <Tuple <string, decimal> > GetCompatibleHeaders( IEnumerable <Tuple <string, decimal> > coercedAcceptHeaders, NegotiationContext negotiationContext) { var permissableMediaRanges = negotiationContext.PermissableMediaRanges; if (permissableMediaRanges.Any(mr => mr.IsWildcard)) { return(coercedAcceptHeaders.Where(header => header.Item2 > 0m)); } return(coercedAcceptHeaders .Where(header => header.Item2 > 0m) .SelectMany(header => permissableMediaRanges .Where(mr => mr.Matches(header.Item1)) .Select(mr => Tuple.Create(mr.ToString(), header.Item2)))); }
private IEnumerable <CompatibleHeader> GetCompatibleHeaders( IEnumerable <Tuple <string, decimal> > coercedAcceptHeaders, NegotiationContext negotiationContext, NancyContext context) { var acceptHeaders = GetCompatibleHeaders(coercedAcceptHeaders, negotiationContext); foreach (var header in acceptHeaders) { var mediaRangeModel = negotiationContext.GetModelForMediaRange(header.Item1); IEnumerable <Tuple <IResponseProcessor, ProcessorMatch> > compatibleProcessors = this.GetCompatibleProcessorsByHeader(header.Item1, mediaRangeModel, context); if (compatibleProcessors.Any()) { yield return(new CompatibleHeader(header.Item1, compatibleProcessors)); } } }
private static void GetAccepHeaderTraceLog( NancyContext context, NegotiationContext negotiationContext, Tuple <string, decimal>[] coercedAcceptHeaders, StringBuilder sb) { var allowableFormats = negotiationContext.PermissableMediaRanges .Select(mr => mr.ToString()) .Aggregate((t1, t2) => t1 + ", " + t2); var originalAccept = context.Request.Headers["accept"].Any() ? string.Join(", ", context.Request.Headers["accept"]) : "None"; var coercedAccept = coercedAcceptHeaders.Any() ? coercedAcceptHeaders.Select(h => h.Item1).Aggregate((t1, t2) => t1 + ", " + t2) : "None"; sb.AppendFormat("[DefaultResponseNegotiator] Original accept header: {0}\n", originalAccept); sb.AppendFormat("[DefaultResponseNegotiator] Coerced accept header: {0}\n", coercedAccept); sb.AppendFormat("[DefaultResponseNegotiator] Acceptable media ranges: {0}\n", allowableFormats); }
public void Should_reset_negotiation_context() { // Given var context = new NancyContext(); var negotiationContext = new NegotiationContext { ViewName = "Index" }; context.NegotiationContext = negotiationContext; // When this.statusCodeHandler.Handle(HttpStatusCode.InternalServerError, context); // Then Assert.Equal(context.NegotiationContext.ViewName, null); }
private static void GetAccepHeaderTraceLog( NancyContext context, NegotiationContext negotiationContext, Tuple<string, decimal>[] coercedAcceptHeaders, StringBuilder sb) { var allowableFormats = negotiationContext.PermissableMediaRanges .Select(mr => mr.ToString()) .Aggregate((t1, t2) => t1 + ", " + t2); var originalAccept = context.Request.Headers["accept"].Any() ? string.Join(", ", context.Request.Headers["accept"]) : "None"; var coercedAccept = coercedAcceptHeaders.Any() ? coercedAcceptHeaders.Select(h => h.Item1).Aggregate((t1, t2) => t1 + ", " + t2) : "None"; sb.AppendFormat("[DefaultResponseNegotiator] Original accept header: {0}\n", originalAccept); sb.AppendFormat("[DefaultResponseNegotiator] Coerced accept header: {0}\n", coercedAccept); sb.AppendFormat("[DefaultResponseNegotiator] Acceptable media ranges: {0}\n", allowableFormats); }
/// <summary> /// Creates a response from the compatible headers. /// </summary> /// <param name="compatibleHeaders">The compatible headers.</param> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="context">The context.</param> /// <returns>A <see cref="Response"/>.</returns> private static Response CreateResponse( IList<CompatibleHeader> compatibleHeaders, NegotiationContext negotiationContext, NancyContext context) { var response = NegotiateResponse(compatibleHeaders, negotiationContext, context); if (response == null) { context.WriteTraceLog(sb => sb.AppendLine("[DefaultResponseNegotiator] Unable to negotiate response - no processors returned valid response")); response = new NotAcceptableResponse(); } response.WithHeader("Vary", "Accept"); AddLinkHeader(compatibleHeaders, response, context.Request.Url); SetStatusCode(negotiationContext, response); SetReasonPhrase(negotiationContext, response); AddCookies(negotiationContext, response); if (response is NotAcceptableResponse) { return response; } AddContentTypeHeader(negotiationContext, response); AddNegotiatedHeaders(negotiationContext, response); return response; }
/// <summary> /// Prioritizes the response processors and tries to negotiate a response. /// </summary> /// <param name="compatibleHeaders">The compatible headers.</param> /// <param name="negotiationContext">The negotiation context.</param> /// <param name="context">The context.</param> /// <returns>Response.</returns> private static Response NegotiateResponse( IEnumerable<CompatibleHeader> compatibleHeaders, NegotiationContext negotiationContext, NancyContext context) { foreach (var compatibleHeader in compatibleHeaders) { var prioritizedProcessors = compatibleHeader.Processors .OrderByDescending(x => x.Item2.ModelResult) .ThenByDescending(x => x.Item2.RequestedContentTypeResult); foreach (var prioritizedProcessor in prioritizedProcessors) { var processorType = prioritizedProcessor.Item1.GetType(); context.WriteTraceLog(sb => sb.AppendFormat("[DefaultResponseNegotiator] Invoking processor: {0}\n", processorType)); var mediaRangeModel = negotiationContext.GetModelForMediaRange(compatibleHeader.MediaRange); var response = prioritizedProcessor.Item1.Process(compatibleHeader.MediaRange, mediaRangeModel, context); if (response != null) { return response; } } } return null; }
private static IEnumerable<Tuple<string, decimal>> GetCompatibleHeaders( IEnumerable<Tuple<string, decimal>> coercedAcceptHeaders, NegotiationContext negotiationContext) { var permissableMediaRanges = negotiationContext.PermissableMediaRanges; if (permissableMediaRanges.Any(mr => mr.IsWildcard)) { return coercedAcceptHeaders.Where(header => header.Item2 > 0m); } return coercedAcceptHeaders .Where(header => header.Item2 > 0m) .SelectMany(header => permissableMediaRanges .Where(mr => mr.Matches(header.Item1)) .Select(mr => Tuple.Create(mr.ToString(), header.Item2))); }
private IEnumerable<CompatibleHeader> GetCompatibleHeaders( IEnumerable<Tuple<string, decimal>> coercedAcceptHeaders, NegotiationContext negotiationContext, NancyContext context) { var acceptHeaders = GetCompatibleHeaders(coercedAcceptHeaders, negotiationContext); foreach (var header in acceptHeaders) { var mediaRangeModel = negotiationContext.GetModelForMediaRange(header.Item1); IEnumerable<Tuple<IResponseProcessor, ProcessorMatch>> compatibleProcessors = this.GetCompatibleProcessorsByHeader(header.Item1, mediaRangeModel, context); if (compatibleProcessors.Any()) { yield return new CompatibleHeader(header.Item1, compatibleProcessors); } } }