2 // WebMessageEncoder.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System
.Net
.Mime
;
31 using System
.Runtime
.Serialization
.Json
;
32 using System
.ServiceModel
;
33 using System
.ServiceModel
.Dispatcher
;
37 namespace System
.ServiceModel
.Channels
39 internal class WebMessageEncoder
: MessageEncoder
41 internal const string ScriptPropertyName
= "618BC2B0-38AA-21A3-DB4A-404FC87B9B11"; // randomly generated
43 WebMessageEncodingBindingElement source
;
45 public WebMessageEncoder (WebMessageEncodingBindingElement source
)
50 public override string ContentType
{
52 get { return MediaType; }
54 get { return MediaType + "; charset=" + source.WriteEncoding.HeaderName; }
58 // FIXME: find out how it can be customized.
59 public override string MediaType
{
60 get { return "application/xml"; }
63 public override MessageVersion MessageVersion
{
64 get { return MessageVersion.None; }
67 public override Message
ReadMessage (ArraySegment
<byte> buffer
, BufferManager bufferManager
, string contentType
)
69 throw new NotImplementedException ();
72 public override Message
ReadMessage (Stream stream
, int maxSizeOfHeaders
, string contentType
)
75 throw new ArgumentNullException ("stream");
77 contentType
= contentType
?? "application/octet-stream";
79 Encoding enc
= Encoding
.UTF8
;
80 ContentType ct
= new ContentType (contentType
);
81 if (ct
.CharSet
!= null)
82 enc
= Encoding
.GetEncoding (ct
.CharSet
);
84 WebContentFormat fmt
= WebContentFormat
.Xml
;
85 if (source
.ContentTypeMapper
!= null)
86 fmt
= source
.ContentTypeMapper
.GetMessageFormatForContentType (contentType
);
88 switch (ct
.MediaType
) {
89 case "application/json":
90 fmt
= WebContentFormat
.Json
;
92 case "application/xml":
93 fmt
= WebContentFormat
.Xml
;
96 fmt
= WebContentFormat
.Raw
;
102 WebBodyFormatMessageProperty wp
= null;
104 case WebContentFormat
.Xml
:
105 // FIXME: is it safe/unsafe/required to keep XmlReader open?
106 msg
= Message
.CreateMessage (MessageVersion
.None
, null, XmlReader
.Create (new StreamReader (stream
, enc
)));
107 wp
= new WebBodyFormatMessageProperty (WebContentFormat
.Xml
);
109 case WebContentFormat
.Json
:
110 // FIXME: is it safe/unsafe/required to keep XmlReader open?
112 msg
= Message
.CreateMessage (MessageVersion
.None
, null, JsonReaderWriterFactory
.CreateJsonReader (stream
, source
.ReaderQuotas
));
114 msg
= Message
.CreateMessage (MessageVersion
.None
, null, JsonReaderWriterFactory
.CreateJsonReader (stream
, enc
, source
.ReaderQuotas
, null));
116 wp
= new WebBodyFormatMessageProperty (WebContentFormat
.Json
);
118 case WebContentFormat
.Raw
:
119 msg
= new WebMessageFormatter
.RawMessage (stream
);
120 wp
= new WebBodyFormatMessageProperty (WebContentFormat
.Raw
);
123 throw new SystemException ("INTERNAL ERROR: cannot determine content format");
126 msg
.Properties
.Add (WebBodyFormatMessageProperty
.Name
, wp
);
130 WebContentFormat
GetContentFormat (Message message
)
132 string name
= WebBodyFormatMessageProperty
.Name
;
133 if (message
.Properties
.ContainsKey (name
))
134 return ((WebBodyFormatMessageProperty
) message
.Properties
[name
]).Format
;
137 case "application/xml":
139 return WebContentFormat
.Xml
;
140 case "application/json":
142 return WebContentFormat
.Json
;
143 case "application/octet-stream":
144 return WebContentFormat
.Raw
;
146 return WebContentFormat
.Default
;
150 public override void WriteMessage (Message message
, Stream stream
)
153 throw new ArgumentNullException ("message");
155 // Handle /js and /jsdebug as the special cases.
156 var script
= message
.Properties
[ScriptPropertyName
] as string;
157 if (script
!= null) {
158 var bytes
= source
.WriteEncoding
.GetBytes (script
);
159 stream
.Write (bytes
, 0, bytes
.Length
);
163 if (!MessageVersion
.Equals (message
.Version
))
164 throw new ProtocolException (String
.Format ("MessageVersion {0} is not supported", message
.Version
));
166 throw new ArgumentNullException ("stream");
168 switch (GetContentFormat (message
)) {
169 case WebContentFormat
.Xml
:
171 using (XmlWriter w
= XmlDictionaryWriter
.CreateDictionaryWriter (XmlWriter
.Create (new StreamWriter (stream
, source
.WriteEncoding
))))
172 message
.WriteMessage (w
);
174 using (XmlWriter w
= XmlDictionaryWriter
.CreateTextWriter (stream
, source
.WriteEncoding
))
175 message
.WriteMessage (w
);
178 case WebContentFormat
.Json
:
179 using (XmlWriter w
= JsonReaderWriterFactory
.CreateJsonWriter (stream
, source
.WriteEncoding
))
180 message
.WriteMessage (w
);
182 case WebContentFormat
.Raw
:
183 var rmsg
= (WebMessageFormatter
.RawMessage
) message
;
184 var src
= rmsg
.Stream
;
185 if (src
== null) // null output
189 byte [] buffer
= new byte [4096];
190 while ((len
= src
.Read (buffer
, 0, buffer
.Length
)) > 0)
191 stream
.Write (buffer
, 0, len
);
193 case WebContentFormat
.Default
:
194 throw new SystemException ("INTERNAL ERROR: cannot determine content format");
198 public override ArraySegment
<byte> WriteMessage (Message message
, int maxMessageSize
, BufferManager bufferManager
,
201 throw new NotImplementedException ();