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