Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / Channels / FramingDecoders.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 namespace System.ServiceModel.Channels
5 {
6     using System.Globalization;
7     using System.ServiceModel;
8     using System.IO;
9     using System.Text;
10
11     static class DecoderHelper
12     {
13         public static void ValidateSize(int size)
14         {
15             if (size <= 0)
16             {
17                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("size", size, SR.GetString(
18                     SR.ValueMustBePositive)));
19             }
20         }
21     }
22
23     struct IntDecoder
24     {
25         int value;
26         short index;
27         bool isValueDecoded;
28         const int LastIndex = 4;
29
30         public int Value
31         {
32             get
33             {
34                 if (!isValueDecoded)
35 #pragma warning suppress 56503 // [....], not a publicly accessible API
36                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
37                 return value;
38             }
39         }
40
41         public bool IsValueDecoded
42         {
43             get { return isValueDecoded; }
44         }
45
46         public void Reset()
47         {
48             index = 0;
49             value = 0;
50             isValueDecoded = false;
51         }
52
53         public int Decode(byte[] buffer, int offset, int size)
54         {
55             DecoderHelper.ValidateSize(size);
56             if (isValueDecoded)
57             {
58                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
59             }
60             int bytesConsumed = 0;
61             while (bytesConsumed < size)
62             {
63                 int next = buffer[offset];
64                 value |= (next & 0x7F) << (index * 7);
65                 bytesConsumed++;
66                 if (index == LastIndex && (next & 0xF8) != 0)
67                 {
68                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.GetString(SR.FramingSizeTooLarge)));
69                 }
70                 index++;
71                 if ((next & 0x80) == 0)
72                 {
73                     isValueDecoded = true;
74                     break;
75                 }
76                 offset++;
77             }
78             return bytesConsumed;
79         }
80     }
81
82     abstract class StringDecoder
83     {
84         int encodedSize;
85         byte[] encodedBytes;
86         int bytesNeeded;
87         string value;
88         State currentState;
89         IntDecoder sizeDecoder;
90         int sizeQuota;
91         int valueLengthInBytes;
92
93         public StringDecoder(int sizeQuota)
94         {
95             this.sizeQuota = sizeQuota;
96             this.sizeDecoder = new IntDecoder();
97             this.currentState = State.ReadingSize;
98             Reset();
99         }
100
101         public bool IsValueDecoded
102         {
103             get { return currentState == State.Done; }
104         }
105
106         public string Value
107         {
108             get
109             {
110                 if (currentState != State.Done)
111 #pragma warning suppress 56503 // [....], not a publicly accessible API
112                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
113                 return value;
114             }
115         }
116
117         public int Decode(byte[] buffer, int offset, int size)
118         {
119             DecoderHelper.ValidateSize(size);
120
121             int bytesConsumed;
122             switch (currentState)
123             {
124                 case State.ReadingSize:
125                     bytesConsumed = sizeDecoder.Decode(buffer, offset, size);
126                     if (sizeDecoder.IsValueDecoded)
127                     {
128                         encodedSize = sizeDecoder.Value;
129                         if (encodedSize > sizeQuota)
130                         {
131                             Exception quotaExceeded = OnSizeQuotaExceeded(encodedSize);
132                             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(quotaExceeded);
133                         }
134                         if (encodedBytes == null || encodedBytes.Length < encodedSize)
135                         {
136                             encodedBytes = DiagnosticUtility.Utility.AllocateByteArray(encodedSize);
137                             value = null;
138                         }
139                         currentState = State.ReadingBytes;
140                         bytesNeeded = encodedSize;
141                     }
142                     break;
143                 case State.ReadingBytes:
144                     if (value != null && valueLengthInBytes == encodedSize && bytesNeeded == encodedSize &&
145                         size >= encodedSize && CompareBuffers(encodedBytes, buffer, offset))
146                     {
147                         bytesConsumed = bytesNeeded;
148                         OnComplete(value);
149                     }
150                     else
151                     {
152                         bytesConsumed = bytesNeeded;
153                         if (size < bytesNeeded)
154                             bytesConsumed = size;
155                         Buffer.BlockCopy(buffer, offset, encodedBytes, encodedSize - bytesNeeded, bytesConsumed);
156                         bytesNeeded -= bytesConsumed;
157                         if (bytesNeeded == 0)
158                         {
159                             value = Encoding.UTF8.GetString(encodedBytes, 0, encodedSize);
160                             valueLengthInBytes = encodedSize;
161                             OnComplete(value);
162                         }
163                     }
164                     break;
165                 default:
166                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine)));
167             }
168
169             return bytesConsumed;
170         }
171
172         protected virtual void OnComplete(string value)
173         {
174             this.currentState = State.Done;
175         }
176
177         static bool CompareBuffers(byte[] buffer1, byte[] buffer2, int offset)
178         {
179             for (int i = 0; i < buffer1.Length; i++)
180             {
181                 if (buffer1[i] != buffer2[i + offset])
182                 {
183                     return false;
184                 }
185             }
186             return true;
187         }
188
189         protected abstract Exception OnSizeQuotaExceeded(int size);
190
191         public void Reset()
192         {
193             currentState = State.ReadingSize;
194             sizeDecoder.Reset();
195         }
196
197         enum State
198         {
199             ReadingSize,
200             ReadingBytes,
201             Done,
202         }
203     }
204
205     class ViaStringDecoder : StringDecoder
206     {
207         Uri via;
208
209         public ViaStringDecoder(int sizeQuota)
210             : base(sizeQuota)
211         {
212         }
213
214         protected override Exception OnSizeQuotaExceeded(int size)
215         {
216             Exception result = new InvalidDataException(SR.GetString(SR.FramingViaTooLong, size));
217             FramingEncodingString.AddFaultString(result, FramingEncodingString.ViaTooLongFault);
218             return result;
219         }
220
221         protected override void OnComplete(string value)
222         {
223             try
224             {
225                 via = new Uri(value);
226                 base.OnComplete(value);
227             }
228             catch (UriFormatException exception)
229             {
230                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidDataException(SR.GetString(SR.FramingViaNotUri, value), exception));
231             }
232         }
233
234         public Uri ValueAsUri
235         {
236             get
237             {
238                 if (!IsValueDecoded)
239 #pragma warning suppress 56503 // [....], not a publicly accessible API
240                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
241                 return via;
242             }
243         }
244     }
245
246     class FaultStringDecoder : StringDecoder
247     {
248         internal const int FaultSizeQuota = 256;
249
250         public FaultStringDecoder()
251             : base(FaultSizeQuota)
252         {
253         }
254
255         protected override Exception OnSizeQuotaExceeded(int size)
256         {
257             return new InvalidDataException(SR.GetString(SR.FramingFaultTooLong, size));
258         }
259
260         public static Exception GetFaultException(string faultString, string via, string contentType)
261         {
262             if (faultString == FramingEncodingString.EndpointNotFoundFault)
263             {
264                 return new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, via));
265             }
266             else if (faultString == FramingEncodingString.ContentTypeInvalidFault)
267             {
268                 return new ProtocolException(SR.GetString(SR.FramingContentTypeMismatch, contentType, via));
269             }
270             else if (faultString == FramingEncodingString.ServiceActivationFailedFault)
271             {
272                 return new ServiceActivationException(SR.GetString(SR.Hosting_ServiceActivationFailed, via));
273             }
274             else if (faultString == FramingEncodingString.ConnectionDispatchFailedFault)
275             {
276                 return new CommunicationException(SR.GetString(SR.Sharing_ConnectionDispatchFailed, via));
277             }
278             else if (faultString == FramingEncodingString.EndpointUnavailableFault)
279             {
280                 return new EndpointNotFoundException(SR.GetString(SR.Sharing_EndpointUnavailable, via));
281             }
282             else if (faultString == FramingEncodingString.MaxMessageSizeExceededFault)
283             {
284                 Exception inner = new QuotaExceededException(SR.GetString(SR.FramingMaxMessageSizeExceeded));
285                 return new CommunicationException(inner.Message, inner);
286             }
287             else if (faultString == FramingEncodingString.UnsupportedModeFault)
288             {
289                 return new ProtocolException(SR.GetString(SR.FramingModeNotSupportedFault, via));
290             }
291             else if (faultString == FramingEncodingString.UnsupportedVersionFault)
292             {
293                 return new ProtocolException(SR.GetString(SR.FramingVersionNotSupportedFault, via));
294             }
295             else if (faultString == FramingEncodingString.ContentTypeTooLongFault)
296             {
297                 Exception inner = new QuotaExceededException(SR.GetString(SR.FramingContentTypeTooLongFault, contentType));
298                 return new CommunicationException(inner.Message, inner);
299             }
300             else if (faultString == FramingEncodingString.ViaTooLongFault)
301             {
302                 Exception inner = new QuotaExceededException(SR.GetString(SR.FramingViaTooLongFault, via));
303                 return new CommunicationException(inner.Message, inner);
304             }
305             else if (faultString == FramingEncodingString.ServerTooBusyFault)
306             {
307                 return new ServerTooBusyException(SR.GetString(SR.ServerTooBusy, via));
308             }
309             else if (faultString == FramingEncodingString.UpgradeInvalidFault)
310             {
311                 return new ProtocolException(SR.GetString(SR.FramingUpgradeInvalid, via));
312             }
313             else
314             {
315                 return new ProtocolException(SR.GetString(SR.FramingFaultUnrecognized, faultString));
316             }
317         }
318     }
319
320     class ContentTypeStringDecoder : StringDecoder
321     {
322         public ContentTypeStringDecoder(int sizeQuota)
323             : base(sizeQuota)
324         {
325         }
326
327         protected override Exception OnSizeQuotaExceeded(int size)
328         {
329             Exception result = new InvalidDataException(SR.GetString(SR.FramingContentTypeTooLong, size));
330             FramingEncodingString.AddFaultString(result, FramingEncodingString.ContentTypeTooLongFault);
331             return result;
332         }
333
334         public static string GetString(FramingEncodingType type)
335         {
336             switch (type)
337             {
338                 case FramingEncodingType.Soap11Utf8:
339                     return FramingEncodingString.Soap11Utf8;
340                 case FramingEncodingType.Soap11Utf16:
341                     return FramingEncodingString.Soap11Utf16;
342                 case FramingEncodingType.Soap11Utf16FFFE:
343                     return FramingEncodingString.Soap11Utf16FFFE;
344                 case FramingEncodingType.Soap12Utf8:
345                     return FramingEncodingString.Soap12Utf8;
346                 case FramingEncodingType.Soap12Utf16:
347                     return FramingEncodingString.Soap12Utf16;
348                 case FramingEncodingType.Soap12Utf16FFFE:
349                     return FramingEncodingString.Soap12Utf16FFFE;
350                 case FramingEncodingType.MTOM:
351                     return FramingEncodingString.MTOM;
352                 case FramingEncodingType.Binary:
353                     return FramingEncodingString.Binary;
354                 case FramingEncodingType.BinarySession:
355                     return FramingEncodingString.BinarySession;
356                 default:
357                     return "unknown" + ((int)type).ToString(CultureInfo.InvariantCulture);
358             }
359         }
360     }
361
362     abstract class FramingDecoder
363     {
364         long streamPosition;
365
366         protected FramingDecoder()
367         {
368         }
369
370         protected FramingDecoder(long streamPosition)
371         {
372             this.streamPosition = streamPosition;
373         }
374
375         protected abstract string CurrentStateAsString { get; }
376
377         public long StreamPosition
378         {
379             get { return streamPosition; }
380             set { streamPosition = value; }
381         }
382
383         protected void ValidateFramingMode(FramingMode mode)
384         {
385             switch (mode)
386             {
387                 case FramingMode.Singleton:
388                 case FramingMode.Duplex:
389                 case FramingMode.Simplex:
390                 case FramingMode.SingletonSized:
391                     break;
392                 default:
393                     {
394                         Exception exception = CreateException(new InvalidDataException(SR.GetString(
395                             SR.FramingModeNotSupported, mode.ToString())), FramingEncodingString.UnsupportedModeFault);
396                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
397                     }
398             }
399         }
400
401         protected void ValidateRecordType(FramingRecordType expectedType, FramingRecordType foundType)
402         {
403             if (foundType != expectedType)
404             {
405                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateInvalidRecordTypeException(expectedType, foundType));
406             }
407         }
408
409         // special validation for Preamble Ack for usability purposes (MB#39593)
410         protected void ValidatePreambleAck(FramingRecordType foundType)
411         {
412             if (foundType != FramingRecordType.PreambleAck)
413             {
414                 Exception inner = CreateInvalidRecordTypeException(FramingRecordType.PreambleAck, foundType);
415                 string exceptionString;
416                 if (((byte)foundType == 'h') || ((byte)foundType == 'H'))
417                 {
418                     exceptionString = SR.GetString(SR.PreambleAckIncorrectMaybeHttp);
419                 }
420                 else
421                 {
422                     exceptionString = SR.GetString(SR.PreambleAckIncorrect);
423                 }
424                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ProtocolException(exceptionString, inner));
425             }
426         }
427
428         Exception CreateInvalidRecordTypeException(FramingRecordType expectedType, FramingRecordType foundType)
429         {
430             return new InvalidDataException(SR.GetString(SR.FramingRecordTypeMismatch, expectedType.ToString(), foundType.ToString()));
431         }
432
433         protected void ValidateMajorVersion(int majorVersion)
434         {
435             if (majorVersion != FramingVersion.Major)
436             {
437                 Exception exception = CreateException(new InvalidDataException(SR.GetString(
438                     SR.FramingVersionNotSupported, majorVersion)), FramingEncodingString.UnsupportedVersionFault);
439                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(exception);
440             }
441         }
442
443         public Exception CreatePrematureEOFException()
444         {
445             return CreateException(new InvalidDataException(SR.GetString(SR.FramingPrematureEOF)));
446         }
447
448         protected Exception CreateException(InvalidDataException innerException, string framingFault)
449         {
450             Exception result = CreateException(innerException);
451             FramingEncodingString.AddFaultString(result, framingFault);
452             return result;
453         }
454
455         protected Exception CreateException(InvalidDataException innerException)
456         {
457             return new ProtocolException(SR.GetString(SR.FramingError, StreamPosition, CurrentStateAsString),
458                 innerException);
459         }
460     }
461
462     // Pattern: 
463     //   Done
464     class ServerModeDecoder : FramingDecoder
465     {
466         State currentState;
467         int majorVersion;
468         int minorVersion;
469         FramingMode mode;
470
471         public ServerModeDecoder()
472         {
473             currentState = State.ReadingVersionRecord;
474         }
475
476         public int Decode(byte[] bytes, int offset, int size)
477         {
478             DecoderHelper.ValidateSize(size);
479
480             try
481             {
482                 int bytesConsumed;
483                 switch (currentState)
484                 {
485                     case State.ReadingVersionRecord:
486                         ValidateRecordType(FramingRecordType.Version, (FramingRecordType)bytes[offset]);
487                         currentState = State.ReadingMajorVersion;
488                         bytesConsumed = 1;
489                         break;
490                     case State.ReadingMajorVersion:
491                         majorVersion = bytes[offset];
492                         ValidateMajorVersion(majorVersion);
493                         currentState = State.ReadingMinorVersion;
494                         bytesConsumed = 1;
495                         break;
496                     case State.ReadingMinorVersion:
497                         minorVersion = bytes[offset];
498                         currentState = State.ReadingModeRecord;
499                         bytesConsumed = 1;
500                         break;
501                     case State.ReadingModeRecord:
502                         ValidateRecordType(FramingRecordType.Mode, (FramingRecordType)bytes[offset]);
503                         currentState = State.ReadingModeValue;
504                         bytesConsumed = 1;
505                         break;
506                     case State.ReadingModeValue:
507                         mode = (FramingMode)bytes[offset];
508                         ValidateFramingMode(mode);
509                         currentState = State.Done;
510                         bytesConsumed = 1;
511                         break;
512                     default:
513                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
514                             CreateException(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine))));
515                 }
516
517                 StreamPosition += bytesConsumed;
518                 return bytesConsumed;
519             }
520             catch (InvalidDataException e)
521             {
522                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
523             }
524         }
525
526         public void Reset()
527         {
528             StreamPosition = 0;
529             currentState = State.ReadingVersionRecord;
530         }
531
532         public State CurrentState
533         {
534             get { return currentState; }
535         }
536
537         protected override string CurrentStateAsString
538         {
539             get { return currentState.ToString(); }
540         }
541
542         public FramingMode Mode
543         {
544             get
545             {
546                 if (currentState != State.Done)
547 #pragma warning suppress 56503 // [....], not a publicly accessible API
548                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
549                 return mode;
550             }
551         }
552
553         public int MajorVersion
554         {
555             get
556             {
557                 if (currentState != State.Done)
558 #pragma warning suppress 56503 // [....], not a publicly accessible API
559                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
560                 return majorVersion;
561             }
562         }
563
564         public int MinorVersion
565         {
566             get
567             {
568                 if (currentState != State.Done)
569 #pragma warning suppress 56503 // [....], not a publicly accessible API
570                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
571                 return minorVersion;
572             }
573         }
574
575         public enum State
576         {
577             ReadingVersionRecord,
578             ReadingMajorVersion,
579             ReadingMinorVersion,
580             ReadingModeRecord,
581             ReadingModeValue,
582             Done,
583         }
584     }
585
586     // Used for Duplex/Simplex
587     // Pattern: 
588     //   Start, 
589     //   (UpgradeRequest, upgrade-content-type)*, 
590     //   (EnvelopeStart, ReadingEnvelopeBytes*, EnvelopeEnd)*, 
591     //   End
592     class ServerSessionDecoder : FramingDecoder
593     {
594         ViaStringDecoder viaDecoder;
595         StringDecoder contentTypeDecoder;
596         IntDecoder sizeDecoder;
597         State currentState;
598         string contentType;
599         int envelopeBytesNeeded;
600         int envelopeSize;
601         string upgrade;
602
603         public ServerSessionDecoder(long streamPosition, int maxViaLength, int maxContentTypeLength)
604             : base(streamPosition)
605         {
606             this.viaDecoder = new ViaStringDecoder(maxViaLength);
607             this.contentTypeDecoder = new ContentTypeStringDecoder(maxContentTypeLength);
608             this.sizeDecoder = new IntDecoder();
609             this.currentState = State.ReadingViaRecord;
610         }
611
612         public State CurrentState
613         {
614             get { return currentState; }
615         }
616
617         protected override string CurrentStateAsString
618         {
619             get { return currentState.ToString(); }
620         }
621
622         public string ContentType
623         {
624             get
625             {
626                 if (currentState < State.PreUpgradeStart)
627 #pragma warning suppress 56503 // [....], not a publicly accessible API
628                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
629                 return contentType;
630             }
631         }
632
633         public Uri Via
634         {
635             get
636             {
637                 if (currentState < State.ReadingContentTypeRecord)
638 #pragma warning suppress 56503 // [....], not a publicly accessible API
639                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
640                 return viaDecoder.ValueAsUri;
641             }
642         }
643
644         public void Reset(long streamPosition)
645         {
646             this.StreamPosition = streamPosition;
647             this.currentState = State.ReadingViaRecord;
648         }
649
650         public string Upgrade
651         {
652             get
653             {
654                 if (currentState != State.UpgradeRequest)
655 #pragma warning suppress 56503 // [....], not a publicly accessible API
656                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
657                 return upgrade;
658             }
659         }
660
661         public int EnvelopeSize
662         {
663             get
664             {
665                 if (currentState < State.EnvelopeStart)
666 #pragma warning suppress 56503 // [....], not a publicly accessible API
667                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
668                 return envelopeSize;
669             }
670         }
671
672         public int Decode(byte[] bytes, int offset, int size)
673         {
674             DecoderHelper.ValidateSize(size);
675
676             try
677             {
678                 int bytesConsumed;
679                 FramingRecordType recordType;
680                 switch (currentState)
681                 {
682                     case State.ReadingViaRecord:
683                         recordType = (FramingRecordType)bytes[offset];
684                         ValidateRecordType(FramingRecordType.Via, recordType);
685                         bytesConsumed = 1;
686                         viaDecoder.Reset();
687                         currentState = State.ReadingViaString;
688                         break;
689                     case State.ReadingViaString:
690                         bytesConsumed = viaDecoder.Decode(bytes, offset, size);
691                         if (viaDecoder.IsValueDecoded)
692                         {
693                             currentState = State.ReadingContentTypeRecord;
694                         }
695                         break;
696                     case State.ReadingContentTypeRecord:
697                         recordType = (FramingRecordType)bytes[offset];
698                         if (recordType == FramingRecordType.KnownEncoding)
699                         {
700                             bytesConsumed = 1;
701                             currentState = State.ReadingContentTypeByte;
702                         }
703                         else
704                         {
705                             ValidateRecordType(FramingRecordType.ExtensibleEncoding, recordType);
706                             bytesConsumed = 1;
707                             contentTypeDecoder.Reset();
708                             currentState = State.ReadingContentTypeString;
709                         }
710                         break;
711                     case State.ReadingContentTypeByte:
712                         contentType = ContentTypeStringDecoder.GetString((FramingEncodingType)bytes[offset]);
713                         bytesConsumed = 1;
714                         currentState = State.PreUpgradeStart;
715                         break;
716                     case State.ReadingContentTypeString:
717                         bytesConsumed = contentTypeDecoder.Decode(bytes, offset, size);
718                         if (contentTypeDecoder.IsValueDecoded)
719                         {
720                             currentState = State.PreUpgradeStart;
721                             contentType = contentTypeDecoder.Value;
722                         }
723                         break;
724                     case State.PreUpgradeStart:
725                         bytesConsumed = 0;
726                         currentState = State.ReadingUpgradeRecord;
727                         break;
728                     case State.ReadingUpgradeRecord:
729                         recordType = (FramingRecordType)bytes[offset];
730                         if (recordType == FramingRecordType.UpgradeRequest)
731                         {
732                             bytesConsumed = 1;
733                             contentTypeDecoder.Reset();
734                             currentState = State.ReadingUpgradeString;
735                         }
736                         else
737                         {
738                             bytesConsumed = 0;
739                             currentState = State.ReadingPreambleEndRecord;
740                         }
741                         break;
742                     case State.ReadingUpgradeString:
743                         bytesConsumed = contentTypeDecoder.Decode(bytes, offset, size);
744                         if (contentTypeDecoder.IsValueDecoded)
745                         {
746                             currentState = State.UpgradeRequest;
747                             upgrade = contentTypeDecoder.Value;
748                         }
749                         break;
750                     case State.UpgradeRequest:
751                         bytesConsumed = 0;
752                         currentState = State.ReadingUpgradeRecord;
753                         break;
754                     case State.ReadingPreambleEndRecord:
755                         recordType = (FramingRecordType)bytes[offset];
756                         ValidateRecordType(FramingRecordType.PreambleEnd, recordType);
757                         bytesConsumed = 1;
758                         currentState = State.Start;
759                         break;
760                     case State.Start:
761                         bytesConsumed = 0;
762                         currentState = State.ReadingEndRecord;
763                         break;
764                     case State.ReadingEndRecord:
765                         recordType = (FramingRecordType)bytes[offset];
766                         if (recordType == FramingRecordType.End)
767                         {
768                             bytesConsumed = 1;
769                             currentState = State.End;
770                         }
771                         else
772                         {
773                             bytesConsumed = 0;
774                             currentState = State.ReadingEnvelopeRecord;
775                         }
776                         break;
777                     case State.ReadingEnvelopeRecord:
778                         ValidateRecordType(FramingRecordType.SizedEnvelope, (FramingRecordType)bytes[offset]);
779                         bytesConsumed = 1;
780                         currentState = State.ReadingEnvelopeSize;
781                         sizeDecoder.Reset();
782                         break;
783                     case State.ReadingEnvelopeSize:
784                         bytesConsumed = sizeDecoder.Decode(bytes, offset, size);
785                         if (sizeDecoder.IsValueDecoded)
786                         {
787                             currentState = State.EnvelopeStart;
788                             envelopeSize = sizeDecoder.Value;
789                             envelopeBytesNeeded = envelopeSize;
790                         }
791                         break;
792                     case State.EnvelopeStart:
793                         bytesConsumed = 0;
794                         currentState = State.ReadingEnvelopeBytes;
795                         break;
796                     case State.ReadingEnvelopeBytes:
797                         bytesConsumed = size;
798                         if (bytesConsumed > envelopeBytesNeeded)
799                             bytesConsumed = envelopeBytesNeeded;
800                         envelopeBytesNeeded -= bytesConsumed;
801                         if (envelopeBytesNeeded == 0)
802                             currentState = State.EnvelopeEnd;
803                         break;
804                     case State.EnvelopeEnd:
805                         bytesConsumed = 0;
806                         currentState = State.ReadingEndRecord;
807                         break;
808                     case State.End:
809                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
810                             CreateException(new InvalidDataException(SR.GetString(SR.FramingAtEnd))));
811                     default:
812                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
813                             CreateException(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine))));
814                 }
815
816                 StreamPosition += bytesConsumed;
817                 return bytesConsumed;
818             }
819             catch (InvalidDataException e)
820             {
821                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
822             }
823         }
824
825         public enum State
826         {
827             ReadingViaRecord,
828             ReadingViaString,
829             ReadingContentTypeRecord,
830             ReadingContentTypeString,
831             ReadingContentTypeByte,
832             PreUpgradeStart,
833             ReadingUpgradeRecord,
834             ReadingUpgradeString,
835             UpgradeRequest,
836             ReadingPreambleEndRecord,
837             Start,
838             ReadingEnvelopeRecord,
839             ReadingEnvelopeSize,
840             EnvelopeStart,
841             ReadingEnvelopeBytes,
842             EnvelopeEnd,
843             ReadingEndRecord,
844             End,
845         }
846     }
847
848     class SingletonMessageDecoder : FramingDecoder
849     {
850         IntDecoder sizeDecoder;
851         int chunkBytesNeeded;
852         int chunkSize;
853         State currentState;
854
855         public SingletonMessageDecoder(long streamPosition)
856             : base(streamPosition)
857         {
858             this.sizeDecoder = new IntDecoder();
859             this.currentState = State.ChunkStart;
860         }
861
862         public void Reset()
863         {
864             this.currentState = State.ChunkStart;
865         }
866
867         public State CurrentState
868         {
869             get { return currentState; }
870         }
871
872         protected override string CurrentStateAsString
873         {
874             get { return currentState.ToString(); }
875         }
876
877         public int ChunkSize
878         {
879             get
880             {
881                 if (currentState < State.ChunkStart)
882                 {
883 #pragma warning suppress 56503 // [....], not a publicly accessible API
884                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
885                 }
886
887                 return this.chunkSize;
888             }
889         }
890
891         public int Decode(byte[] bytes, int offset, int size)
892         {
893             DecoderHelper.ValidateSize(size);
894
895             try
896             {
897                 int bytesConsumed;
898                 switch (currentState)
899                 {
900                     case State.ReadingEnvelopeChunkSize:
901                         bytesConsumed = sizeDecoder.Decode(bytes, offset, size);
902                         if (sizeDecoder.IsValueDecoded)
903                         {
904                             this.chunkSize = sizeDecoder.Value;
905                             sizeDecoder.Reset();
906
907                             if (this.chunkSize == 0)
908                             {
909                                 currentState = State.EnvelopeEnd;
910                             }
911                             else
912                             {
913                                 currentState = State.ChunkStart;
914                                 chunkBytesNeeded = chunkSize;
915                             }
916                         }
917                         break;
918                     case State.ChunkStart:
919                         bytesConsumed = 0;
920                         currentState = State.ReadingEnvelopeBytes;
921                         break;
922                     case State.ReadingEnvelopeBytes:
923                         bytesConsumed = size;
924                         if (bytesConsumed > chunkBytesNeeded)
925                         {
926                             bytesConsumed = chunkBytesNeeded;
927                         }
928                         chunkBytesNeeded -= bytesConsumed;
929                         if (chunkBytesNeeded == 0)
930                         {
931                             currentState = State.ChunkEnd;
932                         }
933                         break;
934                     case State.ChunkEnd:
935                         bytesConsumed = 0;
936                         currentState = State.ReadingEnvelopeChunkSize;
937                         break;
938                     case State.EnvelopeEnd:
939                         ValidateRecordType(FramingRecordType.End, (FramingRecordType)bytes[offset]);
940                         bytesConsumed = 1;
941                         currentState = State.End;
942                         break;
943                     case State.End:
944                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
945                             CreateException(new InvalidDataException(SR.GetString(SR.FramingAtEnd))));
946
947                     default:
948                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
949                             CreateException(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine))));
950                 }
951
952                 StreamPosition += bytesConsumed;
953                 return bytesConsumed;
954             }
955             catch (InvalidDataException e)
956             {
957                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
958             }
959         }
960
961         public enum State
962         {
963             ReadingEnvelopeChunkSize,
964             ChunkStart,
965             ReadingEnvelopeBytes,
966             ChunkEnd,
967             EnvelopeEnd,
968             End,
969         }
970     }
971
972     // Pattern: 
973     //   Start, 
974     //   (UpgradeRequest, upgrade-bytes)*, 
975     //   EnvelopeStart,
976     class ServerSingletonDecoder : FramingDecoder
977     {
978         ViaStringDecoder viaDecoder;
979         ContentTypeStringDecoder contentTypeDecoder;
980         State currentState;
981         string contentType;
982         string upgrade;
983
984         public ServerSingletonDecoder(long streamPosition, int maxViaLength, int maxContentTypeLength)
985             : base(streamPosition)
986         {
987             this.viaDecoder = new ViaStringDecoder(maxViaLength);
988             this.contentTypeDecoder = new ContentTypeStringDecoder(maxContentTypeLength);
989             this.currentState = State.ReadingViaRecord;
990         }
991
992         public void Reset()
993         {
994             this.currentState = State.ReadingViaRecord;
995         }
996
997         public State CurrentState
998         {
999             get { return currentState; }
1000         }
1001
1002         protected override string CurrentStateAsString
1003         {
1004             get { return currentState.ToString(); }
1005         }
1006
1007         public Uri Via
1008         {
1009             get
1010             {
1011                 if (currentState < State.ReadingContentTypeRecord)
1012 #pragma warning suppress 56503 // [....], not a publicly accessible API
1013                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1014                 return viaDecoder.ValueAsUri;
1015             }
1016         }
1017
1018         public string ContentType
1019         {
1020             get
1021             {
1022                 if (currentState < State.PreUpgradeStart)
1023 #pragma warning suppress 56503 // [....], not a publicly accessible API
1024                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1025                 return contentType;
1026             }
1027         }
1028
1029         public string Upgrade
1030         {
1031             get
1032             {
1033                 if (currentState != State.UpgradeRequest)
1034 #pragma warning suppress 56503 // [....], not a publicly accessible API
1035                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1036                 return upgrade;
1037             }
1038         }
1039
1040         public int Decode(byte[] bytes, int offset, int size)
1041         {
1042             DecoderHelper.ValidateSize(size);
1043
1044             try
1045             {
1046                 int bytesConsumed;
1047                 FramingRecordType recordType;
1048                 switch (currentState)
1049                 {
1050                     case State.ReadingViaRecord:
1051                         recordType = (FramingRecordType)bytes[offset];
1052                         ValidateRecordType(FramingRecordType.Via, recordType);
1053                         bytesConsumed = 1;
1054                         viaDecoder.Reset();
1055                         currentState = State.ReadingViaString;
1056                         break;
1057                     case State.ReadingViaString:
1058                         bytesConsumed = viaDecoder.Decode(bytes, offset, size);
1059                         if (viaDecoder.IsValueDecoded)
1060                         {
1061                             currentState = State.ReadingContentTypeRecord;
1062                         }
1063                         break;
1064                     case State.ReadingContentTypeRecord:
1065                         recordType = (FramingRecordType)bytes[offset];
1066                         if (recordType == FramingRecordType.KnownEncoding)
1067                         {
1068                             bytesConsumed = 1;
1069                             currentState = State.ReadingContentTypeByte;
1070                         }
1071                         else
1072                         {
1073                             ValidateRecordType(FramingRecordType.ExtensibleEncoding, recordType);
1074                             bytesConsumed = 1;
1075                             contentTypeDecoder.Reset();
1076                             currentState = State.ReadingContentTypeString;
1077                         }
1078                         break;
1079                     case State.ReadingContentTypeByte:
1080                         contentType = ContentTypeStringDecoder.GetString((FramingEncodingType)bytes[offset]);
1081                         bytesConsumed = 1;
1082                         currentState = State.PreUpgradeStart;
1083                         break;
1084                     case State.ReadingContentTypeString:
1085                         bytesConsumed = contentTypeDecoder.Decode(bytes, offset, size);
1086                         if (contentTypeDecoder.IsValueDecoded)
1087                         {
1088                             currentState = State.PreUpgradeStart;
1089                             contentType = contentTypeDecoder.Value;
1090                         }
1091                         break;
1092                     case State.PreUpgradeStart:
1093                         bytesConsumed = 0;
1094                         currentState = State.ReadingUpgradeRecord;
1095                         break;
1096                     case State.ReadingUpgradeRecord:
1097                         recordType = (FramingRecordType)bytes[offset];
1098                         if (recordType == FramingRecordType.UpgradeRequest)
1099                         {
1100                             bytesConsumed = 1;
1101                             contentTypeDecoder.Reset();
1102                             currentState = State.ReadingUpgradeString;
1103                         }
1104                         else
1105                         {
1106                             bytesConsumed = 0;
1107                             currentState = State.ReadingPreambleEndRecord;
1108                         }
1109                         break;
1110                     case State.ReadingUpgradeString:
1111                         bytesConsumed = contentTypeDecoder.Decode(bytes, offset, size);
1112                         if (contentTypeDecoder.IsValueDecoded)
1113                         {
1114                             currentState = State.UpgradeRequest;
1115                             upgrade = contentTypeDecoder.Value;
1116                         }
1117                         break;
1118                     case State.UpgradeRequest:
1119                         bytesConsumed = 0;
1120                         currentState = State.ReadingUpgradeRecord;
1121                         break;
1122                     case State.ReadingPreambleEndRecord:
1123                         recordType = (FramingRecordType)bytes[offset];
1124                         ValidateRecordType(FramingRecordType.PreambleEnd, recordType);
1125                         bytesConsumed = 1;
1126                         currentState = State.Start;
1127                         break;
1128                     case State.Start:
1129                         bytesConsumed = 0;
1130                         currentState = State.ReadingEnvelopeRecord;
1131                         break;
1132                     case State.ReadingEnvelopeRecord:
1133                         ValidateRecordType(FramingRecordType.UnsizedEnvelope, (FramingRecordType)bytes[offset]);
1134                         bytesConsumed = 1;
1135                         currentState = State.EnvelopeStart;
1136                         break;
1137                     case State.EnvelopeStart:
1138                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1139                             CreateException(new InvalidDataException(SR.GetString(SR.FramingAtEnd))));
1140                     default:
1141                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1142                             CreateException(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine))));
1143                 }
1144
1145                 StreamPosition += bytesConsumed;
1146                 return bytesConsumed;
1147             }
1148             catch (InvalidDataException e)
1149             {
1150                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
1151             }
1152         }
1153
1154         public enum State
1155         {
1156             ReadingViaRecord,
1157             ReadingViaString,
1158             ReadingContentTypeRecord,
1159             ReadingContentTypeString,
1160             ReadingContentTypeByte,
1161             PreUpgradeStart,
1162             ReadingUpgradeRecord,
1163             ReadingUpgradeString,
1164             UpgradeRequest,
1165             ReadingPreambleEndRecord,
1166             Start,
1167             ReadingEnvelopeRecord,
1168             EnvelopeStart,
1169             ReadingEnvelopeChunkSize,
1170             ChunkStart,
1171             ReadingEnvelopeChunk,
1172             ChunkEnd,
1173             End,
1174         }
1175     }
1176
1177     // Pattern: 
1178     //   Start, 
1179     //   EnvelopeStart,
1180     class ServerSingletonSizedDecoder : FramingDecoder
1181     {
1182         ViaStringDecoder viaDecoder;
1183         ContentTypeStringDecoder contentTypeDecoder;
1184         State currentState;
1185         string contentType;
1186
1187         public ServerSingletonSizedDecoder(long streamPosition, int maxViaLength, int maxContentTypeLength)
1188             : base(streamPosition)
1189         {
1190             this.viaDecoder = new ViaStringDecoder(maxViaLength);
1191             this.contentTypeDecoder = new ContentTypeStringDecoder(maxContentTypeLength);
1192             this.currentState = State.ReadingViaRecord;
1193         }
1194
1195         public int Decode(byte[] bytes, int offset, int size)
1196         {
1197             DecoderHelper.ValidateSize(size);
1198
1199             try
1200             {
1201                 int bytesConsumed;
1202                 FramingRecordType recordType;
1203                 switch (currentState)
1204                 {
1205                     case State.ReadingViaRecord:
1206                         recordType = (FramingRecordType)bytes[offset];
1207                         ValidateRecordType(FramingRecordType.Via, recordType);
1208                         bytesConsumed = 1;
1209                         viaDecoder.Reset();
1210                         currentState = State.ReadingViaString;
1211                         break;
1212                     case State.ReadingViaString:
1213                         bytesConsumed = viaDecoder.Decode(bytes, offset, size);
1214                         if (viaDecoder.IsValueDecoded)
1215                             currentState = State.ReadingContentTypeRecord;
1216                         break;
1217                     case State.ReadingContentTypeRecord:
1218                         recordType = (FramingRecordType)bytes[offset];
1219                         if (recordType == FramingRecordType.KnownEncoding)
1220                         {
1221                             bytesConsumed = 1;
1222                             currentState = State.ReadingContentTypeByte;
1223                         }
1224                         else
1225                         {
1226                             ValidateRecordType(FramingRecordType.ExtensibleEncoding, recordType);
1227                             bytesConsumed = 1;
1228                             contentTypeDecoder.Reset();
1229                             currentState = State.ReadingContentTypeString;
1230                         }
1231                         break;
1232                     case State.ReadingContentTypeByte:
1233                         contentType = ContentTypeStringDecoder.GetString((FramingEncodingType)bytes[offset]);
1234                         bytesConsumed = 1;
1235                         currentState = State.Start;
1236                         break;
1237                     case State.ReadingContentTypeString:
1238                         bytesConsumed = contentTypeDecoder.Decode(bytes, offset, size);
1239                         if (contentTypeDecoder.IsValueDecoded)
1240                         {
1241                             currentState = State.Start;
1242                             contentType = contentTypeDecoder.Value;
1243                         }
1244                         break;
1245                     case State.Start:
1246                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1247                             CreateException(new InvalidDataException(SR.GetString(SR.FramingAtEnd))));
1248                     default:
1249                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1250                             CreateException(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine))));
1251                 }
1252
1253                 StreamPosition += bytesConsumed;
1254                 return bytesConsumed;
1255             }
1256             catch (InvalidDataException e)
1257             {
1258                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
1259             }
1260         }
1261
1262         public void Reset(long streamPosition)
1263         {
1264             this.StreamPosition = streamPosition;
1265             this.currentState = State.ReadingViaRecord;
1266         }
1267
1268         public State CurrentState
1269         {
1270             get { return currentState; }
1271         }
1272
1273         protected override string CurrentStateAsString
1274         {
1275             get { return currentState.ToString(); }
1276         }
1277
1278         public Uri Via
1279         {
1280             get
1281             {
1282                 if (currentState < State.ReadingContentTypeRecord)
1283 #pragma warning suppress 56503 // [....], not a publicly accessible API
1284                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1285                 return viaDecoder.ValueAsUri;
1286             }
1287         }
1288
1289         public string ContentType
1290         {
1291             get
1292             {
1293                 if (currentState < State.Start)
1294 #pragma warning suppress 56503 // [....], not a publicly accessible API
1295                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1296                 return contentType;
1297             }
1298         }
1299
1300         public enum State
1301         {
1302             ReadingViaRecord,
1303             ReadingViaString,
1304             ReadingContentTypeRecord,
1305             ReadingContentTypeString,
1306             ReadingContentTypeByte,
1307             Start,
1308         }
1309     }
1310
1311     // common set of states used on the client-side.
1312     enum ClientFramingDecoderState
1313     {
1314         ReadingUpgradeRecord,
1315         ReadingUpgradeMode,
1316         UpgradeResponse,
1317         ReadingAckRecord,
1318         Start,
1319         ReadingFault,
1320         ReadingFaultString,
1321         Fault,
1322         ReadingEnvelopeRecord,
1323         ReadingEnvelopeSize,
1324         EnvelopeStart,
1325         ReadingEnvelopeBytes,
1326         EnvelopeEnd,
1327         ReadingEndRecord,
1328         End,
1329     }
1330
1331     abstract class ClientFramingDecoder : FramingDecoder
1332     {
1333         ClientFramingDecoderState currentState;
1334
1335         protected ClientFramingDecoder(long streamPosition)
1336             : base(streamPosition)
1337         {
1338             this.currentState = ClientFramingDecoderState.ReadingUpgradeRecord;
1339         }
1340
1341         public ClientFramingDecoderState CurrentState
1342         {
1343             get
1344             {
1345                 return this.currentState;
1346             }
1347
1348             protected set
1349             {
1350                 this.currentState = value;
1351             }
1352         }
1353
1354         protected override string CurrentStateAsString
1355         {
1356             get { return currentState.ToString(); }
1357         }
1358
1359         public abstract string Fault
1360         {
1361             get;
1362         }
1363
1364         public abstract int Decode(byte[] bytes, int offset, int size);
1365     }
1366
1367     // Pattern: 
1368     //   (UpgradeResponse, upgrade-bytes)*, (Ack | Fault),
1369     //   ((EnvelopeStart, ReadingEnvelopeBytes*, EnvelopeEnd) | Fault)*, 
1370     //   End
1371     class ClientDuplexDecoder : ClientFramingDecoder
1372     {
1373         IntDecoder sizeDecoder;
1374         FaultStringDecoder faultDecoder;
1375         int envelopeBytesNeeded;
1376         int envelopeSize;
1377
1378         public ClientDuplexDecoder(long streamPosition)
1379             : base(streamPosition)
1380         {
1381             sizeDecoder = new IntDecoder();
1382         }
1383
1384         public int EnvelopeSize
1385         {
1386             get
1387             {
1388                 if (CurrentState < ClientFramingDecoderState.EnvelopeStart)
1389 #pragma warning suppress 56503 // [....], not a publicly accessible API
1390                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1391                 return envelopeSize;
1392             }
1393         }
1394
1395         public override string Fault
1396         {
1397             get
1398             {
1399                 if (CurrentState < ClientFramingDecoderState.Fault)
1400 #pragma warning suppress 56503 // [....], not a publicly accessible API
1401                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1402                 return faultDecoder.Value;
1403             }
1404         }
1405
1406         public override int Decode(byte[] bytes, int offset, int size)
1407         {
1408             DecoderHelper.ValidateSize(size);
1409
1410             try
1411             {
1412                 int bytesConsumed;
1413                 FramingRecordType recordType;
1414                 switch (CurrentState)
1415                 {
1416                     case ClientFramingDecoderState.ReadingUpgradeRecord:
1417                         recordType = (FramingRecordType)bytes[offset];
1418                         if (recordType == FramingRecordType.UpgradeResponse)
1419                         {
1420                             bytesConsumed = 1;
1421                             base.CurrentState = ClientFramingDecoderState.UpgradeResponse;
1422                         }
1423                         else
1424                         {
1425                             bytesConsumed = 0;
1426                             base.CurrentState = ClientFramingDecoderState.ReadingAckRecord;
1427                         }
1428                         break;
1429                     case ClientFramingDecoderState.UpgradeResponse:
1430                         bytesConsumed = 0;
1431                         base.CurrentState = ClientFramingDecoderState.ReadingUpgradeRecord;
1432                         break;
1433                     case ClientFramingDecoderState.ReadingAckRecord:
1434                         recordType = (FramingRecordType)bytes[offset];
1435                         if (recordType == FramingRecordType.Fault)
1436                         {
1437                             bytesConsumed = 1;
1438                             faultDecoder = new FaultStringDecoder();
1439                             base.CurrentState = ClientFramingDecoderState.ReadingFaultString;
1440                             break;
1441                         }
1442                         ValidatePreambleAck(recordType);
1443                         bytesConsumed = 1;
1444                         base.CurrentState = ClientFramingDecoderState.Start;
1445                         break;
1446                     case ClientFramingDecoderState.Start:
1447                         bytesConsumed = 0;
1448                         base.CurrentState = ClientFramingDecoderState.ReadingEnvelopeRecord;
1449                         break;
1450                     case ClientFramingDecoderState.ReadingEnvelopeRecord:
1451                         recordType = (FramingRecordType)bytes[offset];
1452                         if (recordType == FramingRecordType.End)
1453                         {
1454                             bytesConsumed = 1;
1455                             base.CurrentState = ClientFramingDecoderState.End;
1456                             break;
1457                         }
1458                         else if (recordType == FramingRecordType.Fault)
1459                         {
1460                             bytesConsumed = 1;
1461                             faultDecoder = new FaultStringDecoder();
1462                             base.CurrentState = ClientFramingDecoderState.ReadingFaultString;
1463                             break;
1464                         }
1465                         ValidateRecordType(FramingRecordType.SizedEnvelope, recordType);
1466                         bytesConsumed = 1;
1467                         base.CurrentState = ClientFramingDecoderState.ReadingEnvelopeSize;
1468                         sizeDecoder.Reset();
1469                         break;
1470                     case ClientFramingDecoderState.ReadingEnvelopeSize:
1471                         bytesConsumed = sizeDecoder.Decode(bytes, offset, size);
1472                         if (sizeDecoder.IsValueDecoded)
1473                         {
1474                             base.CurrentState = ClientFramingDecoderState.EnvelopeStart;
1475                             envelopeSize = sizeDecoder.Value;
1476                             envelopeBytesNeeded = envelopeSize;
1477                         }
1478                         break;
1479                     case ClientFramingDecoderState.EnvelopeStart:
1480                         bytesConsumed = 0;
1481                         base.CurrentState = ClientFramingDecoderState.ReadingEnvelopeBytes;
1482                         break;
1483                     case ClientFramingDecoderState.ReadingEnvelopeBytes:
1484                         bytesConsumed = size;
1485                         if (bytesConsumed > envelopeBytesNeeded)
1486                             bytesConsumed = envelopeBytesNeeded;
1487                         envelopeBytesNeeded -= bytesConsumed;
1488                         if (envelopeBytesNeeded == 0)
1489                             base.CurrentState = ClientFramingDecoderState.EnvelopeEnd;
1490                         break;
1491                     case ClientFramingDecoderState.EnvelopeEnd:
1492                         bytesConsumed = 0;
1493                         base.CurrentState = ClientFramingDecoderState.ReadingEnvelopeRecord;
1494                         break;
1495                     case ClientFramingDecoderState.ReadingFaultString:
1496                         bytesConsumed = faultDecoder.Decode(bytes, offset, size);
1497                         if (faultDecoder.IsValueDecoded)
1498                         {
1499                             base.CurrentState = ClientFramingDecoderState.Fault;
1500                         }
1501                         break;
1502                     case ClientFramingDecoderState.Fault:
1503                         bytesConsumed = 0;
1504                         base.CurrentState = ClientFramingDecoderState.ReadingEndRecord;
1505                         break;
1506                     case ClientFramingDecoderState.ReadingEndRecord:
1507                         ValidateRecordType(FramingRecordType.End, (FramingRecordType)bytes[offset]);
1508                         bytesConsumed = 1;
1509                         base.CurrentState = ClientFramingDecoderState.End;
1510                         break;
1511                     case ClientFramingDecoderState.End:
1512                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1513                             CreateException(new InvalidDataException(SR.GetString(SR.FramingAtEnd))));
1514                     default:
1515                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1516                             CreateException(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine))));
1517                 }
1518
1519                 StreamPosition += bytesConsumed;
1520                 return bytesConsumed;
1521             }
1522             catch (InvalidDataException e)
1523             {
1524                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
1525             }
1526         }
1527     }
1528
1529     // Pattern: 
1530     //   (UpgradeResponse, upgrade-bytes)*, (Ack | Fault),
1531     //   End
1532     class ClientSingletonDecoder : ClientFramingDecoder
1533     {
1534         FaultStringDecoder faultDecoder;
1535
1536         public ClientSingletonDecoder(long streamPosition)
1537             : base(streamPosition)
1538         {
1539         }
1540
1541         public override string Fault
1542         {
1543             get
1544             {
1545                 if (CurrentState < ClientFramingDecoderState.Fault)
1546 #pragma warning suppress 56503 // [....], not a publicly accessible API
1547                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.FramingValueNotAvailable)));
1548                 return faultDecoder.Value;
1549             }
1550         }
1551
1552         public override int Decode(byte[] bytes, int offset, int size)
1553         {
1554             DecoderHelper.ValidateSize(size);
1555
1556             try
1557             {
1558                 int bytesConsumed;
1559                 FramingRecordType recordType;
1560                 switch (CurrentState)
1561                 {
1562                     case ClientFramingDecoderState.ReadingUpgradeRecord:
1563                         recordType = (FramingRecordType)bytes[offset];
1564                         if (recordType == FramingRecordType.UpgradeResponse)
1565                         {
1566                             bytesConsumed = 1;
1567                             base.CurrentState = ClientFramingDecoderState.UpgradeResponse;
1568                         }
1569                         else
1570                         {
1571                             bytesConsumed = 0;
1572                             base.CurrentState = ClientFramingDecoderState.ReadingAckRecord;
1573                         }
1574                         break;
1575                     case ClientFramingDecoderState.UpgradeResponse:
1576                         bytesConsumed = 0;
1577                         base.CurrentState = ClientFramingDecoderState.ReadingUpgradeRecord;
1578                         break;
1579                     case ClientFramingDecoderState.ReadingAckRecord:
1580                         recordType = (FramingRecordType)bytes[offset];
1581                         if (recordType == FramingRecordType.Fault)
1582                         {
1583                             bytesConsumed = 1;
1584                             faultDecoder = new FaultStringDecoder();
1585                             base.CurrentState = ClientFramingDecoderState.ReadingFaultString;
1586                             break;
1587                         }
1588                         ValidatePreambleAck(recordType);
1589                         bytesConsumed = 1;
1590                         base.CurrentState = ClientFramingDecoderState.Start;
1591                         break;
1592
1593                     case ClientFramingDecoderState.Start:
1594                         bytesConsumed = 0;
1595                         base.CurrentState = ClientFramingDecoderState.ReadingEnvelopeRecord;
1596                         break;
1597
1598                     case ClientFramingDecoderState.ReadingEnvelopeRecord:
1599                         recordType = (FramingRecordType)bytes[offset];
1600                         if (recordType == FramingRecordType.End)
1601                         {
1602                             bytesConsumed = 1;
1603                             base.CurrentState = ClientFramingDecoderState.End;
1604                             break;
1605                         }
1606                         else if (recordType == FramingRecordType.Fault)
1607                         {
1608                             bytesConsumed = 0;
1609                             base.CurrentState = ClientFramingDecoderState.ReadingFault;
1610                             break;
1611                         }
1612                         ValidateRecordType(FramingRecordType.UnsizedEnvelope, recordType);
1613                         bytesConsumed = 1;
1614                         base.CurrentState = ClientFramingDecoderState.EnvelopeStart;
1615                         break;
1616
1617                     case ClientFramingDecoderState.EnvelopeStart:
1618                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1619                             CreateException(new InvalidDataException(SR.GetString(SR.FramingAtEnd))));
1620
1621                     case ClientFramingDecoderState.ReadingFault:
1622                         recordType = (FramingRecordType)bytes[offset];
1623                         ValidateRecordType(FramingRecordType.Fault, recordType);
1624                         bytesConsumed = 1;
1625                         faultDecoder = new FaultStringDecoder();
1626                         base.CurrentState = ClientFramingDecoderState.ReadingFaultString;
1627                         break;
1628                     case ClientFramingDecoderState.ReadingFaultString:
1629                         bytesConsumed = faultDecoder.Decode(bytes, offset, size);
1630                         if (faultDecoder.IsValueDecoded)
1631                         {
1632                             base.CurrentState = ClientFramingDecoderState.Fault;
1633                         }
1634                         break;
1635                     case ClientFramingDecoderState.Fault:
1636                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1637                             CreateException(new InvalidDataException(SR.GetString(SR.FramingAtEnd))));
1638                     default:
1639                         throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
1640                             CreateException(new InvalidDataException(SR.GetString(SR.InvalidDecoderStateMachine))));
1641                 }
1642
1643                 StreamPosition += bytesConsumed;
1644                 return bytesConsumed;
1645             }
1646             catch (InvalidDataException e)
1647             {
1648                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateException(e));
1649             }
1650         }
1651     }
1652 }