diff options
Diffstat (limited to 'mcs/class/System.Net.Http/System.Net.Http.Headers')
19 files changed, 511 insertions, 178 deletions
diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/AuthenticationHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/AuthenticationHeaderValue.cs index 33f87db8f0..7bb2496a94 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/AuthenticationHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/AuthenticationHeaderValue.cs @@ -26,6 +26,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Collections.Generic; + namespace System.Net.Http.Headers { public class AuthenticationHeaderValue : ICloneable @@ -85,8 +87,23 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out AuthenticationHeaderValue parsedValue) { var lexer = new Lexer (input); - var t = lexer.Scan (); - if (t != Token.Type.Token || !(lexer.PeekChar () == ' ' || lexer.PeekChar () == -1)) { + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + + parsedValue = null; + return false; + } + + internal static bool TryParse (string input, int minimalCount, out List<AuthenticationHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + + static bool TryParseElement (Lexer lexer, out AuthenticationHeaderValue parsedValue, out Token t) + { + t = lexer.Scan (); + if (t != Token.Type.Token) { parsedValue = null; return false; } @@ -95,8 +112,11 @@ namespace System.Net.Http.Headers parsedValue.Scheme = lexer.GetStringValue (t); t = lexer.Scan (); - if (t != Token.Type.End) + if (t == Token.Type.Token) { + // TODO: Wrong with multi value parsing parsedValue.Parameter = lexer.GetRemainingStringValue (t.StartPosition); + t = new Token (Token.Type.End, 0, 0); + } return true; } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/CollectionParser.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/CollectionParser.cs new file mode 100644 index 0000000000..cbaafe0f80 --- /dev/null +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/CollectionParser.cs @@ -0,0 +1,117 @@ +// +// CollectionParser.cs +// +// Authors: +// Marek Safar <marek.safar@gmail.com> +// +// Copyright (C) 2014 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.Collections.Generic; + +namespace System.Net.Http.Headers +{ + delegate bool ElementTryParser<T> (Lexer lexer, out T parsedValue, out Token token); + + static class CollectionParser + { + public static bool TryParse<T> (string input, int minimalCount, ElementTryParser<T> parser, out List<T> result) where T : class + { + var lexer = new Lexer (input); + result = new List<T> (); + + while (true) { + Token token; + T parsedValue; + if (!parser (lexer, out parsedValue, out token)) + return false; + + if (parsedValue != null) + result.Add (parsedValue); + + if (token == Token.Type.SeparatorComma) + continue; + + if (token == Token.Type.End) { + if (minimalCount > result.Count) { + result = null; + return false; + } + + return true; + } + + result = null; + return false; + } + } + + public static bool TryParse (string input, int minimalCount, out List<string> result) + { + return TryParse (input, minimalCount, TryParseStringElement, out result); + } + + public static bool TryParseRepetition (string input, int minimalCount, out List<string> result) + { + return TryParseRepetition (input, minimalCount, TryParseStringElement, out result); + } + + static bool TryParseStringElement (Lexer lexer, out string parsedValue, out Token t) + { + t = lexer.Scan (); + if (t == Token.Type.Token) { + parsedValue = lexer.GetStringValue (t); + if (parsedValue.Length == 0) + parsedValue = null; + + t = lexer.Scan (); + } else { + parsedValue = null; + } + + return true; + } + + public static bool TryParseRepetition<T> (string input, int minimalCount, ElementTryParser<T> parser, out List<T> result) where T : class + { + var lexer = new Lexer (input); + result = new List<T> (); + + while (true) { + Token token; + T parsedValue; + if (!parser (lexer, out parsedValue, out token)) + return false; + + if (parsedValue != null) + result.Add (parsedValue); + + if (token == Token.Type.End) { + if (minimalCount > result.Count) + return false; + + return true; + } + } + } + } +}
\ No newline at end of file diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs index a4d1ae275b..9dd41b3d33 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/ContentDispositionHeaderValue.cs @@ -394,7 +394,7 @@ namespace System.Net.Http.Headers switch (t.Kind) { case Token.Type.SeparatorSemicolon: - if (!NameValueHeaderValue.TryParseParameters (lexer, out parameters)) + if (!NameValueHeaderValue.TryParseParameters (lexer, out parameters, out t) || t != Token.Type.End) return false; break; case Token.Type.End: diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/EntityTagHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/EntityTagHeaderValue.cs index 9b10983bbf..8c255cfaed 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/EntityTagHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/EntityTagHeaderValue.cs @@ -26,6 +26,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Collections.Generic; + namespace System.Net.Http.Headers { public class EntityTagHeaderValue : ICloneable @@ -85,14 +87,32 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out EntityTagHeaderValue parsedValue) { + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + parsedValue = null; + return false; + } - var lexer = new Lexer (input); - var t = lexer.Scan (); + static bool TryParseElement (Lexer lexer, out EntityTagHeaderValue parsedValue, out Token t) + { + parsedValue = null; + + t = lexer.Scan (); bool is_weak = false; if (t == Token.Type.Token) { - if (lexer.GetStringValue (t) != "W" || lexer.PeekChar () != '/') + var s = lexer.GetStringValue (t); + if (s == "*") { + parsedValue = any; + + t = lexer.Scan (); + return true; + } + + if (s != "W" || lexer.PeekChar () != '/') return false; is_weak = true; @@ -103,15 +123,20 @@ namespace System.Net.Http.Headers if (t != Token.Type.QuotedString) return false; - if (lexer.Scan () != Token.Type.End) - return false; - parsedValue = new EntityTagHeaderValue (); parsedValue.Tag = lexer.GetStringValue (t); parsedValue.IsWeak = is_weak; + + t = lexer.Scan (); + return true; } + internal static bool TryParse (string input, int minimalCount, out List<EntityTagHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + public override string ToString () { return IsWeak ? diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/HeaderInfo.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/HeaderInfo.cs index 3772180e52..6337319ea1 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/HeaderInfo.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/HeaderInfo.cs @@ -4,7 +4,7 @@ // Authors: // Marek Safar <marek.safar@gmail.com> // -// Copyright (C) 2011 Xamarin Inc (http://www.xamarin.com) +// Copyright (C) 2011, 2014 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 @@ -32,6 +32,7 @@ using System.Collections.Generic; namespace System.Net.Http.Headers { delegate bool TryParseDelegate<T> (string value, out T result); + delegate bool TryParseListDelegate<T> (string value, int minimalCount, out List<T> result); abstract class HeaderInfo { @@ -89,6 +90,32 @@ namespace System.Net.Http.Headers } } + class CollectionHeaderTypeInfo<T, U> : HeaderTypeInfo<T, U> where U : class + { + readonly int minimalCount; + TryParseListDelegate<T> parser; + + public CollectionHeaderTypeInfo (string name, TryParseListDelegate<T> parser, HttpHeaderKind headerKind, int minimalCount) + : base (name, null, headerKind) + { + this.parser = parser; + this.minimalCount = minimalCount; + AllowsMany = true; + } + + public override bool TryParse (string value, out object result) + { + List<T> tresult; + if (!parser (value, minimalCount, out tresult)) { + result = null; + return false; + } + + result = tresult; + return true; + } + } + public bool AllowsMany; public readonly HttpHeaderKind HeaderKind; public readonly string Name; @@ -104,18 +131,12 @@ namespace System.Net.Http.Headers return new HeaderTypeInfo<T, object> (name, parser, headerKind); } - public static HeaderInfo CreateMulti<T> (string name, TryParseDelegate<T> parser, HttpHeaderKind headerKind) where T : class - { - return new HeaderTypeInfo<T, T> (name, parser, headerKind) { - AllowsMany = true, - }; - } - - public static HeaderInfo CreateMultiList<T> (string name, TryParseDelegate<List<T>> parser, HttpHeaderKind headerKind) where T : class + // + // Headers with #rule for defining lists of elements or *rule for defining occurences of elements + // + public static HeaderInfo CreateMulti<T> (string name, TryParseListDelegate<T> elementParser, HttpHeaderKind headerKind, int minimalCount = 1) where T : class { - return new HeaderTypeInfo<List<T>, T> (name, parser, headerKind) { - AllowsMany = true, - }; + return new CollectionHeaderTypeInfo<T, T> (name, elementParser, headerKind, minimalCount); } public object CreateCollection (HttpHeaders headers) diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs index 1dc3affa32..ffef647b5e 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/HttpHeaders.cs @@ -90,14 +90,14 @@ namespace System.Net.Http.Headers HeaderInfo.CreateMulti<StringWithQualityHeaderValue> ("Accept-Charset", StringWithQualityHeaderValue.TryParse, HttpHeaderKind.Request), HeaderInfo.CreateMulti<StringWithQualityHeaderValue> ("Accept-Encoding", StringWithQualityHeaderValue.TryParse, HttpHeaderKind.Request), HeaderInfo.CreateMulti<StringWithQualityHeaderValue> ("Accept-Language", StringWithQualityHeaderValue.TryParse, HttpHeaderKind.Request), - HeaderInfo.CreateMulti<string> ("Accept-Ranges", Parser.Token.TryParse, HttpHeaderKind.Response), + HeaderInfo.CreateMulti<string> ("Accept-Ranges", CollectionParser.TryParse, HttpHeaderKind.Response), HeaderInfo.CreateSingle<TimeSpan> ("Age", Parser.TimeSpanSeconds.TryParse, HttpHeaderKind.Response), - HeaderInfo.CreateMulti<string> ("Allow", Parser.Token.TryParse, HttpHeaderKind.Content), + HeaderInfo.CreateMulti<string> ("Allow", CollectionParser.TryParse, HttpHeaderKind.Content, 0), HeaderInfo.CreateSingle<AuthenticationHeaderValue> ("Authorization", AuthenticationHeaderValue.TryParse, HttpHeaderKind.Request), HeaderInfo.CreateSingle<CacheControlHeaderValue> ("Cache-Control", CacheControlHeaderValue.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), - HeaderInfo.CreateMulti<string> ("Connection", Parser.Token.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), - HeaderInfo.CreateMulti<string> ("Content-Encoding", Parser.Token.TryParse, HttpHeaderKind.Content), - HeaderInfo.CreateMulti<string> ("Content-Language", Parser.Token.TryParse, HttpHeaderKind.Content), + HeaderInfo.CreateMulti<string> ("Connection", CollectionParser.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), + HeaderInfo.CreateMulti<string> ("Content-Encoding", CollectionParser.TryParse, HttpHeaderKind.Content), + HeaderInfo.CreateMulti<string> ("Content-Language", CollectionParser.TryParse, HttpHeaderKind.Content), HeaderInfo.CreateSingle<long> ("Content-Length", Parser.Long.TryParse, HttpHeaderKind.Content), HeaderInfo.CreateSingle<Uri> ("Content-Location", Parser.Uri.TryParse, HttpHeaderKind.Content), HeaderInfo.CreateSingle<byte[]> ("Content-MD5", Parser.MD5.TryParse, HttpHeaderKind.Content), @@ -117,19 +117,19 @@ namespace System.Net.Http.Headers HeaderInfo.CreateSingle<DateTimeOffset> ("Last-Modified", Parser.DateTime.TryParse, HttpHeaderKind.Content), HeaderInfo.CreateSingle<Uri> ("Location", Parser.Uri.TryParse, HttpHeaderKind.Response), HeaderInfo.CreateSingle<int> ("Max-Forwards", Parser.Int.TryParse, HttpHeaderKind.Request), - HeaderInfo.CreateMultiList<NameValueHeaderValue> ("Pragma", NameValueHeaderValue.TryParsePragma, HttpHeaderKind.Request | HttpHeaderKind.Response), + HeaderInfo.CreateMulti<NameValueHeaderValue> ("Pragma", NameValueHeaderValue.TryParsePragma, HttpHeaderKind.Request | HttpHeaderKind.Response), HeaderInfo.CreateMulti<AuthenticationHeaderValue> ("Proxy-Authenticate", AuthenticationHeaderValue.TryParse, HttpHeaderKind.Response), HeaderInfo.CreateSingle<AuthenticationHeaderValue> ("Proxy-Authorization", AuthenticationHeaderValue.TryParse, HttpHeaderKind.Request), HeaderInfo.CreateSingle<RangeHeaderValue> ("Range", RangeHeaderValue.TryParse, HttpHeaderKind.Request), HeaderInfo.CreateSingle<Uri> ("Referer", Parser.Uri.TryParse, HttpHeaderKind.Request), HeaderInfo.CreateSingle<RetryConditionHeaderValue> ("Retry-After", RetryConditionHeaderValue.TryParse, HttpHeaderKind.Response), HeaderInfo.CreateMulti<ProductInfoHeaderValue> ("Server", ProductInfoHeaderValue.TryParse, HttpHeaderKind.Response), - HeaderInfo.CreateMulti<TransferCodingWithQualityHeaderValue> ("TE", TransferCodingWithQualityHeaderValue.TryParse, HttpHeaderKind.Request), - HeaderInfo.CreateMulti<string> ("Trailer", Parser.Token.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), + HeaderInfo.CreateMulti<TransferCodingWithQualityHeaderValue> ("TE", TransferCodingWithQualityHeaderValue.TryParse, HttpHeaderKind.Request, 0), + HeaderInfo.CreateMulti<string> ("Trailer", CollectionParser.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), HeaderInfo.CreateMulti<TransferCodingHeaderValue> ("Transfer-Encoding", TransferCodingHeaderValue.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), HeaderInfo.CreateMulti<ProductHeaderValue> ("Upgrade", ProductHeaderValue.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), - HeaderInfo.CreateMultiList<ProductInfoHeaderValue> ("User-Agent", ProductInfoHeaderValue.TryParse, HttpHeaderKind.Request), - HeaderInfo.CreateMulti<string> ("Vary", Parser.Token.TryParse, HttpHeaderKind.Response), + HeaderInfo.CreateMulti<ProductInfoHeaderValue> ("User-Agent", ProductInfoHeaderValue.TryParse, HttpHeaderKind.Request), + HeaderInfo.CreateMulti<string> ("Vary", CollectionParser.TryParse, HttpHeaderKind.Response), HeaderInfo.CreateMulti<ViaHeaderValue> ("Via", ViaHeaderValue.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), HeaderInfo.CreateMulti<WarningHeaderValue> ("Warning", WarningHeaderValue.TryParse, HttpHeaderKind.Request | HttpHeaderKind.Response), HeaderInfo.CreateMulti<AuthenticationHeaderValue> ("WWW-Authenticate", AuthenticationHeaderValue.TryParse, HttpHeaderKind.Response) @@ -231,16 +231,9 @@ namespace System.Net.Http.Headers if (values == null) throw new ArgumentNullException ("values"); - if (string.IsNullOrEmpty (name)) - return false; - - Parser.Token.Check (name); - HeaderInfo headerInfo; - if (known_headers.TryGetValue (name, out headerInfo) && (headerInfo.HeaderKind & HeaderKind) == 0) { - if (HeaderKind != HttpHeaderKind.None && ((HeaderKind | headerInfo.HeaderKind) & HttpHeaderKind.Content) != 0) - return false; - } + if (!TryCheckName (name, out headerInfo)) + return false; AddInternal (name, values, null, true); return true; @@ -264,6 +257,21 @@ namespace System.Net.Http.Headers return headerInfo; } + bool TryCheckName (string name, out HeaderInfo headerInfo) + { + if (!Parser.Token.TryCheck (name)) { + headerInfo = null; + return false; + } + + if (known_headers.TryGetValue (name, out headerInfo) && (headerInfo.HeaderKind & HeaderKind) == 0) { + if (HeaderKind != HttpHeaderKind.None && ((HeaderKind | headerInfo.HeaderKind) & HttpHeaderKind.Content) != 0) + return false; + } + + return true; + } + public void Clear () { connectionclose = null; @@ -301,6 +309,8 @@ namespace System.Net.Http.Headers public IEnumerable<string> GetValues (string name) { + CheckName (name); + IEnumerable<string> values; if (!TryGetValues (name, out values)) throw new InvalidOperationException (); @@ -316,7 +326,11 @@ namespace System.Net.Http.Headers public bool TryGetValues (string name, out IEnumerable<string> values) { - var header_info = CheckName (name); + HeaderInfo headerInfo; + if (!TryCheckName (name, out headerInfo)) { + values = null; + return false; + } HeaderBucket bucket; if (!headers.TryGetValue (name, out bucket)) { @@ -324,7 +338,7 @@ namespace System.Net.Http.Headers return false; } - values = GetAllHeaderValues (bucket, header_info); + values = GetAllHeaderValues (bucket, headerInfo); return true; } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs index 0f98be658d..f87d4f741b 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/Lexer.cs @@ -46,6 +46,8 @@ namespace System.Net.Http.Headers OpenParens, } + public static readonly Token Empty = new Token (Type.Token, 0, 0); + readonly Type type; public Token (Type type, int startPosition, int endPosition) diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeHeaderValue.cs index 5379a6099f..296010aa2a 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeHeaderValue.cs @@ -33,7 +33,7 @@ namespace System.Net.Http.Headers public class MediaTypeHeaderValue : ICloneable { internal List<NameValueHeaderValue> parameters; - string media_type; + internal string media_type; public MediaTypeHeaderValue (string mediaType) { @@ -150,7 +150,8 @@ namespace System.Net.Http.Headers switch (token.Value.Kind) { case Token.Type.SeparatorSemicolon: - if (!NameValueHeaderValue.TryParseParameters (lexer, out parameters)) + Token t; + if (!NameValueHeaderValue.TryParseParameters (lexer, out parameters, out t) || t != Token.Type.End) return false; break; case Token.Type.End: @@ -167,37 +168,7 @@ namespace System.Net.Http.Headers return true; } - internal static bool TryParse<T> (string input, out T parsedValue, Func<T> factory) where T : MediaTypeHeaderValue - { - parsedValue = null; - - var lexer = new Lexer (input); - - string media; - List<NameValueHeaderValue> parameters = null; - var token = TryParseMediaType (lexer, out media); - if (token == null) - return false; - - switch (token.Value.Kind) { - case Token.Type.SeparatorSemicolon: - if (!NameValueHeaderValue.TryParseParameters (lexer, out parameters)) - return false; - break; - case Token.Type.End: - break; - default: - return false; - } - - parsedValue = factory (); - parsedValue.media_type = media; - parsedValue.parameters = parameters; - - return true; - } - - static Token? TryParseMediaType (Lexer lexer, out string media) + internal static Token? TryParseMediaType (Lexer lexer, out string media) { media = null; diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeWithQualityHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeWithQualityHeaderValue.cs index a3415fc1e1..1cf406dbfd 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeWithQualityHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/MediaTypeWithQualityHeaderValue.cs @@ -26,6 +26,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Collections.Generic; + namespace System.Net.Http.Headers { public sealed class MediaTypeWithQualityHeaderValue : MediaTypeHeaderValue @@ -65,7 +67,40 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out MediaTypeWithQualityHeaderValue parsedValue) { - return TryParse (input, out parsedValue, () => new MediaTypeWithQualityHeaderValue ()); + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + + parsedValue = null; + return false; + } + + static bool TryParseElement (Lexer lexer, out MediaTypeWithQualityHeaderValue parsedValue, out Token t) + { + parsedValue = null; + + string media; + List<NameValueHeaderValue> parameters = null; + var token = TryParseMediaType (lexer, out media); + if (token == null) { + t = Token.Empty; + return false; + } + + t = token.Value; + if (t == Token.Type.SeparatorSemicolon && (!NameValueHeaderValue.TryParseParameters (lexer, out parameters, out t) || t != Token.Type.End)) + return false; + + parsedValue = new MediaTypeWithQualityHeaderValue (); + parsedValue.media_type = media; + parsedValue.parameters = parameters; + return true; + } + + internal static bool TryParse (string input, int minimalCount, out List<MediaTypeWithQualityHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); } } } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueHeaderValue.cs index 906ab3aa65..e3766a4eb1 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueHeaderValue.cs @@ -32,7 +32,7 @@ namespace System.Net.Http.Headers { public class NameValueHeaderValue : ICloneable { - string value; + internal string value; public NameValueHeaderValue (string name) : this (name, null) @@ -53,11 +53,11 @@ namespace System.Net.Http.Headers this.value = source.value; } - private NameValueHeaderValue () + internal NameValueHeaderValue () { } - public string Name { get; private set; } + public string Name { get; internal set; } public string Value { get { @@ -121,27 +121,22 @@ namespace System.Net.Http.Headers throw new FormatException (input); } - internal static bool TryParseParameters (Lexer lexer, out List<NameValueHeaderValue> result) + internal static bool TryParsePragma (string input, int minimalCount, out List<NameValueHeaderValue> result) { - return TryParseCollection (lexer, out result, Token.Type.SeparatorSemicolon); + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); } - internal static bool TryParsePragma (string input, out List<NameValueHeaderValue> result) - { - return TryParseCollection (new Lexer (input), out result, Token.Type.SeparatorComma); - } - - static bool TryParseCollection (Lexer lexer, out List<NameValueHeaderValue> result, Token.Type separator) + internal static bool TryParseParameters (Lexer lexer, out List<NameValueHeaderValue> result, out Token t) { var list = new List<NameValueHeaderValue> (); result = null; - Token t; - - do { + while (true) { var attr = lexer.Scan (); - if (attr != Token.Type.Token) + if (attr != Token.Type.Token) { + t = Token.Empty; return false; + } string value = null; @@ -156,19 +151,17 @@ namespace System.Net.Http.Headers t = lexer.Scan (); } - if (t == separator|| t == Token.Type.End) { - list.Add (new NameValueHeaderValue () { - Name = lexer.GetStringValue (attr), - value = value - }); - } else { - return false; - } + list.Add (new NameValueHeaderValue () { + Name = lexer.GetStringValue (attr), + value = value + }); - } while (t == separator); + if (t == Token.Type.SeparatorSemicolon) + continue; - result = list; - return true; + result = list; + return true; + } } public override string ToString () @@ -181,35 +174,39 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out NameValueHeaderValue parsedValue) { - parsedValue = null; - var lexer = new Lexer (input); - var t = lexer.Scan (); - if (t != Token.Type.Token && t != Token.Type.QuotedString) - return false; + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; - string v = null; - var token2 = lexer.Scan (); - if (token2 != Token.Type.End) { - if (token2 != Token.Type.SeparatorEqual) - return false; - - token2 = lexer.Scan (); + parsedValue = null; + return false; + } - if (token2 == Token.Type.Token || token2 == Token.Type.QuotedString) { - v = lexer.GetStringValue (token2); - token2 = lexer.Scan (); - } + static bool TryParseElement (Lexer lexer, out NameValueHeaderValue parsedValue, out Token t) + { + parsedValue = null; - if (token2 != Token.Type.End) - return false; - } + t = lexer.Scan (); + if (t != Token.Type.Token) + return false; parsedValue = new NameValueHeaderValue () { Name = lexer.GetStringValue (t), - value = v }; + t = lexer.Scan (); + if (t == Token.Type.SeparatorEqual) { + t = lexer.Scan (); + + if (t == Token.Type.Token || t == Token.Type.QuotedString) { + parsedValue.value = lexer.GetStringValue (t); + t = lexer.Scan (); + } else { + return false; + } + } + return true; } } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueWithParametersHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueWithParametersHeaderValue.cs index 81d7bb089c..3d32834184 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueWithParametersHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/NameValueWithParametersHeaderValue.cs @@ -53,8 +53,8 @@ namespace System.Net.Http.Headers } } - private NameValueWithParametersHeaderValue (NameValueHeaderValue source) - : base (source) + private NameValueWithParametersHeaderValue () + : base () { } @@ -102,15 +102,52 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out NameValueWithParametersHeaderValue parsedValue) { - List<NameValueHeaderValue> values; - if (!TryParseParameters (new Lexer (input), out values)) { - parsedValue = null; + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + + parsedValue = null; + return false; + } + + internal static bool TryParse (string input, int minimalCount, out List<NameValueWithParametersHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + + static bool TryParseElement (Lexer lexer, out NameValueWithParametersHeaderValue parsedValue, out Token t) + { + parsedValue = null; + + t = lexer.Scan (); + if (t != Token.Type.Token) return false; + + parsedValue = new NameValueWithParametersHeaderValue () { + Name = lexer.GetStringValue (t), + }; + + t = lexer.Scan (); + if (t == Token.Type.SeparatorEqual) { + t = lexer.Scan (); + + if (t == Token.Type.Token || t == Token.Type.QuotedString) { + parsedValue.value = lexer.GetStringValue (t); + t = lexer.Scan (); + } else { + return false; + } + } + + if (t == Token.Type.SeparatorSemicolon) { + List<NameValueHeaderValue> result; + if (!TryParseParameters (lexer, out result, out t)) + return false; + + parsedValue.parameters = result; } - parsedValue = new NameValueWithParametersHeaderValue (values[0]); - values.RemoveAt (0); - parsedValue.parameters = values; return true; } } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/Parser.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/Parser.cs index cdf73d3a78..79a3ca380c 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/Parser.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/Parser.cs @@ -28,6 +28,7 @@ using System.Net.Mail; using System.Globalization; +using System.Collections.Generic; namespace System.Net.Http.Headers { @@ -64,14 +65,7 @@ namespace System.Net.Http.Headers if (s == null) return false; - if (!Lexer.IsValidToken (s)) { - if (s.Length == 0) - return false; - - return false; - } - - return true; + return Lexer.IsValidToken (s); } public static void CheckQuotedString (string s) diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductHeaderValue.cs index 306c9f228c..9614df1293 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductHeaderValue.cs @@ -26,6 +26,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Collections.Generic; + namespace System.Net.Http.Headers { public class ProductHeaderValue : ICloneable @@ -87,15 +89,30 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out ProductHeaderValue parsedValue) { + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + parsedValue = null; + return false; + } - var lexer = new Lexer (input); - var t = lexer.Scan (); + internal static bool TryParse (string input, int minimalCount, out List<ProductHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + + static bool TryParseElement (Lexer lexer, out ProductHeaderValue parsedValue, out Token t) + { + parsedValue = null; + + t = lexer.Scan (); if (t != Token.Type.Token) return false; - var value = new ProductHeaderValue (); - value.Name = lexer.GetStringValue (t); + parsedValue = new ProductHeaderValue (); + parsedValue.Name = lexer.GetStringValue (t); t = lexer.Scan (); if (t == Token.Type.SeparatorSlash) { @@ -103,14 +120,10 @@ namespace System.Net.Http.Headers if (t != Token.Type.Token) return false; - value.Version = lexer.GetStringValue (t); + parsedValue.Version = lexer.GetStringValue (t); t = lexer.Scan (); } - if (t != Token.Type.End) - return false; - - parsedValue = value; return true; } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductInfoHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductInfoHeaderValue.cs index daf47ac31e..baace53ed8 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductInfoHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/ProductInfoHeaderValue.cs @@ -106,7 +106,7 @@ namespace System.Net.Http.Headers return true; } - internal static bool TryParse (string input, out List<ProductInfoHeaderValue> result) + internal static bool TryParse (string input, int minimalCount, out List<ProductInfoHeaderValue> result) { var list = new List<ProductInfoHeaderValue> (); var lexer = new Lexer (input); @@ -118,8 +118,12 @@ namespace System.Net.Http.Headers return false; if (element == null) { - result = list; - return true; + if (list != null && minimalCount <= list.Count) { + result = list; + return true; + } + + return false; } list.Add (element); diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/StringWithQualityHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/StringWithQualityHeaderValue.cs index 635ed00223..648d4222e3 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/StringWithQualityHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/StringWithQualityHeaderValue.cs @@ -27,6 +27,8 @@ // using System.Globalization; +using System.Collections.Generic; + namespace System.Net.Http.Headers { public class StringWithQualityHeaderValue : ICloneable @@ -82,10 +84,24 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out StringWithQualityHeaderValue parsedValue) { + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + parsedValue = null; + return false; + } - var lexer = new Lexer (input); - var t = lexer.Scan (); + internal static bool TryParse (string input, int minimalCount, out List<StringWithQualityHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + + static bool TryParseElement (Lexer lexer, out StringWithQualityHeaderValue parsedValue, out Token t) + { + parsedValue = null; + t = lexer.Scan (); if (t != Token.Type.Token) return false; @@ -120,9 +136,6 @@ namespace System.Net.Http.Headers t = lexer.Scan (); } - if (t != Token.Type.End) - return false; - parsedValue = value; return true; } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingHeaderValue.cs index 8f0db59283..6e9825ea4c 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingHeaderValue.cs @@ -32,7 +32,7 @@ namespace System.Net.Http.Headers { public class TransferCodingHeaderValue : ICloneable { - string value; + internal string value; internal List<NameValueHeaderValue> parameters; public TransferCodingHeaderValue (string value) @@ -106,30 +106,36 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out TransferCodingHeaderValue parsedValue) { - return TryParse (input, out parsedValue, () => new TransferCodingHeaderValue ()); + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + + parsedValue = null; + return false; } - internal static bool TryParse<T> (string input, out T parsedValue, Func<T> factory) where T : TransferCodingHeaderValue + internal static bool TryParse (string input, int minimalCount, out List<TransferCodingHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + + static bool TryParseElement (Lexer lexer, out TransferCodingHeaderValue parsedValue, out Token t) { parsedValue = null; - var lexer = new Lexer (input); - var t = lexer.Scan (); + t = lexer.Scan (); if (t != Token.Type.Token) return false; - var result = factory (); + var result = new TransferCodingHeaderValue (); result.value = lexer.GetStringValue (t); t = lexer.Scan (); // Parameters parsing - if (t == Token.Type.SeparatorSemicolon) { - if (!NameValueHeaderValue.TryParseParameters (lexer, out result.parameters)) - return false; - } else if (t != Token.Type.End) { + if (t == Token.Type.SeparatorSemicolon && (!NameValueHeaderValue.TryParseParameters (lexer, out result.parameters, out t) || t != Token.Type.End)) return false; - } parsedValue = result; return true; diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingWithQualityHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingWithQualityHeaderValue.cs index 0a6e08373c..845b95ef5c 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingWithQualityHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/TransferCodingWithQualityHeaderValue.cs @@ -26,6 +26,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Collections.Generic; + namespace System.Net.Http.Headers { public sealed class TransferCodingWithQualityHeaderValue : TransferCodingHeaderValue @@ -65,7 +67,39 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out TransferCodingWithQualityHeaderValue parsedValue) { - return TryParse (input, out parsedValue, () => new TransferCodingWithQualityHeaderValue ()); + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + + parsedValue = null; + return false; + } + + internal static bool TryParse (string input, int minimalCount, out List<TransferCodingWithQualityHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + + static bool TryParseElement (Lexer lexer, out TransferCodingWithQualityHeaderValue parsedValue, out Token t) + { + parsedValue = null; + + t = lexer.Scan (); + if (t != Token.Type.Token) + return false; + + var result = new TransferCodingWithQualityHeaderValue (); + result.value = lexer.GetStringValue (t); + + t = lexer.Scan (); + + // Parameters parsing + if (t == Token.Type.SeparatorSemicolon && (!NameValueHeaderValue.TryParseParameters (lexer, out result.parameters, out t) || t != Token.Type.End)) + return false; + + parsedValue = result; + return true; } } } diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/ViaHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/ViaHeaderValue.cs index 4da14004e1..9381977ee1 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/ViaHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/ViaHeaderValue.cs @@ -26,6 +26,8 @@ // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +using System.Collections.Generic; + namespace System.Net.Http.Headers { public class ViaHeaderValue : ICloneable @@ -110,11 +112,25 @@ namespace System.Net.Http.Headers public static bool TryParse (string input, out ViaHeaderValue parsedValue) { + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + parsedValue = null; + return false; + } - var lexer = new Lexer (input); + internal static bool TryParse (string input, int minimalCount, out List<ViaHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } - var t = lexer.Scan (); + static bool TryParseElement (Lexer lexer, out ViaHeaderValue parsedValue, out Token t) + { + parsedValue = null; + + t = lexer.Scan (); if (t != Token.Type.Token) return false; @@ -150,8 +166,9 @@ namespace System.Net.Http.Headers value.ReceivedBy = lexer.GetStringValue (next, t); string comment; - if (!lexer.ScanCommentOptional (out comment)) - return false; + if (lexer.ScanCommentOptional (out comment, out t)) { + t = lexer.Scan (); + } value.Comment = comment; parsedValue = value; diff --git a/mcs/class/System.Net.Http/System.Net.Http.Headers/WarningHeaderValue.cs b/mcs/class/System.Net.Http/System.Net.Http.Headers/WarningHeaderValue.cs index fc58299cf0..5c65339ef7 100644 --- a/mcs/class/System.Net.Http/System.Net.Http.Headers/WarningHeaderValue.cs +++ b/mcs/class/System.Net.Http/System.Net.Http.Headers/WarningHeaderValue.cs @@ -27,6 +27,7 @@ // using System.Globalization; +using System.Collections.Generic; namespace System.Net.Http.Headers { @@ -100,13 +101,28 @@ namespace System.Net.Http.Headers throw new FormatException (input); } - + public static bool TryParse (string input, out WarningHeaderValue parsedValue) { + var lexer = new Lexer (input); + Token token; + if (TryParseElement (lexer, out parsedValue, out token) && token == Token.Type.End) + return true; + parsedValue = null; + return false; + } - var lexer = new Lexer (input); - var t = lexer.Scan (); + internal static bool TryParse (string input, int minimalCount, out List<WarningHeaderValue> result) + { + return CollectionParser.TryParse (input, minimalCount, TryParseElement, out result); + } + + static bool TryParseElement (Lexer lexer, out WarningHeaderValue parsedValue, out Token t) + { + parsedValue = null; + + t = lexer.Scan (); if (t != Token.Type.Token) return false; @@ -148,9 +164,6 @@ namespace System.Net.Http.Headers t = lexer.Scan (); } - if (t != Token.Type.End) - return false; - parsedValue = value; return true; } |