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 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(); }
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); }
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)); }
public int CompareTo(IInterfaceHttpData other) { if (other is InternalAttribute attr) { return this.CompareTo(attr); } return ThrowHelper.ThrowArgumentException_CompareToHttpData(this.DataType, other.DataType); }
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); }
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(); }
// 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)); }
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(); }
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)); }