2 // HttpRequestContext.cs
5 // Atsushi Enomoto <atsushi@ximian.com>
7 // Copyright (C) 2010 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.
31 using System.Threading;
33 namespace System.ServiceModel.Channels.Http
35 internal class HttpRequestContext : RequestContext
37 public HttpRequestContext (HttpReplyChannel channel, HttpContextInfo context, Message request)
40 throw new ArgumentNullException ("channel");
42 throw new ArgumentNullException ("context");
44 throw new ArgumentNullException ("request");
45 this.channel = channel;
46 this.context = context;
47 this.request = request;
51 HttpReplyChannel channel;
52 HttpContextInfo context;
54 public override Message RequestMessage {
55 get { return request; }
58 public HttpReplyChannel Channel {
59 get { return channel; }
62 public HttpContextInfo Context {
63 get { return context; }
66 public override IAsyncResult BeginReply (
67 Message msg, AsyncCallback callback, object state)
69 return BeginReply (msg,
70 Channel.DefaultSendTimeout,
74 Action<Message,TimeSpan> reply_delegate;
76 public override IAsyncResult BeginReply (
77 Message msg, TimeSpan timeout,
78 AsyncCallback callback, object state)
80 if (reply_delegate == null)
81 reply_delegate = new Action<Message,TimeSpan> (Reply);
82 return reply_delegate.BeginInvoke (msg, timeout, callback, state);
85 public override void EndReply (IAsyncResult result)
88 throw new ArgumentNullException ("result");
89 if (reply_delegate == null)
90 throw new InvalidOperationException ("reply operation has not started");
91 reply_delegate.EndInvoke (result);
94 public override void Reply (Message msg)
96 Reply (msg, Channel.DefaultSendTimeout);
99 public override void Reply (Message msg, TimeSpan timeout)
101 InternalReply (msg, timeout);
104 public override void Abort ()
109 public override void Close ()
111 Close (Channel.DefaultSendTimeout);
114 public override void Close (TimeSpan timeout)
116 InternalClose (timeout);
119 // implementation internals
121 protected virtual void InternalAbort ()
126 protected virtual void InternalClose (TimeSpan timeout)
131 protected virtual void InternalReply (Message msg, TimeSpan timeout)
134 throw new ArgumentNullException ("msg");
136 // FIXME: probably in WebHttpBinding land, there should
137 // be some additional code (probably IErrorHandler) that
138 // treats DestinationUnreachable (and possibly any other)
139 // errors as HTTP 400 or something appropriate.
140 // I originally rewrote the HTTP status here, but it
143 // FIXME: should this be done here?
144 if (Channel.MessageVersion.Addressing.Equals (AddressingVersion.None))
145 msg.Headers.Action = null; // prohibited
147 MemoryStream ms = new MemoryStream ();
148 Channel.Encoder.WriteMessage (msg, ms);
149 Context.Response.ContentType = Channel.Encoder.ContentType;
151 string pname = HttpResponseMessageProperty.Name;
152 bool suppressEntityBody = false;
153 if (msg.Properties.ContainsKey (pname)) {
154 HttpResponseMessageProperty hp = (HttpResponseMessageProperty) msg.Properties [pname];
155 string contentType = hp.Headers ["Content-Type"];
156 if (contentType != null)
157 Context.Response.ContentType = contentType;
158 Context.Response.Headers.Add (hp.Headers);
159 if (hp.StatusCode != default (HttpStatusCode))
160 Context.Response.StatusCode = (int) hp.StatusCode;
161 Context.Response.StatusDescription = hp.StatusDescription;
162 if (hp.SuppressEntityBody)
163 suppressEntityBody = true;
166 Context.Response.StatusCode = 500;
167 if (!suppressEntityBody) {
168 Context.Response.SetLength (ms.Length);
169 Context.Response.OutputStream.Write (ms.GetBuffer (), 0, (int) ms.Length);
170 Context.Response.OutputStream.Flush ();
173 Context.Response.SuppressContent = true;