Selaa lähdekoodia

[System] WebHeaderCollection from referencesource

Marek Safar 9 vuotta sitten
vanhempi
sitoutus
ba81e38ecc

+ 164 - 0
mcs/class/System/ReferenceSources/HttpApi.cs

@@ -0,0 +1,164 @@
+using System.Collections;
+
+namespace System.Net
+{
+	static class UnsafeNclNativeMethods
+	{
+		internal static unsafe class HttpApi 
+		{
+			const int HttpHeaderRequestMaximum  = (int)HttpRequestHeader.UserAgent + 1;
+			const int HttpHeaderResponseMaximum = (int)HttpResponseHeader.WwwAuthenticate + 1;
+
+			internal static class HTTP_REQUEST_HEADER_ID {
+				internal static string ToString(int position) {
+					return m_Strings[position];
+				}
+
+				private static string[] m_Strings = {
+					"Cache-Control",
+					"Connection",
+					"Date",
+					"Keep-Alive",
+					"Pragma",
+					"Trailer",
+					"Transfer-Encoding",
+					"Upgrade",
+					"Via",
+					"Warning",
+
+					"Allow",
+					"Content-Length",
+					"Content-Type",
+					"Content-Encoding",
+					"Content-Language",
+					"Content-Location",
+					"Content-MD5",
+					"Content-Range",
+					"Expires",
+					"Last-Modified",
+
+					"Accept",
+					"Accept-Charset",
+					"Accept-Encoding",
+					"Accept-Language",
+					"Authorization",
+					"Cookie",
+					"Expect",
+					"From",
+					"Host",
+					"If-Match",
+
+					"If-Modified-Since",
+					"If-None-Match",
+					"If-Range",
+					"If-Unmodified-Since",
+					"Max-Forwards",
+					"Proxy-Authorization",
+					"Referer",
+					"Range",
+					"Te",
+					"Translate",
+					"User-Agent",
+				};
+			}
+
+			internal static class HTTP_RESPONSE_HEADER_ID {
+				private static Hashtable m_Hashtable;
+
+				static HTTP_RESPONSE_HEADER_ID() {
+					m_Hashtable = new Hashtable((int)Enum.HttpHeaderResponseMaximum);
+					for (int i = 0; i < (int)Enum.HttpHeaderResponseMaximum; i++) {
+						m_Hashtable.Add(m_Strings[i], i);
+					}
+				}
+
+				internal static int IndexOfKnownHeader(string HeaderName) {
+					object index = m_Hashtable[HeaderName];
+					return index==null ? -1 : (int)index;
+				 }
+
+				internal static string ToString(int position) {
+					return m_Strings[position];
+				}
+			}
+
+			internal enum Enum {
+				HttpHeaderCacheControl          = 0,    // general-header [section 4.5]
+				HttpHeaderConnection            = 1,    // general-header [section 4.5]
+				HttpHeaderDate                  = 2,    // general-header [section 4.5]
+				HttpHeaderKeepAlive             = 3,    // general-header [not in rfc]
+				HttpHeaderPragma                = 4,    // general-header [section 4.5]
+				HttpHeaderTrailer               = 5,    // general-header [section 4.5]
+				HttpHeaderTransferEncoding      = 6,    // general-header [section 4.5]
+				HttpHeaderUpgrade               = 7,    // general-header [section 4.5]
+				HttpHeaderVia                   = 8,    // general-header [section 4.5]
+				HttpHeaderWarning               = 9,    // general-header [section 4.5]
+
+				HttpHeaderAllow                 = 10,   // entity-header  [section 7.1]
+				HttpHeaderContentLength         = 11,   // entity-header  [section 7.1]
+				HttpHeaderContentType           = 12,   // entity-header  [section 7.1]
+				HttpHeaderContentEncoding       = 13,   // entity-header  [section 7.1]
+				HttpHeaderContentLanguage       = 14,   // entity-header  [section 7.1]
+				HttpHeaderContentLocation       = 15,   // entity-header  [section 7.1]
+				HttpHeaderContentMd5            = 16,   // entity-header  [section 7.1]
+				HttpHeaderContentRange          = 17,   // entity-header  [section 7.1]
+				HttpHeaderExpires               = 18,   // entity-header  [section 7.1]
+				HttpHeaderLastModified          = 19,   // entity-header  [section 7.1]
+
+
+				// Response Headers
+
+				HttpHeaderAcceptRanges          = 20,   // response-header [section 6.2]
+				HttpHeaderAge                   = 21,   // response-header [section 6.2]
+				HttpHeaderEtag                  = 22,   // response-header [section 6.2]
+				HttpHeaderLocation              = 23,   // response-header [section 6.2]
+				HttpHeaderProxyAuthenticate     = 24,   // response-header [section 6.2]
+				HttpHeaderRetryAfter            = 25,   // response-header [section 6.2]
+				HttpHeaderServer                = 26,   // response-header [section 6.2]
+				HttpHeaderSetCookie             = 27,   // response-header [not in rfc]
+				HttpHeaderVary                  = 28,   // response-header [section 6.2]
+				HttpHeaderWwwAuthenticate       = 29,   // response-header [section 6.2]
+
+				HttpHeaderResponseMaximum       = 30,
+
+
+				HttpHeaderMaximum               = 41
+			}
+
+			private static string[] m_Strings = {
+				"Cache-Control",
+				"Connection",
+				"Date",
+				"Keep-Alive",
+				"Pragma",
+				"Trailer",
+				"Transfer-Encoding",
+				"Upgrade",
+				"Via",
+				"Warning",
+
+				"Allow",
+				"Content-Length",
+				"Content-Type",
+				"Content-Encoding",
+				"Content-Language",
+				"Content-Location",
+				"Content-MD5",
+				"Content-Range",
+				"Expires",
+				"Last-Modified",
+
+				"Accept-Ranges",
+				"Age",
+				"ETag",
+				"Location",
+				"Proxy-Authenticate",
+				"Retry-After",
+				"Server",
+				"Set-Cookie",
+				"Vary",
+				"WWW-Authenticate",
+			};
+		}
+	}
+}

+ 0 - 15
mcs/class/System/ReferenceSources/WebHeaderCollectionType.cs

@@ -1,15 +0,0 @@
-namespace System.Net {
-    internal enum WebHeaderCollectionType : ushort {
-        Unknown,
-        WebRequest,
-        WebResponse,
-        HttpWebRequest,
-        HttpWebResponse,
-        HttpListenerRequest,
-        HttpListenerResponse,
-        FtpWebRequest,
-        FtpWebResponse,
-        FileWebRequest,
-        FileWebResponse,
-    }
-} 

+ 1 - 1
mcs/class/System/System.Net/HttpListenerResponse.cs

@@ -427,7 +427,7 @@ namespace System.Net {
 
 			StreamWriter writer = new StreamWriter (ms, encoding, 256);
 			writer.Write ("HTTP/{0} {1} {2}\r\n", version, status_code, status_description);
-			string headers_str = headers.ToStringMultiValue ();
+			string headers_str = headers.ToString ();
 			writer.Write (headers_str);
 			writer.Flush ();
 			int preamble = (encoding.CodePage == 65001) ? 3 : encoding.GetPreamble ().Length;

+ 48 - 30
mcs/class/System/System.Net/HttpWebRequest.cs

@@ -155,7 +155,7 @@ namespace System.Net
 			this.requestUri = uri;
 			this.actualUri = uri;
 			this.proxy = GlobalProxySelection.Select;
-			this.webHeaders = new WebHeaderCollection (WebHeaderCollection.HeaderInfo.Request);
+			this.webHeaders = new WebHeaderCollection (WebHeaderCollectionType.HttpWebRequest);
 			ThrowOnError = true;
 			ResetAuthorization ();
 		}
@@ -205,11 +205,19 @@ namespace System.Net
 		
 		// Properties
 
+		void SetSpecialHeaders(string HeaderName, string value) {
+			value = WebHeaderCollection.CheckBadChars(value, true);
+			webHeaders.RemoveInternal(HeaderName);
+			if (value.Length != 0) {
+				webHeaders.AddInternal(HeaderName, value);
+			}
+		}
+
 		public string Accept {
 			get { return webHeaders ["Accept"]; }
 			set {
 				CheckRequestStarted ();
-				webHeaders.RemoveAndAdd ("Accept", value);
+				SetSpecialHeaders ("Accept", value);
 			}
 		}
 		
@@ -306,7 +314,7 @@ namespace System.Net
 				if (keepAlive)
 					value = value + ", Keep-Alive";
 				
-				webHeaders.RemoveAndAdd ("Connection", value);
+				webHeaders.CheckUpdate ("Connection", value);
 			}
 		}		
 		
@@ -336,11 +344,7 @@ namespace System.Net
 		public override string ContentType { 
 			get { return webHeaders ["Content-Type"]; }
 			set {
-				if (value == null || value.Trim().Length == 0) {
-					webHeaders.RemoveInternal ("Content-Type");
-					return;
-				}
-				webHeaders.RemoveAndAdd ("Content-Type", value);
+				SetSpecialHeaders ("Content-Type", value);
 			}
 		}
 		
@@ -367,13 +371,17 @@ namespace System.Net
 				return DateTime.ParseExact (date, "r", CultureInfo.InvariantCulture).ToLocalTime ();
 			}
 			set {
-				if (value.Equals (DateTime.MinValue))
-					webHeaders.RemoveInternal ("Date");
-				else
-					webHeaders.RemoveAndAdd ("Date", value.ToUniversalTime ().ToString ("r", CultureInfo.InvariantCulture));
+				SetDateHeaderHelper ("Date", value);
 			}
 		}
 
+		void SetDateHeaderHelper(string headerName, DateTime dateTime) {
+			if (dateTime == DateTime.MinValue)
+				SetSpecialHeaders(headerName, null); // remove header
+			else
+				SetSpecialHeaders(headerName, HttpProtocolUtils.date2string(dateTime));
+		}
+
 #if !NET_2_1
 		[MonoTODO]
 		public static new RequestCachePolicy DefaultCachePolicy
@@ -414,7 +422,8 @@ namespace System.Net
 				if (val == "100-continue")
 					throw new ArgumentException ("100-Continue cannot be set with this property.",
 								     "value");
-				webHeaders.RemoveAndAdd ("Expect", value);
+
+				webHeaders.CheckUpdate ("Expect", value);
 			}
 		}
 		
@@ -427,12 +436,21 @@ namespace System.Net
 			get { return webHeaders; }
 			set {
 				CheckRequestStarted ();
-				WebHeaderCollection newHeaders = new WebHeaderCollection (WebHeaderCollection.HeaderInfo.Request);
-				int count = value.Count;
-				for (int i = 0; i < count; i++) 
-					newHeaders.Add (value.GetKey (i), value.Get (i));
 
-				webHeaders = newHeaders;
+				WebHeaderCollection webHeaders = value;
+				WebHeaderCollection newWebHeaders = new WebHeaderCollection(WebHeaderCollectionType.HttpWebRequest);
+
+				// Copy And Validate -
+				// Handle the case where their object tries to change
+				//  name, value pairs after they call set, so therefore,
+				//  we need to clone their headers.
+				//
+
+				foreach (String headerName in webHeaders.AllKeys ) {
+					newWebHeaders.Add(headerName,webHeaders[headerName]);
+				}
+
+				webHeaders = newWebHeaders;
 			}
 		}
 		
@@ -664,7 +682,7 @@ namespace System.Net
 				if (!sendChunked)
 					throw new ArgumentException ("SendChunked must be True", "value");
 
-				webHeaders.RemoveAndAdd ("Transfer-Encoding", value);
+				webHeaders.CheckUpdate ("Transfer-Encoding", value);
 			}
 		}
 
@@ -772,7 +790,7 @@ namespace System.Net
 		{
 			if (rangeSpecifier == null)
 				throw new ArgumentNullException ("rangeSpecifier");
-			if (!WebHeaderCollection.IsHeaderValue (rangeSpecifier))
+			if (!WebHeaderCollection.IsValidToken (rangeSpecifier))
 				throw new ArgumentException ("Invalid range specifier", "rangeSpecifier");
 
 			string r = webHeaders ["Range"];
@@ -790,7 +808,7 @@ namespace System.Net
 				r = r + "0" + n;
 			else
 				r = r + n + "-";
-			webHeaders.RemoveAndAdd ("Range", r);
+			webHeaders.ChangeInternal ("Range", r);
 		}
 
 		public
@@ -798,7 +816,7 @@ namespace System.Net
 		{
 			if (rangeSpecifier == null)
 				throw new ArgumentNullException ("rangeSpecifier");
-			if (!WebHeaderCollection.IsHeaderValue (rangeSpecifier))
+			if (!WebHeaderCollection.IsValidToken (rangeSpecifier))
 				throw new ArgumentException ("Invalid range specifier", "rangeSpecifier");
 			if (from > to || from < 0)
 				throw new ArgumentOutOfRangeException ("from");
@@ -812,7 +830,7 @@ namespace System.Net
 				r += ",";
 
 			r = String.Format ("{0}{1}-{2}", r, from, to);
-			webHeaders.RemoveAndAdd ("Range", r);
+			webHeaders.ChangeInternal ("Range", r);
 		}
 
 		
@@ -1198,7 +1216,7 @@ namespace System.Net
 			bool continue100 = false;
 			if (sendChunked) {
 				continue100 = true;
-				webHeaders.RemoveAndAdd ("Transfer-Encoding", "chunked");
+				webHeaders.ChangeInternal ("Transfer-Encoding", "chunked");
 				webHeaders.RemoveInternal ("Content-Length");
 			} else if (contentLength != -1) {
 				if (auth_state.NtlmAuthState == NtlmAuthState.Challenge || proxy_auth_state.NtlmAuthState == NtlmAuthState.Challenge) {
@@ -1221,7 +1239,7 @@ namespace System.Net
 
 			if (actualVersion == HttpVersion.Version11 && continue100 &&
 			    servicePoint.SendContinue) { // RFC2616 8.2.3
-				webHeaders.RemoveAndAdd ("Expect" , "100-continue");
+				webHeaders.ChangeInternal ("Expect" , "100-continue");
 				expectContinue = true;
 			} else {
 				webHeaders.RemoveInternal ("Expect");
@@ -1237,16 +1255,16 @@ namespace System.Net
 			if (keepAlive && (version == HttpVersion.Version10 || spoint10)) {
 				if (webHeaders[connectionHeader] == null
 				    || webHeaders[connectionHeader].IndexOf ("keep-alive", StringComparison.OrdinalIgnoreCase) == -1)
-					webHeaders.RemoveAndAdd (connectionHeader, "keep-alive");
+					webHeaders.ChangeInternal (connectionHeader, "keep-alive");
 			} else if (!keepAlive && version == HttpVersion.Version11) {
-				webHeaders.RemoveAndAdd (connectionHeader, "close");
+				webHeaders.ChangeInternal (connectionHeader, "close");
 			}
 
 			webHeaders.SetInternal ("Host", Host);
 			if (cookieContainer != null) {
 				string cookieHeader = cookieContainer.GetCookieHeader (actualUri);
 				if (cookieHeader != "")
-					webHeaders.RemoveAndAdd ("Cookie", cookieHeader);
+					webHeaders.ChangeInternal ("Cookie", cookieHeader);
 				else
 					webHeaders.RemoveInternal ("Cookie");
 			}
@@ -1257,7 +1275,7 @@ namespace System.Net
 			if ((auto_decomp & DecompressionMethods.Deflate) != 0)
 				accept_encoding = accept_encoding != null ? "gzip, deflate" : "deflate";
 			if (accept_encoding != null)
-				webHeaders.RemoveAndAdd ("Accept-Encoding", accept_encoding);
+				webHeaders.ChangeInternal ("Accept-Encoding", accept_encoding);
 
 			if (!usedPreAuth && preAuthenticate)
 				DoPreAuthenticate ();
@@ -1616,7 +1634,7 @@ namespace System.Net
 				if (isProxy && (request.proxy == null || request.proxy.Credentials == null))
 					return false;
 
-				string [] authHeaders = response.Headers.GetValues_internal (isProxy ? "Proxy-Authenticate" : "WWW-Authenticate", false);
+				string [] authHeaders = response.Headers.GetValues (isProxy ? "Proxy-Authenticate" : "WWW-Authenticate");
 				if (authHeaders == null || authHeaders.Length == 0)
 					return false;
 

+ 18 - 3
mcs/class/System/System.Net/WebConnection.cs

@@ -292,7 +292,7 @@ namespace System.Net
 				}
 
 				Data.StatusCode = status;
-				Data.Challenge = result.GetValues_internal ("Proxy-Authenticate", false);
+				Data.Challenge = result.GetValues ("Proxy-Authentic");
 				return false;
 			} else if (status != 200) {
 				string msg = String.Format ("The remote server returned a {0} status code.", status);
@@ -659,8 +659,23 @@ namespace System.Net
 					if (!finished)
 						return 0;
 
-					foreach (string s in headers)
-						data.Headers.SetInternal (s);
+					// .NET uses ParseHeaders or ParseHeadersStrict which is much better
+					foreach (string s in headers) {
+
+						int pos_s = s.IndexOf (':');
+						if (pos_s == -1)
+							throw new ArgumentException ("no colon found", "header");
+
+						var header = s.Substring (0, pos_s);
+						var value = s.Substring (pos_s + 1).Trim ();
+
+						var h = data.Headers;
+						if (h.AllowMultiValues (header)) {
+							h.AddInternal (header, value);
+						} else  {
+							h.SetInternal (header, value);
+						}
+					}
 
 					if (data.StatusCode == (int) HttpStatusCode.Continue) {
 						sPoint.SendContinue = true;

+ 0 - 746
mcs/class/System/System.Net/WebHeaderCollection.cs

@@ -1,746 +0,0 @@
-//
-// System.Net.WebHeaderCollection
-//
-// Authors:
-// 	Lawrence Pit ([email protected])
-//	Gonzalo Paniagua Javier ([email protected])
-//      Miguel de Icaza ([email protected])
-//	Marek Safar ([email protected])
-//
-// Copyright 2003 Ximian, Inc. (http://www.ximian.com)
-// Copyright 2007 Novell, Inc. (http://www.novell.com)
-// Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com)
-//
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-// 
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-// 
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-using System.Collections.Generic;
-using System.Collections.Specialized;
-using System.Runtime.InteropServices;
-using System.Runtime.Serialization;
-using System.Text;
-    
-// See RFC 2068 par 4.2 Message Headers
-    
-namespace System.Net 
-{
-	[Serializable]
-	[ComVisible(true)]
-	public class WebHeaderCollection : NameValueCollection, ISerializable {
-		[Flags]
-		internal enum HeaderInfo
-		{
-			Request = 1,
-			Response = 1 << 1,
-			MultiValue = 1 << 10
-		}
-
-		static readonly bool[] allowed_chars = {
-			false, false, false, false, false, false, false, false, false, false, false, false, false, false,
-			false, false, false, false, false, false, false, false, false, false, false, false, false, false,
-			false, false, false, false, false, true, false, true, true, true, true, false, false, false, true,
-			true, false, true, true, false, true, true, true, true, true, true, true, true, true, true, false,
-			false, false, false, false, false, false, true, true, true, true, true, true, true, true, true,
-			true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
-			false, false, false, true, true, true, true, true, true, true, true, true, true, true, true, true,
-			true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
-			false, true, false
-		};
-
-		static readonly Dictionary<string, HeaderInfo> headers;
-		HeaderInfo? headerRestriction;
-		HeaderInfo? headerConsistency;
-		
-		static WebHeaderCollection () 
-		{
-			headers = new Dictionary<string, HeaderInfo> (StringComparer.OrdinalIgnoreCase) {
-				{ "Allow", HeaderInfo.MultiValue },
-				{ "Accept", HeaderInfo.Request | HeaderInfo.MultiValue },
-				{ "Accept-Charset", HeaderInfo.MultiValue },
-				{ "Accept-Encoding", HeaderInfo.MultiValue },
-				{ "Accept-Language", HeaderInfo.MultiValue },
-				{ "Accept-Ranges", HeaderInfo.MultiValue },
-				{ "Authorization", HeaderInfo.MultiValue },
-				{ "Cache-Control", HeaderInfo.MultiValue },
-				{ "Cookie", HeaderInfo.MultiValue },
-				{ "Connection", HeaderInfo.Request | HeaderInfo.MultiValue },
-				{ "Content-Encoding", HeaderInfo.MultiValue },
-				{ "Content-Length", HeaderInfo.Request | HeaderInfo.Response },
-				{ "Content-Type", HeaderInfo.Request },
-				{ "Content-Language", HeaderInfo.MultiValue },
-				{ "Date", HeaderInfo.Request },
-				{ "Expect", HeaderInfo.Request | HeaderInfo.MultiValue},
-				{ "Host", HeaderInfo.Request },
-				{ "If-Match", HeaderInfo.MultiValue },
-				{ "If-Modified-Since", HeaderInfo.Request },
-				{ "If-None-Match", HeaderInfo.MultiValue },
-				{ "Keep-Alive", HeaderInfo.Response },
-				{ "Pragma", HeaderInfo.MultiValue },
-				{ "Proxy-Authenticate", HeaderInfo.MultiValue },
-				{ "Proxy-Authorization", HeaderInfo.MultiValue },
-				{ "Proxy-Connection", HeaderInfo.Request | HeaderInfo.MultiValue },
-				{ "Range", HeaderInfo.Request | HeaderInfo.MultiValue },
-				{ "Referer", HeaderInfo.Request },
-				{ "Set-Cookie", HeaderInfo.MultiValue },
-				{ "Set-Cookie2", HeaderInfo.MultiValue },
-				{ "TE", HeaderInfo.MultiValue },
-				{ "Trailer", HeaderInfo.MultiValue },
-				{ "Transfer-Encoding", HeaderInfo.Request | HeaderInfo.Response | HeaderInfo.MultiValue },
-				{ "Upgrade", HeaderInfo.MultiValue },
-				{ "User-Agent", HeaderInfo.Request },
-				{ "Vary", HeaderInfo.MultiValue },
-				{ "Via", HeaderInfo.MultiValue },
-				{ "Warning", HeaderInfo.MultiValue },
-				{ "WWW-Authenticate", HeaderInfo.Response | HeaderInfo. MultiValue }
-			};
-		}
-		
-		// Constructors
-		
-		public WebHeaderCollection ()
-		{
-		}
-
-
-        internal WebHeaderCollection(WebHeaderCollectionType type)
-        {
-//            m_Type = type;
-//            if (type == WebHeaderCollectionType.HttpWebResponse)
-//                m_CommonHeaders = new string[s_CommonHeaderNames.Length - 1];  // Minus one for the sentinel.
-        }		
-		
-		protected WebHeaderCollection (SerializationInfo serializationInfo, 
-					       StreamingContext streamingContext)
-		{
-			int count;
-
-			try {
-				count = serializationInfo.GetInt32("Count");
-				for (int i = 0; i < count; i++) 
-					this.Add (serializationInfo.GetString (i.ToString ()),
-						  serializationInfo.GetString ((count + i).ToString ()));
-			} catch (SerializationException){
-				count = serializationInfo.GetInt32("count");
-				for (int i = 0; i < count; i++) 
-					this.Add (serializationInfo.GetString ("k" + i),
-						  serializationInfo.GetString ("v" + i));
-			}
-			
-		}
-
-		internal WebHeaderCollection (HeaderInfo headerRestriction)
-		{
-			this.headerRestriction = headerRestriction;
-		}		
-		
-		// Methods
-		
-		public void Add (string header)
-		{
-			if (header == null)
-				throw new ArgumentNullException ("header");
-			int pos = header.IndexOf (':');
-			if (pos == -1)
-				throw new ArgumentException ("no colon found", "header");
-
-			this.Add (header.Substring (0, pos), header.Substring (pos + 1));
-		}
-		
-		public override void Add (string name, string value)
-		{
-			if (name == null)
-				throw new ArgumentNullException ("name");
-
-			CheckRestrictedHeader (name);
-			this.AddWithoutValidate (name, value);
-		}
-
-		protected void AddWithoutValidate (string headerName, string headerValue)
-		{
-			if (!IsHeaderName (headerName))
-				throw new ArgumentException ("invalid header name: " + headerName, "headerName");
-			if (headerValue == null)
-				headerValue = String.Empty;
-			else
-				headerValue = headerValue.Trim ();
-			if (!IsHeaderValue (headerValue))
-				throw new ArgumentException ("invalid header value: " + headerValue, "headerValue");
-			
-			AddInternal (headerName, headerValue);
-		}
-			
-		internal void AddInternal (string headerName, string headerValue)
-		{
-			base.Add (headerName, headerValue);			
-		}
-
-		internal string [] GetValues_internal (string header, bool split)
-		{
-			if (header == null)
-				throw new ArgumentNullException ("header");
-
-			string [] values = base.GetValues (header);
-			if (values == null || values.Length == 0)
-				return null;
-
-			if (split && IsMultiValue (header)) {
-				List<string> separated = null;
-				foreach (var value in values) {
-					if (value.IndexOf (',') < 0) {
-						if (separated != null)
-							separated.Add (value);
-						
-						continue;
-					}
-
-					if (separated == null) {
-						separated = new List<string> (values.Length + 1);
-						foreach (var v in values) {
-							if (v == value)
-								break;
-
-							separated.Add (v);
-						}
-					}
-
-					var slices = value.Split (',');
-					var slices_length = slices.Length;
-					if (value[value.Length - 1] == ',')
-						--slices_length;
-
-					for (int i = 0; i < slices_length; ++i ) {
-						separated.Add (slices[i].Trim ());
-					}
-				}
-
-				if (separated != null)
-					return separated.ToArray ();
-			}
-
-			return values;
-		}
-
-		public override string [] GetValues (string header)
-		{
-			return GetValues_internal (header, true);
-		}
-
-		public override string[] GetValues (int index)
-		{
-			string[] values = base.GetValues (index);
-
-			if (values == null || values.Length == 0) {
-				return null;
-			}
-			
-			return values;
-		}
-
-		public static bool IsRestricted (string headerName)
-		{
-			return IsRestricted (headerName, false);
-		}
-
-		public static bool IsRestricted (string headerName, bool response)
-		{
-			if (headerName == null)
-				throw new ArgumentNullException ("headerName");
-
-			if (headerName.Length == 0)
-				throw new ArgumentException ("empty string", "headerName");
-
-			if (!IsHeaderName (headerName))
-				throw new ArgumentException ("Invalid character in header");
-
-			HeaderInfo info;
-			if (!headers.TryGetValue (headerName, out info))
-				return false;
-
-			var flag = response ? HeaderInfo.Response : HeaderInfo.Request;
-			return (info & flag) != 0;
-		}
-
-		public override void OnDeserialization (object sender)
-		{
-		}
-
-		public override void Remove (string name)
-		{
-			if (name == null)
-				throw new ArgumentNullException ("name");
-
-			CheckRestrictedHeader (name);
-			base.Remove (name);
-		}
-
-		public override void Set (string name, string value)
-		{
-			if (name == null)
-				throw new ArgumentNullException ("name");
-			if (!IsHeaderName (name))
-				throw new ArgumentException ("invalid header name");
-			if (value == null)
-				value = String.Empty;
-			else
-				value = value.Trim ();
-			if (!IsHeaderValue (value))
-				throw new ArgumentException ("invalid header value");
-
-			CheckRestrictedHeader (name);
-			base.Set (name, value);			
-		}
-
-		public byte[] ToByteArray ()
-		{
-			return Encoding.UTF8.GetBytes(ToString ());
-		}
-
-		internal string ToStringMultiValue ()
-		{
-			StringBuilder sb = new StringBuilder();
-
-			int count = base.Count;
-			for (int i = 0; i < count ; i++) {
-				string key = GetKey (i);
-				if (IsMultiValue (key)) {
-					foreach (string v in GetValues (i)) {
-						sb.Append (key)
-						  .Append (": ")
-						  .Append (v)
-						  .Append ("\r\n");
-					}
-				} else {
-					sb.Append (key)
-					  .Append (": ")
-					  .Append (Get (i))
-					  .Append ("\r\n");
-				}
-			 }
-			return sb.Append("\r\n").ToString();
-		}
-
-		public override string ToString ()
-		{
-			StringBuilder sb = new StringBuilder();
-
-			int count = base.Count;
-			for (int i = 0; i < count ; i++)
-				sb.Append (GetKey (i))
-				  .Append (": ")
-				  .Append (Get (i))
-				  .Append ("\r\n");
-
-			return sb.Append("\r\n").ToString();
-		}
-		void ISerializable.GetObjectData (SerializationInfo serializationInfo,
-						  StreamingContext streamingContext)
-		{
-			GetObjectData (serializationInfo, streamingContext);
-		}
-		public override void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
-		{
-			int count = base.Count;
-			serializationInfo.AddValue ("Count", count);
-			for (int i = 0; i < count; i++) {
-				serializationInfo.AddValue (i.ToString (), GetKey (i));
-				serializationInfo.AddValue ((count + i).ToString (), Get (i));
-			}
-		}
-
-		public override string[] AllKeys {
-			get {
-				return base.AllKeys;
-			}
-		}
-		
-		public override int Count {
-			get {
-				return base.Count;
-			}
-		}
-
-		public override KeysCollection Keys {
-			get {
-				return base.Keys;
-			}
-		}
-
-		public override string Get (int index)
-		{
-			return base.Get (index);
-		}
-		
-		public override string Get (string name)
-		{
-			return base.Get (name);
-		}
-		
-		public override string GetKey (int index)
-		{
-			return base.GetKey (index);
-		}
-
-		public void Add (HttpRequestHeader header, string value)
-		{
-			Add (RequestHeaderToString (header), value);
-		}
-
-		public void Remove (HttpRequestHeader header)
-		{
-			Remove (RequestHeaderToString (header));
-		}
-
-		public void Set (HttpRequestHeader header, string value)
-		{
-			Set (RequestHeaderToString (header), value);
-		}
-
-		public void Add (HttpResponseHeader header, string value)
-		{
-			Add (ResponseHeaderToString (header), value);
-		}
-
-		public void Remove (HttpResponseHeader header)
-		{
-			Remove (ResponseHeaderToString (header));
-		}
-
-		public void Set (HttpResponseHeader header, string value)
-		{
-			Set (ResponseHeaderToString (header), value);
-		}
-
-		public string this [HttpRequestHeader header] {
-			get {
-				return Get (RequestHeaderToString (header));
-			}
-			
-			set {
-				Set (header, value);
-			}
-		}
-
-		public string this [HttpResponseHeader header] {
-			get {
-				return Get (ResponseHeaderToString (header));
-			}
-
-			set {
-				Set (header, value);
-			}
-		}
-
-		public override void Clear ()
-		{
-			base.Clear ();
-		}
-
-		public override IEnumerator GetEnumerator ()
-		{
-			return base.GetEnumerator ();
-		}
-
-		// Internal Methods
-		
-		// With this we don't check for invalid characters in header. See bug #55994.
-		internal void SetInternal (string header)
-		{
-			int pos = header.IndexOf (':');
-			if (pos == -1)
-				throw new ArgumentException ("no colon found", "header");				
-
-			SetInternal (header.Substring (0, pos), header.Substring (pos + 1));
-		}
-
-		internal void SetInternal (string name, string value)
-		{
-			if (value == null)
-				value = String.Empty;
-			else
-				value = value.Trim ();
-			if (!IsHeaderValue (value))
-				throw new ArgumentException ("invalid header value");
-
-			if (IsMultiValue (name)) {
-				base.Add (name, value);
-			} else {
-				base.Remove (name);
-				base.Set (name, value);	
-			}
-		}
-
-		internal void RemoveAndAdd (string name, string value)
-		{
-			if (value == null)
-				value = String.Empty;
-			else
-				value = value.Trim ();
-
-			base.Remove (name);
-			base.Set (name, value);
-		}
-
-		internal void RemoveInternal (string name)
-		{
-			if (name == null)
-				throw new ArgumentNullException ("name");
-			base.Remove (name);
-		}		
-		
-		// Private Methods
-
-		string RequestHeaderToString (HttpRequestHeader value)
-		{
-			CheckHeaderConsistency (HeaderInfo.Request);
-
-			switch (value) {
-			case HttpRequestHeader.CacheControl:
-				return "Cache-Control";
-			case HttpRequestHeader.Connection:
-				return "Connection";
-			case HttpRequestHeader.Date:
-				return "Date";
-			case HttpRequestHeader.KeepAlive:
-				return "Keep-Alive";
-			case HttpRequestHeader.Pragma:
-				return "Pragma";
-			case HttpRequestHeader.Trailer:
-				return "Trailer";
-			case HttpRequestHeader.TransferEncoding:
-				return "Transfer-Encoding";
-			case HttpRequestHeader.Upgrade:
-				return "Upgrade";
-			case HttpRequestHeader.Via:
-				return "Via";
-			case HttpRequestHeader.Warning:
-				return "Warning";
-			case HttpRequestHeader.Allow:
-				return "Allow";
-			case HttpRequestHeader.ContentLength:
-				return "Content-Length";
-			case HttpRequestHeader.ContentType:
-				return "Content-Type";
-			case HttpRequestHeader.ContentEncoding:
-				return "Content-Encoding";
-			case HttpRequestHeader.ContentLanguage:
-				return "Content-Language";
-			case HttpRequestHeader.ContentLocation:
-				return "Content-Location";
-			case HttpRequestHeader.ContentMd5:
-				return "Content-MD5";
-			case HttpRequestHeader.ContentRange:
-				return "Content-Range";
-			case HttpRequestHeader.Expires:
-				return "Expires";
-			case HttpRequestHeader.LastModified:
-				return "Last-Modified";
-			case HttpRequestHeader.Accept:
-				return "Accept";
-			case HttpRequestHeader.AcceptCharset:
-				return "Accept-Charset";
-			case HttpRequestHeader.AcceptEncoding:
-				return "Accept-Encoding";
-			case HttpRequestHeader.AcceptLanguage:
-				return "accept-language";
-			case HttpRequestHeader.Authorization:
-				return "Authorization";
-			case HttpRequestHeader.Cookie:
-				return "Cookie";
-			case HttpRequestHeader.Expect:
-				return "Expect";
-			case HttpRequestHeader.From:
-				return "From";
-			case HttpRequestHeader.Host:
-				return "Host";
-			case HttpRequestHeader.IfMatch:
-				return "If-Match";
-			case HttpRequestHeader.IfModifiedSince:
-				return "If-Modified-Since";
-			case HttpRequestHeader.IfNoneMatch:
-				return "If-None-Match";
-			case HttpRequestHeader.IfRange:
-				return "If-Range";
-			case HttpRequestHeader.IfUnmodifiedSince:
-				return "If-Unmodified-Since";
-			case HttpRequestHeader.MaxForwards:
-				return "Max-Forwards";
-			case HttpRequestHeader.ProxyAuthorization:
-				return "Proxy-Authorization";
-			case HttpRequestHeader.Referer:
-				return "Referer";
-			case HttpRequestHeader.Range:
-				return "Range";
-			case HttpRequestHeader.Te:
-				return "TE";
-			case HttpRequestHeader.Translate:
-				return "Translate";
-			case HttpRequestHeader.UserAgent:
-				return "User-Agent";
-			default:
-				throw new InvalidOperationException ();
-			}
-		}
-
-		string ResponseHeaderToString (HttpResponseHeader value)
-		{
-			CheckHeaderConsistency (HeaderInfo.Response);
-
-			switch (value) {
-			case HttpResponseHeader.CacheControl:
-				return "Cache-Control";
-			case HttpResponseHeader.Connection:
-				return "Connection";
-			case HttpResponseHeader.Date:
-				return "Date";
-			case HttpResponseHeader.KeepAlive:
-				return "Keep-Alive";
-			case HttpResponseHeader.Pragma:
-				return "Pragma";
-			case HttpResponseHeader.Trailer:
-				return "Trailer";
-			case HttpResponseHeader.TransferEncoding:
-				return "Transfer-Encoding";
-			case HttpResponseHeader.Upgrade:
-				return "Upgrade";
-			case HttpResponseHeader.Via:
-				return "Via";
-			case HttpResponseHeader.Warning:
-				return "Warning";
-			case HttpResponseHeader.Allow:
-				return "Allow";
-			case HttpResponseHeader.ContentLength:
-				return "Content-Length";
-			case HttpResponseHeader.ContentType:
-				return "Content-Type";
-			case HttpResponseHeader.ContentEncoding:
-				return "Content-Encoding";
-			case HttpResponseHeader.ContentLanguage:
-				return "Content-Language";
-			case HttpResponseHeader.ContentLocation:
-				return "Content-Location";
-			case HttpResponseHeader.ContentMd5:
-				return "Content-MD5";
-			case HttpResponseHeader.ContentRange:
-				return "Content-Range";
-			case HttpResponseHeader.Expires:
-				return "Expires";
-			case HttpResponseHeader.LastModified:
-				return "Last-Modified";
-			case HttpResponseHeader.AcceptRanges:
-				return "Accept-Ranges";
-			case HttpResponseHeader.Age:
-				return "Age";
-			case HttpResponseHeader.ETag:
-				return "ETag";
-			case HttpResponseHeader.Location:
-				return "Location";
-			case HttpResponseHeader.ProxyAuthenticate:
-				return "Proxy-Authenticate";
-			case HttpResponseHeader.RetryAfter:
-				return "Retry-After";
-			case HttpResponseHeader.Server:
-				return "Server";
-			case HttpResponseHeader.SetCookie:
-				return "Set-Cookie";
-			case HttpResponseHeader.Vary:
-				return "Vary";
-			case HttpResponseHeader.WwwAuthenticate:
-				return "WWW-Authenticate";
-			default:
-				throw new InvalidOperationException ();
-			}
-		}
-
-		void CheckRestrictedHeader (string headerName)
-		{
-			if (!headerRestriction.HasValue)
-				return;
-
-			HeaderInfo info;
-			if (!headers.TryGetValue (headerName, out info))
-				return;
-
-			if ((info & headerRestriction.Value) != 0)
-				throw new ArgumentException ("This header must be modified with the appropriate property.");
-		}
-
-		void CheckHeaderConsistency (HeaderInfo value)
-		{
-			if (!headerConsistency.HasValue) {
-				headerConsistency = value;
-				return;
-			}
-
-			if ((headerConsistency & value) == 0)
-				throw new InvalidOperationException ();
-		}
-		
-		internal static bool IsMultiValue (string headerName)
-		{
-			if (headerName == null)
-				return false;
-
-			HeaderInfo info;
-			return headers.TryGetValue (headerName, out info) && (info & HeaderInfo.MultiValue) != 0;
-		}		
-		
-		internal static bool IsHeaderValue (string value)
-		{
-			// TEXT any 8 bit value except CTL's (0-31 and 127)
-			//      but including \r\n space and \t
-			//      after a newline at least one space or \t must follow
-			//      certain header fields allow comments ()
-				
-			int len = value.Length;
-			for (int i = 0; i < len; i++) {			
-				char c = value [i];
-				if (c == 127)
-					return false;
-				if (c < 0x20 && (c != '\r' && c != '\n' && c != '\t'))
-					return false;
-				if (c == '\n' && ++i < len) {
-					c = value [i];
-					if (c != ' ' && c != '\t')
-						return false;
-				}
-			}
-			
-			return true;
-		}
-		
-		internal static bool IsHeaderName (string name)
-		{
-			if (name == null || name.Length == 0)
-				return false;
-
-			int len = name.Length;
-			for (int i = 0; i < len; i++) {			
-				char c = name [i];
-				if (c > 126 || !allowed_chars [c])
-					return false;
-			}
-			
-			return true;
-		}
-	}
-}

+ 5 - 2
mcs/class/System/System.dll.sources

@@ -438,7 +438,6 @@ System.Net/WebConnection.cs
 System.Net/WebConnectionData.cs
 System.Net/WebConnectionGroup.cs
 System.Net/WebConnectionStream.cs
-System.Net/WebHeaderCollection.cs
 System.Net/WebProxy.cs
 System.Net/WebRequest.cs
 System.Net.WebSockets/ClientWebSocket.cs
@@ -591,6 +590,7 @@ ReferenceSources/ConfigurationManagerInternalFactory.cs
 ReferenceSources/CAPI.cs
 ReferenceSources/EnvironmentHelpers.cs
 ReferenceSources/Internal.cs
+ReferenceSources/HttpApi.cs
 ReferenceSources/HttpSysSettings.cs
 ReferenceSources/Logging.cs
 ReferenceSources/NativeMethods.cs
@@ -600,7 +600,6 @@ ReferenceSources/SR.cs
 ReferenceSources/SR2.cs
 ReferenceSources/SRCategoryAttribute.cs
 ReferenceSources/SystemNetworkCredential.cs
-ReferenceSources/WebHeaderCollectionType.cs
 ReferenceSources/Win32Exception.cs
 
 ReferenceSources/SSPIConfiguration.cs
@@ -995,6 +994,10 @@ ReferenceSources/_SslStream.cs
 ../referencesource/System/net/System/UriScheme.cs
 
 ../referencesource/System/net/System/Net/_BufferOffsetSize.cs
+../referencesource/System/net/System/Net/_Connection.cs
+../referencesource/System/net/System/Net/_HeaderInfo.cs
+../referencesource/System/net/System/Net/_HeaderInfoTable.cs
+../referencesource/System/net/System/Net/_HTTPDateParse.cs
 ../referencesource/System/net/System/Net/_IStreams.cs
 ../referencesource/System/net/System/Net/_NetRes.cs
 ../referencesource/System/net/System/Net/_LazyAsyncResult.cs

+ 3 - 1
mcs/class/System/Test/System.Net/HttpWebRequestTest.cs

@@ -1718,7 +1718,9 @@ namespace MonoTests.System.Net
 				Where = "first write";
 				StreamWriter writer = new StreamWriter (ns, Encoding.ASCII);
 				writer.Write (  "HTTP/1.1 401 Unauthorized\r\n" +
-						"WWW-Authenticate: NTLM\r\n" +
+					"WWW-Authenticate: ignore\r\n" +
+					"WWW-Authenticate: NTLM\r\n" +
+					"WWW-Authenticate: ignore,K\r\n" +
 						"Content-Length: 5\r\n\r\nWRONG");
 
 				writer.Flush ();

+ 5 - 2
mcs/class/System/mobile_System.dll.sources

@@ -217,7 +217,6 @@ System.Net/WebConnection.cs
 System.Net/WebConnectionData.cs
 System.Net/WebConnectionGroup.cs
 System.Net/WebConnectionStream.cs
-System.Net/WebHeaderCollection.cs
 System.Net/WebProxy.cs
 System.Net/WebRequest.cs
 System.Net.WebSockets/ClientWebSocket.cs
@@ -322,6 +321,7 @@ Mono.Net.Security/SystemCertificateValidator.cs
 ReferenceSources/AssertWrapper.cs
 ReferenceSources/CAPI.cs
 ReferenceSources/EnvironmentHelpers.cs
+ReferenceSources/HttpApi.cs
 ReferenceSources/Internal.cs
 ReferenceSources/HttpSysSettings.cs
 ReferenceSources/Logging.cs
@@ -331,7 +331,6 @@ ReferenceSources/Socket.cs
 ReferenceSources/SR.cs
 ReferenceSources/SRCategoryAttribute.cs
 ReferenceSources/SystemNetworkCredential.cs
-ReferenceSources/WebHeaderCollectionType.cs
 ReferenceSources/Win32Exception.cs
 
 ../referencesource/System/regex/system/text/regularexpressions/Regex.cs
@@ -707,6 +706,10 @@ ReferenceSources/Win32Exception.cs
 ../referencesource/System/net/System/UriScheme.cs
 
 ../referencesource/System/net/System/Net/_BufferOffsetSize.cs
+../referencesource/System/net/System/Net/_Connection.cs
+../referencesource/System/net/System/Net/_HeaderInfo.cs
+../referencesource/System/net/System/Net/_HeaderInfoTable.cs
+../referencesource/System/net/System/Net/_HTTPDateParse.cs
 ../referencesource/System/net/System/Net/_IStreams.cs
 ../referencesource/System/net/System/Net/_NetRes.cs
 ../referencesource/System/net/System/Net/_LazyAsyncResult.cs

+ 0 - 2
mcs/class/referencesource/System/net/System/Net/Internal.cs

@@ -1961,7 +1961,6 @@ typedef struct _SCHANNEL_CRED
         }
     }
 
-#if MONO_FEATURE_WEB_STACK
     //
     // HttpProtocolUtils - A collection of utility functions for HTTP usage.
     //
@@ -1995,7 +1994,6 @@ typedef struct _SCHANNEL_CRED
             return D.ToUniversalTime().ToString("R", dateFormat);
         }
     }
-#endif
 
 #if !FEATURE_PAL
     // Proxy class for linking between ICertificatePolicy <--> ICertificateDecider

+ 10 - 3
mcs/class/referencesource/System/net/System/Net/WebHeaderCollection.cs

@@ -14,7 +14,7 @@ namespace System.Net {
     using System.Globalization;
     using System.Security.Permissions;
     using System.Diagnostics.CodeAnalysis;
-#if !MONO
+
     internal enum WebHeaderCollectionType : ushort {
         Unknown,
         WebRequest,
@@ -246,7 +246,14 @@ namespace System.Net {
         // this is the object that created the header collection.
         private WebHeaderCollectionType m_Type;
 
-#if !FEATURE_PAL
+#if MONO
+        internal bool AllowMultiValues (string name)
+        {
+            return HInfo[name].AllowMultiValues;
+        }
+#endif
+
+#if !FEATURE_PAL || MONO
         private bool AllowHttpRequestHeader {
             get {
                 if (m_Type==WebHeaderCollectionType.Unknown) {
@@ -1971,7 +1978,7 @@ quit:
                 m_InnerCollection.Clear();
         }
     } // class WebHeaderCollection
-#endif
+
 
     internal class CaseInsensitiveAscii : IEqualityComparer, IComparer{
         // ASCII char ToLower table

+ 4 - 1
mcs/class/referencesource/System/net/System/Net/_Connection.cs

@@ -17,12 +17,14 @@ namespace System.Net {
     using System.Net.Configuration;
     using System.Diagnostics.CodeAnalysis;
 
+#if !MONO
     internal enum ReadState {
         Start,
         StatusLine, // about to parse status line
         Headers,    // reading headers
         Data        // now read data
     }
+#endif
 
     internal enum DataParseStatus {
         NeedMoreData = 0,   // need more data
@@ -64,7 +66,7 @@ namespace System.Net {
         public WebParseErrorCode     Code;
     }
 
-
+#if !MONO
     struct TunnelStateObject {
         internal TunnelStateObject(HttpWebRequest r, Connection c){
             Connection = c;
@@ -3846,4 +3848,5 @@ done:
         }
 #endif
     }
+#endif
 }