PageRenderTime 70ms CodeModel.GetById 53ms app.highlight 13ms RepoModel.GetById 1ms app.codeStats 0ms

/src/Manos/Manos.Http/HttpResponse.cs

http://github.com/jacksonh/manos
C# | 282 lines | 205 code | 53 blank | 24 comment | 22 complexity | 2e08798ee1525e2f690134f6c934015b MD5 | raw file
  1//
  2// Copyright (C) 2010 Jackson Harper (jackson@manosdemono.com)
  3//
  4// Permission is hereby granted, free of charge, to any person obtaining
  5// a copy of this software and associated documentation files (the
  6// "Software"), to deal in the Software without restriction, including
  7// without limitation the rights to use, copy, modify, merge, publish,
  8// distribute, sublicense, and/or sell copies of the Software, and to
  9// permit persons to whom the Software is furnished to do so, subject to
 10// the following conditions:
 11// 
 12// The above copyright notice and this permission notice shall be
 13// included in all copies or substantial portions of the Software.
 14// 
 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 16// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 17// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 18// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 19// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 20// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 21// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 22//
 23//
 24
 25
 26
 27
 28
 29using System;
 30using System.IO;
 31using System.Text;
 32using System.Collections;
 33using System.Collections.Generic;
 34
 35using Libev;
 36using Manos.IO;
 37using Manos.Collections;
 38
 39
 40namespace Manos.Http {
 41
 42	public class HttpResponse : HttpEntity, IHttpResponse {
 43
 44		private StreamWriter writer;
 45		private Dictionary<string, HttpCookie> cookies;
 46
 47		public HttpResponse (Context context, IHttpRequest request, ITcpSocket socket)
 48			: base (context)
 49		{
 50			Request = request;
 51			Socket = socket;
 52
 53			StatusCode = 200;
 54
 55			WriteHeaders = true;
 56
 57			Stream = new HttpStream (this, socket.GetSocketStream ());
 58			Stream.Chunked = (request.MajorVersion > 0 && request.MinorVersion > 0);
 59		}
 60
 61		public IHttpRequest Request {
 62			get;
 63			private set;
 64		}
 65
 66		public StreamWriter Writer {
 67			get {
 68				if (writer == null)
 69					writer = new StreamWriter (new HttpStreamWriterWrapper (Stream));
 70				return writer;
 71			}
 72		}
 73
 74		public int StatusCode {
 75			get;
 76			set;
 77		}
 78
 79		public bool WriteHeaders {
 80			get;
 81			set;
 82		}
 83
 84		public Dictionary<string,HttpCookie> Cookies {
 85			get {
 86				if (cookies == null)
 87					cookies = new Dictionary<string, HttpCookie> ();
 88				return cookies;
 89			}
 90		}
 91
 92		public void Redirect (string url)
 93		{
 94			StatusCode =  302;
 95			Headers.SetNormalizedHeader ("Location", url);
 96			
 97//			WriteMetadata ();
 98			End ();
 99		}
100		
101		public override void WriteMetadata (StringBuilder builder)
102		{
103			WriteStatusLine (builder);
104
105			if (WriteHeaders) {
106				
107				Headers.Write (builder, cookies == null ? null : Cookies.Values, Encoding.ASCII);
108			}
109		}
110
111		public void SetHeader (string name, string value)
112		{
113			Headers.SetHeader (name, value);
114		}
115
116		public void SetCookie (string name, HttpCookie cookie)
117		{
118			Cookies [name] = cookie;
119		}
120		
121		public HttpCookie SetCookie (string name, string value)
122		{
123			if (name == null)
124				throw new ArgumentNullException ("name");
125			if (value == null)
126				throw new ArgumentNullException ("value");
127			
128			var cookie = new HttpCookie (name, value);
129			
130			SetCookie (name, cookie);
131			return cookie;
132		}
133		
134		public HttpCookie SetCookie (string name, string value, string domain)
135		{
136			if (name == null)
137				throw new ArgumentNullException ("name");
138			if (value == null)
139				throw new ArgumentNullException ("value");
140			
141			var cookie = new HttpCookie (name, value);
142			cookie.Domain = domain;
143			
144			SetCookie (name, cookie);
145			return cookie;
146		}
147		
148		public HttpCookie SetCookie (string name, string value, DateTime expires)
149		{
150			return SetCookie (name, value, null, expires);
151		}
152		
153		public HttpCookie SetCookie (string name, string value, string domain, DateTime expires)
154		{
155			if (name == null)
156				throw new ArgumentNullException ("name");
157			if (value == null)
158				throw new ArgumentNullException ("value");
159			
160			var cookie = new HttpCookie (name, value);
161			
162			cookie.Domain = domain;
163			cookie.Expires = expires;
164			
165			SetCookie (name, cookie);
166			return cookie;
167		}
168		
169		public HttpCookie SetCookie (string name, string value, TimeSpan max_age)
170		{
171			return SetCookie (name, value, DateTime.Now + max_age);
172		}
173		
174		public HttpCookie SetCookie (string name, string value, string domain, TimeSpan max_age)
175		{
176			return SetCookie (name, value, domain, DateTime.Now + max_age);
177		}
178
179		public void RemoveCookie(string name)
180		{
181			var cookie = new HttpCookie (name, "");
182			cookie.Expires = DateTime.Now.AddYears(-1);
183		
184			SetCookie (name, cookie);
185		}
186		
187		public override void Reset ()
188		{
189			cookies = null;
190			base.Reset ();
191		}
192
193		public override ParserSettings CreateParserSettings ()
194		{
195			ParserSettings settings = new ParserSettings ();
196
197			settings.OnBody = OnBody;
198			return settings;
199		}
200
201		protected override int OnHeadersComplete (HttpParser parser)
202		{
203			base.OnHeadersComplete (parser);
204
205			StatusCode = parser.StatusCode;
206
207			if (Request.Method == HttpMethod.HTTP_HEAD)
208				return 1;
209			return 0;
210		}
211
212		private void WriteStatusLine (StringBuilder builder)
213		{
214			builder.Append ("HTTP/");
215			builder.Append (Request.MajorVersion);
216			builder.Append (".");
217			builder.Append (Request.MinorVersion);
218			builder.Append (" ");
219			builder.Append (StatusCode);
220			builder.Append (" ");
221			builder.Append (GetStatusDescription (StatusCode));
222			builder.Append ("\r\n");
223		}
224
225		private static string GetStatusDescription (int code)
226		{
227			switch (code){
228			case 100: return "Continue";
229			case 101: return "Switching Protocols";
230			case 102: return "Processing";
231			case 200: return "OK";
232			case 201: return "Created";
233			case 202: return "Accepted";
234			case 203: return "Non-Authoritative Information";
235			case 204: return "No Content";
236			case 205: return "Reset Content";
237			case 206: return "Partial Content";
238			case 207: return "Multi-Status";
239			case 300: return "Multiple Choices";
240			case 301: return "Moved Permanently";
241			case 302: return "Found";
242			case 303: return "See Other";
243			case 304: return "Not Modified";
244			case 305: return "Use Proxy";
245			case 307: return "Temporary Redirect";
246			case 400: return "Bad Request";
247			case 401: return "Unauthorized";
248			case 402: return "Payment Required";
249			case 403: return "Forbidden";
250			case 404: return "Not Found";
251			case 405: return "Method Not Allowed";
252			case 406: return "Not Acceptable";
253			case 407: return "Proxy Authentication Required";
254			case 408: return "Request Timeout";
255			case 409: return "Conflict";
256			case 410: return "Gone";
257			case 411: return "Length Required";
258			case 412: return "Precondition Failed";
259			case 413: return "Request Entity Too Large";
260			case 414: return "Request-Uri Too Long";
261			case 415: return "Unsupported Media Type";
262			case 416: return "Requested Range Not Satisfiable";
263			case 417: return "Expectation Failed";
264			case 422: return "Unprocessable Entity";
265			case 423: return "Locked";
266			case 424: return "Failed Dependency";
267			case 500: return "Internal Server Error";
268			case 501: return "Not Implemented";
269			case 502: return "Bad Gateway";
270			case 503: return "Service Unavailable";
271			case 504: return "Gateway Timeout";
272			case 505: return "Http Version Not Supported";
273			case 507: return "Insufficient Storage";
274			}
275			return "";
276		}
277	}
278
279}
280
281
282