PageRenderTime 25ms CodeModel.GetById 14ms app.highlight 7ms RepoModel.GetById 2ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.ApplicationServer.Http/Microsoft/ApplicationServer/Http/Channels/HttpMessageEncoderFactory.cs

#
C# | 342 lines | 219 code | 52 blank | 71 comment | 29 complexity | a480a26a5a2c4c6a1dc45835544a5137 MD5 | raw file
  1// <copyright>
  2//   Copyright (c) Microsoft Corporation.  All rights reserved.
  3// </copyright>
  4
  5namespace Microsoft.ApplicationServer.Http.Channels
  6{
  7    using System;
  8    using System.IO;
  9    using System.Net.Http;
 10    using System.ServiceModel;
 11    using System.ServiceModel.Channels;
 12    using Microsoft.Server.Common;
 13    using Microsoft.ServiceModel.Channels;
 14
 15    // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available
 16    //// using SMTD = System.ServiceModel.Diagnostics.Application.TD;
 17    //// using WebTD = System.ServiceModel.Web.Diagnostics.Application.TD;
 18
 19    internal class HttpMessageEncoderFactory : MessageEncoderFactory
 20    {
 21        private HttpMessageEncoder encoder;
 22
 23        public HttpMessageEncoderFactory()
 24        {
 25            this.encoder = new HttpMessageEncoder();
 26        }
 27
 28        public override MessageEncoder Encoder
 29        {
 30            get
 31            {
 32                return this.encoder;
 33            }
 34        }
 35
 36        public override MessageVersion MessageVersion
 37        {
 38            get
 39            {
 40                return MessageVersion.None;
 41            }
 42        }
 43
 44        public override MessageEncoder CreateSessionEncoder()
 45        {
 46            throw Fx.Exception.AsError(
 47                new NotSupportedException(
 48                    Http.SR.HttpMessageEncoderFactoryDoesNotSupportSessionEncoder(typeof(HttpMessageEncoderFactory))));
 49        }
 50
 51        private class HttpMessageEncoder : MessageEncoder
 52        {
 53            private const string ContentTypeHeaderName = "Content-Type";
 54            private const string MaxSentMessageSizeExceededResourceStringName = "MaxSentMessageSizeExceeded";
 55            private static readonly string httpBindingClassName = typeof(HttpBinding).FullName;
 56            private static readonly string httpResponseMessageClassName = typeof(HttpResponseMessage).FullName;
 57
 58            public override string ContentType
 59            {
 60                get
 61                {
 62                    return string.Empty;
 63                }
 64            }
 65
 66            public override string MediaType
 67            {
 68                get
 69                {
 70                    return string.Empty;
 71                }
 72            }
 73
 74            public override MessageVersion MessageVersion
 75            {
 76                get
 77                {
 78                    return MessageVersion.None;
 79                }
 80            }
 81
 82            public override bool IsContentTypeSupported(string contentType)
 83            {
 84                if (contentType == null)
 85                {
 86                    throw Fx.Exception.ArgumentNull("contentType");
 87                }
 88
 89                return true;
 90            }
 91
 92            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "disposed later.")]
 93            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
 94            {
 95                if (bufferManager == null)
 96                {
 97                    throw Fx.Exception.ArgumentNull("bufferManager");
 98                }
 99
100                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
101                //// if (WebTD.HttpMessageDecodingStartIsEnabled())
102                //// {
103                ////     WebTD.HttpMessageDecodingStart();
104                //// }
105
106                HttpRequestMessage request = new HttpRequestMessage();
107                request.Content = new ByteArrayBufferManagerContent(bufferManager, buffer.Array, buffer.Offset, buffer.Count);
108                if (!string.IsNullOrEmpty(contentType))
109                {
110                    request.Content.Headers.Add(ContentTypeHeaderName, contentType);
111                }
112
113                Message message = request.ToMessage();
114                message.Properties.Encoder = this;
115
116                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
117                //// if (TD.MessageReadByEncoderIsEnabled() && buffer != null)
118                //// {
119                ////     TD.MessageReadByEncoder(
120                ////             EventTraceActivityHelper.TryExtractActivity(message, true),
121                ////             buffer.Count,
122                ////             this);
123                //// }
124
125                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
126                //// if (MessageLogger.LogMessagesAtTransportLevel)
127                //// {
128                ////     MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
129                //// }
130
131                return message;
132            }
133
134            [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope", Justification = "disposed later.")]
135            public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType)
136            {
137                if (stream == null)
138                {
139                    throw Fx.Exception.ArgumentNull("stream");
140                }
141
142                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
143                //// if (WebTD.HttpMessageDecodingStartIsEnabled())
144                //// {
145                ////     WebTD.HttpMessageDecodingStart();
146                //// }
147
148                HttpRequestMessage request = new HttpRequestMessage();
149                request.Content = new StreamContent(stream);
150                if (!string.IsNullOrEmpty(contentType))
151                {
152                    request.Content.Headers.Add(ContentTypeHeaderName, contentType);
153                }
154
155                Message message = request.ToMessage();
156                message.Properties.Encoder = this;
157
158                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
159                //// if (TD.StreamedMessageReadByEncoderIsEnabled())
160                //// {
161                ////     TD.StreamedMessageReadByEncoder(EventTraceActivityHelper.TryExtractActivity(message, true));
162                //// }
163
164                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
165                //// if (MessageLogger.LogMessagesAtTransportLevel)
166                //// {
167                ////     MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportReceive);
168                //// }
169
170                return message;
171            }
172
173            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset)
174            {
175                if (message == null)
176                {
177                    throw Fx.Exception.ArgumentNull("message");
178                }
179
180                if (bufferManager == null)
181                {
182                    throw Fx.Exception.ArgumentNull("bufferManager");
183                }
184
185                if (maxMessageSize < 0)
186                {
187                    throw Fx.Exception.AsError(new ArgumentOutOfRangeException("maxMessageSize"));
188                }
189
190                if (messageOffset < 0)
191                {
192                    throw Fx.Exception.AsError(new ArgumentOutOfRangeException("messageOffset"));
193                }
194
195                if (messageOffset > maxMessageSize)
196                {
197                    throw Fx.Exception.Argument(
198                        string.Empty,
199                        Http.SR.ParameterMustBeLessThanOrEqualSecondParameter("messageOffset", "maxMessageSize"));
200                }
201
202                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
203                //// EventTraceActivity eventTraceActivity = null;
204                //// if (WebTD.HttpMessagEncodingStartIsEnabled())
205                //// {
206                ////     eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
207                ////     WebTD.HttpMessagEncodingStart(eventTraceActivity);
208                //// }
209
210                using (BufferManagerOutputStream stream = new BufferManagerOutputStream(MaxSentMessageSizeExceededResourceStringName, 0, maxMessageSize, bufferManager))
211                {
212                    int num;
213                    stream.Skip(messageOffset);
214                    this.WriteMessage(message, stream);
215                    ArraySegment<byte> messageData = new ArraySegment<byte>(stream.ToArray(out num), 0, num - messageOffset);
216                    
217                    // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
218                    //// if (SMTD.MessageWrittenByEncoderIsEnabled() && messageData != null)
219                    //// {
220                    ////     SMTD.MessageWrittenByEncoder(
221                    ////             eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message),
222                    ////             messageData.Count,
223                    ////             this);
224                    //// }
225
226                    return messageData;
227                }
228            }
229
230            public override void WriteMessage(Message message, Stream stream)
231            {
232                if (message == null)
233                {
234                    throw Fx.Exception.ArgumentNull("message");
235                }
236
237                if (stream == null)
238                {
239                    throw Fx.Exception.ArgumentNull("stream");
240                }
241
242                this.ThrowIfMismatchedMessageVersion(message);
243
244                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
245                //// EventTraceActivity eventTraceActivity = null;
246                //// if (WebTD.HttpMessagEncodingStartIsEnabled())
247                //// {
248                ////     eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(message);
249                ////     WebTD.HttpMessagEncodingStart(eventTraceActivity);
250                //// }
251
252                message.Properties.Encoder = this;
253
254                HttpResponseMessage response = GetHttpResponseMessageOrThrow(message);
255
256                if (response.Content != null)
257                {
258                    response.Content.CopyToAsync(stream).Wait();
259                }
260
261                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
262                //// if (SMTD.StreamedMessageWrittenByEncoderIsEnabled())
263                //// {
264                ////     SMTD.StreamedMessageWrittenByEncoder(eventTraceActivity ?? EventTraceActivityHelper.TryExtractActivity(message));
265                //// }
266
267                // TODO: CSDMAIN 205175 -- reactivate when tracing and logging are available:
268                //// if (MessageLogger.LogMessagesAtTransportLevel)
269                //// {
270                ////     MessageLogger.LogMessage(ref message, MessageLoggingSource.TransportSend);
271                //// }
272            }
273
274            internal void ThrowIfMismatchedMessageVersion(Message message)
275            {
276                if (message.Version != MessageVersion)
277                {
278                    throw Fx.Exception.AsError(
279                        new ProtocolException(
280                            Http.SR.EncoderMessageVersionMismatch(message.Version, MessageVersion)));
281                }
282            }
283
284            private static HttpResponseMessage GetHttpResponseMessageOrThrow(Message message)
285            {
286                HttpResponseMessage response = message.ToHttpResponseMessage();
287                if (response == null)
288                {
289                    throw Fx.Exception.AsError(
290                        new InvalidOperationException(
291                            Http.SR.MessageInvalidForHttpMessageEncoder(
292                                httpBindingClassName,
293                                HttpMessageExtensionMethods.ToMessageMethodName,
294                                httpResponseMessageClassName)));
295                }
296
297                return response;
298            }
299
300            private class ByteArrayBufferManagerContent : ByteArrayContent
301            {
302                private bool disposed;
303                private BufferManager bufferManager;
304                private byte[] content;
305                private object disposingLock;
306
307                public ByteArrayBufferManagerContent(BufferManager bufferManager, byte[] content, int offset, int count)
308                    : base(content, offset, count)
309                {
310                    Fx.Assert(bufferManager != null, "The 'bufferManager' parameter should never be null.");
311
312                    this.bufferManager = bufferManager;
313                    this.content = content;
314                    this.disposingLock = new object();
315                }
316
317                protected override void Dispose(bool disposing)
318                {
319                    try
320                    {
321                        if (disposing && !this.disposed)
322                        {
323                            lock (this.disposingLock)
324                            {
325                                if (!this.disposed)
326                                {
327                                    this.disposed = true;
328                                    this.bufferManager.ReturnBuffer(this.content);
329                                    this.content = null;
330                                }
331                            }
332                        }
333                    }
334                    finally
335                    {
336                        base.Dispose(disposing);
337                    }
338                }
339            }
340        }
341    }
342}