Made MessagingUtilities.CreateQueryString exception more useful.
[dotnetoauth.git] / src / DotNetOpenAuth / Messaging / HttpRequestInfo.cs
blobe498c6f58e1256b791392d1a23b5e088d1d83116
1 //-----------------------------------------------------------------------
2 // <copyright file="HttpRequestInfo.cs" company="Andrew Arnott">
3 // Copyright (c) Andrew Arnott. All rights reserved.
4 // </copyright>
5 //-----------------------------------------------------------------------
7 namespace DotNetOpenAuth.Messaging {
8 using System;
9 using System.Collections.Specialized;
10 using System.Diagnostics;
11 using System.IO;
12 using System.Net;
13 using System.ServiceModel.Channels;
14 using System.Web;
16 /// <summary>
17 /// A property store of details of an incoming HTTP request.
18 /// </summary>
19 /// <remarks>
20 /// This serves a very similar purpose to <see cref="HttpRequest"/>, except that
21 /// ASP.NET does not let us fully initialize that class, so we have to write one
22 /// of our one.
23 /// </remarks>
24 public class HttpRequestInfo {
25 /// <summary>
26 /// The key/value pairs found in the entity of a POST request.
27 /// </summary>
28 private NameValueCollection form;
30 /// <summary>
31 /// The key/value pairs found in the querystring of the incoming request.
32 /// </summary>
33 private NameValueCollection queryString;
35 /// <summary>
36 /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
37 /// </summary>
38 internal HttpRequestInfo() {
41 /// <summary>
42 /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
43 /// </summary>
44 /// <param name="request">The ASP.NET structure to copy from.</param>
45 internal HttpRequestInfo(HttpRequest request) {
46 if (request == null) {
47 throw new ArgumentNullException("request");
50 this.HttpMethod = request.HttpMethod;
51 this.Url = request.Url;
52 this.Headers = GetHeaderCollection(request.Headers);
53 this.InputStream = request.InputStream;
55 // These values would normally be calculated, but we'll reuse them from
56 // HttpRequest since they're already calculated, and there's a chance (<g>)
57 // that ASP.NET does a better job of being comprehensive about gathering
58 // these as well.
59 this.form = request.Form;
60 this.queryString = request.QueryString;
63 /// <summary>
64 /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
65 /// </summary>
66 /// <param name="request">The WCF incoming request structure to get the HTTP information from.</param>
67 /// <param name="requestUri">The URI of the service endpoint.</param>
68 internal HttpRequestInfo(HttpRequestMessageProperty request, Uri requestUri) {
69 if (request == null) {
70 throw new ArgumentNullException("request");
73 this.HttpMethod = request.Method;
74 this.Headers = request.Headers;
75 this.Url = requestUri;
78 /// <summary>
79 /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
80 /// </summary>
81 /// <param name="request">The HttpWebRequest (that was never used) to copy from.</param>
82 internal HttpRequestInfo(WebRequest request) {
83 this.HttpMethod = request.Method;
84 this.Url = request.RequestUri;
85 this.Headers = GetHeaderCollection(request.Headers);
86 this.InputStream = null;
89 /// <summary>
90 /// Initializes a new instance of the <see cref="HttpRequestInfo"/> class.
91 /// </summary>
92 /// <param name="message">The message being passed in through a mock transport.</param>
93 internal HttpRequestInfo(IDirectedProtocolMessage message) {
94 this.Message = message;
97 /// <summary>
98 /// Gets or sets the message that is being sent over a mock transport (for testing).
99 /// </summary>
100 internal IDirectedProtocolMessage Message { get; set; }
102 /// <summary>
103 /// Gets or sets the verb in the request (i.e. GET, POST, etc.)
104 /// </summary>
105 internal string HttpMethod { get; set; }
107 /// <summary>
108 /// Gets or sets the entire URL of the request.
109 /// </summary>
110 internal Uri Url { get; set; }
112 /// <summary>
113 /// Gets the query part of the URL (The ? and everything after it).
114 /// </summary>
115 internal string Query {
116 get { return this.Url != null ? this.Url.Query : null; }
119 /// <summary>
120 /// Gets or sets the collection of headers that came in with the request.
121 /// </summary>
122 internal WebHeaderCollection Headers { get; set; }
124 /// <summary>
125 /// Gets or sets the entity, or body of the request, if any.
126 /// </summary>
127 internal Stream InputStream { get; set; }
129 /// <summary>
130 /// Gets the key/value pairs found in the entity of a POST request.
131 /// </summary>
132 internal NameValueCollection Form {
133 get {
134 if (this.form == null) {
135 if (this.HttpMethod == "POST" && this.Headers[HttpRequestHeader.ContentType] == "application/x-www-form-urlencoded") {
136 StreamReader reader = new StreamReader(this.InputStream);
137 long originalPosition = this.InputStream.Position;
138 this.form = HttpUtility.ParseQueryString(reader.ReadToEnd());
139 if (this.InputStream.CanSeek) {
140 this.InputStream.Seek(originalPosition, SeekOrigin.Begin);
142 } else {
143 this.form = new NameValueCollection();
147 return this.form;
151 /// <summary>
152 /// Gets the key/value pairs found in the querystring of the incoming request.
153 /// </summary>
154 internal NameValueCollection QueryString {
155 get {
156 if (this.queryString == null) {
157 this.queryString = HttpUtility.ParseQueryString(this.Query);
160 return this.queryString;
164 /// <summary>
165 /// Converts a NameValueCollection to a WebHeaderCollection.
166 /// </summary>
167 /// <param name="pairs">The collection a HTTP headers.</param>
168 /// <returns>A new collection of the given headers.</returns>
169 private static WebHeaderCollection GetHeaderCollection(NameValueCollection pairs) {
170 Debug.Assert(pairs != null, "pairs == null");
172 WebHeaderCollection headers = new WebHeaderCollection();
173 foreach (string key in pairs) {
174 headers.Add(key, pairs[key]);
177 return headers;