public Task HandshakeAsync(IChannel channel, IFullHttpRequest req, HttpHeaders responseHeaders) { var completion = new TaskCompletionSource(); this.Handshake(channel, req, responseHeaders, completion); return(completion.Task); }
public virtual bool PrepareUpgradeResponse(IChannelHandlerContext ctx, IFullHttpRequest upgradeRequest, HttpHeaders headers) { try { // Decode the HTTP2-Settings header and set the settings on the handler to make // sure everything is fine with the request. var upgradeHeaders = upgradeRequest.Headers.GetAll(Http2CodecUtil.HttpUpgradeSettingsHeader); var upgradeHeadersCount = upgradeHeaders.Count; if (upgradeHeadersCount <= 0 || upgradeHeadersCount > 1) { ThrowHelper.ThrowArgumentException_MustOnlyOne(); } _settings = DecodeSettingsHeader(ctx, upgradeHeaders[0]); // Everything looks good. return(true); } catch (Exception cause) { if (Logger.InfoEnabled) { Logger.ErrorDuringUpgradeToHTTP2(cause); } return(false); } }
IByteBuffer encodeFullHttpRequest(IChannelHandlerContext ctx, string appkey, IFullHttpRequest request) { StringBuilder sb = new StringBuilder(); sb.Append(request.Method.ToString()); sb.Append(" "); int pos = request.Uri.IndexOf("/" + appkey); var tmp = request.Uri.Substring(pos + appkey.Length + 1); sb.Append(tmp); sb.Append(" "); sb.Append(request.ProtocolVersion.ToString()); sb.AppendLine(" "); sb.AppendLine(" "); var cl = HttpUtil.GetContentLength(request, -1L); if (cl == -1 && request.Content.ReadableBytes > 0) { request.Headers.Add(HttpHeaderNames.ContentLength, request.Content.ReadableBytes); } foreach (var obj in request.Headers) { sb.AppendLine(string.Format("{0}:{1}", obj.Key, obj.Value)); } sb.AppendLine(" "); sb.AppendLine(" "); var bbs = ctx.Allocator.Buffer(); bbs.WriteString(sb.ToString(), System.Text.Encoding.UTF8); bbs.WriteBytes(request.Content); return(bbs); }
public virtual void UpgradeTo(IChannelHandlerContext ctx, IFullHttpRequest upgradeRequest) { try { var pipeline = ctx.Pipeline; // Add the HTTP/2 connection handler to the pipeline immediately following the current handler. _ = pipeline.AddAfter(ctx.Name, _handlerName, _connectionHandler); // Add also all extra handlers as these may handle events / messages produced by the connectionHandler. // See https://github.com/netty/netty/issues/9314 if (_handlers != null) { var name = pipeline.Context(_connectionHandler).Name; for (int i = _handlers.Length - 1; i >= 0; i--) { _ = pipeline.AddAfter(name, null, _handlers[i]); } } _connectionHandler.OnHttpServerUpgrade(_settings); } catch (Http2Exception e) { _ = ctx.FireExceptionCaught(e); _ = ctx.CloseAsync(); } }
/// <summary> /// 处理Body和Url参数 /// </summary> /// <param name="request"></param> /// <param name="parameters"></param> /// <param name="response"></param> /// <returns></returns> protected virtual object[] HandlerBodyAndUrlParams(IFullHttpRequest request, IReadOnlyList <ParameterInfo> parameters, ref IFullHttpResponse response) { string bodyParams = GetBodyParams(request); Dictionary <string, string> urlParams = GetUrlParams(request); if (parameters.Count <= 0) { return(null); } var @params = new object[parameters.Count]; for (var i = 0; i < parameters.Count; i++) { if (!string.IsNullOrEmpty(bodyParams) && parameters[i].ParameterType.IsClass && parameters[i].ParameterType != typeof(string)) { @params[i] = bodyParams.JsonToObject(parameters[i].ParameterType); continue; } if (urlParams.ContainsKey(parameters[i].Name ?? throw new MateralDotNettyException("参数为空"))) { @params[i] = urlParams[parameters[i].Name].ConvertTo(parameters[i].ParameterType); continue; } if (@params[i] == null) { ResultModel resultModel = ResultModel.Fail($"参数{parameters[i].Name}错误"); response = HttpResponseHelper.GetHttpResponse(HttpResponseStatus.BadRequest, resultModel.ToJson()); return(null); } } return(@params); }
/// <summary> /// 获得Response /// </summary> private async Task <IFullHttpResponse> GetResponseAsync(IFullHttpRequest request, BaseController baseController, MethodInfo action) { IFullHttpResponse result = null; string bodyParams = GetBodyParams(request); Dictionary <string, string> urlParams = GetUrlParams(request); ParameterInfo[] parameters = action.GetParameters(); object[] @params = null; if (parameters.Length > 0) { @params = new object[parameters.Length]; for (var i = 0; i < parameters.Length; i++) { if (!string.IsNullOrEmpty(bodyParams) && parameters[i].ParameterType.IsClass && parameters[i].ParameterType != typeof(string)) { @params[i] = bodyParams.JsonToT <object>(parameters[i].ParameterType); continue; } if (urlParams.ContainsKey(parameters[i].Name)) { @params[i] = urlParams[parameters[i].Name].ConvertTo(parameters[i].ParameterType); continue; } if (@params[i] == null) { //ResultModel resultModel = ResultModel.Fail($"参数{parameters[i].Name}错误"); result = GetHttpResponse(HttpResponseStatus.BadRequest, $"参数{parameters[i].Name}错误)"); break; } } } result = result ?? await GetResponseAsync(baseController, action, @params); return(result); }
/// <summary> /// 处理 /// </summary> /// <param name="request"></param> /// <param name="response"></param> public void Handler(IFullHttpRequest request, IFullHttpResponse response) { if (!IsMatch(request.Method.Name)) { response.SetStatus(HttpResponseStatus.BadRequest); } }
static string GetWebSocketLocation(IFullHttpRequest req) { bool result = req.Headers.TryGet(HttpHeaderNames.Host, out ICharSequence value); string location = value.ToString() + WebsocketPath; return("ws://" + location); }
/// <summary> /// 获取Url参数 /// </summary> /// <param name="request"></param> /// <returns></returns> private Dictionary <string, string> GetUrlParams(IFullHttpRequest request) { var result = new Dictionary <string, string>(); string[] tempString = request.Uri.Split('?'); if (tempString.Length <= 1) { return(result); } string[] paramsString = tempString[1].Split('&'); foreach (string param in paramsString) { if (string.IsNullOrEmpty(param)) { continue; } string[] values = param.Split('='); if (values.Length != 2 || result.ContainsKey(values[0])) { continue; } result.Add(values[0], values[1]); } return(result); #endregion }
/// <summary> /// Performs the opening handshake /// When call this method you <c>MUST NOT</c> retain the <see cref="IFullHttpRequest"/> which is passed in. /// </summary> /// <param name="channel">Channel</param> /// <param name="req">HTTP Request</param> /// <param name="responseHeaders">Extra headers to add to the handshake response or <code>null</code> if no extra headers should be added</param> /// <returns></returns> public Task HandshakeAsync(IChannel channel, IFullHttpRequest req, HttpHeaders responseHeaders) { var completion = channel.NewPromise(); Handshake(channel, req, responseHeaders, completion); return(completion.Task); }
void HandleHttpRequest(IChannelHandlerContext ctx, IFullHttpRequest req) { // Handle a bad request. if (!req.Result.IsSuccess) { SendHttpResponse(ctx, req, new DefaultFullHttpResponse(Http11, BadRequest)); return; } // Allow only GET methods. if (!Equals(req.Method, HttpMethod.Get)) { SendHttpResponse(ctx, req, new DefaultFullHttpResponse(Http11, Forbidden)); return; } // Handshake var wsFactory = new WebSocketServerHandshakerFactory( GetWebSocketLocation(req), null, true, 5 * 1024 * 1024); _handshaker = wsFactory.NewHandshaker(req); if (this._handshaker == null) { WebSocketServerHandshakerFactory.SendUnsupportedVersionResponse(ctx.Channel); } else { _logger.LogInformation($"New client to handshake:{ctx.Channel}"); var appSession = new AppSession(); appSession.Initialize(ctx.Channel, ctx.Channel.RemoteAddress); _appSessionContainer.Set(ctx.Channel.Id.ToString(), appSession); _handshaker.HandshakeAsync(ctx.Channel, req); } }
/// <summary> /// 获得Response /// </summary> /// <param name="request"></param> /// <param name="baseController"></param> /// <param name="action"></param> /// <param name="globalFilters"></param> /// <returns></returns> protected virtual async Task <IFullHttpResponse> GetResponseAsync(IFullHttpRequest request, BaseController baseController, ActionInfo action, IFilter[] globalFilters) { IFullHttpResponse response = action.HandlerMethod(request); if (response.Status.Code != HttpResponseStatus.OK.Code) { return(response); } response = await action.HandlerAuthorityFilterAsync(request, globalFilters); if (response.Status.Code != HttpResponseStatus.OK.Code) { return(response); } response = await action.HandlerActionBeforeFilterAsync(request, globalFilters); if (response.Status.Code != HttpResponseStatus.OK.Code) { return(response); } response = await HandlerParamsAsync(request, baseController, action); await action.HandlerActionAfterFilterAsync(request, response, globalFilters); return(response); }
/// <summary> /// Performs the opening handshake /// When call this method you <c>MUST NOT</c> retain the <see cref="IFullHttpRequest"/> which is passed in. /// </summary> /// <param name="channel">Channel</param> /// <param name="req">HTTP Request</param> /// <param name="responseHeaders">Extra headers to add to the handshake response or <code>null</code> if no extra headers should be added</param> /// <param name="completion">the <see cref="IPromise"/> to be notified when the opening handshake is done</param> public void Handshake(IChannel channel, IFullHttpRequest req, HttpHeaders responseHeaders, IPromise completion) { #if DEBUG if (Logger.DebugEnabled) { Logger.WebSocketVersionServerHandshake(channel, _version); } #endif IFullHttpResponse response = NewHandshakeResponse(req, responseHeaders); IChannelPipeline p = channel.Pipeline; if (p.Get <HttpObjectAggregator>() is object) { _ = p.Remove <HttpObjectAggregator>(); } if (p.Get <HttpContentCompressor>() is object) { _ = p.Remove <HttpContentCompressor>(); } if (p.Get <CorsHandler>() is object) { _ = p.Remove <CorsHandler>(); } if (p.Get <HttpServerExpectContinueHandler>() is object) { _ = p.Remove <HttpServerExpectContinueHandler>(); } if (p.Get <HttpServerKeepAliveHandler>() is object) { _ = p.Remove <HttpServerKeepAliveHandler>(); } IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>(); string encoderName; if (ctx is null) { // this means the user use an HttpServerCodec ctx = p.Context <HttpServerCodec>(); if (ctx is null) { _ = completion.TrySetException(ThrowHelper.GetInvalidOperationException_NoHttpDecoderAndServerCodec()); return; } encoderName = ctx.Name; _ = p.AddBefore(encoderName, "wsencoder", NewWebSocketEncoder()); _ = p.AddBefore(encoderName, "wsdecoder", NewWebsocketDecoder()); } else { _ = p.Replace(ctx.Name, "wsdecoder", NewWebsocketDecoder()); encoderName = p.Context <HttpResponseEncoder>().Name; _ = p.AddBefore(encoderName, "wsencoder", NewWebSocketEncoder()); } _ = channel.WriteAndFlushAsync(response).ContinueWith(RemoveHandlerAfterWriteAction, (completion, p, encoderName), TaskContinuationOptions.ExecuteSynchronously); }
/// <summary> /// 处理HttpMethodAttribute /// </summary> /// <param name="request"></param> /// <returns></returns> public IFullHttpResponse HandlerMethod(IFullHttpRequest request) { IFullHttpResponse response = HttpResponseHelper.GetHttpResponse(HttpResponseStatus.OK); var attribute = Action.GetCustomAttribute <HttpMethodAttribute>(); attribute?.Handler(request, response); return(response); }
protected override void ChannelRead0(IChannelHandlerContext ctx, IFullHttpRequest request) { if (HttpUtil.Is100ContinueExpected(request)) { ctx.WriteAsync(new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.Continue, Unpooled.Empty)); } base.ChannelRead0(ctx, request); }
public void Handshake(IChannel channel, IFullHttpRequest req, HttpHeaders responseHeaders, TaskCompletionSource completion) { if (Logger.DebugEnabled) { Logger.Debug("{} WebSocket version {} server handshake", channel, this.version); } IFullHttpResponse response = this.NewHandshakeResponse(req, responseHeaders); IChannelPipeline p = channel.Pipeline; if (p.Get <HttpObjectAggregator>() != null) { p.Remove <HttpObjectAggregator>(); } if (p.Get <HttpContentCompressor>() != null) { p.Remove <HttpContentCompressor>(); } IChannelHandlerContext ctx = p.Context <HttpRequestDecoder>(); string encoderName; if (ctx == null) { // this means the user use a HttpServerCodec ctx = p.Context <HttpServerCodec>(); if (ctx == null) { completion.TrySetException(new InvalidOperationException("No HttpDecoder and no HttpServerCodec in the pipeline")); return; } p.AddBefore(ctx.Name, "wsdecoder", this.NewWebsocketDecoder()); p.AddBefore(ctx.Name, "wsencoder", this.NewWebSocketEncoder()); encoderName = ctx.Name; } else { p.Replace(ctx.Name, "wsdecoder", this.NewWebsocketDecoder()); encoderName = p.Context <HttpResponseEncoder>().Name; p.AddBefore(encoderName, "wsencoder", this.NewWebSocketEncoder()); } channel.WriteAndFlushAsync(response).ContinueWith(t => { if (t.Status == TaskStatus.RanToCompletion) { p.Remove(encoderName); completion.TryComplete(); } else { completion.TrySetException(t.Exception); } }); }
private bool IsNotWebSocketPath(IFullHttpRequest req) { string websocketPath = _serverConfig.WebsocketPath; return(_serverConfig.CheckStartsWith ? !req.Uri.StartsWith(websocketPath, StringComparison.Ordinal) : !string.Equals(req.Uri, websocketPath #if NETCOREAPP_3_0_GREATER || NETSTANDARD_2_0_GREATER ));
/// <summary> /// 获得文件返回 /// </summary> /// <param name="request"></param> /// <returns></returns> protected virtual async Task <IFullHttpResponse> GetFileResponseAsync(IFullHttpRequest request) { string url = HttpUtility.UrlDecode(request.Uri, System.Text.Encoding.UTF8); url = string.IsNullOrEmpty(Path.GetExtension(url)) ? Path.Combine(url ?? throw new DotNettyException("Url为空"), "Index.html") : url; ICharSequence IfModifiedSince = request.Headers.Get(HttpHeaderNames.IfModifiedSince, null); return(await GetFileResponseAsync(url, IfModifiedSince)); }
/// <summary> /// 处理Options /// </summary> /// <param name="ctx"></param> /// <param name="request"></param> /// <param name="action"></param> /// <param name="response"></param> /// <returns></returns> protected virtual bool HandlerOptions(IChannelHandlerContext ctx, IFullHttpRequest request, ActionInfo action, ref IFullHttpResponse response) { if (request.Method.Name != HttpMethod.Options.Name) { return(false); } response = GetOptionsResponse(action.GetMethodName()); return(true); }
public void UpgradeTo(IChannelHandlerContext ctx, IFullHttpRequest upgradeRequest) { // Ensure that the HttpServerUpgradeHandler is still installed when this is called Assert.Equal(ctx.Channel.Pipeline.Context <HttpServerUpgradeHandler>(), ctx); Assert.NotNull(ctx.Channel.Pipeline.Get <HttpServerUpgradeHandler>()); // Add a marker handler to signal that the upgrade has happened ctx.Channel.Pipeline.AddAfter(ctx.Name, "marker", new ChannelHandlerAdapter()); }
public async Task <IFullHttpResponse> GetHttpResponse(IFullHttpRequest request) { if (!request.Result.IsSuccess) { return(GetHttpResponse(HttpResponseStatus.BadRequest)); } //return GetHttpResponse(HttpResponseStatus.OK, "Hello World!"); return(await GetFileResponseAsync(request)); }
internal static StringBuilder AppendFullRequest(StringBuilder buf, IFullHttpRequest req) { AppendFullCommon(buf, req); AppendInitialLine(buf, req); AppendHeaders(buf, req.Headers); AppendHeaders(buf, req.TrailingHeaders); RemoveLastNewLine(buf); return(buf); }
void HandleHttpRequest(IChannelHandlerContext ctx, IFullHttpRequest req) { // Handle a bad request. if (!req.Result.IsSuccess) { SendHttpResponse(ctx, req, new DefaultFullHttpResponse(Http11, BadRequest)); return; } // Allow only GET methods. if (!Equals(req.Method, HttpMethod.Get)) { SendHttpResponse(ctx, req, new DefaultFullHttpResponse(Http11, Forbidden)); return; } // Send the demo page and favicon.ico if ("/".Equals(req.Uri)) { IByteBuffer content = Unpooled.WrappedBuffer(Encoding.ASCII.GetBytes( "<html><head><title>XMPP WebSocket Proxy</title></head>" + Environment.NewLine + "<body>" + Environment.NewLine + "<h1>XMPP WebSocket server</h1>" + Environment.NewLine + "<p>running at: " + GetWebSocketLocation(req) + "</p>" + Environment.NewLine + "</body>" + Environment.NewLine + "</html>")); var res = new DefaultFullHttpResponse(Http11, OK, content); res.Headers.Set(HttpHeaderNames.ContentType, "text/html; charset=UTF-8"); HttpUtil.SetContentLength(res, content.ReadableBytes); SendHttpResponse(ctx, req, res); return; } if ("/favicon.ico".Equals(req.Uri)) { var res = new DefaultFullHttpResponse(Http11, NotFound); SendHttpResponse(ctx, req, res); return; } // Handshake var wsFactory = new WebSocketServerHandshakerFactory( GetWebSocketLocation(req), "xmpp", true, 5 * 1024 * 1024); this.handshaker = wsFactory.NewHandshaker(req); if (this.handshaker == null) { WebSocketServerHandshakerFactory.SendUnsupportedVersionResponse(ctx.Channel); } else { this.handshaker.HandshakeAsync(ctx.Channel, req); } }
/// <summary> /// 发送Http返回 /// </summary> /// <param name="ctx"></param> /// <param name="req"></param> /// <param name="res"></param> private void SendHttpResponse(IChannelHandlerContext ctx, IFullHttpRequest req, IFullHttpResponse res) { Task task = ctx.Channel.WriteAndFlushAsync(res); if (!HttpUtil.IsKeepAlive(req) || res.Status.Code != 200) { task.ContinueWith((t, c) => ((IChannelHandlerContext)c).CloseAsync(), ctx, TaskContinuationOptions.ExecuteSynchronously); } }
/// <summary> /// Method验证 /// </summary> /// <param name="request"></param> /// <param name="action"></param> /// <returns></returns> private bool CanMethodSuccess(IFullHttpRequest request, MethodInfo action) { Attribute[] attribute = action.GetCustomAttributes().ToArray(); if (request.Method.Name == "GET" && attribute.Any(m => m is HttpGetAttribute) || request.Method.Name == "POST" && attribute.Any(m => m is HttpPostAttribute)) { return(true); } return(false); }
/// <summary> /// 执行请求 /// <para/> /// 需手动调用 <see cref="IFullHttpResponse"/> 的Release方法 /// </summary> /// <param name="request"></param> /// <param name="token"></param> /// <returns></returns> public async Task <IFullHttpResponse> ExecuteAsync(IFullHttpRequest request, CancellationToken token) { CheckDisposed(); Interlocked.Exchange(ref _lastTicks, DateTime.UtcNow.Ticks); _requestSetupFunc?.Invoke(request); var channel = await GetChannelAsync().ConfigureAwait(false); var completionSource = new TaskCompletionSource <IFullHttpResponse>(); if (token.CanBeCanceled) { token.Register(() => { _ = CloseChannelAsync().ContinueWith(_ => { completionSource.TrySetException(new OperationCanceledException()); }, TaskScheduler.Default); }); } _responseHandler.SetCallback((ctx, innerResponse) => { try { innerResponse.Retain(); completionSource.TrySetResult(innerResponse); } #pragma warning disable CA1031 // 不捕获常规异常类型 catch (Exception ex) #pragma warning restore CA1031 // 不捕获常规异常类型 { completionSource.TrySetException(ex); } }); var sendTask = channel.WriteAndFlushAsync(request); try { var response = await completionSource.Task.ConfigureAwait(false); return(response); } finally { if (!sendTask.IsCompleted) { await CloseChannelAsync().ConfigureAwait(false); } } }
private string GetWebSocketLocation(IFullHttpRequest req) { req.Headers.TryGet(HttpHeaderNames.Host, out ICharSequence value); string location = value.ToString() + WebsocketPath; if (_webSocketConfig.IsSsl) { return("wss://" + location); } return("ws://" + location); }
/// <summary> /// 处理请求 /// </summary> /// <param name="ctx"></param> /// <param name="request"></param> /// <returns></returns> protected virtual async Task HandlerRequestAsync(IChannelHandlerContext ctx, IFullHttpRequest request) { IFullHttpResponse response = await GetFileResponseAsync(request); if (!CanNext || response.Status.Code == HttpResponseStatus.OK.Code) { await SendHttpResponseAsync(ctx, request, response); StopHandler(); } }
public void ForbiddenShouldReleaseRequest() { CorsConfig config = CorsConfigBuilder.ForOrigin((AsciiString)"https://localhost").ShortCircuit().Build(); var channel = new EmbeddedChannel(new CorsHandler(config), new EchoHandler()); IFullHttpRequest request = CreateHttpRequest(HttpMethod.Get); request.Headers.Set(HttpHeaderNames.Origin, "http://localhost:8888"); Assert.False(channel.WriteInbound(request)); Assert.Equal(0, request.ReferenceCount); Assert.True(ReferenceCountUtil.Release(channel.ReadOutbound())); Assert.False(channel.Finish()); }
/// <summary> /// Handle the web socket handshake for the web socket specification <a href= /// "http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-07">HyBi version 7</a>. /// /// <para> /// Browser request to the server: /// </para> /// /// <![CDATA[ /// GET /chat HTTP/1.1 /// Host: server.example.com /// Upgrade: websocket /// Connection: Upgrade /// Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== /// Sec-WebSocket-Origin: http://example.com /// Sec-WebSocket-Protocol: chat, superchat /// Sec-WebSocket-Version: 7 /// ]]> /// /// <para> /// Server response: /// </para> /// /// <![CDATA[ /// HTTP/1.1 101 Switching Protocols /// Upgrade: websocket /// Connection: Upgrade /// Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= /// Sec-WebSocket-Protocol: chat /// ]]> /// </summary> protected internal override IFullHttpResponse NewHandshakeResponse(IFullHttpRequest req, HttpHeaders headers) { if (!req.Headers.TryGet(HttpHeaderNames.SecWebsocketKey, out ICharSequence key) || key is null) { ThrowHelper.ThrowWebSocketHandshakeException_MissingKey(); } var res = new DefaultFullHttpResponse(HttpVersion.Http11, HttpResponseStatus.SwitchingProtocols, req.Content.Allocator.Buffer(0)); if (headers is object) { _ = res.Headers.Add(headers); } string acceptSeed = key + Websocket07AcceptGuid; byte[] sha1 = WebSocketUtil.Sha1(Encoding.ASCII.GetBytes(acceptSeed)); string accept = WebSocketUtil.Base64String(sha1); #if DEBUG if (Logger.DebugEnabled) { Logger.WebSocketVersion07ServerHandshakeKey(key, accept); } #endif _ = res.Headers.Set(HttpHeaderNames.Upgrade, HttpHeaderValues.Websocket) .Set(HttpHeaderNames.Connection, HttpHeaderValues.Upgrade) .Set(HttpHeaderNames.SecWebsocketAccept, accept); if (req.Headers.TryGet(HttpHeaderNames.SecWebsocketProtocol, out ICharSequence subprotocols) && subprotocols is object) { string selectedSubprotocol = this.SelectSubprotocol(subprotocols.ToString()); if (selectedSubprotocol is null) { #if DEBUG if (Logger.DebugEnabled) { Logger.RequestedSubprotocolNotSupported(subprotocols); } #endif } else { _ = res.Headers.Add(HttpHeaderNames.SecWebsocketProtocol, selectedSubprotocol); } } return(res); }