@@ -277,9 +277,12 @@ private static string DetectBoundary(RebufferableBinaryReader reader)
277277 // Remove the two dashes
278278 string boundary = line . Substring ( 2 ) ;
279279
280- // If the string ends with '--' it means that we found the "end" boundary and we
281- // need to trim the two dashes to get the actual boundary
282- if ( boundary . EndsWith ( "--" ) )
280+ // If the string ends with '--' and it's not followed by content, we can safely assume that we
281+ // found the "end" boundary. In this scenario, we must trim the two dashes to get the actual boundary.
282+ // Otherwise, the boundary must be accepted as-is. The reason we check for "additional content" is to
283+ // resolve the problem explained in GH-123.
284+ var moreContentAvailable = MoreContentAvailable ( reader ) ;
285+ if ( boundary . EndsWith ( "--" ) && ! moreContentAvailable )
283286 {
284287 boundary = boundary . Substring ( 0 , boundary . Length - 2 ) ;
285288 reader . Buffer ( $ "--{ boundary } --\n ") ;
@@ -333,9 +336,12 @@ private static async Task<string> DetectBoundaryAsync(RebufferableBinaryReader r
333336 // Remove the two dashes
334337 string boundary = line . Substring ( 2 ) ;
335338
336- // If the string ends with '--' it means that we found the "end" boundary and we
337- // need to trim the two dashes to get the actual boundary.
338- if ( boundary . EndsWith ( "--" ) )
339+ // If the string ends with '--' and it's not followed by content, we can safely assume that we
340+ // found the "end" boundary. In this scenario, we must trim the two dashes to get the actual boundary.
341+ // Otherwise, the boundary must be accepted as-is. The reason we check for "additional content" is to
342+ // resolve the problem explained in GH-123.
343+ var moreContentAvailable = await MoreContentAvailableAsync ( reader ) . ConfigureAwait ( false ) ;
344+ if ( boundary . EndsWith ( "--" ) && ! moreContentAvailable )
339345 {
340346 boundary = boundary . Substring ( 0 , boundary . Length - 2 ) ;
341347 reader . Buffer ( $ "--{ boundary } --\n ") ;
@@ -348,6 +354,47 @@ private static async Task<string> DetectBoundaryAsync(RebufferableBinaryReader r
348354 return boundary ;
349355 }
350356
357+ /// <summary>
358+ /// Determine if there is more content.
359+ /// </summary>
360+ /// <param name="reader">
361+ /// The binary reader to parse.
362+ /// </param>
363+ /// <returns>
364+ /// A boolean indicating whether more content is available in the binary reader.
365+ /// </returns>
366+ private static bool MoreContentAvailable ( RebufferableBinaryReader reader )
367+ {
368+ var line = reader . ReadLine ( ) ;
369+
370+ if ( line == null ) return false ;
371+ else reader . Buffer ( $ "{ line } \n ") ;
372+
373+ return true ;
374+ }
375+
376+ /// <summary>
377+ /// Determine if there is more content.
378+ /// </summary>
379+ /// <param name="reader">
380+ /// The binary reader to parse.
381+ /// </param>
382+ /// <param name="cancellationToken">
383+ /// The cancellation token.
384+ /// </param>
385+ /// <returns>
386+ /// A boolean indicating whether more content is available in the binary reader.
387+ /// </returns>
388+ private static async Task < bool > MoreContentAvailableAsync ( RebufferableBinaryReader reader , CancellationToken cancellationToken = default )
389+ {
390+ var line = await reader . ReadLineAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
391+
392+ if ( line == null ) return false ;
393+ else reader . Buffer ( $ "{ line } \n ") ;
394+
395+ return true ;
396+ }
397+
351398 /// <summary>
352399 /// Use a few assumptions to determine if a section contains a file.
353400 /// </summary>
@@ -686,7 +733,7 @@ private void ParseFilePart(Dictionary<string, string> parameters, RebufferableBi
686733 // We also want to chop off the newline that is inserted by the protocol.
687734 // We can do this by reducing endPos by the length of newline in this environment
688735 // and encoding
689- FileHandler ( name , filename , contentType , contentDisposition , fullBuffer , endPos - bufferNewlineLength , partNumber ++ , additionalParameters ) ;
736+ FileHandler ? . Invoke ( name , filename , contentType , contentDisposition , fullBuffer , endPos - bufferNewlineLength , partNumber ++ , additionalParameters ) ;
690737
691738 int writeBackOffset = endPos + endPosLength + boundaryNewlineOffset ;
692739 int writeBackAmount = ( prevLength + curLength ) - writeBackOffset ;
@@ -696,7 +743,7 @@ private void ParseFilePart(Dictionary<string, string> parameters, RebufferableBi
696743 }
697744
698745 // No end, consume the entire previous buffer
699- FileHandler ( name , filename , contentType , contentDisposition , prevBuffer , prevLength , partNumber ++ , additionalParameters ) ;
746+ FileHandler ? . Invoke ( name , filename , contentType , contentDisposition , prevBuffer , prevLength , partNumber ++ , additionalParameters ) ;
700747
701748 // Now we want to swap the two buffers, we don't care
702749 // what happens to the data from prevBuffer so we set
@@ -843,7 +890,7 @@ private async Task ParseFilePartAsync(Dictionary<string, string> parameters, Reb
843890 // We also want to chop off the newline that is inserted by the protocl.
844891 // We can do this by reducing endPos by the length of newline in this environment
845892 // and encoding
846- FileHandler ( name , filename , contentType , contentDisposition , fullBuffer , endPos - bufferNewlineLength , partNumber ++ , additionalParameters ) ;
893+ FileHandler ? . Invoke ( name , filename , contentType , contentDisposition , fullBuffer , endPos - bufferNewlineLength , partNumber ++ , additionalParameters ) ;
847894
848895 int writeBackOffset = endPos + endPosLength + boundaryNewlineOffset ;
849896 int writeBackAmount = ( prevLength + curLength ) - writeBackOffset ;
@@ -853,7 +900,7 @@ private async Task ParseFilePartAsync(Dictionary<string, string> parameters, Reb
853900 }
854901
855902 // No end, consume the entire previous buffer
856- FileHandler ( name , filename , contentType , contentDisposition , prevBuffer , prevLength , partNumber ++ , additionalParameters ) ;
903+ FileHandler ? . Invoke ( name , filename , contentType , contentDisposition , prevBuffer , prevLength , partNumber ++ , additionalParameters ) ;
857904
858905 // Now we want to swap the two buffers, we don't care
859906 // what happens to the data from prevBuffer so we set
@@ -898,7 +945,7 @@ private void ParseParameterPart(Dictionary<string, string> parameters, Rebuffera
898945 if ( line . SequenceEqual ( endBoundaryBinary ) ) readEndBoundary = true ;
899946
900947 var part = new ParameterPartBinary ( parameters [ "name" ] , data ) ;
901- ParameterHandler ( part ) ;
948+ ParameterHandler ? . Invoke ( part ) ;
902949 }
903950
904951 /// <summary>
@@ -933,7 +980,7 @@ private async Task ParseParameterPartAsync(Dictionary<string, string> parameters
933980 if ( line . SequenceEqual ( endBoundaryBinary ) ) readEndBoundary = true ;
934981
935982 var part = new ParameterPartBinary ( parameters [ "name" ] , data ) ;
936- ParameterHandler ( part ) ;
983+ ParameterHandler ? . Invoke ( part ) ;
937984 }
938985
939986 /// <summary>
0 commit comments