~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/maccore/src/CoreServices/CFHTTPMessage.cs

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//
 
2
// CFHTTPMessage.cs:
 
3
//
 
4
// Authors:
 
5
//      Martin Baulig (martin.baulig@gmail.com)
 
6
//      Marek Safar (marek.safar@gmail.com)
 
7
//
 
8
// Copyright 2012-2013 Xamarin Inc. (http://www.xamarin.com)
 
9
//
 
10
//
 
11
// Permission is hereby granted, free of charge, to any person obtaining
 
12
// a copy of this software and associated documentation files (the
 
13
// "Software"), to deal in the Software without restriction, including
 
14
// without limitation the rights to use, copy, modify, merge, publish,
 
15
// distribute, sublicense, and/or sell copies of the Software, and to
 
16
// permit persons to whom the Software is furnished to do so, subject to
 
17
// the following conditions:
 
18
// 
 
19
// The above copyright notice and this permission notice shall be
 
20
// included in all copies or substantial portions of the Software.
 
21
// 
 
22
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 
23
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
24
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 
25
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 
26
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 
27
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 
28
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
29
//
 
30
using System;
 
31
using System.Net;
 
32
using System.Security.Authentication;
 
33
using System.Runtime.InteropServices;
 
34
using MonoMac.Foundation;
 
35
using MonoMac.CoreFoundation;
 
36
using MonoMac.ObjCRuntime;
 
37
 
 
38
namespace MonoMac.CoreServices {
 
39
 
 
40
        public class CFHTTPMessage : CFType, INativeObject, IDisposable {
 
41
                internal IntPtr handle;
 
42
 
 
43
                internal CFHTTPMessage (IntPtr handle)
 
44
                        : this (handle, false)
 
45
                {
 
46
                }
 
47
 
 
48
                internal CFHTTPMessage (IntPtr handle, bool owns)
 
49
                {
 
50
                        if (!owns)
 
51
                                CFObject.CFRetain (handle);
 
52
                        this.handle = handle;
 
53
                }
 
54
 
 
55
                static readonly NSString _HTTPVersion1_0;
 
56
                static readonly NSString _HTTPVersion1_1;
 
57
                static readonly NSString _AuthenticationSchemeBasic;
 
58
                static readonly NSString _AuthenticationSchemeNegotiate;
 
59
                static readonly NSString _AuthenticationSchemeNTLM;
 
60
                static readonly NSString _AuthenticationSchemeDigest;
 
61
                static readonly NSString _AuthenticationUsername;
 
62
                static readonly NSString _AuthenticationPassword;
 
63
                static readonly NSString _AuthenticationAccountDomain;
 
64
 
 
65
                static CFHTTPMessage ()
 
66
                {
 
67
                        var handle = Dlfcn.dlopen (Constants.CFNetworkLibrary, 0);
 
68
                        if (handle == IntPtr.Zero)
 
69
                                throw new InvalidOperationException ();
 
70
 
 
71
                        try {
 
72
                                _HTTPVersion1_0 = GetStringConstant (handle, "kCFHTTPVersion1_0");
 
73
                                _HTTPVersion1_1 = GetStringConstant (handle, "kCFHTTPVersion1_1");
 
74
 
 
75
                                _AuthenticationSchemeBasic = GetStringConstant (
 
76
                                        handle, "kCFHTTPAuthenticationSchemeBasic");
 
77
                                _AuthenticationSchemeNegotiate = GetStringConstant (
 
78
                                        handle, "kCFHTTPAuthenticationSchemeNegotiate");
 
79
                                _AuthenticationSchemeNTLM = GetStringConstant (
 
80
                                        handle, "kCFHTTPAuthenticationSchemeNTLM");
 
81
                                _AuthenticationSchemeDigest = GetStringConstant (
 
82
                                        handle, "kCFHTTPAuthenticationSchemeDigest");
 
83
 
 
84
                                _AuthenticationUsername = GetStringConstant (
 
85
                                        handle, "kCFHTTPAuthenticationUsername");
 
86
                                _AuthenticationPassword = GetStringConstant (
 
87
                                        handle, "kCFHTTPAuthenticationPassword");
 
88
                                _AuthenticationAccountDomain = GetStringConstant (
 
89
                                        handle, "kCFHTTPAuthenticationAccountDomain");
 
90
                        } finally {
 
91
                                Dlfcn.dlclose (handle);
 
92
                        }
 
93
                }
 
94
 
 
95
                static NSString GetStringConstant (IntPtr handle, string name)
 
96
                {
 
97
                        var result = Dlfcn.GetStringConstant (handle, name);
 
98
                        if (result == null)
 
99
                                throw new InvalidOperationException (
 
100
                                        string.Format ("Cannot get '{0}' property.", name));
 
101
                        return result;
 
102
                }
 
103
 
 
104
                [DllImport (Constants.CFNetworkLibrary, EntryPoint="CFHTTPMessageGetTypeID")]
 
105
                public extern static int GetTypeID ();
 
106
 
 
107
                ~CFHTTPMessage ()
 
108
                {
 
109
                        Dispose (false);
 
110
                }
 
111
                
 
112
                protected void CheckHandle ()
 
113
                {
 
114
                        if (handle == IntPtr.Zero)
 
115
                                throw new ObjectDisposedException (GetType ().Name);
 
116
                }
 
117
 
 
118
                public void Dispose ()
 
119
                {
 
120
                        Dispose (true);
 
121
                        GC.SuppressFinalize (this);
 
122
                }
 
123
 
 
124
                public IntPtr Handle {
 
125
                        get {
 
126
                                CheckHandle ();
 
127
                                return handle;
 
128
                        }
 
129
                }
 
130
                
 
131
                protected virtual void Dispose (bool disposing)
 
132
                {
 
133
                        if (handle != IntPtr.Zero) {
 
134
                                CFObject.CFRelease (handle);
 
135
                                handle = IntPtr.Zero;
 
136
                        }
 
137
                }
 
138
 
 
139
                static IntPtr GetVersion (Version version)
 
140
                {
 
141
                        if ((version == null) || version.Equals (HttpVersion.Version11))
 
142
                                return _HTTPVersion1_1.Handle;
 
143
                        else if (version.Equals (HttpVersion.Version10))
 
144
                                return _HTTPVersion1_0.Handle;
 
145
                        else
 
146
                                throw new ArgumentException ();
 
147
                }
 
148
 
 
149
                [DllImport (Constants.CFNetworkLibrary)]
 
150
                extern static IntPtr CFHTTPMessageCreateEmpty (IntPtr allocator, bool isRequest);
 
151
 
 
152
                public static CFHTTPMessage CreateEmpty (bool request)
 
153
                {
 
154
                        var handle = CFHTTPMessageCreateEmpty (IntPtr.Zero, request);
 
155
                        if (handle == IntPtr.Zero)
 
156
                                return null;
 
157
 
 
158
                        return new CFHTTPMessage (handle);                      
 
159
                }
 
160
 
 
161
                [DllImport (Constants.CFNetworkLibrary)]
 
162
                extern static IntPtr CFHTTPMessageCreateRequest (IntPtr allocator, IntPtr requestMethod,
 
163
                                                                 IntPtr url, IntPtr httpVersion);
 
164
 
 
165
                public static CFHTTPMessage CreateRequest (CFUrl url, NSString method, Version version)
 
166
                {
 
167
                        var handle = CFHTTPMessageCreateRequest (
 
168
                                IntPtr.Zero, method.Handle, url.Handle, GetVersion (version));
 
169
                        if (handle == IntPtr.Zero)
 
170
                                return null;
 
171
 
 
172
                        return new CFHTTPMessage (handle);
 
173
                }
 
174
 
 
175
                public static CFHTTPMessage CreateRequest (Uri uri, string method)
 
176
                {
 
177
                        return CreateRequest (uri, method, null);
 
178
                }
 
179
 
 
180
                public static CFHTTPMessage CreateRequest (Uri uri, string method, Version version)
 
181
                {
 
182
                        CFUrl urlRef = null;
 
183
                        NSString methodRef = null;
 
184
 
 
185
                        var escaped = Uri.EscapeUriString (uri.ToString ());
 
186
 
 
187
                        try {
 
188
                                urlRef = CFUrl.FromUrlString (escaped, null);
 
189
                                if (urlRef == null)
 
190
                                        throw new ArgumentException ("Invalid URL.");
 
191
                                methodRef = new NSString (method);
 
192
 
 
193
                                var msg = CreateRequest (urlRef, methodRef, version);
 
194
                                if (msg == null)
 
195
                                        throw new ArgumentException ("Invalid URL.");
 
196
 
 
197
                                return msg;
 
198
                        } finally {
 
199
                                if (urlRef != null)
 
200
                                        urlRef.Dispose ();
 
201
                                if (methodRef != null)
 
202
                                        methodRef.Dispose ();
 
203
                        }
 
204
                }
 
205
 
 
206
                [DllImport (Constants.CFNetworkLibrary)]
 
207
                extern static bool CFHTTPMessageIsRequest (IntPtr handle);
 
208
 
 
209
                public bool IsRequest {
 
210
                        get {
 
211
                                CheckHandle ();
 
212
                                return CFHTTPMessageIsRequest (Handle);
 
213
                        }
 
214
                }
 
215
 
 
216
                [DllImport (Constants.CFNetworkLibrary)]
 
217
                extern static CFIndex CFHTTPMessageGetResponseStatusCode (IntPtr handle);
 
218
 
 
219
                public HttpStatusCode ResponseStatusCode {
 
220
                        get {
 
221
                                if (IsRequest)
 
222
                                        throw new InvalidOperationException ();
 
223
                                int status = CFHTTPMessageGetResponseStatusCode (Handle);
 
224
                                return (HttpStatusCode)status;
 
225
                        }
 
226
                }
 
227
 
 
228
                [DllImport (Constants.CFNetworkLibrary)]
 
229
                extern static IntPtr CFHTTPMessageCopyResponseStatusLine (IntPtr handle);
 
230
 
 
231
                public string ResponseStatusLine {
 
232
                        get {
 
233
                                if (IsRequest)
 
234
                                        throw new InvalidOperationException ();
 
235
                                var ptr = CFHTTPMessageCopyResponseStatusLine (Handle);
 
236
                                if (ptr == IntPtr.Zero)
 
237
                                        return null;
 
238
                                using (var line = new NSString (ptr))
 
239
                                        return line.ToString ();
 
240
                        }
 
241
                }
 
242
 
 
243
                [DllImport (Constants.CFNetworkLibrary)]
 
244
                extern static IntPtr CFHTTPMessageCopyVersion (IntPtr handle);
 
245
 
 
246
                public Version Version {
 
247
                        get {
 
248
                                CheckHandle ();
 
249
                                IntPtr ptr = CFHTTPMessageCopyVersion (handle);
 
250
                                try {
 
251
                                        if (ptr.Equals (_HTTPVersion1_0.Handle))
 
252
                                                return HttpVersion.Version10;
 
253
                                        else
 
254
                                                return HttpVersion.Version11;
 
255
                                } finally {
 
256
                                        if (ptr != IntPtr.Zero)
 
257
                                                CFObject.CFRelease (ptr);
 
258
                                }
 
259
                        }
 
260
                }
 
261
 
 
262
                [DllImport (Constants.CFNetworkLibrary)]
 
263
                extern static bool CFHTTPMessageIsHeaderComplete (IntPtr handle);
 
264
 
 
265
                public bool IsHeaderComplete {
 
266
                        get {
 
267
                                CheckHandle ();
 
268
                                return CFHTTPMessageIsHeaderComplete (Handle);
 
269
                        }
 
270
                }
 
271
 
 
272
                [DllImport (Constants.CFNetworkLibrary)]
 
273
                extern static bool CFHTTPMessageAppendBytes (IntPtr message, ref byte[] newBytes, CFIndex numBytes);
 
274
 
 
275
                public bool AppendBytes (byte[] bytes)
 
276
                {
 
277
                        if (bytes == null)
 
278
                                throw new ArgumentNullException ("bytes");
 
279
 
 
280
                        return AppendBytes (bytes, bytes.Length);
 
281
                }
 
282
 
 
283
                public bool AppendBytes (byte[] bytes, int count)
 
284
                {
 
285
                        if (bytes == null)
 
286
                                throw new ArgumentNullException ("bytes");
 
287
 
 
288
                        return CFHTTPMessageAppendBytes (Handle, ref bytes, count);
 
289
                }
 
290
 
 
291
                [DllImport (Constants.CFNetworkLibrary)]
 
292
                extern static IntPtr CFHTTPMessageCopyAllHeaderFields (IntPtr handle);
 
293
 
 
294
                public NSDictionary GetAllHeaderFields ()
 
295
                {
 
296
                        CheckHandle ();
 
297
                        IntPtr ptr = CFHTTPMessageCopyAllHeaderFields (handle);
 
298
                        if (ptr == IntPtr.Zero)
 
299
                                return null;
 
300
                        return new NSDictionary (ptr);
 
301
                }
 
302
 
 
303
                #region Authentication
 
304
 
 
305
                struct CFStreamError {
 
306
                        public int domain;
 
307
                        public int code;
 
308
                }
 
309
 
 
310
                enum ErrorHTTPAuthentication {
 
311
                        TypeUnsupported = -1000,
 
312
                        BadUserName = -1001,
 
313
                        BadPassword = -1002
 
314
                }
 
315
 
 
316
                AuthenticationException GetException (ErrorHTTPAuthentication code)
 
317
                {
 
318
                        switch (code) {
 
319
                        case ErrorHTTPAuthentication.BadUserName:
 
320
                                throw new InvalidCredentialException ("Bad username.");
 
321
                        case ErrorHTTPAuthentication.BadPassword:
 
322
                                throw new InvalidCredentialException ("Bad password.");
 
323
                        case ErrorHTTPAuthentication.TypeUnsupported:
 
324
                                throw new AuthenticationException ("Authentication type not supported.");
 
325
                        default:
 
326
                                throw new AuthenticationException ("Unknown error.");
 
327
                        }
 
328
                }
 
329
 
 
330
                [DllImport (Constants.CFNetworkLibrary)]
 
331
                extern static bool CFHTTPMessageApplyCredentials (IntPtr request, IntPtr auth,
 
332
                                                                  IntPtr user, IntPtr pass,
 
333
                                                                  out CFStreamError error);
 
334
 
 
335
                public void ApplyCredentials (CFHTTPAuthentication auth, NetworkCredential credential)
 
336
                {
 
337
                        if (auth.RequiresAccountDomain) {
 
338
                                ApplyCredentialDictionary (auth, credential);
 
339
                                return;
 
340
                        }
 
341
 
 
342
                        var username = new CFString (credential.UserName);
 
343
                        var password = new CFString (credential.Password);
 
344
 
 
345
                        try {
 
346
                                CFStreamError error;
 
347
 
 
348
                                var ok = CFHTTPMessageApplyCredentials (
 
349
                                        Handle, auth.Handle, username.Handle, password.Handle,
 
350
                                        out error);
 
351
                                if (!ok)
 
352
                                        throw GetException ((ErrorHTTPAuthentication)error.code);
 
353
                        } finally {
 
354
                                username.Dispose ();
 
355
                                password.Dispose ();
 
356
                        }
 
357
                }
 
358
 
 
359
                public enum AuthenticationScheme {
 
360
                        Default,
 
361
                        Basic,
 
362
                        Negotiate,
 
363
                        NTLM,
 
364
                        Digest
 
365
                }
 
366
 
 
367
                internal static IntPtr GetAuthScheme (AuthenticationScheme scheme)
 
368
                {
 
369
                        switch (scheme) {
 
370
                        case AuthenticationScheme.Default:
 
371
                                return IntPtr.Zero;
 
372
                        case AuthenticationScheme.Basic:
 
373
                                return _AuthenticationSchemeBasic.Handle;
 
374
                        case AuthenticationScheme.Negotiate:
 
375
                                return _AuthenticationSchemeNegotiate.Handle;
 
376
                        case AuthenticationScheme.NTLM:
 
377
                                return _AuthenticationSchemeNTLM.Handle;
 
378
                        case AuthenticationScheme.Digest:
 
379
                                return _AuthenticationSchemeDigest.Handle;
 
380
                        default:
 
381
                                throw new ArgumentException ();
 
382
                        }
 
383
                }
 
384
 
 
385
                [DllImport (Constants.CFNetworkLibrary)]
 
386
                extern static bool CFHTTPMessageAddAuthentication (IntPtr request, IntPtr response,
 
387
                                                                   IntPtr username, IntPtr password,
 
388
                                                                   IntPtr scheme, bool forProxy);
 
389
 
 
390
                public bool AddAuthentication (CFHTTPMessage failureResponse, NSString username,
 
391
                                               NSString password, AuthenticationScheme scheme,
 
392
                                               bool forProxy)
 
393
                {
 
394
                        return CFHTTPMessageAddAuthentication (
 
395
                                Handle, failureResponse.Handle, username.Handle,
 
396
                                password.Handle, GetAuthScheme (scheme), forProxy);
 
397
                }
 
398
 
 
399
                [DllImport (Constants.CFNetworkLibrary)]
 
400
                extern static bool CFHTTPMessageApplyCredentialDictionary (IntPtr request, IntPtr auth,
 
401
                                                                           IntPtr dict, out CFStreamError error);
 
402
 
 
403
                public void ApplyCredentialDictionary (CFHTTPAuthentication auth, NetworkCredential credential)
 
404
                {
 
405
                        var keys = new NSString [3];
 
406
                        var values = new CFString [3];
 
407
                        keys [0] = _AuthenticationUsername;
 
408
                        keys [1] = _AuthenticationPassword;
 
409
                        keys [2] = _AuthenticationAccountDomain;
 
410
                        values [0] = (CFString)credential.UserName;
 
411
                        values [1] = (CFString)credential.Password;
 
412
                        values [2] = credential.Domain != null ? (CFString)credential.Domain : null;
 
413
 
 
414
                        var dict = CFDictionary.FromObjectsAndKeys (values, keys);
 
415
 
 
416
                        try {
 
417
                                CFStreamError error;
 
418
                                var ok = CFHTTPMessageApplyCredentialDictionary (
 
419
                                        Handle, auth.Handle, dict.Handle, out error);
 
420
                                if (ok)
 
421
                                        return;
 
422
                                throw GetException ((ErrorHTTPAuthentication)error.code);
 
423
                        } finally {
 
424
                                dict.Dispose ();
 
425
                                values [0].Dispose ();
 
426
                                values [1].Dispose ();
 
427
                                if (values [2] != null)
 
428
                                        values [2].Dispose ();
 
429
                        }
 
430
                }
 
431
 
 
432
                #endregion
 
433
 
 
434
                [DllImport (Constants.CFNetworkLibrary)]
 
435
                extern static void CFHTTPMessageSetHeaderFieldValue (IntPtr message, IntPtr headerField,
 
436
                                                                     IntPtr value);
 
437
 
 
438
                public void SetHeaderFieldValue (string name, string value)
 
439
                {
 
440
                        NSString nstr = (NSString)name;
 
441
                        NSString vstr = value != null ? (NSString)value : null;
 
442
                        IntPtr vptr = vstr != null ? vstr.Handle : IntPtr.Zero;
 
443
 
 
444
                        CFHTTPMessageSetHeaderFieldValue (Handle, nstr.Handle, vptr);
 
445
 
 
446
                        nstr.Dispose ();
 
447
                        if (vstr != null)
 
448
                                vstr.Dispose ();
 
449
                }
 
450
 
 
451
                [DllImport (Constants.CFNetworkLibrary)]
 
452
                extern static void CFHTTPMessageSetBody (IntPtr message, IntPtr data);
 
453
 
 
454
                internal void SetBody (CFData data)
 
455
                {
 
456
                        CFHTTPMessageSetBody (Handle, data.Handle);
 
457
                }
 
458
 
 
459
                public void SetBody (byte[] buffer)
 
460
                {
 
461
                        using (var data = new CFDataBuffer (buffer))
 
462
                                CFHTTPMessageSetBody (Handle, data.Handle);
 
463
                }
 
464
        }
 
465
}