Xamarin Public Jenkins (auto-signing) 94b2861243 Imported Upstream version 4.8.0.309
Former-commit-id: 5f9c6ae75f295e057a7d2971f3a6df4656fa8850
2016-11-10 13:04:39 +00:00

212 lines
6.8 KiB
C#

//
// WebMessageEncoder.cs
//
// Author:
// Atsushi Enomoto <atsushi@ximian.com>
//
// Copyright (C) 2008 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Dispatcher;
using System.Text;
using System.Xml;
namespace System.ServiceModel.Channels
{
internal class WebMessageEncoder : MessageEncoder
{
internal const string ScriptPropertyName = "618BC2B0-38AA-21A3-DB4A-404FC87B9B11"; // randomly generated
WebMessageEncodingBindingElement source;
public WebMessageEncoder (WebMessageEncodingBindingElement source)
{
this.source = source;
}
public override string ContentType {
#if MOBILE
get { return MediaType; }
#else
get { return MediaType + "; charset=" + source.WriteEncoding.HeaderName; }
#endif
}
// FIXME: find out how it can be customized.
public override string MediaType {
get { return "application/xml"; }
}
public override MessageVersion MessageVersion {
get { return MessageVersion.None; }
}
public override bool IsContentTypeSupported (string contentType)
{
if (contentType == null)
throw new ArgumentNullException ("contentType");
return true; // anything is accepted.
}
public override Message ReadMessage (ArraySegment<byte> buffer, BufferManager bufferManager, string contentType)
{
throw new NotImplementedException ();
}
public override Message ReadMessage (Stream stream, int maxSizeOfHeaders, string contentType)
{
if (stream == null)
throw new ArgumentNullException ("stream");
contentType = contentType ?? "application/octet-stream";
Encoding enc = Encoding.UTF8;
var ct = new System.Net.Mime.ContentType (contentType);
if (ct.CharSet != null)
enc = Encoding.GetEncoding (ct.CharSet);
WebContentFormat fmt = WebContentFormat.Xml;
if (source.ContentTypeMapper != null)
fmt = source.ContentTypeMapper.GetMessageFormatForContentType (contentType);
else {
switch (ct.MediaType) {
case "application/json":
fmt = WebContentFormat.Json;
break;
case "application/xml":
fmt = WebContentFormat.Xml;
break;
default:
fmt = WebContentFormat.Raw;
break;
}
}
Message msg = null;
WebBodyFormatMessageProperty wp = null;
switch (fmt) {
case WebContentFormat.Xml:
// FIXME: is it safe/unsafe/required to keep XmlReader open?
msg = Message.CreateMessage (MessageVersion.None, null, XmlReader.Create (new StreamReader (stream, enc)));
wp = new WebBodyFormatMessageProperty (WebContentFormat.Xml);
break;
case WebContentFormat.Json:
// FIXME: is it safe/unsafe/required to keep XmlReader open?
#if MOBILE
msg = Message.CreateMessage (MessageVersion.None, null, JsonReaderWriterFactory.CreateJsonReader (stream, source.ReaderQuotas));
#else
msg = Message.CreateMessage (MessageVersion.None, null, JsonReaderWriterFactory.CreateJsonReader (stream, enc, source.ReaderQuotas, null));
#endif
wp = new WebBodyFormatMessageProperty (WebContentFormat.Json);
break;
case WebContentFormat.Raw:
msg = new WebMessageFormatter.RawMessage (stream);
wp = new WebBodyFormatMessageProperty (WebContentFormat.Raw);
break;
default:
throw new SystemException ("INTERNAL ERROR: cannot determine content format");
}
if (wp != null)
msg.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
msg.Properties.Encoder = this;
return msg;
}
WebContentFormat GetContentFormat (Message message)
{
string name = WebBodyFormatMessageProperty.Name;
if (message.Properties.ContainsKey (name))
return ((WebBodyFormatMessageProperty) message.Properties [name]).Format;
switch (MediaType) {
case "application/xml":
case "text/xml":
return WebContentFormat.Xml;
case "application/json":
case "text/json":
return WebContentFormat.Json;
case "application/octet-stream":
return WebContentFormat.Raw;
default:
return WebContentFormat.Default;
}
}
public override void WriteMessage (Message message, Stream stream)
{
if (message == null)
throw new ArgumentNullException ("message");
// Handle /js and /jsdebug as the special cases.
var script = message.Properties [ScriptPropertyName] as string;
if (script != null) {
var bytes = source.WriteEncoding.GetBytes (script);
stream.Write (bytes, 0, bytes.Length);
return;
}
if (!MessageVersion.Equals (message.Version))
throw new ProtocolException (String.Format ("MessageVersion {0} is not supported", message.Version));
if (stream == null)
throw new ArgumentNullException ("stream");
switch (GetContentFormat (message)) {
case WebContentFormat.Xml:
#if MOBILE
using (XmlWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (new StreamWriter (stream, source.WriteEncoding))))
message.WriteMessage (w);
#else
using (XmlWriter w = XmlDictionaryWriter.CreateTextWriter (stream, source.WriteEncoding, false))
message.WriteMessage (w);
#endif
break;
case WebContentFormat.Json:
using (XmlWriter w = JsonReaderWriterFactory.CreateJsonWriter (stream, source.WriteEncoding, false))
message.WriteMessage (w);
break;
case WebContentFormat.Raw:
var rmsg = (WebMessageFormatter.RawMessage) message;
var src = rmsg.Stream;
if (src == null) // null output
break;
int len = 0;
byte [] buffer = new byte [4096];
while ((len = src.Read (buffer, 0, buffer.Length)) > 0)
stream.Write (buffer, 0, len);
break;
case WebContentFormat.Default:
throw new SystemException ("INTERNAL ERROR: cannot determine content format");
}
}
public override ArraySegment<byte> WriteMessage (Message message, int maxMessageSize, BufferManager bufferManager,
int messageOffset)
{
throw new NotImplementedException ();
}
}
}