2010-07-14 Atsushi Enomoto <atsushi@ximian.com>
[mono-project.git] / mcs / class / System.ServiceModel.Web / System.ServiceModel.Channels / WebMessageEncoder.cs
blob736ad0c6beba1413586f05fc1e41be80bd6af58b
1 //
2 // WebMessageEncoder.cs
3 //
4 // Author:
5 // Atsushi Enomoto <atsushi@ximian.com>
6 //
7 // Copyright (C) 2008 Novell, Inc (http://www.novell.com)
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
28 using System;
29 using System.IO;
30 using System.Net.Mime;
31 using System.Runtime.Serialization.Json;
32 using System.ServiceModel;
33 using System.ServiceModel.Dispatcher;
34 using System.Text;
35 using System.Xml;
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)
47 this.source = source;
50 public override string ContentType {
51 #if NET_2_1
52 get { return MediaType; }
53 #else
54 get { return MediaType + "; charset=" + source.WriteEncoding.HeaderName; }
55 #endif
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)
74 if (stream == null)
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);
87 else {
88 switch (ct.MediaType) {
89 case "application/json":
90 fmt = WebContentFormat.Json;
91 break;
92 case "application/xml":
93 fmt = WebContentFormat.Xml;
94 break;
95 default:
96 fmt = WebContentFormat.Raw;
97 break;
101 Message msg = null;
102 WebBodyFormatMessageProperty wp = null;
103 switch (fmt) {
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);
108 break;
109 case WebContentFormat.Json:
110 // FIXME: is it safe/unsafe/required to keep XmlReader open?
111 #if NET_2_1
112 msg = Message.CreateMessage (MessageVersion.None, null, JsonReaderWriterFactory.CreateJsonReader (stream, source.ReaderQuotas));
113 #else
114 msg = Message.CreateMessage (MessageVersion.None, null, JsonReaderWriterFactory.CreateJsonReader (stream, enc, source.ReaderQuotas, null));
115 #endif
116 wp = new WebBodyFormatMessageProperty (WebContentFormat.Json);
117 break;
118 case WebContentFormat.Raw:
119 msg = new WebMessageFormatter.RawMessage (stream);
120 wp = new WebBodyFormatMessageProperty (WebContentFormat.Raw);
121 break;
122 default:
123 throw new SystemException ("INTERNAL ERROR: cannot determine content format");
125 if (wp != null)
126 msg.Properties.Add (WebBodyFormatMessageProperty.Name, wp);
127 return msg;
130 WebContentFormat GetContentFormat (Message message)
132 string name = WebBodyFormatMessageProperty.Name;
133 if (message.Properties.ContainsKey (name))
134 return ((WebBodyFormatMessageProperty) message.Properties [name]).Format;
136 switch (MediaType) {
137 case "application/xml":
138 case "text/xml":
139 return WebContentFormat.Xml;
140 case "application/json":
141 case "text/json":
142 return WebContentFormat.Json;
143 case "application/octet-stream":
144 return WebContentFormat.Raw;
145 default:
146 return WebContentFormat.Default;
150 public override void WriteMessage (Message message, Stream stream)
152 if (message == null)
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);
160 return;
163 if (!MessageVersion.Equals (message.Version))
164 throw new ProtocolException (String.Format ("MessageVersion {0} is not supported", message.Version));
165 if (stream == null)
166 throw new ArgumentNullException ("stream");
168 switch (GetContentFormat (message)) {
169 case WebContentFormat.Xml:
170 #if NET_2_1
171 using (XmlWriter w = XmlDictionaryWriter.CreateDictionaryWriter (XmlWriter.Create (new StreamWriter (stream, source.WriteEncoding))))
172 message.WriteMessage (w);
173 #else
174 using (XmlWriter w = XmlDictionaryWriter.CreateTextWriter (stream, source.WriteEncoding))
175 message.WriteMessage (w);
176 #endif
177 break;
178 case WebContentFormat.Json:
179 using (XmlWriter w = JsonReaderWriterFactory.CreateJsonWriter (stream, source.WriteEncoding))
180 message.WriteMessage (w);
181 break;
182 case WebContentFormat.Raw:
183 var rmsg = (WebMessageFormatter.RawMessage) message;
184 var src = rmsg.Stream;
185 if (src == null) // null output
186 break;
188 int len = 0;
189 byte [] buffer = new byte [4096];
190 while ((len = src.Read (buffer, 0, buffer.Length)) > 0)
191 stream.Write (buffer, 0, len);
192 break;
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,
199 int messageOffset)
201 throw new NotImplementedException ();