Exemple #1
0
        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();
        }
Exemple #2
0
        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();
        }
Exemple #3
0
        static string GetRequestBody(HttpPostRequestEncoder encoder)
        {
            encoder.FinalizeRequest();

            List <IInterfaceHttpData> chunks = encoder.MultipartHttpDatas;
            var buffers = new IByteBuffer[chunks.Count];

            for (int i = 0; i < buffers.Length; i++)
            {
                IInterfaceHttpData data = chunks[i];
                if (data is InternalAttribute attribute)
                {
                    buffers[i] = attribute.ToByteBuffer();
                }
                else if (data is IHttpData httpData)
                {
                    buffers[i] = httpData.GetByteBuffer();
                }
            }

            IByteBuffer content    = Unpooled.WrappedBuffer(buffers);
            string      contentStr = content.ToString(Encoding.UTF8);

            content.Release();
            return(contentStr);
        }
Exemple #4
0
        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 RemoveHttpDataFromClean(IHttpRequest request, IInterfaceHttpData data)
        {
            if (!(data is IHttpData httpData))
            {
                return;
            }

            // Do not use getList because it adds empty list to requestFileDeleteMap
            // if request is not found
            if (!_requestFileDeleteMap.TryGetValue(request, out List <IHttpData> list))
            {
                return;
            }

            // Can't simply call list.remove(data), because different data items may be equal.
            // Need to check identity.
            int index = -1;

            for (int i = 0; i < list.Count; i++)
            {
                if (ReferenceEquals(list[i], httpData))
                {
                    index = i;
                    break;
                }
            }
            if ((uint)index < (uint)list.Count) // index != -1
            {
                list.RemoveAt(index);
            }
            if (0u >= (uint)list.Count)
            {
                _ = _requestFileDeleteMap.TryRemove(request, out _);
            }
        }
 /**
  * Example of reading request by chunk and getting values from chunk to chunk
  */
 private void ReadHttpDataChunkByChunk()
 {
     try
     {
         IInterfaceHttpData data = null;
         while (_decoder.HasNext)
         {
             data = _decoder.Next();
             if (data != null)
             {
                 // check if current HttpData is a FileUpload and previously set as partial
                 if (_partialContent == data)
                 {
                     s_logger.LogInformation(" 100% (FinalSize: " + _partialContent.Length + ")");
                     _partialContent = null;
                 }
                 // new value
                 WriteHttpData(data);
             }
         }
         // Check partial decoding for a FileUpload
         data = _decoder.CurrentPartialHttpData;
         if (data != null)
         {
             StringBuilder builder = new StringBuilder();
             if (_partialContent == null)
             {
                 _partialContent = (IHttpData)data;
                 if (_partialContent is IFileUpload fileUpload)
                 {
                     builder.Append("Start FileUpload: ")
                     .Append(fileUpload.FileName).Append(" ");
                 }
                 else
                 {
                     builder.Append("Start Attribute: ")
                     .Append(_partialContent.Name).Append(" ");
                 }
                 builder.Append("(DefinedSize: ").Append(_partialContent.DefinedLength).Append(")");
             }
             if (_partialContent.DefinedLength > 0)
             {
                 builder.Append(" ").Append(_partialContent.Length * 100 / _partialContent.DefinedLength)
                 .Append("% ");
                 s_logger.LogInformation(builder.ToString());
             }
             else
             {
                 builder.Append(" ").Append(_partialContent.Length).Append(" ");
                 s_logger.LogInformation(builder.ToString());
             }
         }
     }
     catch (EndOfDataDecoderException)
     {
         // end
         _responseContent.Append("\r\n\r\nEND OF CONTENT CHUNK BY CHUNK\r\n\r\n");
     }
 }
        IHttpContent NextChunk()
        {
            if (this.isLastChunk)
            {
                this.isLastChunkSent = true;
                return(EmptyLastHttpContent.Default);
            }
            // first test if previous buffer is not empty
            int size = this.CalculateRemainingSize();

            if (size <= 0)
            {
                // NextChunk from buffer
                IByteBuffer buffer = this.FillByteBuffer();
                return(new DefaultHttpContent(buffer));
            }
            // size > 0
            if (this.currentData != null)
            {
                // continue to read data
                IHttpContent chunk = this.isMultipart
                    ? this.EncodeNextChunkMultipart(size)
                    : this.EncodeNextChunkUrlEncoded(size);
                if (chunk != null)
                {
                    // NextChunk from data
                    return(chunk);
                }
                size = this.CalculateRemainingSize();
            }
            if (!this.iterator.HasNext())
            {
                return(this.LastChunk());
            }
            while (size > 0 && this.iterator.HasNext())
            {
                this.currentData = this.iterator.Next();
                IHttpContent chunk;
                if (this.isMultipart)
                {
                    chunk = this.EncodeNextChunkMultipart(size);
                }
                else
                {
                    chunk = this.EncodeNextChunkUrlEncoded(size);
                }
                if (chunk == null)
                {
                    // not enough
                    size = this.CalculateRemainingSize();
                    continue;
                }
                // NextChunk from data
                return(chunk);
            }
            // end since no more data
            return(this.LastChunk());
        }
        public int CompareTo(IInterfaceHttpData other)
        {
            if (!(other is InternalAttribute))
            {
                throw new ArgumentException($"Cannot compare {this.DataType} with {other.DataType}");
            }

            return(this.CompareTo((InternalAttribute)other));
        }
Exemple #9
0
        public int CompareTo(IInterfaceHttpData other)
        {
            if (other is InternalAttribute attr)
            {
                return this.CompareTo(attr);
            }

            return ThrowHelper.ThrowArgumentException_CompareToHttpData(this.DataType, other.DataType);
        }
Exemple #10
0
        public override int CompareTo(IInterfaceHttpData other)
        {
            if (other is IAttribute attr)
            {
                return(CompareTo(attr));
            }

            return(ThrowHelper.ThrowArgumentException_CompareToHttpData(DataType, other.DataType));
        }
            public IInterfaceHttpData Next()
            {
                if (!this.HasNext())
                {
                    throw new InvalidOperationException("No more element to iterate");
                }

                IInterfaceHttpData data = this.list[this.index++];

                return(data);
            }
Exemple #12
0
        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();
            }
        }
Exemple #13
0
        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();
            }
        }
Exemple #14
0
        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();
        }
        // From the current context(currentBuffer and currentData), returns the next
        // HttpChunk(if possible) trying to get sizeleft bytes more into the currentBuffer.
        // This is the Multipart version.
        IHttpContent EncodeNextChunkMultipart(int sizeleft)
        {
            if (this.currentData == null)
            {
                return(null);
            }
            IByteBuffer buffer;

            if (this.currentData is InternalAttribute internalAttribute)
            {
                buffer           = internalAttribute.ToByteBuffer();
                this.currentData = null;
            }
            else
            {
                try
                {
                    buffer = ((IHttpData)this.currentData).GetChunk(sizeleft);
                }
                catch (IOException e)
                {
                    throw new ErrorDataEncoderException(e);
                }
                if (buffer.Capacity == 0)
                {
                    // end for current InterfaceHttpData, need more data
                    this.currentData = null;
                    return(null);
                }
            }
            this.currentBuffer = this.currentBuffer == null
                ? buffer
                : Unpooled.WrappedBuffer(this.currentBuffer, buffer);

            if (this.currentBuffer.ReadableBytes < HttpPostBodyUtil.ChunkSize)
            {
                this.currentData = null;
                return(null);
            }

            buffer = this.FillByteBuffer();
            return(new DefaultHttpContent(buffer));
        }
Exemple #16
0
        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();
        }
Exemple #17
0
        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 override int CompareTo(IInterfaceHttpData other)
 {
     throw new NotSupportedException("Should never be called.");
 }
        public void AddBodyHttpData(IInterfaceHttpData data)
        {
            if (data is null)
            {
                ThrowHelper.ThrowArgumentNullException(ExceptionArgument.data);
            }
            if (this.headerFinalized)
            {
                ThrowHelper.ThrowErrorDataEncoderException_CannotAddValue();
            }
            this.bodyListDatas.Add(data);
            if (!this.isMultipart)
            {
                switch (data)
                {
                case IAttribute dataAttribute:
                    try
                    {
                        // name=value& with encoded name and attribute
                        string     key          = this.EncodeAttribute(dataAttribute.Name, this.charset);
                        string     value        = this.EncodeAttribute(dataAttribute.Value, this.charset);
                        IAttribute newattribute = this.factory.CreateAttribute(this.request, key, value);
                        this.MultipartHttpDatas.Add(newattribute);
                        this.globalBodySize += newattribute.Name.Length + 1 + newattribute.Length + 1;
                    }
                    catch (IOException e)
                    {
                        ThrowHelper.ThrowErrorDataEncoderException(e);
                    }
                    break;

                case IFileUpload fileUpload:
                    // since not Multipart, only name=filename => Attribute
                    // name=filename& with encoded name and filename
                    string     key0          = this.EncodeAttribute(fileUpload.Name, this.charset);
                    string     value0        = this.EncodeAttribute(fileUpload.FileName, this.charset);
                    IAttribute newattribute0 = this.factory.CreateAttribute(this.request, key0, value0);
                    this.MultipartHttpDatas.Add(newattribute0);
                    this.globalBodySize += newattribute0.Name.Length + 1 + newattribute0.Length + 1;
                    break;
                }
                return;
            }
            //  Logic:
            //  if not Attribute:
            //       add Data to body list
            //       if (duringMixedMode)
            //           add endmixedmultipart delimiter
            //           currentFileUpload = null
            //           duringMixedMode = false;
            //       add multipart delimiter, multipart body header and Data to multipart list
            //       reset currentFileUpload, duringMixedMode
            //  if FileUpload: take care of multiple file for one field => mixed mode
            //       if (duringMixedMode)
            //           if (currentFileUpload.name == data.name)
            //               add mixedmultipart delimiter, mixedmultipart body header and Data to multipart list
            //           else
            //               add endmixedmultipart delimiter, multipart body header and Data to multipart list
            //               currentFileUpload = data
            //               duringMixedMode = false;
            //       else
            //           if (currentFileUpload.name == data.name)
            //               change multipart body header of previous file into multipart list to
            //                       mixedmultipart start, mixedmultipart body header
            //               add mixedmultipart delimiter, mixedmultipart body header and Data to multipart list
            //               duringMixedMode = true
            //           else
            //               add multipart delimiter, multipart body header and Data to multipart list
            //               currentFileUpload = data
            //               duringMixedMode = false;
            //  Do not add last delimiter! Could be:
            //  if duringmixedmode: endmixedmultipart + endmultipart
            //  else only endmultipart
            //
            if (data is IAttribute attribute)
            {
                InternalAttribute internalAttribute;
                if (this.duringMixedMode)
                {
                    internalAttribute = new InternalAttribute(this.charset);
                    internalAttribute.AddValue($"\r\n--{this.MultipartMixedBoundary}--");
                    this.MultipartHttpDatas.Add(internalAttribute);
                    this.MultipartMixedBoundary = null;
                    this.currentFileUpload      = null;
                    this.duringMixedMode        = false;
                }
                internalAttribute = new InternalAttribute(this.charset);
                if ((uint)this.MultipartHttpDatas.Count > 0u)
                {
                    // previously a data field so CRLF
                    internalAttribute.AddValue("\r\n");
                }
                internalAttribute.AddValue($"--{this.MultipartDataBoundary}\r\n");
                // content-disposition: form-data; name="field1"
                internalAttribute.AddValue($"{HttpHeaderNames.ContentDisposition}: {HttpHeaderValues.FormData}; {HttpHeaderValues.Name}=\"{attribute.Name}\"\r\n");
                // Add Content-Length: xxx
                internalAttribute.AddValue($"{HttpHeaderNames.ContentLength}: {attribute.Length}\r\n");
                Encoding localcharset = attribute.Charset;
                if (localcharset is object)
                {
                    // Content-Type: text/plain; charset=charset
                    internalAttribute.AddValue($"{HttpHeaderNames.ContentType}: {HttpPostBodyUtil.DefaultTextContentType}; {HttpHeaderValues.Charset}={localcharset.WebName}\r\n");
                }
                // CRLF between body header and data
                internalAttribute.AddValue("\r\n");
                this.MultipartHttpDatas.Add(internalAttribute);
                this.MultipartHttpDatas.Add(data);
                this.globalBodySize += attribute.Length + internalAttribute.Size;
            }
            else if (data is IFileUpload fileUpload)
            {
                var internalAttribute = new InternalAttribute(this.charset);
                if ((uint)this.MultipartHttpDatas.Count > 0u)
                {
                    // previously a data field so CRLF
                    internalAttribute.AddValue("\r\n");
                }
                bool localMixed;
                if (this.duringMixedMode)
                {
                    if (this.currentFileUpload is object && string.Equals(this.currentFileUpload.Name, fileUpload.Name
#if NETCOREAPP_3_0_GREATER || NETSTANDARD_2_0_GREATER
                                                                          ))
#else
                                                                          , StringComparison.Ordinal))
#endif
                    {
                        // continue a mixed mode

                        localMixed = true;
                    }
                    else
                    {
                        // end a mixed mode

                        // add endmixedmultipart delimiter, multipart body header
                        // and
                        // Data to multipart list
                        internalAttribute.AddValue($"--{this.MultipartMixedBoundary}--");
                        this.MultipartHttpDatas.Add(internalAttribute);
                        this.MultipartMixedBoundary = null;
                        // start a new one (could be replaced if mixed start again
                        // from here
                        internalAttribute = new InternalAttribute(this.charset);
                        internalAttribute.AddValue("\r\n");
                        localMixed = false;
                        // new currentFileUpload and no more in Mixed mode
                        this.currentFileUpload = fileUpload;
                        this.duringMixedMode   = false;
                    }
                }
                else
                {
                    if (this.encoderMode != EncoderMode.HTML5 && this.currentFileUpload is object &&
                        string.Equals(this.currentFileUpload.Name, fileUpload.Name
#if NETCOREAPP_3_0_GREATER || NETSTANDARD_2_0_GREATER
                                      ))
#else
                                      , StringComparison.Ordinal))
#endif
                    {
                        // create a new mixed mode (from previous file)

                        // change multipart body header of previous file into
                        // multipart list to
                        // mixedmultipart start, mixedmultipart body header

                        // change Internal (size()-2 position in multipartHttpDatas)
                        // from (line starting with *)
                        // --AaB03x
                        // * Content-Disposition: form-data; name="files";
                        // filename="file1.txt"
                        // Content-Type: text/plain
                        // to (lines starting with *)
                        // --AaB03x
                        // * Content-Disposition: form-data; name="files"
                        // * Content-Type: multipart/mixed; boundary=BbC04y
                        // *
                        // * --BbC04y
                        // * Content-Disposition: attachment; filename="file1.txt"
                        // Content-Type: text/plain

                        this.InitMixedMultipart();
                        var pastAttribute = (InternalAttribute)this.MultipartHttpDatas[this.MultipartHttpDatas.Count - 2];
                        // remove past size
                        this.globalBodySize -= pastAttribute.Size;
                        var replacement = StringBuilderManager.Allocate(
                            139 + this.MultipartDataBoundary.Length + this.MultipartMixedBoundary.Length * 2
                            + fileUpload.FileName.Length + fileUpload.Name.Length)
                                          .Append("--")
                                          .Append(this.MultipartDataBoundary)
                                          .Append("\r\n")

                                          .Append(HttpHeaderNames.ContentDisposition)
                                          .Append(": ")
                                          .Append(HttpHeaderValues.FormData)
                                          .Append("; ")
                                          .Append(HttpHeaderValues.Name)
                                          .Append("=\"")
                                          .Append(fileUpload.Name)
                                          .Append("\"\r\n")

                                          .Append(HttpHeaderNames.ContentType)
                                          .Append(": ")
                                          .Append(HttpHeaderValues.MultipartMixed)
                                          .Append("; ")
                                          .Append(HttpHeaderValues.Boundary)
                                          .Append('=')
                                          .Append(this.MultipartMixedBoundary)
                                          .Append("\r\n\r\n")

                                          .Append("--")
                                          .Append(this.MultipartMixedBoundary)
                                          .Append("\r\n")

                                          .Append(HttpHeaderNames.ContentDisposition)
                                          .Append(": ")
                                          .Append(HttpHeaderValues.Attachment);

                        if ((uint)fileUpload.FileName.Length > 0u)
                        {
                            replacement.Append("; ")
                            .Append(HttpHeaderValues.FileName)
                            .Append("=\"")
                            .Append(this.currentFileUpload.FileName)
                            .Append('"');
                        }

                        replacement.Append("\r\n");

                        pastAttribute.SetValue(StringBuilderManager.ReturnAndFree(replacement), 1);
                        pastAttribute.SetValue("", 2);

                        // update past size
                        this.globalBodySize += pastAttribute.Size;

                        // now continue
                        // add mixedmultipart delimiter, mixedmultipart body header
                        // and
                        // Data to multipart list
                        localMixed           = true;
                        this.duringMixedMode = true;
                    }
        public void AddBodyHttpData(IInterfaceHttpData data)
        {
            Contract.Requires(data != null);
            if (this.headerFinalized)
            {
                throw new ErrorDataEncoderException("Cannot add value once finalized");
            }
            this.bodyListDatas.Add(data);
            if (!this.isMultipart)
            {
                if (data is IAttribute dataAttribute)
                {
                    try
                    {
                        // name=value& with encoded name and attribute
                        string     key          = this.EncodeAttribute(dataAttribute.Name, this.charset);
                        string     value        = this.EncodeAttribute(dataAttribute.Value, this.charset);
                        IAttribute newattribute = this.factory.CreateAttribute(this.request, key, value);
                        this.MultipartHttpDatas.Add(newattribute);
                        this.globalBodySize += newattribute.Name.Length + 1 + newattribute.Length + 1;
                    }
                    catch (IOException e)
                    {
                        throw new ErrorDataEncoderException(e);
                    }
                }
                else if (data is IFileUpload fileUpload)
                {
                    // since not Multipart, only name=filename => Attribute
                    // name=filename& with encoded name and filename
                    string     key          = this.EncodeAttribute(fileUpload.Name, this.charset);
                    string     value        = this.EncodeAttribute(fileUpload.FileName, this.charset);
                    IAttribute newattribute = this.factory.CreateAttribute(this.request, key, value);
                    this.MultipartHttpDatas.Add(newattribute);
                    this.globalBodySize += newattribute.Name.Length + 1 + newattribute.Length + 1;
                }
                return;
            }
            //  Logic:
            //  if not Attribute:
            //       add Data to body list
            //       if (duringMixedMode)
            //           add endmixedmultipart delimiter
            //           currentFileUpload = null
            //           duringMixedMode = false;
            //       add multipart delimiter, multipart body header and Data to multipart list
            //       reset currentFileUpload, duringMixedMode
            //  if FileUpload: take care of multiple file for one field => mixed mode
            //       if (duringMixedMode)
            //           if (currentFileUpload.name == data.name)
            //               add mixedmultipart delimiter, mixedmultipart body header and Data to multipart list
            //           else
            //               add endmixedmultipart delimiter, multipart body header and Data to multipart list
            //               currentFileUpload = data
            //               duringMixedMode = false;
            //       else
            //           if (currentFileUpload.name == data.name)
            //               change multipart body header of previous file into multipart list to
            //                       mixedmultipart start, mixedmultipart body header
            //               add mixedmultipart delimiter, mixedmultipart body header and Data to multipart list
            //               duringMixedMode = true
            //           else
            //               add multipart delimiter, multipart body header and Data to multipart list
            //               currentFileUpload = data
            //               duringMixedMode = false;
            //  Do not add last delimiter! Could be:
            //  if duringmixedmode: endmixedmultipart + endmultipart
            //  else only endmultipart
            //
            if (data is IAttribute attribute)
            {
                InternalAttribute internalAttribute;
                if (this.duringMixedMode)
                {
                    internalAttribute = new InternalAttribute(this.charset);
                    internalAttribute.AddValue($"\r\n--{this.MultipartMixedBoundary}--");
                    this.MultipartHttpDatas.Add(internalAttribute);
                    this.MultipartMixedBoundary = null;
                    this.currentFileUpload      = null;
                    this.duringMixedMode        = false;
                }
                internalAttribute = new InternalAttribute(this.charset);
                if (this.MultipartHttpDatas.Count > 0)
                {
                    // previously a data field so CRLF
                    internalAttribute.AddValue("\r\n");
                }
                internalAttribute.AddValue($"--{this.MultipartDataBoundary}\r\n");
                // content-disposition: form-data; name="field1"
                internalAttribute.AddValue($"{HttpHeaderNames.ContentDisposition}: {HttpHeaderValues.FormData}; {HttpHeaderValues.Name}=\"{attribute.Name}\"\r\n");
                // Add Content-Length: xxx
                internalAttribute.AddValue($"{HttpHeaderNames.ContentLength}: {attribute.Length}\r\n");
                Encoding localcharset = attribute.Charset;
                if (localcharset != null)
                {
                    // Content-Type: text/plain; charset=charset
                    internalAttribute.AddValue($"{HttpHeaderNames.ContentType}: {HttpPostBodyUtil.DefaultTextContentType}; {HttpHeaderValues.Charset}={localcharset.WebName}\r\n");
                }
                // CRLF between body header and data
                internalAttribute.AddValue("\r\n");
                this.MultipartHttpDatas.Add(internalAttribute);
                this.MultipartHttpDatas.Add(data);
                this.globalBodySize += attribute.Length + internalAttribute.Size;
            }
            else if (data is IFileUpload fileUpload)
            {
                var internalAttribute = new InternalAttribute(this.charset);
                if (this.MultipartHttpDatas.Count > 0)
                {
                    // previously a data field so CRLF
                    internalAttribute.AddValue("\r\n");
                }
                bool localMixed;
                if (this.duringMixedMode)
                {
                    if (this.currentFileUpload != null && this.currentFileUpload.Name.Equals(fileUpload.Name))
                    {
                        // continue a mixed mode

                        localMixed = true;
                    }
                    else
                    {
                        // end a mixed mode

                        // add endmixedmultipart delimiter, multipart body header
                        // and
                        // Data to multipart list
                        internalAttribute.AddValue($"--{this.MultipartMixedBoundary}--");
                        this.MultipartHttpDatas.Add(internalAttribute);
                        this.MultipartMixedBoundary = null;
                        // start a new one (could be replaced if mixed start again
                        // from here
                        internalAttribute = new InternalAttribute(this.charset);
                        internalAttribute.AddValue("\r\n");
                        localMixed = false;
                        // new currentFileUpload and no more in Mixed mode
                        this.currentFileUpload = fileUpload;
                        this.duringMixedMode   = false;
                    }
                }
                else
                {
                    if (this.encoderMode != EncoderMode.HTML5 && this.currentFileUpload != null &&
                        this.currentFileUpload.Name.Equals(fileUpload.Name))
                    {
                        // create a new mixed mode (from previous file)

                        // change multipart body header of previous file into
                        // multipart list to
                        // mixedmultipart start, mixedmultipart body header

                        // change Internal (size()-2 position in multipartHttpDatas)
                        // from (line starting with *)
                        // --AaB03x
                        // * Content-Disposition: form-data; name="files";
                        // filename="file1.txt"
                        // Content-Type: text/plain
                        // to (lines starting with *)
                        // --AaB03x
                        // * Content-Disposition: form-data; name="files"
                        // * Content-Type: multipart/mixed; boundary=BbC04y
                        // *
                        // * --BbC04y
                        // * Content-Disposition: attachment; filename="file1.txt"
                        // Content-Type: text/plain

                        this.InitMixedMultipart();
                        var pastAttribute = (InternalAttribute)this.MultipartHttpDatas[this.MultipartHttpDatas.Count - 2];
                        // remove past size
                        this.globalBodySize -= pastAttribute.Size;
                        StringBuilder replacement = new StringBuilder(
                            139 + this.MultipartDataBoundary.Length + this.MultipartMixedBoundary.Length * 2
                            + fileUpload.FileName.Length + fileUpload.Name.Length)
                                                    .Append("--")
                                                    .Append(this.MultipartDataBoundary)
                                                    .Append("\r\n")

                                                    .Append(HttpHeaderNames.ContentDisposition)
                                                    .Append(": ")
                                                    .Append(HttpHeaderValues.FormData)
                                                    .Append("; ")
                                                    .Append(HttpHeaderValues.Name)
                                                    .Append("=\"")
                                                    .Append(fileUpload.Name)
                                                    .Append("\"\r\n")

                                                    .Append(HttpHeaderNames.ContentType)
                                                    .Append(": ")
                                                    .Append(HttpHeaderValues.MultipartMixed)
                                                    .Append("; ")
                                                    .Append(HttpHeaderValues.Boundary)
                                                    .Append('=')
                                                    .Append(this.MultipartMixedBoundary)
                                                    .Append("\r\n\r\n")

                                                    .Append("--")
                                                    .Append(this.MultipartMixedBoundary)
                                                    .Append("\r\n")

                                                    .Append(HttpHeaderNames.ContentDisposition)
                                                    .Append(": ")
                                                    .Append(HttpHeaderValues.Attachment);

                        if (fileUpload.FileName.Length > 0)
                        {
                            replacement.Append("; ")
                            .Append(HttpHeaderValues.FileName)
                            .Append("=\"")
                            .Append(fileUpload.FileName)
                            .Append('"');
                        }

                        replacement.Append("\r\n");

                        pastAttribute.SetValue(replacement.ToString(), 1);
                        pastAttribute.SetValue("", 2);

                        // update past size
                        this.globalBodySize += pastAttribute.Size;

                        // now continue
                        // add mixedmultipart delimiter, mixedmultipart body header
                        // and
                        // Data to multipart list
                        localMixed           = true;
                        this.duringMixedMode = true;
                    }
                    else
                    {
                        // a simple new multipart
                        // add multipart delimiter, multipart body header and Data
                        // to multipart list
                        localMixed             = false;
                        this.currentFileUpload = fileUpload;
                        this.duringMixedMode   = false;
                    }
                }

                if (localMixed)
                {
                    // add mixedmultipart delimiter, mixedmultipart body header and
                    // Data to multipart list
                    internalAttribute.AddValue($"--{this.MultipartMixedBoundary}\r\n");

                    if (fileUpload.FileName.Length == 0)
                    {
                        // Content-Disposition: attachment
                        internalAttribute.AddValue($"{HttpHeaderNames.ContentDisposition}: {HttpHeaderValues.Attachment}\r\n");
                    }
                    else
                    {
                        // Content-Disposition: attachment; filename="file1.txt"
                        internalAttribute.AddValue($"{HttpHeaderNames.ContentDisposition}: {HttpHeaderValues.Attachment}; {HttpHeaderValues.FileName}=\"{fileUpload.FileName}\"\r\n");
                    }
                }
                else
                {
                    internalAttribute.AddValue($"--{this.MultipartDataBoundary}\r\n");

                    if (fileUpload.FileName.Length == 0)
                    {
                        // Content-Disposition: form-data; name="files";
                        internalAttribute.AddValue($"{HttpHeaderNames.ContentDisposition}: {HttpHeaderValues.FormData}; {HttpHeaderValues.Name}=\"{fileUpload.Name}\"\r\n");
                    }
                    else
                    {
                        // Content-Disposition: form-data; name="files";
                        // filename="file1.txt"
                        internalAttribute.AddValue($"{HttpHeaderNames.ContentDisposition}: {HttpHeaderValues.FormData}; {HttpHeaderValues.Name}=\"{fileUpload.Name}\"; {HttpHeaderValues.FileName}=\"{fileUpload.FileName}\"\r\n");
                    }
                }
                // Add Content-Length: xxx
                internalAttribute.AddValue($"{HttpHeaderNames.ContentLength}: {fileUpload.Length}\r\n");
                // Content-Type: image/gif
                // Content-Type: text/plain; charset=ISO-8859-1
                // Content-Transfer-Encoding: binary
                internalAttribute.AddValue($"{HttpHeaderNames.ContentType}: {fileUpload.ContentType}");
                string contentTransferEncoding = fileUpload.ContentTransferEncoding;
                if (contentTransferEncoding != null &&
                    contentTransferEncoding.Equals(HttpPostBodyUtil.TransferEncodingMechanism.Binary.Value))
                {
                    internalAttribute.AddValue($"\r\n{HttpHeaderNames.ContentTransferEncoding}: {HttpPostBodyUtil.TransferEncodingMechanism.Binary.Value}\r\n\r\n");
                }
                else if (fileUpload.Charset != null)
                {
                    internalAttribute.AddValue($"; {HttpHeaderValues.Charset}={fileUpload.Charset.WebName}\r\n\r\n");
                }
                else
                {
                    internalAttribute.AddValue("\r\n\r\n");
                }
                this.MultipartHttpDatas.Add(internalAttribute);
                this.MultipartHttpDatas.Add(data);
                this.globalBodySize += fileUpload.Length + internalAttribute.Size;
            }
        }
 private void WriteHttpData(IInterfaceHttpData data)
 {
     if (data.DataType == HttpDataType.Attribute)
     {
         var    attribute = (IAttribute)data;
         string value;
         try
         {
             value = attribute.Value;
         }
         catch (Exception e1)
         {
             // Error while reading data from File, only print name and error
             s_logger.LogError(e1.ToString());
             _responseContent.Append("\r\nBODY Attribute: " + attribute.DataType + ": "
                                     + attribute.Name + " Error while reading value: " + e1.Message + "\r\n");
             return;
         }
         if (value.Length > 100)
         {
             _responseContent.Append("\r\nBODY Attribute: " + attribute.DataType + ": "
                                     + attribute.Name + " data too long\r\n");
         }
         else
         {
             _responseContent.Append("\r\nBODY Attribute: " + attribute.DataType + ": "
                                     + attribute + "\r\n");
         }
     }
     else
     {
         _responseContent.Append("\r\nBODY FileUpload: " + data.DataType + ": " + data
                                 + "\r\n");
         if (data.DataType == HttpDataType.FileUpload)
         {
             var fileUpload = (IFileUpload)data;
             if (fileUpload.IsCompleted)
             {
                 if (fileUpload.Length < 10000)
                 {
                     _responseContent.Append("\tContent of file\r\n");
                     try
                     {
                         _responseContent.Append(fileUpload.GetString(fileUpload.Charset));
                     }
                     catch (Exception e1)
                     {
                         // do nothing for the example
                         s_logger.LogError(e1.ToString());
                     }
                     _responseContent.Append("\r\n");
                 }
                 else
                 {
                     _responseContent.Append("\tFile too long to be printed out:" + fileUpload.Length + "\r\n");
                 }
                 // fileUpload.isInMemory();// tells if the file is in Memory
                 // or on File
                 // fileUpload.renameTo(dest); // enable to move into another
                 // File dest
                 // decoder.removeFileUploadFromClean(fileUpload); //remove
                 // the File of to delete file
             }
             else
             {
                 _responseContent.Append("\tFile to be continued but should not!\r\n");
             }
         }
     }
 }
        // From the current context(currentBuffer and currentData), returns the next HttpChunk(if possible)
        // trying to get* sizeleft bytes more into the currentBuffer.This is the UrlEncoded version.
        IHttpContent EncodeNextChunkUrlEncoded(int sizeleft)
        {
            if (this.currentData == null)
            {
                return(null);
            }
            int         size = sizeleft;
            IByteBuffer buffer;

            // Set name=
            if (this.isKey)
            {
                string key = this.currentData.Name;
                buffer     = Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes(key));
                this.isKey = false;
                if (this.currentBuffer == null)
                {
                    this.currentBuffer = Unpooled.WrappedBuffer(buffer,
                                                                Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("=")));
                    // continue
                    size -= buffer.ReadableBytes + 1;
                }
                else
                {
                    this.currentBuffer = Unpooled.WrappedBuffer(this.currentBuffer, buffer,
                                                                Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("=")));
                    // continue
                    size -= buffer.ReadableBytes + 1;
                }
                if (this.currentBuffer.ReadableBytes >= HttpPostBodyUtil.ChunkSize)
                {
                    buffer = this.FillByteBuffer();
                    return(new DefaultHttpContent(buffer));
                }
            }

            // Put value into buffer
            try
            {
                buffer = ((IHttpData)this.currentData).GetChunk(size);
            }
            catch (IOException e)
            {
                throw new ErrorDataEncoderException(e);
            }

            // Figure out delimiter
            IByteBuffer delimiter = null;

            if (buffer.ReadableBytes < size)
            {
                this.isKey = true;
                delimiter  = this.iterator.HasNext()
                    ? Unpooled.WrappedBuffer(Encoding.UTF8.GetBytes("&"))
                    : null;
            }

            // End for current InterfaceHttpData, need potentially more data
            if (buffer.Capacity == 0)
            {
                this.currentData = null;
                if (this.currentBuffer == null)
                {
                    this.currentBuffer = delimiter;
                }
                else
                {
                    if (delimiter != null)
                    {
                        this.currentBuffer = Unpooled.WrappedBuffer(this.currentBuffer, delimiter);
                    }
                }
                Debug.Assert(this.currentBuffer != null);
                if (this.currentBuffer.ReadableBytes >= HttpPostBodyUtil.ChunkSize)
                {
                    buffer = this.FillByteBuffer();
                    return(new DefaultHttpContent(buffer));
                }
                return(null);
            }

            // Put it all together: name=value&
            if (this.currentBuffer == null)
            {
                this.currentBuffer = delimiter != null
                    ? Unpooled.WrappedBuffer(buffer, delimiter)
                    : buffer;
            }
            else
            {
                this.currentBuffer = delimiter != null
                    ? Unpooled.WrappedBuffer(this.currentBuffer, buffer, delimiter)
                    : Unpooled.WrappedBuffer(this.currentBuffer, buffer);
            }

            // end for current InterfaceHttpData, need more data
            if (this.currentBuffer.ReadableBytes < HttpPostBodyUtil.ChunkSize)
            {
                this.currentData = null;
                this.isKey       = true;
                return(null);
            }

            buffer = this.FillByteBuffer();
            return(new DefaultHttpContent(buffer));
        }