public async Task <GameSocket> ConnectAsync(Uri uri, CancellationToken cancellationToken) { GameSocketFeature gameSocketFeature = null; var contextBuilder = new ProtoContextBuilder(_application, AllowSynchronousIO); contextBuilder.Configure(context => { var request = context.Request; var scheme = uri.Scheme; scheme = (scheme == "ws") ? "http" : scheme; scheme = (scheme == "wss") ? "https" : scheme; request.Scheme = scheme; request.Path = PathString.FromUriComponent(uri); request.PathBase = PathString.Empty; if (request.Path.StartsWithSegments(_pathBase, out var remainder)) { request.Path = remainder; request.PathBase = _pathBase; } request.QueryString = QueryString.FromUriComponent(uri); request.Headers.Add("Connection", new string[] { "Upgrade" }); request.Headers.Add("Upgrade", new string[] { "gamesocket" }); request.Headers.Add("Sec-GameSocket-Version", new string[] { "13" }); request.Headers.Add("Sec-GameSocket-Key", new string[] { CreateRequestKey() }); request.Body = Stream.Null; // GameSocket gameSocketFeature = new GameSocketFeature(context); context.Features.Set <IProtoGameSocketFeature>(gameSocketFeature); ConfigureRequest?.Invoke(context.Request); }); var httpContext = await contextBuilder.SendAsync(cancellationToken); if (httpContext.Response.StatusCode != StatusCodes.Status101SwitchingProtocols) { throw new InvalidOperationException("Incomplete handshake, status code: " + httpContext.Response.StatusCode); } if (gameSocketFeature.ClientGameSocket == null) { throw new InvalidOperationException("Incomplete handshake"); } return(gameSocketFeature.ClientGameSocket); }
/// <summary> /// This adapts ProtoRequestMessages to ASP.NET Core requests, dispatches them through the pipeline, and returns the /// associated ProtoResponseMessage. /// </summary> /// <param name="request"></param> /// <param name="cancellationToken"></param> /// <returns></returns> protected override async Task <ProtoResponseMessage> SendAsync( ProtoRequestMessage request, CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } var contextBuilder = new ProtoContextBuilder(_application, AllowSynchronousIO); Stream responseBody = null; var requestContent = request.Content ?? new StreamContent(Stream.Null); var body = await requestContent.ReadAsStreamAsync(); contextBuilder.Configure(context => { var req = context.Request; req.Protocol = "HTTP/" + request.Version.ToString(fieldCount: 2); req.Method = request.Method.ToString(); req.Scheme = request.RequestUri.Scheme; foreach (var header in request.Headers) { req.Headers.Append(header.Key, header.Value.ToArray()); } if (!req.Host.HasValue) { // If Host wasn't explicitly set as a header, let's infer it from the Uri req.Host = HostString.FromUriComponent(request.RequestUri); if (request.RequestUri.IsDefaultPort) { req.Host = new HostString(req.Host.Host); } } req.Path = PathString.FromUriComponent(request.RequestUri); req.PathBase = PathString.Empty; if (req.Path.StartsWithSegments(_pathBase, out var remainder)) { req.Path = remainder; req.PathBase = _pathBase; } req.QueryString = QueryString.FromUriComponent(request.RequestUri); if (requestContent != null) { foreach (var header in requestContent.Headers) { req.Headers.Append(header.Key, header.Value.ToArray()); } } if (body.CanSeek) { // This body may have been consumed before, rewind it. body.Seek(0, SeekOrigin.Begin); } req.Body = new AsyncStreamWrapper(body, () => contextBuilder.AllowSynchronousIO); responseBody = context.Response.Body; }); var httpContext = await contextBuilder.SendAsync(cancellationToken); var response = new ProtoResponseMessage(); response.StatusCode = (ProtoStatusCode)httpContext.Response.StatusCode; response.ReasonPhrase = httpContext.Features.Get <IProtoResponseFeature>().ReasonPhrase; response.RequestMessage = request; response.Content = new StreamContent(responseBody); foreach (var header in httpContext.Response.Headers) { if (!response.Headers.TryAddWithoutValidation(header.Key, (IEnumerable <string>)header.Value)) { bool success = response.Content.Headers.TryAddWithoutValidation(header.Key, (IEnumerable <string>)header.Value); Contract.Assert(success, "Bad header"); } } return(response); }