| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249 |
- //-----------------------------------------------------------------------------
- // Copyright (c) Microsoft Corporation. All rights reserved.
- //-----------------------------------------------------------------------------
- namespace System.ServiceModel.Channels
- {
- using System;
- using System.IO;
- using System.Net.Mime;
- using System.Runtime.Serialization;
- using System.Runtime.Diagnostics;
- using System.ServiceModel.Diagnostics;
- using System.Runtime;
- using System.Threading;
- using System.ServiceModel.Diagnostics.Application;
- public abstract class MessageEncoder
- {
- private string traceSourceString;
- public abstract string ContentType { get; }
- public abstract string MediaType { get; }
- public abstract MessageVersion MessageVersion { get; }
- public virtual T GetProperty<T>() where T : class
- {
- if (typeof(T) == typeof(FaultConverter))
- {
- return (T)(object)FaultConverter.GetDefaultFaultConverter(this.MessageVersion);
- }
- return null;
- }
- public Message ReadMessage(Stream stream, int maxSizeOfHeaders)
- {
- return ReadMessage(stream, maxSizeOfHeaders, null);
- }
- public abstract Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType);
- public Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager)
- {
- Message message = ReadMessage(buffer, bufferManager, null);
- return message;
- }
- public abstract Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType);
- // used for buffered streaming
- internal ArraySegment<byte> BufferMessageStream(Stream stream, BufferManager bufferManager, int maxBufferSize)
- {
- byte[] buffer = bufferManager.TakeBuffer(ConnectionOrientedTransportDefaults.ConnectionBufferSize);
- int offset = 0;
- int currentBufferSize = Math.Min(buffer.Length, maxBufferSize);
- while (offset < currentBufferSize)
- {
- int count = stream.Read(buffer, offset, currentBufferSize - offset);
- if (count == 0)
- {
- stream.Close();
- break;
- }
- offset += count;
- if (offset == currentBufferSize)
- {
- if (currentBufferSize >= maxBufferSize)
- {
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(MaxMessageSizeStream.CreateMaxReceivedMessageSizeExceededException(maxBufferSize));
- }
- currentBufferSize = Math.Min(currentBufferSize * 2, maxBufferSize);
- byte[] temp = bufferManager.TakeBuffer(currentBufferSize);
- Buffer.BlockCopy(buffer, 0, temp, 0, offset);
- bufferManager.ReturnBuffer(buffer);
- buffer = temp;
- }
- }
- return new ArraySegment<byte>(buffer, 0, offset);
- }
- // used for buffered streaming
- internal virtual Message ReadMessage(Stream stream, BufferManager bufferManager, int maxBufferSize, string contentType)
- {
- return ReadMessage(BufferMessageStream(stream, bufferManager, maxBufferSize), bufferManager, contentType);
- }
- public override string ToString()
- {
- return ContentType;
- }
- public abstract void WriteMessage(Message message, Stream stream);
- public virtual IAsyncResult BeginWriteMessage(Message message, Stream stream, AsyncCallback callback, object state)
- {
- return new WriteMessageAsyncResult(message, stream, this, callback, state);
- }
- public virtual void EndWriteMessage(IAsyncResult result)
- {
- WriteMessageAsyncResult.End(result);
- }
- public ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager)
- {
- ArraySegment<byte> arraySegment = WriteMessage(message, maxMessageSize, bufferManager, 0);
- return arraySegment;
- }
- public abstract ArraySegment<byte> WriteMessage(Message message, int maxMessageSize,
- BufferManager bufferManager, int messageOffset);
- public virtual bool IsContentTypeSupported(string contentType)
- {
- if (contentType == null)
- throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("contentType"));
- return IsContentTypeSupported(contentType, this.ContentType, this.MediaType);
- }
- internal bool IsContentTypeSupported(string contentType, string supportedContentType, string supportedMediaType)
- {
- if (supportedContentType == contentType)
- return true;
- if (contentType.Length > supportedContentType.Length &&
- contentType.StartsWith(supportedContentType, StringComparison.Ordinal) &&
- contentType[supportedContentType.Length] == ';')
- return true;
- // now check case-insensitively
- if (contentType.StartsWith(supportedContentType, StringComparison.OrdinalIgnoreCase))
- {
- if (contentType.Length == supportedContentType.Length)
- {
- return true;
- }
- else if (contentType.Length > supportedContentType.Length)
- {
- char ch = contentType[supportedContentType.Length];
- // Linear Whitespace is allowed to appear between the end of one property and the semicolon.
- // LWS = [CRLF]? (SP | HT)+
- if (ch == ';')
- {
- return true;
- }
- // Consume the [CRLF]?
- int i = supportedContentType.Length;
- if (ch == '\r' && contentType.Length > supportedContentType.Length + 1 && contentType[i + 1] == '\n')
- {
- i += 2;
- ch = contentType[i];
- }
- // Look for a ';' or nothing after (SP | HT)+
- if (ch == ' ' || ch == '\t')
- {
- i++;
- while (i < contentType.Length)
- {
- ch = contentType[i];
- if (ch != ' ' && ch != '\t')
- break;
- ++i;
- }
- }
- if (ch == ';' || i == contentType.Length)
- return true;
- }
- }
- // sometimes we get a contentType that has parameters, but our encoders
- // merely expose the base content-type, so we will check a stripped version
- try
- {
- ContentType parsedContentType = new ContentType(contentType);
- if (supportedMediaType.Length > 0 && !supportedMediaType.Equals(parsedContentType.MediaType, StringComparison.OrdinalIgnoreCase))
- return false;
- if (!IsCharSetSupported(parsedContentType.CharSet))
- return false;
- }
- catch (FormatException)
- {
- // bad content type, so we definitely don't support it!
- return false;
- }
- return true;
- }
- internal virtual bool IsCharSetSupported(string charset)
- {
- return false;
- }
- internal void ThrowIfMismatchedMessageVersion(Message message)
- {
- if (message.Version != MessageVersion)
- {
- throw TraceUtility.ThrowHelperError(
- new ProtocolException(SR.GetString(SR.EncoderMessageVersionMismatch, message.Version, MessageVersion)),
- message);
- }
- }
- internal string GetTraceSourceString()
- {
- if (this.traceSourceString == null)
- {
- this.traceSourceString = DiagnosticTraceBase.CreateDefaultSourceString(this);
- }
- return this.traceSourceString;
- }
- class WriteMessageAsyncResult : ScheduleActionItemAsyncResult
- {
- MessageEncoder encoder;
- Message message;
- Stream stream;
- public WriteMessageAsyncResult(Message message, Stream stream, MessageEncoder encoder, AsyncCallback callback, object state)
- : base(callback, state)
- {
- Fx.Assert(encoder != null, "encoder should never be null");
- this.encoder = encoder;
- this.message = message;
- this.stream = stream;
- Schedule();
- }
- protected override void OnDoWork()
- {
- this.encoder.WriteMessage(this.message, this.stream);
- }
- }
- }
- }
|