@@ -135,9 +135,12 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
135
135
boundary = BoundaryType . None ;
136
136
headerCount = 0 ;
137
137
138
+ currentContentEncodingLineNumber = - 1 ;
139
+ currentContentEncodingOffset = - 1 ;
138
140
currentContentLength = null ;
139
141
currentContentType = null ;
140
142
currentEncoding = null ;
143
+ hasMimeVersion = false ;
141
144
142
145
await OnHeadersBeginAsync ( headerBlockBegin , headersBeginLineNumber , cancellationToken ) . ConfigureAwait ( false ) ;
143
146
@@ -166,6 +169,7 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
166
169
}
167
170
168
171
// Note: This can happen if a message is truncated immediately after a boundary marker (e.g. where subpart headers would begin).
172
+ OnComplianceIssueEncountered ( MimeComplianceStatus . MissingBodySeparator , beginOffset , beginLineNumber ) ;
169
173
state = MimeParserState . Content ;
170
174
break ;
171
175
}
@@ -196,6 +200,7 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
196
200
197
201
if ( invalid ) {
198
202
// Figure out why this is an invalid header.
203
+ OnComplianceIssueEncountered ( MimeComplianceStatus . InvalidHeader , beginOffset , lineNumber ) ;
199
204
200
205
if ( input [ inputIndex ] == ( byte ) '-' ) {
201
206
// Check for a boundary marker. If the message is properly formatted, this will NEVER happen.
@@ -214,8 +219,10 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
214
219
} while ( true ) ;
215
220
216
221
// Note: If a boundary was discovered, then the state will be updated to MimeParserState.Boundary.
217
- if ( state == MimeParserState . Boundary )
222
+ if ( state == MimeParserState . Boundary ) {
223
+ OnComplianceIssueEncountered ( MimeComplianceStatus . MissingBodySeparator , beginOffset , beginLineNumber ) ;
218
224
break ;
225
+ }
219
226
220
227
// Fall through and act as if we're consuming a header.
221
228
} else if ( input [ inputIndex ] == ( byte ) 'F' || input [ inputIndex ] == ( byte ) '>' ) {
@@ -238,8 +245,10 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
238
245
// 1. Complete: This means that we've found an actual mbox marker
239
246
// 2. Error: Invalid *first* header and it was not a valid mbox marker
240
247
// 3. MessageHeaders or Headers: let it fall through and treat it as an invalid headers
241
- if ( state != MimeParserState . MessageHeaders && state != MimeParserState . Headers )
248
+ if ( state != MimeParserState . MessageHeaders && state != MimeParserState . Headers ) {
249
+ OnComplianceIssueEncountered ( MimeComplianceStatus . MissingBodySeparator , beginOffset , beginLineNumber ) ;
242
250
break ;
251
+ }
243
252
244
253
// Fall through and act as if we're consuming a header.
245
254
} else {
@@ -269,6 +278,10 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
269
278
}
270
279
271
280
if ( await ReadAheadAsync ( 1 , 0 , cancellationToken ) . ConfigureAwait ( false ) == 0 ) {
281
+ if ( midline )
282
+ OnComplianceIssueEncountered ( MimeComplianceStatus . IncompleteHeader , beginOffset , beginLineNumber ) ;
283
+ else
284
+ OnComplianceIssueEncountered ( MimeComplianceStatus . MissingBodySeparator , beginOffset , beginLineNumber ) ;
272
285
state = MimeParserState . Content ;
273
286
eof = true ;
274
287
break ;
@@ -280,11 +293,17 @@ async Task StepHeadersAsync (CancellationToken cancellationToken)
280
293
return ;
281
294
}
282
295
283
- var header = CreateHeader ( beginOffset , fieldNameLength , headerFieldLength , invalid ) ;
296
+ var header = CreateHeader ( beginOffset , beginLineNumber , fieldNameLength , headerFieldLength , invalid ) ;
284
297
285
298
await OnHeaderReadAsync ( header , beginLineNumber , cancellationToken ) . ConfigureAwait ( false ) ;
286
299
} while ( ! eof ) ;
287
300
301
+ #if DEBUG
302
+ // If the state hasn't been updated at this point, that means there's a bug somewhere in the above loop.
303
+ if ( state == MimeParserState . MessageHeaders || state == MimeParserState . Headers )
304
+ Debugger . Break ( ) ;
305
+ #endif
306
+
288
307
headerBlockEnd = GetOffset ( inputIndex ) ;
289
308
290
309
await OnHeadersEndAsync ( headerBlockBegin , headersBeginLineNumber , headerBlockEnd , lineNumber , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -442,6 +461,9 @@ async Task<int> ConstructMessagePartAsync (int depth, CancellationToken cancella
442
461
443
462
await OnMimeMessageBeginAsync ( currentBeginOffset , beginLineNumber , cancellationToken ) . ConfigureAwait ( false ) ;
444
463
464
+ if ( currentContentType != null && ! hasMimeVersion )
465
+ OnComplianceIssueEncountered ( MimeComplianceStatus . MissingMimeVersion , currentBeginOffset , beginLineNumber ) ;
466
+
445
467
var type = GetContentType ( null ) ;
446
468
MimeEntityType entityType ;
447
469
int lines ;
@@ -582,11 +604,10 @@ async Task<int> ConstructMultipartAsync (ContentType contentType, int depth, Can
582
604
var beginLineNumber = lineNumber ;
583
605
long endOffset ;
584
606
585
- if ( marker is null ) {
586
- #if DEBUG
587
- Debug . WriteLine ( "Multipart without a boundary encountered!" ) ;
588
- #endif
607
+ if ( currentEncoding . HasValue && currentEncoding != ContentEncoding . SevenBit && currentEncoding != ContentEncoding . EightBit )
608
+ OnComplianceIssueEncountered ( MimeComplianceStatus . InvalidContentTransferEncoding , currentContentEncodingOffset , currentContentEncodingLineNumber ) ;
589
609
610
+ if ( marker is null ) {
590
611
// Note: this will scan all content into the preamble...
591
612
await MultipartScanPreambleAsync ( cancellationToken ) . ConfigureAwait ( false ) ;
592
613
@@ -603,8 +624,6 @@ async Task<int> ConstructMultipartAsync (ContentType contentType, int depth, Can
603
624
604
625
if ( boundary == BoundaryType . ImmediateEndBoundary ) {
605
626
// consume the end boundary and read the epilogue (if there is one)
606
- // FIXME: multipart.WriteEndBoundary = true;
607
-
608
627
var boundaryOffset = GetOffset ( inputIndex ) ;
609
628
var boundaryLineNumber = lineNumber ;
610
629
@@ -621,8 +640,6 @@ async Task<int> ConstructMultipartAsync (ContentType contentType, int depth, Can
621
640
return GetLineCount ( beginLineNumber , beginOffset , endOffset ) ;
622
641
}
623
642
624
- // FIXME: multipart.WriteEndBoundary = false;
625
-
626
643
// We either found the end of the stream or we found a parent's boundary
627
644
PopBoundary ( ) ;
628
645
@@ -637,6 +654,8 @@ async Task<int> ConstructMultipartAsync (ContentType contentType, int depth, Can
637
654
638
655
endOffset = GetEndOffset ( inputIndex ) ;
639
656
657
+ OnComplianceIssueEncountered ( MimeComplianceStatus . MissingMultipartBoundary , endOffset , lineNumber ) ;
658
+
640
659
return GetLineCount ( beginLineNumber , beginOffset , endOffset ) ;
641
660
}
642
661
@@ -659,6 +678,7 @@ async Task<int> ConstructMultipartAsync (ContentType contentType, int depth, Can
659
678
/// </exception>
660
679
public async Task ReadHeadersAsync ( CancellationToken cancellationToken = default )
661
680
{
681
+ ComplianceStatus = MimeComplianceStatus . Compliant ;
662
682
state = MimeParserState . Headers ;
663
683
toplevel = true ;
664
684
@@ -689,6 +709,7 @@ public async Task ReadEntityAsync (CancellationToken cancellationToken = default
689
709
{
690
710
var beginLineNumber = lineNumber ;
691
711
712
+ ComplianceStatus = MimeComplianceStatus . Compliant ;
692
713
state = MimeParserState . Headers ;
693
714
toplevel = true ;
694
715
@@ -757,6 +778,8 @@ public async Task ReadEntityAsync (CancellationToken cancellationToken = default
757
778
/// </exception>
758
779
public async Task ReadMessageAsync ( CancellationToken cancellationToken = default )
759
780
{
781
+ ComplianceStatus = MimeComplianceStatus . Compliant ;
782
+
760
783
// scan the from-line if we are parsing an mbox
761
784
while ( state != MimeParserState . MessageHeaders ) {
762
785
switch ( await StepAsync ( cancellationToken ) . ConfigureAwait ( false ) ) {
@@ -788,6 +811,9 @@ public async Task ReadMessageAsync (CancellationToken cancellationToken = defaul
788
811
else
789
812
contentEnd = 0 ;
790
813
814
+ if ( currentContentType != null && ! hasMimeVersion )
815
+ OnComplianceIssueEncountered ( MimeComplianceStatus . MissingMimeVersion , currentBeginOffset , beginLineNumber ) ;
816
+
791
817
var type = GetContentType ( null ) ;
792
818
MimeEntityType entityType ;
793
819
int lines ;
0 commit comments