public void TestLiteralWithIncrementalIndexingCompleteEviction() { // Verify indexed host header this.Decode("4004" + Hex("name") + "05" + Hex("value")); mockHeaders.Verify(x => x.Add(AsciiString.Of("name"), AsciiString.Of("value"))); mockHeaders.VerifyNoOtherCalls(); mockHeaders.Reset(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < 4096; i++) { sb.Append('a'); } var value = sb.ToString(); sb = new StringBuilder(); sb.Append("417F811F"); for (int i = 0; i < 4096; i++) { sb.Append("61"); // 'a' } this.Decode(sb.ToString()); mockHeaders.Verify(x => x.Add(AsciiString.Of(":authority"), AsciiString.Of(value))); mockHeaders.VerifyNoOtherCalls(); mockHeaders.Reset(); // Verify next header is inserted at index 62 this.Decode("4004" + Hex("name") + "05" + Hex("value") + "BE"); mockHeaders.Verify(x => x.Add(AsciiString.Of("name"), AsciiString.Of("value")), Times.AtLeast(2)); mockHeaders.VerifyNoOtherCalls(); }
public void TrailerWithEmptyLineInSeparateBuffer() { HttpResponseDecoder decoder = new HttpResponseDecoder(); EmbeddedChannel channel = new EmbeddedChannel(decoder); String headers = "HTTP/1.1 200 OK\r\n" + "Transfer-Encoding: chunked\r\n" + "Trailer: My-Trailer\r\n"; Assert.False(channel.WriteInbound(Unpooled.CopiedBuffer(Encoding.ASCII.GetBytes(headers)))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer(Encoding.ASCII.GetBytes("\r\n")))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer("0\r\n", Encoding.ASCII))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer("My-Trailer: 42\r\n", Encoding.ASCII))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer("\r\n", Encoding.ASCII))); var response = channel.ReadInbound <IHttpResponse>(); Assert.Equal(2, response.Headers.Size); Assert.Equal("chunked", response.Headers.Get(HttpHeaderNames.TransferEncoding, null)); Assert.Equal("My-Trailer", response.Headers.Get(HttpHeaderNames.Trailer, null)); var lastContent = channel.ReadInbound <ILastHttpContent>(); Assert.Equal(1, lastContent.TrailingHeaders.Size); Assert.Equal("42", lastContent.TrailingHeaders.Get(AsciiString.Of("My-Trailer"), null)); Assert.Equal(0, lastContent.Content.ReadableBytes); lastContent.Release(); Assert.False(channel.Finish()); }
public static void ToHttp2Headers(HttpHeaders inHeaders, IHttp2Headers output) { // Choose 8 as a default size because it is unlikely we will see more than 4 Connection headers values, but // still allowing for "enough" space in the map to reduce the chance of hash code collision. var connectionBlacklist = ToLowercaseMap(inHeaders.GetAll(HttpHeaderNames.Connection), 8); foreach (var entry in inHeaders) { AsciiString aName = entry.Key.ToLowerCase(); if (!HttpToHttp2HeaderBlacklist.Contains(aName) && !connectionBlacklist.Contains(aName)) { // https://tools.ietf.org/html/rfc7540#section-8.1.2.2 makes a special exception for TE if (aName.ContentEqualsIgnoreCase(HttpHeaderNames.Te)) { ToHttp2HeadersFilterTE(entry, output); } else if (aName.ContentEqualsIgnoreCase(HttpHeaderNames.Cookie)) { AsciiString value = AsciiString.Of(entry.Value); uint uValueCount = (uint)value.Count; // split up cookies to allow for better compression // https://tools.ietf.org/html/rfc7540#section-8.1.2.5 try { int index = value.ForEachByte(ByteProcessor.FindSemicolon); if (uValueCount > (uint)index) // != -1 { int start = 0; do { _ = output.Add(HttpHeaderNames.Cookie, value.SubSequence(start, index, false)); // skip 2 characters "; " (see https://tools.ietf.org/html/rfc6265#section-4.2.1) start = index + 2; } while ((uint)start < uValueCount && uValueCount > (uint)(index = value.ForEachByte(start, value.Count - start, ByteProcessor.FindSemicolon))); // != -1 if ((uint)start >= uValueCount) { ThrowHelper.ThrowArgumentException_CookieValueIsOfUnexpectedFormat(value); } _ = output.Add(HttpHeaderNames.Cookie, value.SubSequence(start, value.Count, false)); } else { _ = output.Add(HttpHeaderNames.Cookie, value); } } catch (Exception) { // This is not expect to happen because FIND_SEMI_COLON never throws but must be caught // because of the ByteProcessor interface. ThrowHelper.ThrowInvalidOperationException(); } } else { _ = output.Add(aName, entry.Value); } } } }
private static void SetHttp2Scheme(HttpHeaders input, Uri uri, IHttp2Headers output) { var value = uri.Scheme; if (value is object) { output.Scheme = new AsciiString(value); return; } // Consume the Scheme extension header if present if (input.TryGet(ExtensionHeaderNames.Scheme, out var cValue)) { output.Scheme = AsciiString.Of(cValue); return; } if (uri.Port == HttpScheme.Https.Port) { output.Scheme = HttpScheme.Https.Name; } else if (uri.Port == HttpScheme.Http.Port) { output.Scheme = HttpScheme.Http.Name; } ThrowHelper.ThrowArgumentException_SchemeMustBeSpecified(); }
public void CharSequenceComparerIgnoreCaseTest() { var dict = new Dictionary <ICharSequence, int>(AsciiString.CaseInsensitiveHasher); dict.Add(AsciiString.Of("Town"), 0); dict.Add(AsciiString.Of("fOo"), 1); dict.Add(AsciiString.Of("baR"), 2); Assert.True(dict.ContainsKey((AsciiString)"town")); Assert.Equal(0, dict[(AsciiString)"town"]); Assert.True(dict.ContainsKey((AsciiString)"foo")); Assert.Equal(1, dict[(AsciiString)"foo"]); Assert.True(dict.ContainsKey((AsciiString)"bar")); Assert.Equal(2, dict[(AsciiString)"bar"]); Assert.True(AsciiString.Of("town").ContentEqualsIgnoreCase(new StringCharSequence("town"))); Assert.True(dict.ContainsKey(new StringCharSequence("town"))); Assert.Equal(0, dict[new StringCharSequence("town")]); Assert.True(dict.ContainsKey(new StringCharSequence("foo"))); Assert.Equal(1, dict[new StringCharSequence("foo")]); Assert.True(dict.ContainsKey(new StringCharSequence("bar"))); Assert.Equal(2, dict[new StringCharSequence("bar")]); dict.Clear(); }
public void HeadersOnlyRequest() { this.BootstrapEnv(2, 1, 0); IFullHttpRequest request = new DefaultFullHttpRequest(DotNetty.Codecs.Http.HttpVersion.Http11, HttpMethod.Get, "http://[email protected]:5555/example"); HttpHeaders httpHeaders = request.Headers; httpHeaders.SetInt(HttpConversionUtil.ExtensionHeaderNames.StreamId, 5); httpHeaders.Set(HttpHeaderNames.Host, "[email protected]:5555"); httpHeaders.Set(HttpConversionUtil.ExtensionHeaderNames.Scheme, "http"); httpHeaders.Add(AsciiString.Of("foo"), AsciiString.Of("goo")); httpHeaders.Add(AsciiString.Of("foo"), AsciiString.Of("goo2")); httpHeaders.Add(AsciiString.Of("foo2"), AsciiString.Of("goo2")); var http2Headers = new DefaultHttp2Headers() { Method = new AsciiString("GET"), Path = new AsciiString("/example"), Authority = new AsciiString("www.example.org:5555"), Scheme = new AsciiString("http") }; http2Headers.Add(new AsciiString("foo"), new AsciiString("goo")); http2Headers.Add(new AsciiString("foo"), new AsciiString("goo2")); http2Headers.Add(new AsciiString("foo2"), new AsciiString("goo2")); var writePromise = this.NewPromise(); this.VerifyHeadersOnly(http2Headers, writePromise, this.clientChannel.WriteAndFlushAsync(request, writePromise)); }
public void TestPseudoHeadersWithRemovePreservesPseudoIterationOrder() { var headers = NewHeaders(); var nonPseudoHeaders = new DefaultHttp2Headers(); foreach (var entry in headers) { if (entry.Key.Count == 0 || entry.Key[0] != ':' && !nonPseudoHeaders.Contains(entry.Key)) { nonPseudoHeaders.Add(entry.Key, entry.Value); } } Assert.False(nonPseudoHeaders.IsEmpty); // Remove all the non-pseudo headers and verify foreach (var nonPseudoHeaderEntry in nonPseudoHeaders) { Assert.True(headers.Remove(nonPseudoHeaderEntry.Key)); VerifyPseudoHeadersFirst(headers); VerifyAllPseudoHeadersPresent(headers); } // Add back all non-pseudo headers foreach (var nonPseudoHeaderEntry in nonPseudoHeaders) { headers.Add(nonPseudoHeaderEntry.Key, AsciiString.Of("goo")); VerifyPseudoHeadersFirst(headers); VerifyAllPseudoHeadersPresent(headers); } }
public void ContentEqualsIgnoreCase() { byte[] bytes = { 32, (byte)'a' }; AsciiString asciiString = new AsciiString(bytes, 1, 1, false); // https://github.com/netty/netty/issues/9475 Assert.False(asciiString.ContentEqualsIgnoreCase(new StringCharSequence("b"))); Assert.False(asciiString.ContentEqualsIgnoreCase(AsciiString.Of("b"))); }
public void TestExceptionDuringConnect() { IEventLoopGroup group = null; IChannel serverChannel = null; IChannel clientChannel = null; try { group = new DefaultEventLoopGroup(1); var addr = new LocalAddress("a"); var exception = new AtomicReference <Exception>(); var sf = new ServerBootstrap().Channel <LocalServerChannel>().Group(group).ChildHandler( new ActionChannelInitializer <IChannel>(ch => { ch.Pipeline.AddFirst(new HttpResponseEncoder()); var response = new DefaultFullHttpResponse( HttpVersion.Http11, HttpResponseStatus.BadGateway); response.Headers.Add(AsciiString.Of("name"), "value"); response.Headers.Add(HttpHeaderNames.ContentLength, "0"); ch.WriteAndFlushAsync(response); } )).BindAsync(addr); serverChannel = sf.Result; var cf = new Bootstrap().Channel <LocalChannel>().Group(group).Handler( new ActionChannelInitializer <IChannel>(ch => { ch.Pipeline.AddFirst(new HttpProxyHandler(addr)); ch.Pipeline.AddLast(new ErrorCaptureHandler(exception)); })).ConnectAsync(new DnsEndPoint("localhost", 1234)); clientChannel = cf.Result; clientChannel.CloseAsync().Wait(); Assert.True(exception.Value is HttpProxyConnectException); var actual = (HttpProxyConnectException)exception.Value; Assert.NotNull(actual.Headers); Assert.Equal("value", actual.Headers.GetAsString(AsciiString.Of("name"))); } finally { if (clientChannel != null) { clientChannel.CloseAsync(); } if (serverChannel != null) { serverChannel.CloseAsync(); } if (group != null) { @group.ShutdownGracefullyAsync().Wait(); } } }
private static IHttp2Headers Headers() { var headers = new DefaultHttp2Headers(false); headers.Method = AsciiString.Of("GET"); headers.Scheme = AsciiString.Of("https"); headers.Authority = AsciiString.Of("example.org"); headers.Path = AsciiString.Of("/some/path/resource2"); headers.Add(Http2TestUtil.RandomString(), Http2TestUtil.RandomString()); return(headers); }
private static IHttp2Headers LargeHeaders() { DefaultHttp2Headers headers = new DefaultHttp2Headers(false); for (int i = 0; i < 100; ++i) { string key = "this-is-a-test-header-key-" + i; string value = "this-is-a-test-header-value-" + i; headers.Add(AsciiString.Of(key), AsciiString.Of(value)); } return(headers); }
public void TestDuplicateHandshakeResponseHeaders() { WebSocketServerHandshaker serverHandshaker = NewHandshaker("ws://example.com/chat", "chat", WebSocketDecoderConfig.Default); IFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Get, "/chat"); request.Headers .Set(HttpHeaderNames.Host, "example.com") .Set(HttpHeaderNames.Origin, "example.com") .Set(HttpHeaderNames.Upgrade, HttpHeaderValues.Websocket) .Set(HttpHeaderNames.Connection, HttpHeaderValues.Upgrade) .Set(HttpHeaderNames.SecWebsocketKey, "dGhlIHNhbXBsZSBub25jZQ==") .Set(HttpHeaderNames.SecWebsocketOrigin, "http://example.com") .Set(HttpHeaderNames.SecWebsocketProtocol, "chat, superchat") .Set(HttpHeaderNames.SecWebsocketVersion, WebSocketVersion().ToHttpHeaderValue()); HttpHeaders customResponseHeaders = new DefaultHttpHeaders(); // set duplicate required headers and one custom customResponseHeaders .Set(HttpHeaderNames.Connection, HttpHeaderValues.Upgrade) .Set(HttpHeaderNames.Upgrade, HttpHeaderValues.Websocket) .Set(AsciiString.Of("custom"), AsciiString.Of("header")); if (WebSocketVersion() != Http.WebSockets.WebSocketVersion.V00) { customResponseHeaders.Set(HttpHeaderNames.SecWebsocketAccept, "12345"); } IFullHttpResponse response = null; try { response = serverHandshaker.NewHandshakeResponse(request, customResponseHeaders); HttpHeaders responseHeaders = response.Headers; Assert.Equal(1, responseHeaders.GetAll(HttpHeaderNames.Connection).Count); Assert.Equal(1, responseHeaders.GetAll(HttpHeaderNames.Upgrade).Count); Assert.True(responseHeaders.ContainsValue(AsciiString.Of("custom"), AsciiString.Of("header"), true)); if (WebSocketVersion() != Http.WebSockets.WebSocketVersion.V00) { Assert.False(responseHeaders.ContainsValue(HttpHeaderNames.SecWebsocketAccept, AsciiString.Of("12345"), false)); } } finally { request.Release(); if (response != null) { response.Release(); } } }
public void TestCustomHeaders() { EndPoint socketAddress = new DnsEndPoint("10.0.0.1", 8080); TestInitialMessage( socketAddress, "10.0.0.1:8080", "10.0.0.1:8080", new DefaultHttpHeaders() .Add(AsciiString.Of("CUSTOM_HEADER"), "CUSTOM_VALUE1") .Add(AsciiString.Of("CUSTOM_HEADER"), "CUSTOM_VALUE2"), true); }
public void DontCombineSetCookieHeadersRegardlessOfCase() { CombinedHttpHeaders headers = NewCombinedHttpHeaders(); headers.Add(AsciiString.Of("Set-Cookie"), "a"); CombinedHttpHeaders otherHeaders = NewCombinedHttpHeaders(); otherHeaders.Add(AsciiString.Of("set-cookie"), "b"); otherHeaders.Add(AsciiString.Of("SET-COOKIE"), "c"); headers.Add(otherHeaders); var list = headers.GetAll(HttpHeaderNames.SetCookie); Assert.Equal(3, headers.GetAll(HttpHeaderNames.SetCookie).Count); }
private static IHttp2Headers NewHeaders() { var headers = new DefaultHttp2Headers(); headers.Add(AsciiString.Of("name1"), new[] { AsciiString.Of("value1"), AsciiString.Of("value2") }); headers.Method = AsciiString.Of("POST"); headers.Add(AsciiString.Of("2name"), AsciiString.Of("value3")); headers.Path = AsciiString.Of("/index.html"); headers.Status = AsciiString.Of("200"); headers.Authority = AsciiString.Of("netty.io"); headers.Add(AsciiString.Of("name3"), AsciiString.Of("value4")); headers.Scheme = AsciiString.Of("https"); return(headers); }
public void AsciiStringComparerIgnoreCaseTest() { var dict = new Dictionary <AsciiString, int>(AsciiStringComparer.IgnoreCase); dict.Add(AsciiString.Of("Town"), 0); dict.Add(AsciiString.Of("fOo"), 1); dict.Add(AsciiString.Of("baR"), 2); Assert.True(dict.ContainsKey((AsciiString)"town")); Assert.Equal(0, dict[(AsciiString)"town"]); Assert.True(dict.ContainsKey((AsciiString)"foo")); Assert.Equal(1, dict[(AsciiString)"foo"]); Assert.True(dict.ContainsKey((AsciiString)"bar")); Assert.Equal(2, dict[(AsciiString)"bar"]); }
public void TranslateHeaders(IEnumerable <HeaderEntry <ICharSequence, ICharSequence> > inputHeaders) { // lazily created as needed StringBuilder cookies = null; foreach (var entry in inputHeaders) { var name = entry.Key; var value = entry.Value; if (_translations.TryGet(name, out var translatedName)) { _ = _output.Add(translatedName, AsciiString.Of(value)); } else if (!PseudoHeaderName.IsPseudoHeader(name)) { // https://tools.ietf.org/html/rfc7540#section-8.1.2.3 // All headers that start with ':' are only valid in HTTP/2 context if (0u >= (uint)name.Count || name[0] == ':') { StringBuilderManager.Free(cookies); ThrowHelper.ThrowStreamError_InvalidHttp2HeaderEncounteredInTranslationToHttp1(_streamId, name); } var cookie = HttpHeaderNames.Cookie; if (cookie.Equals(name)) { // combine the cookie values into 1 header entry. // https://tools.ietf.org/html/rfc7540#section-8.1.2.5 if (cookies is null) { cookies = StringBuilderManager.Allocate(); } else if ((uint)cookies.Length > 0u) { _ = cookies.Append("; "); } _ = cookies.Append(value.ToString()); } else { _ = _output.Add(AsciiString.Of(name), value); } } } if (cookies is object) { _ = _output.Add(HttpHeaderNames.Cookie, StringBuilderManager.ReturnAndFree(cookies)); } }
static IHttp2Headers Http1HeadersToHttp2Headers(IFullHttpRequest request) { IHttp2Headers http2Headers = new DefaultHttp2Headers() { Method = HttpMethod.Get.AsciiName, Path = AsciiString.Of(request.Uri), Scheme = HttpScheme.Http.Name }; if (request.Headers.TryGet(HttpHeaderNames.Host, out var host)) { http2Headers.Authority = host; } return(http2Headers); }
public void IndexOf() { AsciiString foo = AsciiString.Of("This is a test"); int i1 = foo.IndexOf(' ', 0); Assert.Equal(4, i1); int i2 = foo.IndexOf(' ', i1 + 1); Assert.Equal(7, i2); int i3 = foo.IndexOf(' ', i2 + 1); Assert.Equal(9, i3); Assert.True(i3 + 1 < foo.Count); int i4 = foo.IndexOf(' ', i3 + 1); Assert.Equal(-1, i4); }
public void ClientRequestTrailingHeaders() { this.BootstrapEnv(1, 1, 1); string text = "some data"; IByteBuffer content = Unpooled.CopiedBuffer(Encoding.UTF8.GetBytes(text)); IFullHttpRequest request = new DefaultFullHttpRequest(DotNetty.Codecs.Http.HttpVersion.Http11, HttpMethod.Get, "/some/path/resource2", content, true); try { HttpHeaders httpHeaders = request.Headers; httpHeaders.SetInt(HttpConversionUtil.ExtensionHeaderNames.StreamId, 3); httpHeaders.SetInt(HttpHeaderNames.ContentLength, text.Length); httpHeaders.SetShort(HttpConversionUtil.ExtensionHeaderNames.StreamWeight, 16); HttpHeaders trailingHeaders = request.TrailingHeaders; trailingHeaders.Set(AsciiString.Of("Foo"), AsciiString.Of("goo")); trailingHeaders.Set(AsciiString.Of("fOo2"), AsciiString.Of("goo2")); trailingHeaders.Add(AsciiString.Of("foO2"), AsciiString.Of("goo3")); var http2Headers = new DefaultHttp2Headers() { Method = new AsciiString("GET"), Path = new AsciiString("/some/path/resource2"), }; IHttp2Headers http2Headers2 = new DefaultHttp2Headers(); http2Headers2.Set(new AsciiString("foo"), new AsciiString("goo")); http2Headers2.Set(new AsciiString("foo2"), new AsciiString("goo2")); http2Headers2.Add(new AsciiString("foo2"), new AsciiString("goo3")); Http2TestUtil.RunInChannel(this.clientChannel, () => { this.clientHandler.Encoder.WriteHeadersAsync(this.CtxClient(), 3, http2Headers, 0, false, this.NewPromiseClient()); this.clientHandler.Encoder.WriteDataAsync(this.CtxClient(), 3, content.RetainedDuplicate(), 0, false, this.NewPromiseClient()); this.clientHandler.Encoder.WriteHeadersAsync(this.CtxClient(), 3, http2Headers2, 0, true, this.NewPromiseClient()); this.clientChannel.Flush(); }); this.AwaitRequests(); var requestCaptor = new ArgumentCaptor <IFullHttpMessage>(); this.serverListener.Verify(x => x.MessageReceived(It.Is <IHttpObject>(v => requestCaptor.Capture((IFullHttpMessage)v)))); this.capturedRequests = requestCaptor.GetAllValues(); Assert.Equal(request, (IFullHttpRequest)this.capturedRequests[0]); } finally { request.Release(); } }
public void TestTransferCodingGZIPAndChunked() { string requestStr = "POST / HTTP/1.1\r\n" + "Host: example.com\r\n" + "Content-Type: application/x-www-form-urlencoded\r\n" + "Trailer: My-Trailer\r\n" + "Transfer-Encoding: gzip, chunked\r\n" + "\r\n"; HttpRequestDecoder decoder = new HttpRequestDecoder(); HttpContentDecoder decompressor = new HttpContentDecompressor(); EmbeddedChannel channel = new EmbeddedChannel(decoder, decompressor); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer(requestStr, Encoding.ASCII))); string chunkLength = GzHelloWorld.Length.ToString("x2"); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer(chunkLength + "\r\n", Encoding.ASCII))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer(GzHelloWorld))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer(Encoding.ASCII.GetBytes("\r\n")))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer("0\r\n", Encoding.ASCII))); Assert.True(channel.WriteInbound(Unpooled.CopiedBuffer("My-Trailer: 42\r\n\r\n", Encoding.ASCII))); IHttpRequest request = channel.ReadInbound <IHttpRequest>(); Assert.True(request.Result.IsSuccess); Assert.True(request.Headers.ContainsValue(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked, true)); Assert.False(request.Headers.Contains(HttpHeaderNames.ContentLength)); IHttpContent chunk1 = channel.ReadInbound <IHttpContent>(); Assert.True(chunk1.Result.IsSuccess); Assert.Equal(HelloWorld, chunk1.Content.ToString(Encoding.ASCII)); chunk1.Release(); ILastHttpContent chunk2 = channel.ReadInbound <ILastHttpContent>(); Assert.True(chunk2.Result.IsSuccess); Assert.Equal("42", chunk2.TrailingHeaders.Get(AsciiString.Of("My-Trailer"), null)); chunk2.Release(); Assert.False(channel.Finish()); channel.ReleaseInbound(); }
/// <summary> /// Converts the given HTTP/1.x headers into HTTP/2 headers. /// The following headers are only used if they can not be found in from the <c>HOST</c> header or the /// <c>Request-Line</c> as defined by <a href="https://tools.ietf.org/html/rfc7230">rfc7230</a> /// <para><see cref="ExtensionHeaderNames.Scheme"/></para> /// <see cref="ExtensionHeaderNames.Path"/> is ignored and instead extracted from the <c>Request-Line</c>. /// </summary> /// <param name="input"></param> /// <param name="validateHeaders"></param> /// <returns></returns> public static IHttp2Headers ToHttp2Headers(IHttpMessage input, bool validateHeaders) { HttpHeaders inHeaders = input.Headers; IHttp2Headers output = new DefaultHttp2Headers(validateHeaders, inHeaders.Size); if (input is IHttpRequest request) { output.Method = request.Method.AsciiName; // TODO java.net.URI isOriginForm isAsteriskForm if (Uri.TryCreate(request.Uri, UriKind.Absolute, out var requestTargetUri) && !requestTargetUri.IsFile) // .NETCore 非Windows系统,会把 '/' 打头的相对 url 默认为 UnixFileUri { output.Path = ToHttp2Path(requestTargetUri); SetHttp2Scheme(inHeaders, requestTargetUri, output); _ = requestTargetUri.Authority; // Attempt to take from HOST header before taking from the request-line var host = inHeaders.GetAsString(HttpHeaderNames.Host); SetHttp2Authority(string.IsNullOrEmpty(host) ? requestTargetUri.Authority : host, output); } else { output.Path = new AsciiString(request.Uri); // Consume the Scheme extension header if present if (inHeaders.TryGet(ExtensionHeaderNames.Scheme, out var cValue)) { output.Scheme = AsciiString.Of(cValue); } if (output.Scheme is null) { ThrowHelper.ThrowArgumentException_SchemeMustBeSpecified(); } var host = inHeaders.GetAsString(HttpHeaderNames.Host); SetHttp2Authority(host, output); } } else if (input is IHttpResponse response) { output.Status = response.Status.CodeAsText; } // Add the HTTP headers which have not been consumed above ToHttp2Headers(inHeaders, output); return(output); }
private static CharSequenceMap <AsciiString> ToLowercaseMap(IEnumerable <ICharSequence> values, int arraySizeHint) { var valueConverter = UnsupportedValueConverter <AsciiString> .Instance; var result = new CharSequenceMap <AsciiString>(true, valueConverter, arraySizeHint); foreach (var item in values) { AsciiString lowerCased = AsciiString.Of(item).ToLowerCase(); try { int index = lowerCased.ForEachByte(ByteProcessor.FindComma); if (index != -1) { int start = 0; do { _ = result.Add(lowerCased.SubSequence(start, index, false).Trim(), AsciiString.Empty); start = index + 1; } while (start < lowerCased.Count && (index = lowerCased.ForEachByte(start, lowerCased.Count - start, ByteProcessor.FindComma)) != -1); _ = result.Add(lowerCased.SubSequence(start, lowerCased.Count, false).Trim(), AsciiString.Empty); } else { _ = result.Add(lowerCased.Trim(), AsciiString.Empty); } } catch (Exception) { // This is not expect to happen because FIND_COMMA never throws but must be caught // because of the ByteProcessor interface. ThrowHelper.ThrowInvalidOperationException(); } } return(result); }
public void TestLiteralNeverIndexedWithEmptyName() { this.Decode("100005" + Hex("value")); mockHeaders.Verify(x => x.Add(AsciiString.Empty, AsciiString.Of("value")), Times.Once); }
public void ChunkedRequestWithBodyAndTrailingHeaders() { string text = "foooooo"; string text2 = "goooo"; List <string> receivedBuffers = new List <string>(); this.serverListener .Setup(x => x.OnDataRead( It.IsAny <IChannelHandlerContext>(), It.Is <int>(v => v == 3), It.IsAny <IByteBuffer>(), It.Is <int>(v => v == 0), It.Is <bool>(v => v == false))) .Returns <IChannelHandlerContext, int, IByteBuffer, int, bool>((ctx, id, buf, p, e) => { lock (receivedBuffers) { receivedBuffers.Add(buf.ToString(Encoding.UTF8)); } return(0); }); this.BootstrapEnv(4, 1, 1); IHttpRequest request = new DefaultHttpRequest(DotNetty.Codecs.Http.HttpVersion.Http11, HttpMethod.Post, "http://[email protected]:5555/example"); HttpHeaders httpHeaders = request.Headers; httpHeaders.Set(HttpHeaderNames.Host, "www.example.org:5555"); httpHeaders.Add(HttpHeaderNames.TransferEncoding, "chunked"); httpHeaders.Add(AsciiString.Of("foo"), AsciiString.Of("goo")); httpHeaders.Add(AsciiString.Of("foo"), AsciiString.Of("goo2")); httpHeaders.Add(AsciiString.Of("foo2"), AsciiString.Of("goo2")); var http2Headers = new DefaultHttp2Headers() { Method = new AsciiString("POST"), Path = new AsciiString("/example"), Authority = new AsciiString("www.example.org:5555"), Scheme = new AsciiString("http") }; http2Headers.Add(new AsciiString("foo"), new AsciiString("goo")); http2Headers.Add(new AsciiString("foo"), new AsciiString("goo2")); http2Headers.Add(new AsciiString("foo2"), new AsciiString("goo2")); DefaultHttpContent httpContent = new DefaultHttpContent(Unpooled.CopiedBuffer(text, Encoding.UTF8)); ILastHttpContent lastHttpContent = new DefaultLastHttpContent(Unpooled.CopiedBuffer(text2, Encoding.UTF8)); lastHttpContent.TrailingHeaders.Add(AsciiString.Of("trailing"), AsciiString.Of("bar")); IHttp2Headers http2TrailingHeaders = new DefaultHttp2Headers { { new AsciiString("trailing"), new AsciiString("bar") } }; var writePromise = this.NewPromise(); var writeFuture = this.clientChannel.WriteAsync(request, writePromise); var contentPromise = this.NewPromise(); var contentFuture = this.clientChannel.WriteAsync(httpContent, contentPromise); var lastContentPromise = this.NewPromise(); var lastContentFuture = this.clientChannel.WriteAsync(lastHttpContent, lastContentPromise); this.clientChannel.Flush(); Assert.True(writePromise.Task.Wait(TimeSpan.FromSeconds(WAIT_TIME_SECONDS))); Assert.True(writePromise.IsSuccess); Assert.True(writeFuture.Wait(TimeSpan.FromSeconds(WAIT_TIME_SECONDS))); Assert.True(writeFuture.IsSuccess()); Assert.True(contentPromise.Task.Wait(TimeSpan.FromSeconds(WAIT_TIME_SECONDS))); Assert.True(contentPromise.IsSuccess); Assert.True(contentFuture.Wait(TimeSpan.FromSeconds(WAIT_TIME_SECONDS))); Assert.True(contentFuture.IsSuccess()); Assert.True(lastContentPromise.Task.Wait(TimeSpan.FromSeconds(WAIT_TIME_SECONDS))); Assert.True(lastContentPromise.IsSuccess); Assert.True(lastContentFuture.Wait(TimeSpan.FromSeconds(WAIT_TIME_SECONDS))); Assert.True(lastContentFuture.IsSuccess()); this.AwaitRequests(); this.serverListener.Verify( x => x.OnHeadersRead( It.IsAny <IChannelHandlerContext>(), It.Is <int>(v => v == 3), It.Is <IHttp2Headers>(v => v.Equals(http2Headers)), It.Is <int>(v => v == 0), It.IsAny <short>(), It.IsAny <bool>(), It.Is <int>(v => v == 0), It.Is <bool>(v => v == false))); this.serverListener.Verify( x => x.OnDataRead( It.IsAny <IChannelHandlerContext>(), It.Is <int>(v => v == 3), It.IsAny <IByteBuffer>(), It.Is <int>(v => v == 0), It.Is <bool>(v => v == false))); this.serverListener.Verify( x => x.OnHeadersRead( It.IsAny <IChannelHandlerContext>(), It.Is <int>(v => v == 3), It.Is <IHttp2Headers>(v => v.Equals(http2TrailingHeaders)), It.Is <int>(v => v == 0), It.IsAny <short>(), It.IsAny <bool>(), It.Is <int>(v => v == 0), It.Is <bool>(v => v == true))); lock (receivedBuffers) { Assert.Single(receivedBuffers); Assert.Equal(text + text2, receivedBuffers[0]); } }
public void SupportIanaStatusCodes() { var forbiddenIanaCodes = new HashSet <int>(); forbiddenIanaCodes.Add(1004); forbiddenIanaCodes.Add(1005); forbiddenIanaCodes.Add(1006); var validIanaCodes = new HashSet <int>(); for (int i = 1000; i < 1015; i++) { validIanaCodes.Add(i); } validIanaCodes.ExceptWith(forbiddenIanaCodes); foreach (int statusCode in validIanaCodes) { var encoderChannel = new EmbeddedChannel(new WebSocket08FrameEncoder(true)); var decoderChannel = new EmbeddedChannel(new WebSocket08FrameDecoder(true, true, 65535, false)); Assert.True(encoderChannel.WriteOutbound(new CloseWebSocketFrame(statusCode, AsciiString.Of("Bye")))); Assert.True(encoderChannel.Finish()); var serializedCloseFrame = encoderChannel.ReadOutbound <IByteBuffer>(); Assert.Null(encoderChannel.ReadOutbound <object>()); Assert.True(decoderChannel.WriteInbound(serializedCloseFrame)); Assert.True(decoderChannel.Finish()); var outputFrame = decoderChannel.ReadInbound <CloseWebSocketFrame>(); Assert.Null(decoderChannel.ReadOutbound <object>()); try { Assert.Equal(statusCode, outputFrame.StatusCode()); } finally { outputFrame.Release(); } } }
static async Task Main(string[] args) { ExampleHelper.SetConsoleLogger(); bool useLibuv = ClientSettings.UseLibuv; Console.WriteLine("Transport type : " + (useLibuv ? "Libuv" : "Socket")); IEventLoopGroup group; if (useLibuv) { group = new EventLoopGroup(); } else { group = new MultithreadEventLoopGroup(); } X509Certificate2 cert = null; string targetHost = null; if (ClientSettings.IsSsl) { cert = new X509Certificate2(Path.Combine(ExampleHelper.ProcessDirectory, "dotnetty.com.pfx"), "password"); targetHost = cert.GetNameInfo(X509NameType.DnsName, false); } try { var bootstrap = new Bootstrap(); bootstrap .Group(group) .Option(ChannelOption.TcpNodelay, true) .Option(ChannelOption.SoKeepalive, true); if (useLibuv) { bootstrap.Channel <TcpChannel>(); } else { bootstrap.Channel <TcpSocketChannel>(); } bootstrap.Handler(new Http2ClientFrameInitializer(cert, targetHost)); IChannel channel = await bootstrap.ConnectAsync(new IPEndPoint(ClientSettings.Host, ClientSettings.Port)); try { Console.WriteLine("Connected to [" + ClientSettings.Host + ':' + ClientSettings.Port + ']'); Http2ClientStreamFrameResponseHandler streamFrameResponseHandler = new Http2ClientStreamFrameResponseHandler(); Http2StreamChannelBootstrap streamChannelBootstrap = new Http2StreamChannelBootstrap(channel); IHttp2StreamChannel streamChannel = await streamChannelBootstrap.OpenAsync(); streamChannel.Pipeline.AddLast(streamFrameResponseHandler); // Send request (a HTTP/2 HEADERS frame - with ':method = GET' in this case) var path = ExampleHelper.Configuration["path"]; HttpScheme scheme = ClientSettings.IsSsl ? HttpScheme.Https : HttpScheme.Http; DefaultHttp2Headers headers = new DefaultHttp2Headers { Method = HttpMethod.Get.AsciiName, Path = AsciiString.Of(path), Scheme = scheme.Name }; IHttp2HeadersFrame headersFrame = new DefaultHttp2HeadersFrame(headers); await streamChannel.WriteAndFlushAsync(headersFrame); Console.WriteLine("Sent HTTP/2 GET request to " + path); // Wait for the responses (or for the latch to expire), then clean up the connections if (!streamFrameResponseHandler.ResponseSuccessfullyCompleted()) { Console.WriteLine("Did not get HTTP/2 response in expected time."); } Console.WriteLine("Finished HTTP/2 request, will close the connection."); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine(ex.ToString()); Console.WriteLine("按任意键退出"); Console.ReadKey(); } finally { // Wait until the connection is closed. await channel.CloseAsync(); } } finally { await group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)); } }
/// <summary> /// Create a new object to contain the request data. /// </summary> /// <param name="streamId">The stream associated with the request</param> /// <param name="http2Headers">The initial set of HTTP/2 headers to create the request with</param> /// <param name="validateHttpHeaders"><c>true</c> to validate HTTP headers in the http-codec /// <para><c>false</c> not to validate HTTP headers in the http-codec</para></param> /// <returns>A new request object which represents headers for a chunked request</returns> /// <exception cref="Http2Exception">See <see cref="AddHttp2ToHttpHeaders(int, IHttp2Headers, HttpHeaders, DotNettyHttpVersion, bool, bool)"/></exception> public static IHttpRequest ToHttpRequest(int streamId, IHttp2Headers http2Headers, bool validateHttpHeaders) { // HTTP/2 does not define a way to carry the version identifier that is included in the HTTP/1.1 request line. var method = http2Headers.Method; if (method is null) { ThrowHelper.ThrowArgumentNullException_MethodHeader(); } var path = http2Headers.Path; if (path is null) { ThrowHelper.ThrowArgumentNullException_PathHeader(); } var msg = new DefaultHttpRequest(DotNettyHttpVersion.Http11, HttpMethod.ValueOf(AsciiString.Of(method)), path.ToString(), validateHttpHeaders); try { AddHttp2ToHttpHeaders(streamId, http2Headers, msg.Headers, msg.ProtocolVersion, false, true); } catch (Http2Exception) { throw; } catch (Exception t) { ThrowHelper.ThrowStreamError_Http2ToHttp1HeadersConversionError(streamId, t); } return(msg); }
public void TestLiteralWithIncrementalIndexingWithEmptyName() { this.Decode("400005" + Hex("value")); mockHeaders.Verify(x => x.Add(AsciiString.Empty, AsciiString.Of("value")), Times.Once); }
public void TestHeaderNameValidation() { var headers = NewHeaders(); Assert.Throws <Http2Exception>(() => headers.Add(AsciiString.Of("Foo"), AsciiString.Of("foo"))); }