protected internal virtual async Task <JToken> GetResponseSafeInBatch(IUntypedCall call, HandlingContext context) { try { var response = await SafeNext(call, context, false); switch (response) { case JsonServerResponseWrapper jsonResponseWrapper: return(jsonResponseWrapper.Value); case RawServerResponseWrapper rawResponseWrapper: throw new JsonRpcInternalException("Raw responses are not supported in batches", null, null, rawResponseWrapper.Source.StatusCode); case null: throw new ArgumentNullException(nameof(response)); default: throw new ArgumentOutOfRangeException(nameof(response), response.GetType().Name); } } catch (Exception e) { if (!(e is JsonRpcErrorResponseException)) { log.LogWarning(e, $"{nameof(GetResponseSafeInBatch)} failed: converting exception to json response"); } return(errorFactory.ConvertExceptionToResponse(e, headerJsonRpcSerializer)); } }
protected internal virtual async Task <IServerResponseWrapper> SafeNext(IUntypedCall call, HandlingContext context, bool allowRawResponses) { log.LogTrace($"{nameof(SafeNext)}: Started. {nameof(allowRawResponses)} is [{allowRawResponses}]"); IHeaderDictionary nestedHeaders = null; try { context.OriginalHttpContext.RequestAborted.ThrowIfCancellationRequested(); var nestedHttpContext = nestedContextFactory.Create(context.OriginalHttpContext, call, context.RequestEncoding); log.LogTrace($"{nameof(SafeNext)}: invoking pipeline on nested context"); await context.Next(nestedHttpContext); nestedHeaders = nestedHttpContext.Response.Headers; var result = await responseReader.GetResponse(nestedHttpContext, call, allowRawResponses, context.OriginalHttpContext.RequestAborted); if (result == null) { throw new JsonRpcInternalException($"{nameof(ResponseReader)} returned null"); } log.LogTrace($"{nameof(SafeNext)}: Completed"); return(result); } catch (Exception e) { log.LogWarning(e, $"{nameof(SafeNext)} failed: converting exception to json response"); var response = errorFactory.ConvertExceptionToResponse(e, headerJsonRpcSerializer); return(new JsonServerResponseWrapper(response, call, nestedHeaders)); } }
internal static JToken SetId(JToken value, IUntypedCall call) { if (call is UntypedRequest request) { value[JsonRpcConstants.IdProperty] = request.RawId; } return(value); }
public JsonServerResponseWrapper(JToken value, IUntypedCall call, IHeaderDictionary headers) { if (value == null) { throw new ArgumentNullException(nameof(value)); } Value = SetId(value, call); Headers = headers; }
public HttpContext Create(HttpContext context, IUntypedCall call, Encoding requestEncoding) { var newFeatures = new FeatureCollection(context.Features); OverrideRequestDataFeatures(newFeatures, context.Features, call, requestEncoding); // NOTE: factory breaks HttpContextAccessor var result = httpContextFactory.Create(newFeatures); log.LogTrace($"Created HttpContext [{result}]"); return(result); }
protected virtual IHttpRequestFeature CreateRequest(IHttpRequestFeature originalRequest, IUntypedCall call, Encoding requestEncoding) { var headers = new Dictionary <string, StringValues>(originalRequest.Headers, StringComparer.Ordinal); var result = new HttpRequestFeature { Protocol = originalRequest.Protocol, Method = originalRequest.Method, Scheme = originalRequest.Scheme, Path = originalRequest.Path, PathBase = originalRequest.PathBase, QueryString = originalRequest.QueryString, RawTarget = originalRequest.RawTarget, Headers = new HeaderDictionary(headers), Body = new MemoryStream(requestEncoding.GetBytes(call.RawJson)) }; log.LogTrace($"Copied request: [{result.Protocol}] [{result.Method}] [{result.Scheme}] [{result.Path}] [{result.PathBase}] [{result.QueryString}] [{result.RawTarget}], [{headers.Count}] headers"); return(result); }
protected virtual void OverrideRequestDataFeatures(IFeatureCollection newFeatures, IFeatureCollection originalFeatures, IUntypedCall call, Encoding requestEncoding) { var itemsFeature = CreateItems(originalFeatures.Get <IItemsFeature>()); itemsFeature.Items[JsonRpcConstants.RequestItemKey] = call; itemsFeature.Items[JsonRpcConstants.NestedPipelineItemKey] = true; newFeatures.Set(itemsFeature); var requestFeature = CreateRequest(originalFeatures.Get <IHttpRequestFeature>(), call, requestEncoding); newFeatures.Set(requestFeature); var responseFeature = new StreamResponseBodyFeature(new MemoryStream()); newFeatures.Set <IHttpResponseBodyFeature>(responseFeature); }
public void WithSingle(IUntypedCall singleCall) { SingleCall = singleCall; }
/// <summary> /// Normal result of action when it returns object /// </summary> /// <param name="response"></param> /// <param name="call"></param> /// <param name="responseBody"></param> /// <param name="encoding"></param> /// <param name="token"></param> /// <returns></returns> protected internal virtual async Task <IServerResponseWrapper> HandleObjectResult(HttpResponse response, IUntypedCall call, MemoryStream responseBody, Encoding encoding, CancellationToken token) { log.LogTrace($"{nameof(HandleObjectResult)}"); var jToken = await ReadJsonResponse(responseBody, encoding, token); return(new JsonServerResponseWrapper(jToken, call, response.Headers)); }
protected internal virtual async Task <IServerResponseWrapper> HandleResultType(HttpResponse response, Type actionResultType, IUntypedCall call, MemoryStream responseBody, Encoding encoding, CancellationToken token) { switch (actionResultType) { case Type objectResult when objectResult == typeof(ObjectResult): return(await HandleObjectResult(response, call, responseBody, encoding, token)); case null: return(await HandleNullResult(response, call, responseBody, encoding, token)); default: return(await HandleUnknownResult(response, call, responseBody, encoding, token)); } }
protected internal virtual async Task <IServerResponseWrapper> GetResponseWrapper(HttpResponse response, Type actionResultType, IUntypedCall call, CancellationToken token) { if (!(response.Body is MemoryStream ms)) { throw new JsonRpcInternalException("Expected MemoryStream to read response"); } var contentType = response.GetTypedHeaders().ContentType; // TODO not sure if this will be right encoding var encoding = contentType?.Encoding ?? Encoding.UTF8; log.LogTrace($"{nameof(GetResponseWrapper)}: {nameof(encoding)} is [{encoding.EncodingName}]"); ms.Seek(0, SeekOrigin.Begin); return(await HandleResultType(response, actionResultType, call, ms, encoding, token)); }
public virtual async Task <IServerResponseWrapper> GetResponse(HttpContext nestedHttpContext, IUntypedCall call, bool allowRawResponses, CancellationToken token) { var actionResultType = Utils.GetActionResultType(nestedHttpContext); log.LogTrace($"{nameof(GetResponse)}: {nameof(allowRawResponses)} is [{allowRawResponses}], {nameof(actionResultType)} is [{actionResultType}]"); var responseWrapper = await GetResponseWrapper(nestedHttpContext.Response, actionResultType, call, token); switch (responseWrapper) { case RawServerResponseWrapper _ when !allowRawResponses: throw new JsonRpcInternalException($"Raw responses are not allowed by default and not supported in batches, check {nameof(JsonRpcOptions)}"); case null: throw new ArgumentNullException(nameof(responseWrapper)); default: return(responseWrapper); } }
/// <summary> /// Unknown action results are treated as raw responses /// </summary> /// <param name="response"></param> /// <param name="call"></param> /// <param name="responseBody"></param> /// <param name="encoding"></param> /// <param name="token"></param> /// <returns></returns> protected internal virtual Task <IServerResponseWrapper> HandleUnknownResult(HttpResponse response, IUntypedCall call, MemoryStream responseBody, Encoding encoding, CancellationToken token) { log.LogTrace($"{nameof(GetResponseWrapper)}: return raw response"); return(Task.FromResult <IServerResponseWrapper>(new RawServerResponseWrapper(response))); }
/// <summary> /// Framework decided to reject our request, eg. 404 when routing failed /// </summary> /// <param name="response"></param> /// <param name="call"></param> /// <param name="responseBody"></param> /// <param name="encoding"></param> /// <param name="token"></param> /// <returns></returns> protected internal virtual Task <IServerResponseWrapper> HandleNullResult(HttpResponse response, IUntypedCall call, MemoryStream responseBody, Encoding encoding, CancellationToken token) { log.LogTrace($"{nameof(HandleNullResult)}"); var body = ReadTextBody(responseBody, encoding); var jToken = FormatHttpErrorResponse(response, body); return(Task.FromResult <IServerResponseWrapper>(new JsonServerResponseWrapper(jToken, call, response.Headers))); }