private async Task HandleGrpcWebRequest(HttpContext httpContext, ServerGrpcWebContext grcpWebContext) { var feature = new GrpcWebFeature(grcpWebContext, httpContext); var initialProtocol = httpContext.Request.Protocol; // Modifying the request is required to stop Grpc.AspNetCore.Server from rejecting it httpContext.Request.Protocol = GrpcWebProtocolConstants.Http2Protocol; httpContext.Request.ContentType = ResolveContentType(GrpcWebProtocolConstants.GrpcContentType, httpContext.Request.ContentType !); // Update response content type back to gRPC-Web httpContext.Response.OnStarting(() => { // Reset request protocol back to its original value. Not doing this causes a 2 second // delay when making HTTP/1.1 calls. httpContext.Request.Protocol = initialProtocol; if (CommonGrpcProtocolHelpers.IsContentType(GrpcWebProtocolConstants.GrpcContentType, httpContext.Response.ContentType !)) { var contentType = grcpWebContext.Response == ServerGrpcWebMode.GrpcWeb ? GrpcWebProtocolConstants.GrpcWebContentType : GrpcWebProtocolConstants.GrpcWebTextContentType; var responseContentType = ResolveContentType(contentType, httpContext.Response.ContentType); httpContext.Response.ContentType = responseContentType; Log.SendingGrpcWebResponse(_logger, responseContentType); } return(Task.CompletedTask); }); try { await _next(httpContext); // If trailers have already been written in CompleteAsync then this will no-op await feature.WriteTrailersAsync(); } finally { feature.DetachFromContext(httpContext); } }
public GrpcWebFeature(ServerGrpcWebContext grcpWebContext, HttpContext httpContext) { // Capture existing features. We'll use these internally, and restore them onto the context // once the middleware has finished executing. // Note that some of these will be missing depending on the host and protocol. // e.g. // - IHttpResponseTrailersFeature and IHttpResetFeature will be missing when HTTP/1.1. // - IRequestBodyPipeFeature will be missing when in IIS. _initialRequestFeature = httpContext.Features.Get <IRequestBodyPipeFeature>(); _initialResponseFeature = GetRequiredFeature <IHttpResponseBodyFeature>(httpContext); _initialResetFeature = httpContext.Features.Get <IHttpResetFeature>(); _initialTrailersFeature = httpContext.Features.Get <IHttpResponseTrailersFeature>(); var innerReader = _initialRequestFeature?.Reader ?? httpContext.Request.BodyReader; var innerWriter = _initialResponseFeature.Writer ?? httpContext.Response.BodyWriter; Trailers = new HeaderDictionary(); if (grcpWebContext.Request == ServerGrpcWebMode.GrpcWebText) { Reader = new Base64PipeReader(innerReader); } else { Reader = innerReader; } if (grcpWebContext.Response == ServerGrpcWebMode.GrpcWebText) { Writer = new Base64PipeWriter(innerWriter); } else { Writer = innerWriter; } httpContext.Features.Set <IRequestBodyPipeFeature>(this); httpContext.Features.Set <IHttpResponseBodyFeature>(this); httpContext.Features.Set <IHttpResponseTrailersFeature>(this); httpContext.Features.Set <IHttpResetFeature>(this); }