Wrap always_inline and noinline attributes in compiler checks and use MSVC equivalent.
[mono.git] / mcs / class / System.Net.Http / System.Net.Http / HttpClientHandler.cs
1 //
2 // HttpClientHandler.cs
3 //
4 // Authors:
5 //      Marek Safar  <marek.safar@gmail.com>
6 //
7 // Copyright (C) 2011 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.Threading;
30 using System.Threading.Tasks;
31 using System.Collections.Specialized;
32 using System.Net.Http.Headers;
33
34 namespace System.Net.Http
35 {
36         public class HttpClientHandler : HttpMessageHandler
37         {
38                 bool allowAutoRedirect;
39                 DecompressionMethods automaticDecompression;
40                 CookieContainer cookieContainer;
41                 ICredentials credentials;
42                 int maxAutomaticRedirections;
43                 long maxRequestContentBufferSize;
44                 bool preAuthenticate;
45                 IWebProxy proxy;
46                 bool useCookies;
47                 bool useDefaultCredentials;
48                 bool useProxy;
49                 ClientCertificateOption certificate;
50                 bool sentRequest;
51
52                 public HttpClientHandler ()
53                 {
54                         allowAutoRedirect = true;
55                         maxAutomaticRedirections = 50;
56                         maxRequestContentBufferSize = int.MaxValue;
57                         useCookies = true;
58                         useProxy = true;
59                 }
60
61                 void EnsureModifiability ()
62                 {
63                         if (sentRequest)
64                                 throw new InvalidOperationException (
65                                         "This instance has already started one or more requests. " +
66                                         "Properties can only be modified before sending the first request.");
67                 }
68
69                 public bool AllowAutoRedirect {
70                         get {
71                                 return allowAutoRedirect;
72                         }
73                         set {
74                                 EnsureModifiability ();
75                                 allowAutoRedirect = value;
76                         }
77                 }
78
79                 public DecompressionMethods AutomaticDecompression {
80                         get {
81                                 return automaticDecompression;
82                         }
83                         set {
84                                 EnsureModifiability ();
85                                 automaticDecompression = value;
86                         }
87                 }
88
89                 public ClientCertificateOption ClientCertificateOptions {
90                         get {
91                                 return certificate;
92                         }
93                         set {
94                                 EnsureModifiability ();
95                                 certificate = value;
96                         }
97                 }
98
99                 public CookieContainer CookieContainer {
100                         get {
101                                 return cookieContainer ?? (cookieContainer = new CookieContainer ());
102                         }
103                         set {
104                                 EnsureModifiability ();
105                                 cookieContainer = value;
106                         }
107                 }
108
109                 public ICredentials Credentials {
110                         get {
111                                 return credentials;
112                         }
113                         set {
114                                 EnsureModifiability ();
115                                 credentials = value;
116                         }
117                 }
118
119                 public int MaxAutomaticRedirections {
120                         get {
121                                 return maxAutomaticRedirections;
122                         }
123                         set {
124                                 EnsureModifiability ();
125                                 if (value <= 0)
126                                         throw new ArgumentOutOfRangeException ();
127
128                                 maxAutomaticRedirections = value;
129                         }
130                 }
131
132                 public long MaxRequestContentBufferSize {
133                         get {
134                                 return maxRequestContentBufferSize;
135                         }
136                         set {
137                                 EnsureModifiability ();
138                                 if (value < 0)
139                                         throw new ArgumentOutOfRangeException ();
140
141                                 maxRequestContentBufferSize = value;
142                         }
143                 }
144
145                 public bool PreAuthenticate {
146                         get {
147                                 return preAuthenticate;
148                         }
149                         set {
150                                 EnsureModifiability ();
151                                 preAuthenticate = value;
152                         }
153                 }
154
155                 public IWebProxy Proxy {
156                         get {
157                                 return proxy;
158                         }
159                         set {
160                                 EnsureModifiability ();
161                                 if (!UseProxy)
162                                         throw new InvalidOperationException ();
163
164                                 proxy = value;
165                         }
166                 }
167
168                 public virtual bool SupportsAutomaticDecompression {
169                         get {
170                                 return true;
171                         }
172                 }
173
174                 public virtual bool SupportsProxy {
175                         get {
176                                 return true;
177                         }
178                 }
179
180                 public virtual bool SupportsRedirectConfiguration {
181                         get {
182                                 return true;
183                         }
184                 }
185
186                 public bool UseCookies {
187                         get {
188                                 return useCookies;
189                         }
190                         set {
191                                 EnsureModifiability ();
192                                 useCookies = value;
193                         }
194                 }
195
196                 public bool UseDefaultCredentials {
197                         get {
198                                 return useDefaultCredentials;
199                         }
200                         set {
201                                 EnsureModifiability ();
202                                 useDefaultCredentials = value;
203                         }
204                 }
205
206                 public bool UseProxy {
207                         get {
208                                 return useProxy;
209                         }
210                         set {
211                                 EnsureModifiability ();
212                                 useProxy = value;
213                         }
214                 }
215
216                 protected override void Dispose (bool disposing)
217                 {
218                         // TODO: ?
219                         base.Dispose (disposing);
220                 }
221
222                 HttpWebRequest CreateWebRequest (HttpRequestMessage request)
223                 {
224                         var wr = new HttpWebRequest (request.RequestUri);
225                         wr.ThrowOnError = false;
226
227                         wr.ConnectionGroupName = "HttpClientHandler";
228                         wr.Method = request.Method.Method;
229                         wr.ProtocolVersion = request.Version;
230
231                         if (wr.ProtocolVersion == HttpVersion.Version10) {
232                                 wr.KeepAlive = request.Headers.ConnectionKeepAlive;
233                         } else {
234                                 wr.KeepAlive = request.Headers.ConnectionClose != true;
235                         }
236
237                         wr.ServicePoint.Expect100Continue = request.Headers.ExpectContinue == true;
238
239                         if (allowAutoRedirect) {
240                                 wr.AllowAutoRedirect = true;
241                                 wr.MaximumAutomaticRedirections = maxAutomaticRedirections;
242                         } else {
243                                 wr.AllowAutoRedirect = false;
244                         }
245
246                         wr.AutomaticDecompression = automaticDecompression;
247                         wr.PreAuthenticate = preAuthenticate;
248
249                         if (useCookies) {
250                                 wr.CookieContainer = cookieContainer;
251                         }
252
253                         if (useDefaultCredentials) {
254                                 wr.UseDefaultCredentials = true;
255                         } else {
256                                 wr.Credentials = credentials;
257                         }
258
259                         if (useProxy) {
260                                 wr.Proxy = proxy;
261                         }
262
263                         // Add request headers
264                         var headers = wr.Headers;
265                         foreach (var header in request.Headers) {
266                                 foreach (var value in header.Value) {
267                                         headers.AddValue (header.Key, value);
268                                 }
269                         }
270                         
271                         return wr;
272                 }
273
274                 HttpResponseMessage CreateResponseMessage (HttpWebResponse wr, HttpRequestMessage requestMessage)
275                 {
276                         var response = new HttpResponseMessage (wr.StatusCode);
277                         response.RequestMessage = requestMessage;
278                         response.ReasonPhrase = wr.StatusDescription;
279                         response.Content = new StreamContent (wr.GetResponseStream ());
280
281                         var headers = wr.Headers;
282                         for (int i = 0; i < headers.Count; ++i) {
283                                 var key = headers.GetKey(i);
284                                 var value = headers.GetValues (i);
285
286                                 HttpHeaders item_headers;
287                                 if (HttpHeaders.GetKnownHeaderKind (key) == Headers.HttpHeaderKind.Content)
288                                         item_headers = response.Content.Headers;
289                                 else
290                                         item_headers = response.Headers;
291                                         
292                                 item_headers.TryAddWithoutValidation (key, value);
293                         }
294
295                         return response;
296                 }
297
298                 protected async internal override Task<HttpResponseMessage> SendAsync (HttpRequestMessage request, CancellationToken cancellationToken)
299                 {
300                         sentRequest = true;
301                         var wrequest = CreateWebRequest (request);
302
303                         if (request.Content != null) {
304                                 var headers = wrequest.Headers;
305                                 foreach (var header in request.Content.Headers) {
306                                         foreach (var value in header.Value) {
307                                                 headers.AddValue (header.Key, value);
308                                         }
309                                 }
310                                 
311                                 var stream = wrequest.GetRequestStream ();
312                                 await request.Content.CopyToAsync (stream);
313                         }
314
315                         // FIXME: GetResponseAsync does not accept cancellationToken
316                         var wresponse = (HttpWebResponse) await wrequest.GetResponseAsync ().ConfigureAwait (false);
317                         return CreateResponseMessage (wresponse, request);
318                 }
319         }
320 }