< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Channels.WebMessageEncoderFactory
Assembly: CoreWCF.WebHttp
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.WebHttp/src/CoreWCF/Channels/WebMessageEncoderFactory.cs
Line coverage
68%
Covered lines: 102
Uncovered lines: 47
Coverable lines: 149
Total lines: 425
Line coverage: 68.4%
Branch coverage
57%
Covered branches: 47
Total branches: 82
Branch coverage: 57.3%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
GetContentType(...)50%2275%
.ctor(...)50%2292.3%
IsContentTypeSupported(...)50%101066.66%
ReadMessage(...)66.66%6685.71%
ReadMessageAsync()50%6666.66%
WriteMessage(...)57.14%141456.25%
WriteMessageAsync()0%880%
IsCharSetSupported(...)100%110%
ExtractFormatFromMessage(...)66.66%6685.71%
GetFormatForContentType(...)80%101090.9%
TryGetContentTypeMapping(...)16.66%6623.07%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.WebHttp/src/CoreWCF/Channels/WebMessageEncoderFactory.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Globalization;
 6using System.IO;
 7using System.Text;
 8using System.Threading.Tasks;
 9using System.Xml;
 10using CoreWCF.Runtime;
 11
 12namespace CoreWCF.Channels
 13{
 14    public class WebMessageEncoderFactory : MessageEncoderFactory
 15    {
 16        private readonly WebMessageEncoder _messageEncoder;
 17
 4018        public WebMessageEncoderFactory(Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, XmlDictionary
 19        {
 4020            _messageEncoder = new WebMessageEncoder(writeEncoding, maxReadPoolSize, maxWritePoolSize, quotas, contentTyp
 4021        }
 22
 10823        public override MessageEncoder Encoder => _messageEncoder;
 24
 025        public override MessageVersion MessageVersion => _messageEncoder.MessageVersion;
 26
 27        internal static string GetContentType(string mediaType, Encoding encoding)
 28        {
 7229            string charset = TextEncoderDefaults.EncodingToCharSet(encoding);
 7230            if (!string.IsNullOrEmpty(charset))
 31            {
 7232                return string.Format(CultureInfo.InvariantCulture, "{0}; charset={1}", mediaType, charset);
 33            }
 34
 035            return mediaType;
 36        }
 37
 38        internal class WebMessageEncoder : MessageEncoder
 39        {
 40            private const string DefaultMediaType = "application/xml";
 41            private readonly WebContentTypeMapper _contentTypeMapper;
 42            private readonly string _defaultContentType;
 43
 44            // Double-checked locking pattern requires volatile for read/write synchronization
 45            private volatile MessageEncoder _jsonMessageEncoder;
 46            private readonly int _maxReadPoolSize;
 47            private readonly int _maxWritePoolSize;
 48
 49            // Double-checked locking pattern requires volatile for read/write synchronization
 50            private volatile MessageEncoder _rawMessageEncoder;
 51            private readonly XmlDictionaryReaderQuotas _readerQuotas;
 52
 53            // Double-checked locking pattern requires volatile for read/write synchronization
 54            private volatile MessageEncoder _textMessageEncoder;
 55            private readonly Encoding _writeEncoding;
 56            //bool javascriptCallbackEnabled;
 57
 4058            public WebMessageEncoder(Encoding writeEncoding, int maxReadPoolSize, int maxWritePoolSize, XmlDictionaryRea
 59            {
 4060                if (writeEncoding == null)
 61                {
 062                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(writeEncoding));
 63                }
 64
 4065                ThisLock = new object();
 66
 4067                TextEncoderDefaults.ValidateEncoding(writeEncoding);
 4068                _writeEncoding = writeEncoding;
 69
 4070                _maxReadPoolSize = maxReadPoolSize;
 4071                _maxWritePoolSize = maxWritePoolSize;
 4072                _contentTypeMapper = contentTypeMapper;
 73                //this.javascriptCallbackEnabled = javascriptCallbackEnabled;
 74
 4075                _readerQuotas = new XmlDictionaryReaderQuotas();
 4076                quotas.CopyTo(_readerQuotas);
 77
 4078                _defaultContentType = GetContentType(DefaultMediaType, writeEncoding);
 4079            }
 80
 581            public override string ContentType => _defaultContentType;
 82
 083            public override string MediaType => DefaultMediaType;
 84
 5885            public override MessageVersion MessageVersion => MessageVersion.None;
 86
 87            private MessageEncoder JsonMessageEncoder
 88            {
 89                get
 90                {
 3991                    if (_jsonMessageEncoder == null)
 92                    {
 2993                        lock (ThisLock)
 94                        {
 2995                            if (_jsonMessageEncoder == null)
 96                            {
 2997                                _jsonMessageEncoder = new JsonMessageEncoderFactory(_writeEncoding, _maxReadPoolSize, _m
 98                            }
 2999                        }
 100                    }
 101
 39102                    return _jsonMessageEncoder;
 103                }
 104            }
 105
 106            private MessageEncoder RawMessageEncoder
 107            {
 108                get
 109                {
 46110                    if (_rawMessageEncoder == null)
 111                    {
 33112                        lock (ThisLock)
 113                        {
 33114                            if (_rawMessageEncoder == null)
 115                            {
 33116                                var bsmebe = new ByteStreamMessageEncodingBindingElement(_readerQuotas);
 117                                // Backdoor method to do the equivalent of calling IWebMessageEncoderHelper.EnableBodyRe
 33118                                _ = bsmebe.GetProperty<WebMessageEncoder>(new BindingContext(new CustomBinding(), new Bi
 33119                                _rawMessageEncoder = bsmebe.CreateMessageEncoderFactory().Encoder;
 120                            }
 33121                        }
 122                    }
 123
 46124                    return _rawMessageEncoder;
 125                }
 126            }
 127
 128            private MessageEncoder TextMessageEncoder
 129            {
 130                get
 131                {
 7132                    if (_textMessageEncoder == null)
 133                    {
 4134                        lock (ThisLock)
 135                        {
 4136                            if (_textMessageEncoder == null)
 137                            {
 4138                                TextMessageEncodingBindingElement textBindingElement = new TextMessageEncodingBindingEle
 4139                                {
 4140                                    MaxReadPoolSize = _maxReadPoolSize,
 4141                                    MaxWritePoolSize = _maxWritePoolSize,
 4142                                };
 4143                                _readerQuotas.CopyTo(textBindingElement.ReaderQuotas);
 4144                                _textMessageEncoder = textBindingElement.CreateMessageEncoderFactory().Encoder;
 145                            }
 4146                        }
 147                    }
 148
 7149                    return _textMessageEncoder;
 150                }
 151            }
 152
 66153            private object ThisLock { get; }
 154
 155            public override bool IsContentTypeSupported(string contentType)
 156            {
 38157                if (contentType == null)
 158                {
 0159                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(contentType));
 160                }
 161
 38162                if (TryGetContentTypeMapping(contentType, out WebContentFormat messageFormat) &&
 38163                    (messageFormat != WebContentFormat.Default))
 164                {
 0165                    return true;
 166                }
 167
 38168                return RawMessageEncoder.IsContentTypeSupported(contentType) || JsonMessageEncoder.IsContentTypeSupporte
 169            }
 170
 171            public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentTy
 172            {
 9173                if (bufferManager == null)
 174                {
 0175                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(bufferMan
 176                }
 177
 9178                WebContentFormat format = GetFormatForContentType(contentType);
 179                Message message;
 180
 181                switch (format)
 182                {
 183                    case WebContentFormat.Json:
 6184                        message = JsonMessageEncoder.ReadMessage(buffer, bufferManager, contentType);
 6185                        message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.JsonPrope
 6186                        break;
 187                    case WebContentFormat.Xml:
 1188                        message = TextMessageEncoder.ReadMessage(buffer, bufferManager, contentType);
 1189                        message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProper
 1190                        break;
 191                    case WebContentFormat.Raw:
 2192                        message = RawMessageEncoder.ReadMessage(buffer, bufferManager, contentType);
 2193                        message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProper
 2194                        break;
 195                    default:
 0196                        throw Fx.AssertAndThrow("This should never get hit because GetFormatForContentType shouldn't ret
 197                }
 198
 9199                return message;
 200            }
 201
 202            public override async Task<Message> ReadMessageAsync(Stream stream, int maxSizeOfHeaders, string contentType
 203            {
 2204                if (stream == null)
 205                {
 0206                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(stream)))
 207                }
 208
 2209                WebContentFormat format = GetFormatForContentType(contentType);
 210                Message message;
 211                switch (format)
 212                {
 213                    case WebContentFormat.Json:
 0214                        message = await JsonMessageEncoder.ReadMessageAsync(stream, maxSizeOfHeaders, contentType);
 0215                        message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.JsonPrope
 0216                        break;
 217                    case WebContentFormat.Xml:
 1218                        message = await TextMessageEncoder.ReadMessageAsync(stream, maxSizeOfHeaders, contentType);
 1219                        message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.XmlProper
 1220                        break;
 221                    case WebContentFormat.Raw:
 1222                        message = await RawMessageEncoder.ReadMessageAsync(stream, maxSizeOfHeaders, contentType);
 1223                        message.Properties.Add(WebBodyFormatMessageProperty.Name, WebBodyFormatMessageProperty.RawProper
 1224                        break;
 225                    default:
 0226                        throw Fx.AssertAndThrow("This should never get hit because GetFormatForContentType shouldn't ret
 227                }
 2228                return message;
 2229            }
 230
 231            public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferMan
 232            {
 31233                if (message == null)
 234                {
 0235                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(message))
 236                }
 237
 31238                if (bufferManager == null)
 239                {
 0240                    throw TraceUtility.ThrowHelperError(new ArgumentNullException(nameof(bufferManager)), message);
 241                }
 242
 31243                if (maxMessageSize < 0)
 244                {
 0245                    throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(maxMessageSize), maxMessa
 0246                        SR.Format(SRCommon.ValueMustBeNonNegative)), message);
 247                }
 248
 31249                if (messageOffset < 0 || messageOffset > maxMessageSize)
 250                {
 0251                    throw TraceUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(messageOffset), messageOf
 0252                        SR.Format(SR.JsonValueMustBeInRange, 0, maxMessageSize)), message);
 253                }
 254
 31255                ThrowIfMismatchedMessageVersion(message);
 256
 31257                WebContentFormat messageFormat = ExtractFormatFromMessage(message);
 258                //JavascriptCallbackResponseMessageProperty javascriptResponseMessageProperty;
 259                switch (messageFormat)
 260                {
 261                    case WebContentFormat.Json:
 24262                        return JsonMessageEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
 263                    case WebContentFormat.Xml:
 264                        //if (message.Properties.TryGetValue<JavascriptCallbackResponseMessageProperty>(JavascriptCallba
 265                        //    javascriptResponseMessageProperty != null &&
 266                        //    !String.IsNullOrEmpty(javascriptResponseMessageProperty.CallbackFunctionName))
 267                        //{
 268                        //    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.JavascriptCallbackNot
 269                        //}
 2270                        return TextMessageEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
 271                    case WebContentFormat.Raw:
 272                        //if (message.Properties.TryGetValue<JavascriptCallbackResponseMessageProperty>(JavascriptCallba
 273                        //    javascriptResponseMessageProperty != null &&
 274                        //    !String.IsNullOrEmpty(javascriptResponseMessageProperty.CallbackFunctionName))
 275                        //{
 276                        //    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.JavascriptCallbackNot
 277                        //}
 5278                        return RawMessageEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset);
 279                    default:
 0280                        throw Fx.AssertAndThrow("This should never get hit because GetFormatForContentType shouldn't ret
 281                }
 282            }
 283
 284            public override async Task WriteMessageAsync(Message message, Stream stream)
 285            {
 0286                if (message == null)
 287                {
 0288                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(message))
 289                }
 290
 0291                if (stream == null)
 292                {
 0293                    throw TraceUtility.ThrowHelperError(new ArgumentNullException("stream"), message);
 294                }
 295
 0296                ThrowIfMismatchedMessageVersion(message);
 297
 0298                WebContentFormat messageFormat = ExtractFormatFromMessage(message);
 299                //JavascriptCallbackResponseMessageProperty javascriptResponseMessageProperty;
 300                switch (messageFormat)
 301                {
 302                    case WebContentFormat.Json:
 0303                        await JsonMessageEncoder.WriteMessageAsync(message, stream);
 0304                        break;
 305                    case WebContentFormat.Xml:
 306                        //if (message.Properties.TryGetValue<JavascriptCallbackResponseMessageProperty>(JavascriptCallba
 307                        //    javascriptResponseMessageProperty != null &&
 308                        //    !string.IsNullOrEmpty(javascriptResponseMessageProperty.CallbackFunctionName))
 309                        //{
 310                        //    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.JavascriptCallbackNot
 311                        //}
 0312                        await TextMessageEncoder.WriteMessageAsync(message, stream);
 0313                        break;
 314                    case WebContentFormat.Raw:
 315                        //if (message.Properties.TryGetValue<JavascriptCallbackResponseMessageProperty>(JavascriptCallba
 316                        //    javascriptResponseMessageProperty != null &&
 317                        //    !string.IsNullOrEmpty(javascriptResponseMessageProperty.CallbackFunctionName))
 318                        //{
 319                        //    throw TraceUtility.ThrowHelperError(new InvalidOperationException(SR.JavascriptCallbackNot
 320                        //}
 0321                        await RawMessageEncoder.WriteMessageAsync(message, stream);
 0322                        break;
 323                    default:
 0324                        throw Fx.AssertAndThrow("This should never get hit because GetFormatForContentType shouldn't ret
 325                }
 0326            }
 327
 0328            protected override bool IsCharSetSupported(string charSet) => TextEncoderDefaults.TryGetEncoding(charSet, ou
 329
 330            private WebContentFormat ExtractFormatFromMessage(Message message)
 331            {
 31332                message.Properties.TryGetValue(WebBodyFormatMessageProperty.Name, out object messageFormatProperty);
 31333                if (messageFormatProperty == null)
 334                {
 2335                    return WebContentFormat.Xml;
 336                }
 337
 29338                if ((!(messageFormatProperty is WebBodyFormatMessageProperty typedMessageFormatProperty)) ||
 29339                    (typedMessageFormatProperty.Format == WebContentFormat.Default))
 340                {
 0341                    return WebContentFormat.Xml;
 342                }
 343
 29344                return typedMessageFormatProperty.Format;
 345            }
 346
 347            private WebContentFormat GetFormatForContentType(string contentType)
 348            {
 11349                if (TryGetContentTypeMapping(contentType, out WebContentFormat messageFormat) &&
 11350                    (messageFormat != WebContentFormat.Default))
 351                {
 352                    //if (DiagnosticUtility.ShouldTraceInformation)
 353                    //{
 354                    //    if (string.IsNullOrEmpty(contentType))
 355                    //    {
 356                    //        contentType = "<null>";
 357                    //    }
 358                    //    TraceUtility.TraceEvent(TraceEventType.Information,
 359                    //        TraceCode.RequestFormatSelectedFromContentTypeMapper,
 360                    //        SR.GetString(SR.TraceCodeRequestFormatSelectedFromContentTypeMapper, messageFormat.ToStrin
 361                    //}
 0362                    return messageFormat;
 363                }
 364
 365                // Don't pass on null content types to IsContentTypeSupported methods -- they might throw.
 366                // If null content type isn't already mapped, return the default format of Raw.
 367
 11368                if (contentType == null)
 369                {
 2370                    messageFormat = WebContentFormat.Raw;
 371                }
 9372                else if (JsonMessageEncoder.IsContentTypeSupported(contentType))
 373                {
 6374                    messageFormat = WebContentFormat.Json;
 375                }
 3376                else if (TextMessageEncoder.IsContentTypeSupported(contentType))
 377                {
 2378                    messageFormat = WebContentFormat.Xml;
 379                }
 380                else
 381                {
 1382                    messageFormat = WebContentFormat.Raw;
 383                }
 384
 385                //if (DiagnosticUtility.ShouldTraceInformation)
 386                //{
 387                //    TraceUtility.TraceEvent(TraceEventType.Information,
 388                //        TraceCode.RequestFormatSelectedByEncoderDefaults,
 389                //        SR.GetString(SR.TraceCodeRequestFormatSelectedByEncoderDefaults, messageFormat.ToString(), con
 390                //}
 391
 11392                return messageFormat;
 393            }
 394
 395           private bool TryGetContentTypeMapping(string contentType, out WebContentFormat format)
 396            {
 49397                if (_contentTypeMapper == null)
 398                {
 49399                    format = WebContentFormat.Default;
 49400                    return false;
 401                }
 402
 403                try
 404                {
 0405                    format = _contentTypeMapper.GetMessageFormatForContentType(contentType);
 0406                    if (!WebContentFormatHelper.IsDefined(format))
 407                    {
 0408                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.Unk
 409                    }
 0410                    return true;
 411                }
 0412                catch (Exception e)
 413                {
 0414                    if (Fx.IsFatal(e))
 415                    {
 0416                        throw;
 417                    }
 418
 0419                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new CommunicationException(
 0420                        SR.Format(SR.ErrorEncounteredInContentTypeMapper), e));
 421                }
 0422            }
 423        }
 424    }
 425}