Ensure the linker can eliminate the *RequestCreator code without extra instructions.
[mono.git] / mcs / class / System.Net / System.Net / WebRequest_2_1.cs
1 //
2 // System.Net.WebRequest (for 2.1 profile)
3 //
4 // Authors:
5 //      Jb Evain  <jbevain@novell.com>
6 //      Sebastien Pouliot <sebastien@ximian.com>
7 //
8 // Copyright (C) 2008-2010 Novell, Inc (http://www.novell.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //
31
32 #if NET_2_1
33
34 using System.Collections.Generic;
35 using System.IO;
36
37 namespace System.Net {
38
39         public abstract class WebRequest {
40
41                 const string SystemWindows = "System.Windows, PublicKey=00240000048000009400000006020000002400005253413100040000010001008D56C76F9E8649383049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B37AB";
42                 const string BrowserStack = "System.Net.Browser.BrowserHttpWebRequestCreator, " + SystemWindows;
43                 const string ClientStack = "System.Net.Browser.ClientHttpWebRequestCreator, " + SystemWindows;
44
45                 static IWebRequestCreate default_creator;
46                 static IWebRequestCreate browser_creator;
47                 static IWebRequestCreate client_creator;
48                 static Dictionary<string, IWebRequestCreate> registred_prefixes;
49
50                 internal Action<long,long> progress;
51
52                 public abstract string ContentType { get; set; }
53                 public abstract WebHeaderCollection Headers { get; set; }
54                 public abstract string Method { get; set; }
55                 public abstract Uri RequestUri { get; }
56
57                 public virtual long ContentLength {
58                         get { throw NotImplemented (); }
59                         set { throw NotImplemented (); }
60                 }
61
62                 // custom registered prefixes return null (unless they override this)
63                 public virtual IWebRequestCreate CreatorInstance { 
64                         get { return null; }
65                 }
66
67                 public virtual ICredentials Credentials {
68                         get { throw NotImplemented (); }
69                         set { throw NotImplemented (); }
70                 }
71
72                 public virtual bool UseDefaultCredentials {
73                         get { throw NotImplemented (); }
74                         set { throw NotImplemented (); }
75                 }
76
77                 static WebRequest ()
78                 {
79                         registred_prefixes = new Dictionary<string, IWebRequestCreate> (StringComparer.OrdinalIgnoreCase);
80                         browser_creator = (IWebRequestCreate) Activator.CreateInstance (Type.GetType (BrowserStack));
81                         client_creator = (IWebRequestCreate) Activator.CreateInstance (Type.GetType (ClientStack));
82                         default_creator = browser_creator;
83                 }
84
85                 protected WebRequest ()
86                 {
87                 }
88
89                 public abstract void Abort();
90                 public abstract IAsyncResult BeginGetRequestStream (AsyncCallback callback, object state);
91                 public abstract IAsyncResult BeginGetResponse (AsyncCallback callback, object state);
92                 public abstract Stream EndGetRequestStream (IAsyncResult asyncResult);
93                 public abstract WebResponse EndGetResponse (IAsyncResult asyncResult);
94
95                 internal virtual IAsyncResult BeginGetResponse (AsyncCallback callback, object state, bool policy)
96                 {
97                         return BeginGetResponse (callback, state);
98                 }
99
100                 public static WebRequest Create (string requestUriString)
101                 {
102                         return Create (new Uri (requestUriString));
103                 }
104
105                 public static WebRequest Create (Uri requestUri)
106                 {
107                         if (requestUri == null)
108                                 throw new ArgumentNullException ("requestUri");
109                         if (!requestUri.IsAbsoluteUri)
110                                 throw new InvalidOperationException ("This operation is not supported for a relative URI.");
111
112                         IWebRequestCreate creator = null;
113                         int n = -1;
114                         // look for the most promising match in the registred prefixes
115                         foreach (KeyValuePair<string, IWebRequestCreate> kvp in registred_prefixes) {
116                                 string key = kvp.Key;
117                                 if ((key.Length > n) && requestUri.AbsoluteUri.StartsWith (key)) {
118                                         creator = kvp.Value;
119                                         n = key.Length;
120                                 }
121                         }
122
123                         // 'http:/[/]' or 'https:/[/]' needs to be registred otherwise it gets ignored
124                         // note that this is unlike other protocols (e.g. 'ftp') - see unit tests
125                         string scheme = requestUri.Scheme;
126                         if ((scheme == "http" && n <= 5) || (scheme == "https" && n <= 6))
127                                 creator = default_creator;
128
129                         if (creator == null)
130                                 throw new NotSupportedException (string.Format ("Scheme {0} not supported", scheme));
131
132                         return creator.Create (requestUri);
133                 }
134
135                 public static HttpWebRequest CreateHttp (string requestUriString)
136                 {
137                         return CreateHttp (new Uri (requestUriString));
138                 }
139
140                 public static HttpWebRequest CreateHttp (Uri requestUri)
141                 {
142                         if (requestUri == null)
143                                 throw new ArgumentNullException ("requestUri");
144                         if (!requestUri.IsAbsoluteUri)
145                                 throw new InvalidOperationException ("Uri is not absolute.");
146
147                         // we do not check the registred prefixes from CreateHttp and *always* use the client HTTP stack
148                         switch (requestUri.Scheme) {
149                         case "http":
150                         case "https":
151                                 return (HttpWebRequest) client_creator.Create (requestUri);
152                         default:
153                                 throw new NotSupportedException (string.Format ("Scheme {0} not supported", requestUri.Scheme));
154                         }
155                 }
156
157                 // We can register for
158                 // * a protocol (e.g. http) for all requests
159                 // * a protocol (e.g. https) for a domain
160                 // * a protocol (e.g. http) for a single request
161                 //
162                 // See "How to: Specify Browser or Client HTTP Handling" for more details
163                 // http://msdn.microsoft.com/en-us/library/dd920295%28VS.95%29.aspx
164                 public static bool RegisterPrefix (string prefix, IWebRequestCreate creator)
165                 {
166                         if (prefix == null)
167                                 throw new ArgumentNullException ("prefix");
168                         if (creator == null)
169                                 throw new ArgumentNullException ("creator");
170
171                         Uri uri;
172                         if (Uri.TryCreate (prefix, UriKind.Absolute, out uri)) {
173                                 // if a valid URI is supplied then only register the scheme + domain
174                                 prefix = uri.Scheme + Uri.SchemeDelimiter + uri.DnsSafeHost;
175                         }
176
177                         // registering 'http', 'http://' or even 'http:/' are all ok - but *never* would 'http:' be correct!
178                         if ((String.Compare (prefix, "http:", StringComparison.OrdinalIgnoreCase) == 0) ||
179                             (String.Compare (prefix, "https:", StringComparison.OrdinalIgnoreCase) == 0))
180                                 return false;
181
182                         if (registred_prefixes.ContainsKey (prefix))
183                                 return false;
184
185                         registred_prefixes.Add (prefix, creator);
186                         return true;
187                 }
188
189                 static Exception NotImplemented ()
190                 {
191                         // hide the "normal" NotImplementedException from corcompare-like tools
192                         return new NotImplementedException ();
193                 }
194         }
195 }
196
197 #endif