public void DecodeContentDispositionFieldParameters() { const string Boundary = "74e78d11b0214bdcbc2f86491eeb4902"; const string Charset = "utf-8"; const string Filename = "attached_файл.txt"; string filenameEncoded = HttpUtility.UrlEncode(Filename, Encoding.UTF8); string body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename*=" + Charset + "''" + filenameEncoded + "\r\n\r\n" + "foo\r\n" + "\r\n" + "--" + Boundary + "--"; var req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost", Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(body))); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); var inMemoryFactory = new DefaultHttpDataFactory(false); var decoder = new HttpPostRequestDecoder(inMemoryFactory, req); Assert.False(decoder.GetBodyHttpDatas().Count == 0); IInterfaceHttpData part1 = decoder.GetBodyHttpDatas()[0]; Assert.IsAssignableFrom <IFileUpload>(part1); var fileUpload = (IFileUpload)part1; Assert.Equal(Filename, fileUpload.FileName); decoder.Destroy(); req.Release(); }
public void MultipartRequestWithoutContentTypeBody() { const string Boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; var req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); req.Result = DecoderResult.Success; req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); req.Headers.Add(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked); // Force to use memory-based data. var inMemoryFactory = new DefaultHttpDataFactory(false); var values = new[] { "", "\r", "\r\r", "\r\r\r" }; foreach (string data in values) { string body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"tmp-0.txt\"\r\n" + "\r\n" + data + "\r\n" + "--" + Boundary + "--\r\n"; req.Content.WriteBytes(Encoding.UTF8.GetBytes(body)); } // Create decoder instance to test without any exception. var decoder = new HttpPostRequestDecoder(inMemoryFactory, req); List <IInterfaceHttpData> list = decoder.GetBodyHttpDatas(); Assert.NotNull(list); Assert.False(list.Count == 0); decoder.Destroy(); }
public void MultipartRequestWithFieldInvalidCharset() { const string Boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; var req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); // Force to use memory-based data. var inMemoryFactory = new DefaultHttpDataFactory(false); const string BodyData = "some data would be here. the data should be long enough that it " + "will be longer than the original buffer length of 256 bytes in " + "the HttpPostRequestDecoder in order to trigger the issue. Some more " + "data just to be on the safe side."; const string Body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"root\"\r\n" + "Content-Type: text/plain; charset=ABCD\r\n" + "\r\n" + BodyData + "\r\n" + "--" + Boundary + "--\r\n"; req.Content.WriteBytes(Encoding.UTF8.GetBytes(Body)); Assert.Throws <ErrorDataDecoderException>(() => new HttpPostRequestDecoder(inMemoryFactory, req)); }
public void DataIsMultipleOfChunkSize1() { var factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MinSize); var request = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); var encoder = new HttpPostRequestEncoder(factory, request, true, HttpPostRequestEncoder.EncoderMode.RFC1738); var first = new MemoryFileUpload("resources", "", "application/json", null, Encoding.UTF8, -1); first.MaxSize = -1; first.SetContent(new MemoryStream(new byte[7955])); encoder.AddBodyHttpData(first); var second = new MemoryFileUpload("resources2", "", "application/json", null, Encoding.UTF8, -1); second.MaxSize = -1; second.SetContent(new MemoryStream(new byte[7928])); encoder.AddBodyHttpData(second); Assert.NotNull(encoder.FinalizeRequest()); CheckNextChunkSize(encoder, 8080); CheckNextChunkSize(encoder, 8055); IHttpContent httpContent = encoder.ReadChunk(default(IByteBufferAllocator)); Assert.True(httpContent is ILastHttpContent, "Expected LastHttpContent is not received"); httpContent.Release(); Assert.True(encoder.IsEndOfInput, "Expected end of input is not receive"); }
public void DecodeMalformedEmptyContentTypeFieldParameters() { const string Boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; var req = new DefaultFullHttpRequest( HttpVersion.Http11, HttpMethod.Post, "http://localhost"); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); // Force to use memory-based data. var inMemoryFactory = new DefaultHttpDataFactory(false); const string Data = "asdf"; const string Filename = "tmp-0.txt"; const string Body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + Filename + "\"\r\n" + "Content-Type: \r\n" + "\r\n" + Data + "\r\n" + "--" + Boundary + "--\r\n"; req.Content.WriteBytes(Encoding.UTF8.GetBytes(Body)); // Create decoder instance to test. var decoder = new HttpPostRequestDecoder(inMemoryFactory, req); Assert.False(decoder.GetBodyHttpDatas().Count == 0); IInterfaceHttpData part1 = decoder.GetBodyHttpDatas()[0]; Assert.IsAssignableFrom <IFileUpload>(part1); var fileUpload = (IFileUpload)part1; Assert.Equal(Filename, fileUpload.FileName); decoder.Destroy(); }
public void FilenameContainingSemicolon2() { const string Boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; var req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); // Force to use memory-based data. var inMemoryFactory = new DefaultHttpDataFactory(false); const string Data = "asdf"; const string Filename = "tmp;0.txt"; const string Body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + Filename + "\"\r\n" + "Content-Type: image/gif\r\n" + "\r\n" + Data + "\r\n" + "--" + Boundary + "--\r\n"; req.Content.WriteBytes(Encoding.UTF8.GetBytes(Body)); var decoder = new HttpPostRequestDecoder(inMemoryFactory, req); List <IInterfaceHttpData> list = decoder.GetBodyHttpDatas(); Assert.NotNull(list); Assert.False(list.Count == 0); IInterfaceHttpData part1 = list[0]; Assert.IsAssignableFrom <IFileUpload>(part1); var fileUpload = (IFileUpload)part1; Assert.Equal("tmp 0.txt", fileUpload.FileName); decoder.Destroy(); }
public DefaultHttpDataFactoryTest() { // Before doing anything, assert that the requests are equal Assert.Equal(_req1.GetHashCode(), _req2.GetHashCode()); Assert.True(_req1.Equals(_req2)); _factory = new DefaultHttpDataFactory(); }
public void BinaryStreamUpload(bool withSpace) { const string Boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; string contentTypeValue; if (withSpace) { contentTypeValue = "multipart/form-data; boundary=" + Boundary; } else { contentTypeValue = "multipart/form-data;boundary=" + Boundary; } var req = new DefaultHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); req.Result = DecoderResult.Success; req.Headers.Add(HttpHeaderNames.ContentType, contentTypeValue); req.Headers.Add(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked); // Force to use memory-based data. var inMemoryFactory = new DefaultHttpDataFactory(false); var values = new[] { "", "\r", "\r\r", "\r\r\r" }; foreach (string data in values) { string body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"tmp-0.txt\"\r\n" + "Content-Type: image/gif\r\n" + "\r\n" + data + "\r\n" + "--" + Boundary + "--\r\n"; // Create decoder instance to test. var decoder = new HttpPostRequestDecoder(inMemoryFactory, req); decoder.Offer(new DefaultHttpContent(Unpooled.CopiedBuffer(Encoding.UTF8.GetBytes(body)))); decoder.Offer(new DefaultHttpContent(Unpooled.Empty)); // Validate it's enough chunks to decode upload. Assert.True(decoder.HasNext); // Decode binary upload. IInterfaceHttpData next = decoder.Next(); Assert.IsType <MemoryFileUpload>(next); var upload = (MemoryFileUpload)next; // Validate data has been parsed correctly as it was passed into request. Assert.Equal(data, upload.GetString(Encoding.UTF8)); upload.Release(); decoder.Destroy(); } }
public void MultipartCodecWithCRasEndOfAttribute() { const string Boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; // Force to use memory-based data. var inMemoryFactory = new DefaultHttpDataFactory(false); const string Extradata = "aaaa"; var strings = new string[5]; for (int i = 0; i < 4; i++) { strings[i] = Extradata; for (int j = 0; j < i; j++) { strings[i] += '\r'; } } for (int i = 0; i < 4; i++) { var req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); req.Result = DecoderResult.Success; req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); req.Headers.Add(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked); string body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file" + i + "\"\r\n" + "Content-Type: image/gif\r\n" + "\r\n" + strings[i] + "\r\n" + "--" + Boundary + "--\r\n"; req.Content.WriteBytes(Encoding.UTF8.GetBytes(body)); // Create decoder instance to test. var decoder = new HttpPostRequestDecoder(inMemoryFactory, req); List <IInterfaceHttpData> list = decoder.GetBodyHttpDatas(); Assert.NotNull(list); Assert.False(list.Count == 0); // Check correctness: data size IInterfaceHttpData httpData = decoder.GetBodyHttpData($"file{i}"); Assert.NotNull(httpData); var attribute = httpData as IAttribute; Assert.NotNull(attribute); byte[] data = attribute.GetBytes(); Assert.NotNull(data); Assert.Equal(Encoding.UTF8.GetBytes(strings[i]).Length, data.Length); decoder.Destroy(); } }
public void NoZeroOut() { const string Boundary = "E832jQp_Rq2ErFmAduHSR8YlMSm0FCY"; var aMemFactory = new DefaultHttpDataFactory(false); var aRequest = new DefaultHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); aRequest.Headers.Set(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); aRequest.Headers.Set(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked); var aDecoder = new HttpPostRequestDecoder(aMemFactory, aRequest); const string BodyData = "some data would be here. the data should be long enough that it " + "will be longer than the original buffer length of 256 bytes in " + "the HttpPostRequestDecoder in order to trigger the issue. Some more " + "data just to be on the safe side."; const string Body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"root\"\r\n" + "Content-Type: text/plain\r\n" + "\r\n" + BodyData + "\r\n" + "--" + Boundary + "--\r\n"; byte[] aBytes = Encoding.UTF8.GetBytes(Body); const int Split = 125; UnpooledByteBufferAllocator aAlloc = UnpooledByteBufferAllocator.Default; IByteBuffer aSmallBuf = aAlloc.Buffer(Split, Split); IByteBuffer aLargeBuf = aAlloc.Buffer(aBytes.Length - Split, aBytes.Length - Split); aSmallBuf.WriteBytes(aBytes, 0, Split); aLargeBuf.WriteBytes(aBytes, Split, aBytes.Length - Split); aDecoder.Offer(new DefaultHttpContent(aSmallBuf)); aDecoder.Offer(new DefaultHttpContent(aLargeBuf)); aDecoder.Offer(EmptyLastHttpContent.Default); Assert.True(aDecoder.HasNext); IInterfaceHttpData aDecodedData = aDecoder.Next(); Assert.Equal(HttpDataType.Attribute, aDecodedData.DataType); var aAttr = (IAttribute)aDecodedData; Assert.Equal(BodyData, aAttr.Value); aDecodedData.Release(); aDecoder.Destroy(); }
public void SingleFileUploadInHtml5Mode() { var request = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); var factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MinSize); var encoder = new HttpPostRequestEncoder( factory, request, true, //Encoding.UTF8, HttpPostRequestEncoder.EncoderMode.HTML5); FileStream fileStream1 = File.Open("./Multipart/file-01.txt", FileMode.Open, FileAccess.Read); this.files.Add(fileStream1); FileStream fileStream2 = File.Open("./Multipart/file-02.txt", FileMode.Open, FileAccess.Read); this.files.Add(fileStream2); encoder.AddBodyAttribute("foo", "bar"); encoder.AddBodyFileUpload("quux", fileStream1, "text/plain", false); encoder.AddBodyFileUpload("quux", fileStream2, "text/plain", false); string multipartDataBoundary = encoder.MultipartDataBoundary; string content = GetRequestBody(encoder); string expected = "--" + multipartDataBoundary + "\r\n" + HttpHeaderNames.ContentDisposition + ": form-data; name=\"foo\"" + "\r\n" + HttpHeaderNames.ContentLength + ": 3" + "\r\n" + HttpHeaderNames.ContentType + ": text/plain; charset=utf-8" + "\r\n" + "\r\n" + "bar" + "\r\n" + "--" + multipartDataBoundary + "\r\n" + HttpHeaderNames.ContentDisposition + ": form-data; name=\"quux\"; filename=\"file-01.txt\"" + "\r\n" + HttpHeaderNames.ContentLength + ": " + fileStream1.Length + "\r\n" + HttpHeaderNames.ContentType + ": text/plain" + "\r\n" + HttpHeaderNames.ContentTransferEncoding + ": binary" + "\r\n" + "\r\n" + "File 01" + /*StringUtil.*/ Newline + "\r\n" + "--" + multipartDataBoundary + "\r\n" + HttpHeaderNames.ContentDisposition + ": form-data; name=\"quux\"; filename=\"file-02.txt\"" + "\r\n" + HttpHeaderNames.ContentLength + ": " + fileStream2.Length + "\r\n" + HttpHeaderNames.ContentType + ": text/plain" + "\r\n" + HttpHeaderNames.ContentTransferEncoding + ": binary" + "\r\n" + "\r\n" + "File 02" + /*StringUtil.*/ Newline + "\r\n" + "--" + multipartDataBoundary + "--" + "\r\n"; Assert.Equal(expected, content); }
public void CustomBaseDirAndDeleteOnExit() { DefaultHttpDataFactory defaultHttpDataFactory = new DefaultHttpDataFactory(true); string dir = "target/DefaultHttpDataFactoryTest/customBaseDirAndDeleteOnExit"; defaultHttpDataFactory.SetBaseDir(dir); defaultHttpDataFactory.SetDeleteOnExit(true); IAttribute attr = defaultHttpDataFactory.CreateAttribute(_req1, "attribute1"); IFileUpload fu = defaultHttpDataFactory.CreateFileUpload( _req1, "attribute1", "f.txt", "text/plain", null, null, 0); Assert.Equal(dir, ((DiskAttribute)attr).BaseDirectory); Assert.Equal(dir, ((DiskFileUpload)fu).BaseDirectory); Assert.True(((DiskAttribute)attr).DeleteOnExit); Assert.True(((DiskFileUpload)fu).DeleteOnExit); }
public void MultipartRequestWithFileInvalidCharset() { const string Boundary = "dLV9Wyq26L_-JQxk6ferf-RT153LhOO"; var req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost"); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); // Force to use memory-based data. var inMemoryFactory = new DefaultHttpDataFactory(false); const string Data = "asdf"; const string FileName = "tmp;0.txt"; string body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"" + FileName + "\"\r\n" + "Content-Type: image/gif; charset=ABCD\r\n" + "\r\n" + Data + "\r\n" + "--" + Boundary + "--\r\n"; req.Content.WriteBytes(Encoding.UTF8.GetBytes(body)); Assert.Throws <ErrorDataDecoderException>(() => new HttpPostRequestDecoder(inMemoryFactory, req)); }
public void DecodeMalformedNotEncodedContentDispositionFieldParameters() { const string Boundary = "74e78d11b0214bdcbc2f86491eeb4902"; const string Body = "--" + Boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename*=not-encoded\r\n" + "\r\n" + "foo\r\n" + "\r\n" + "--" + Boundary + "--"; var req = new DefaultFullHttpRequest( HttpVersion.Http11, HttpMethod.Post, "http://localhost", Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(Body))); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + Boundary); var inMemoryFactory = new DefaultHttpDataFactory(false); Assert.Throws <ErrorDataDecoderException>(() => new HttpPostRequestDecoder(inMemoryFactory, req)); req.Release(); }
public void DecodeOtherMimeHeaderFields() { string boundary = "74e78d11b0214bdcbc2f86491eeb4902"; string filecontent = "123456"; string body = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=" + "\"" + "attached.txt" + "\"" + "\r\n" + "Content-Type: application/octet-stream" + "\r\n" + "Content-Encoding: gzip" + "\r\n" + "\r\n" + filecontent + "\r\n" + "--" + boundary + "--"; DefaultFullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost", Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(body))); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + boundary); req.Headers.Add(HttpHeaderNames.TransferEncoding, HttpHeaderValues.Chunked); DefaultHttpDataFactory inMemoryFactory = new DefaultHttpDataFactory(false); HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(inMemoryFactory, req); Assert.False(decoder.GetBodyHttpDatas().Count == 0); IInterfaceHttpData part1 = decoder.GetBodyHttpDatas()[0]; Assert.True(part1 is IFileUpload, "the item should be a FileUpload"); IFileUpload fileUpload = (IFileUpload)part1; byte[] fileBytes = fileUpload.GetBytes(); Assert.True(filecontent.Equals(Encoding.UTF8.GetString(fileBytes)), "the filecontent should not be decoded"); decoder.Destroy(); req.Release(); }
public void DecodeWithLanguageContentDispositionFieldParametersForFix() { string boundary = "952178786863262625034234"; string encoding = "UTF-8"; string filename = "测试test.txt"; string filenameEncoded = UrlEncoder.Default.Encode(filename /*, encoding*/); string body = "--" + boundary + "\r\n" + "Content-Disposition: form-data; name=\"file\"; filename*=\"" + encoding + "''" + filenameEncoded + "\"\r\n" + "\r\n" + "foo\r\n" + "\r\n" + "--" + boundary + "--"; DefaultFullHttpRequest req = new DefaultFullHttpRequest(HttpVersion.Http11, HttpMethod.Post, "http://localhost", Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(body))); req.Headers.Add(HttpHeaderNames.ContentType, "multipart/form-data; boundary=" + boundary); DefaultHttpDataFactory inMemoryFactory = new DefaultHttpDataFactory(false); HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(inMemoryFactory, req); Assert.NotEmpty(decoder.GetBodyHttpDatas()); IInterfaceHttpData part1 = decoder.GetBodyHttpDatas()[0]; Assert.True(part1 is IFileUpload); // "the item should be a FileUpload" IFileUpload fileUpload = (IFileUpload)part1; Assert.Equal(filename, fileUpload.FileName); // "the filename should be decoded" decoder.Destroy(); req.Release(); }
static async Task Main(string[] args) { var builder = new UriBuilder { Scheme = ClientSettings.IsSsl ? "https" : "http", Host = ClientSettings.Host.ToString(), Port = ClientSettings.Port, }; var baseUri = builder.Uri.ToString(); ExampleHelper.SetConsoleLogger(); string postSimple, postFile, get; if (baseUri.EndsWith("/")) { postSimple = baseUri + "formpost"; postFile = baseUri + "formpostmultipart"; get = baseUri + "formget"; } else { postSimple = baseUri + "/formpost"; postFile = baseUri + "/formpostmultipart"; get = baseUri + "/formget"; } var uriSimple = new Uri(postSimple); var uriFile = new Uri(postFile); 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); if (useLibuv) { bootstrap.Channel <TcpChannel>(); } else { bootstrap.Channel <TcpSocketChannel>(); } bootstrap.Handler(new ActionChannelInitializer <IChannel>(channel => { IChannelPipeline pipeline = channel.Pipeline; if (cert != null) { pipeline.AddLast("tls", new TlsHandler(stream => new SslStream(stream, true, (sender, certificate, chain, errors) => true), new ClientTlsSettings(targetHost))); } //pipeline.AddLast(new LoggingHandler("CONN")); pipeline.AddLast("codec", new HttpClientCodec()); // Remove the following line if you don't want automatic content decompression. pipeline.AddLast("inflater", new HttpContentDecompressor()); // to be used since huge file transfer pipeline.AddLast("chunkedWriter", new ChunkedWriteHandler <IHttpContent>()); pipeline.AddLast("handler", new HttpUploadClientHandler()); })); // setup the factory: here using a mixed memory/disk based on size threshold var factory = new DefaultHttpDataFactory(DefaultHttpDataFactory.MinSize); // Disk if MINSIZE exceed DiskFileUpload.DeleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) DiskFileUpload.FileBaseDirectory = null; // system temp directory DiskAttribute.DeleteOnExitTemporaryFile = true; // should delete file on exit (in normal exit) DiskAttribute.DiskBaseDirectory = null; // system temp directory // Simple Get form: no factory used (not usable) var headers = await FormgetAsync(bootstrap, get, uriSimple); if (headers == null) { factory.CleanAllHttpData(); return; } using (var file = new FileStream("upload.txt", FileMode.Open, FileAccess.Read)) { // Simple Post form: factory used for big attributes var bodylist = await FormpostAsync(bootstrap, uriSimple, file, factory, headers); if (bodylist == null) { factory.CleanAllHttpData(); return; } // Multipart Post form: factory used await FormpostmultipartAsync(bootstrap, uriFile, factory, headers, bodylist); } Console.WriteLine("按任意键退出"); Console.ReadKey(); } finally { await group.ShutdownGracefullyAsync(TimeSpan.FromMilliseconds(100), TimeSpan.FromSeconds(1)); } }