Add [Category ("NotWorking")] to failing test.
[mono.git] / mcs / class / System / System / UriParseComponents.cs
1 //
2 // Internal UriParseComponents class
3 //
4 // Author:
5 //      Vinicius Jarina  <vinicius.jarina@xamarin.com>
6 //
7 // Copyright (C) 2012 Xamarin, Inc (http://www.xamarin.com)
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
16 // 
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 // 
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28
29 using System.Text;
30
31
32 namespace System {
33         
34         internal class ParserState
35         {
36                 public ParserState (string uri)
37                 {
38                         remaining = uri;
39                         elements  = new UriElements ();
40                 }
41                 
42                 public string remaining;
43                 public UriElements elements;
44         }
45         
46         // Parse Uri components (scheme, userinfo, host, query, fragment)
47         // http://www.ietf.org/rfc/rfc3986.txt
48         internal static class UriParseComponents
49         {
50                 public static UriElements ParseComponents (string uri)
51                 {
52                         ParserState state = new ParserState (uri);
53                         
54                         bool ok = ParseScheme (ref state);
55                         if (ok)
56                             ok = ParseAuthority (ref state);
57                         if (ok)
58                             ok = ParsePath (ref state);
59                         if (ok)
60                             ok = ParseQuery (ref state);
61                         if (ok)
62                             ParseFragment (ref state);
63                         
64                         return state.elements;
65                 }
66                                 // ALPHA
67                 private static bool IsAlpha (char ch)
68                 {
69                         return (('a' <= ch) && (ch <= 'z')) ||
70                                    (('A' <= ch) && (ch <= 'Z'));
71                 }
72                 
73                 // 3.1) scheme      = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
74                 private static bool ParseScheme (ref ParserState state) 
75                 {
76                         string part = state.remaining;
77                         
78                         if (!IsAlpha (part [0]))
79                                 return part.Length > 0;
80                         
81                         StringBuilder sb = new StringBuilder ();
82                         sb.Append (part [0]);
83                         
84                         int index;
85                         for (index = 1; index < part.Length; index++ ) {
86                                 char ch = part [index];
87                                 if (ch != '.' && ch != '-' && ch != '+' && !IsAlpha (ch))
88                                         break;
89                                 
90                                 sb.Append (ch);
91                         }
92                         
93                         if (index + 1 <= part.Length && part [index] == ':') {
94                                 state.elements.scheme = sb.ToString ();
95                                 state.remaining = part.Substring (index + 1);
96                         }
97                                 
98                         return state.remaining.Length > 0;
99                 }
100                 
101                 private static bool ParseAuthority (ref ParserState state)
102                 {
103                         string part = state.remaining;
104                         
105                         if (part.Length < 2 || part [0] != '/' || part [1] != '/')
106                                 return part.Length > 0;
107                         
108                         state.remaining = part.Substring (2);
109                         
110                         bool ok = ParseUser (ref state);
111                         if (ok)
112                                 ok = ParseHost (ref state);
113                         if (ok)
114                                 ok = ParsePort (ref state);
115                         return ok;
116                 }
117                 
118                 // userinfo    = *( unreserved / pct-encoded / sub-delims / ":" )
119                 private static bool ParseUser (ref ParserState state)
120                 {
121                         string part = state.remaining;
122                         StringBuilder sb = new StringBuilder ();
123                         
124                         int index;
125                         for (index = 0; index < part.Length; index++) {
126                                 
127                                 char ch = part [index];
128                                 
129                                 if (ch == '@' || ch == '/' && ch == '#' && ch == '?')
130                                         break;
131                                 
132                                 sb.Append (ch);
133                         }
134                         
135                         if (index + 1 <= part.Length && part [index] == '@') {
136                                 
137                                 state.elements.user = sb.ToString ();
138                                 state.remaining = state.remaining.Substring (index + 1);
139                         }
140                                 
141                         return state.remaining.Length > 0;
142                 }
143                 
144                 // host        = IP-literal / IPv4address / reg-name
145                 private static bool ParseHost (ref ParserState state)
146                 {
147                         string part = state.remaining;
148                         StringBuilder sb = new StringBuilder ();
149                         
150                         int index;
151                         for (index = 0; index < part.Length; index++) { 
152                                 
153                                 char ch = part [index];
154                                 
155                                 if (ch == '/' || ch == ':' || ch == '#' || ch == '?')
156                                         break;
157                                 
158                                 sb.Append (ch);
159                         }
160                         
161                         if (index  <= part.Length)
162                                 state.remaining = part.Substring (index);
163                         
164                         state.elements.host = sb.ToString();
165                                 
166                         return state.remaining.Length > 0;
167                 }
168                 
169                 // port          = *DIGIT
170                 private static bool ParsePort (ref ParserState state)
171                 {
172                         string part = state.remaining;
173                         if (part.Length == 0 || part [0] != ':')
174                                 return part.Length > 0;
175                         
176                         StringBuilder sb = new StringBuilder ();
177                         
178                         int index;
179                         for (index = 1; index < part.Length; index++ ) {
180                                 char ch = part [index];
181                                 
182                                 if (!char.IsDigit (ch))
183                                         break;
184                                 
185                                 sb.Append (ch);
186                         }
187                         
188                         if (index <= part.Length)
189                                 state.remaining = part.Substring (index);
190                         
191                         state.elements.port = sb.ToString();
192                                 
193                         return state.remaining.Length > 0;
194                 }
195                 
196                 private static bool ParsePath (ref ParserState state)
197                 {
198                         string part = state.remaining;
199                         StringBuilder sb = new StringBuilder ();
200                         
201                         int index;
202                         for (index = 0; index < part.Length; index++) {
203                                 
204                                 char ch = part [index];
205                                 
206                                 if (ch == '#' || ch == '?')
207                                         break;
208                                 
209                                 sb.Append (ch);
210                         }
211                         
212                         if (index <= part.Length)
213                                 state.remaining = part.Substring (index);
214                         
215                         state.elements.path  = sb.ToString ();
216                                 
217                         return state.remaining.Length > 0;
218                 }
219                 
220                 private static bool ParseQuery (ref ParserState state)
221                 {
222                         string part = state.remaining;
223                         
224                         if (part.Length == 0 || part [0] != '?')
225                                 return part.Length > 0;
226                         
227                         StringBuilder sb = new StringBuilder ();
228                         
229                         int index;
230                         for (index = 1; index < part.Length; index++) {
231                                 
232                                 char ch = part [index];
233                                 
234                                 if (ch == '#')
235                                         break;
236                                 
237                                 sb.Append (ch);
238                         }
239                         
240                         if (index <= part.Length)
241                                 state.remaining = part.Substring (index);
242                         
243                         state.elements.query  = sb.ToString ();
244                                 
245                         return state.remaining.Length > 0;
246                 }
247                 
248                 private static bool ParseFragment (ref ParserState state)
249                 {
250                         string part = state.remaining;
251                         
252                         if (part.Length == 0 || part [0] != '#')
253                                 return part.Length > 0;
254                         
255                         StringBuilder sb = new StringBuilder ();
256                         
257                         int index;
258                         for (index = 1; index < part.Length; index++) { 
259                                 
260                                 char ch = part [index];
261                                 
262                                 sb.Append (ch);
263                         }
264                         
265                         state.elements.fragment = sb.ToString ();
266                         
267                         return false;
268                 }
269         }
270 }