aboutsummaryrefslogtreecommitdiff
path: root/SocketHttpListener/Net/HttpListenerContext.Managed.cs
blob: 79742bf37f141a4b38222188d1efd9cc44a39df0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
using System;
using System.ComponentModel;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using SocketHttpListener.Net.WebSockets;

namespace SocketHttpListener.Net
{
    public sealed partial class HttpListenerContext
    {
        private HttpConnection _connection;

        internal HttpListenerContext(HttpConnection connection)
        {
            _connection = connection;
            _response = new HttpListenerResponse(this);
            Request = new HttpListenerRequest(this);
            ErrorStatus = 400;
        }

        internal int ErrorStatus { get; set; }

        internal string ErrorMessage { get; set; }

        internal bool HaveError => ErrorMessage != null;

        internal HttpConnection Connection => _connection;

        internal void ParseAuthentication(System.Net.AuthenticationSchemes expectedSchemes)
        {
            if (expectedSchemes == System.Net.AuthenticationSchemes.Anonymous)
                return;

            string header = Request.Headers["Authorization"];
            if (string.IsNullOrEmpty(header))
                return;

            if (IsBasicHeader(header))
            {
                _user = ParseBasicAuthentication(header.Substring(AuthenticationTypes.Basic.Length + 1));
            }
        }

        internal IPrincipal ParseBasicAuthentication(string authData) =>
            TryParseBasicAuth(authData, out HttpStatusCode errorCode, out string username, out string password) ?
                new GenericPrincipal(new HttpListenerBasicIdentity(username, password), Array.Empty<string>()) :
                null;

        internal static bool IsBasicHeader(string header) =>
            header.Length >= 6 &&
            header[5] == ' ' &&
            string.Compare(header, 0, AuthenticationTypes.Basic, 0, 5, StringComparison.OrdinalIgnoreCase) == 0;

        internal static bool TryParseBasicAuth(string headerValue, out HttpStatusCode errorCode, out string username, out string password)
        {
            errorCode = HttpStatusCode.OK;
            username = password = null;
            try
            {
                if (string.IsNullOrWhiteSpace(headerValue))
                {
                    return false;
                }

                string authString = Encoding.UTF8.GetString(Convert.FromBase64String(headerValue));
                int colonPos = authString.IndexOf(':');
                if (colonPos < 0)
                {
                    // username must be at least 1 char
                    errorCode = HttpStatusCode.BadRequest;
                    return false;
                }

                username = authString.Substring(0, colonPos);
                password = authString.Substring(colonPos + 1);
                return true;
            }
            catch
            {
                errorCode = HttpStatusCode.InternalServerError;
                return false;
            }
        }

        public Task<HttpListenerWebSocketContext> AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval)
        {
            return HttpWebSocket.AcceptWebSocketAsyncCore(this, subProtocol, receiveBufferSize, keepAliveInterval);
        }

        [EditorBrowsable(EditorBrowsableState.Never)]
        public Task<HttpListenerWebSocketContext> AcceptWebSocketAsync(string subProtocol, int receiveBufferSize, TimeSpan keepAliveInterval, ArraySegment<byte> internalBuffer)
        {
            WebSocketValidate.ValidateArraySegment(internalBuffer, nameof(internalBuffer));
            HttpWebSocket.ValidateOptions(subProtocol, receiveBufferSize, HttpWebSocket.MinSendBufferSize, keepAliveInterval);
            return HttpWebSocket.AcceptWebSocketAsyncCore(this, subProtocol, receiveBufferSize, keepAliveInterval, internalBuffer);
        }
    }
}