aboutsummaryrefslogtreecommitdiff
path: root/SocketHttpListener/PayloadData.cs
blob: 6d15a6bcb17cc780375301159f0dd67badd596bd (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
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace SocketHttpListener
{
    internal class PayloadData : IEnumerable<byte>
    {
        #region Private Fields

        private byte[] _applicationData;
        private byte[] _extensionData;
        private bool _masked;

        #endregion

        #region Public Const Fields

        public const ulong MaxLength = long.MaxValue;

        #endregion

        #region Public Constructors

        public PayloadData()
          : this(new byte[0], new byte[0], false)
        {
        }

        public PayloadData(byte[] applicationData)
          : this(new byte[0], applicationData, false)
        {
        }

        public PayloadData(string applicationData)
          : this(new byte[0], Encoding.UTF8.GetBytes(applicationData), false)
        {
        }

        public PayloadData(byte[] applicationData, bool masked)
          : this(new byte[0], applicationData, masked)
        {
        }

        public PayloadData(byte[] extensionData, byte[] applicationData, bool masked)
        {
            _extensionData = extensionData;
            _applicationData = applicationData;
            _masked = masked;
        }

        #endregion

        #region Internal Properties

        internal bool ContainsReservedCloseStatusCode =>
            _applicationData.Length > 1 &&
            _applicationData.SubArray(0, 2).ToUInt16(ByteOrder.Big).IsReserved();

        #endregion

        #region Public Properties

        public byte[] ApplicationData => _applicationData;

        public byte[] ExtensionData => _extensionData;

        public bool IsMasked => _masked;

        public ulong Length => (ulong)(_extensionData.Length + _applicationData.Length);

        #endregion

        #region Private Methods

        private static void mask(byte[] src, byte[] key)
        {
            for (long i = 0; i < src.Length; i++)
                src[i] = (byte)(src[i] ^ key[i % 4]);
        }

        #endregion

        #region Public Methods

        public IEnumerator<byte> GetEnumerator()
        {
            foreach (byte b in _extensionData)
                yield return b;

            foreach (byte b in _applicationData)
                yield return b;
        }

        public void Mask(byte[] maskingKey)
        {
            if (_extensionData.Length > 0)
                mask(_extensionData, maskingKey);

            if (_applicationData.Length > 0)
                mask(_applicationData, maskingKey);

            _masked = !_masked;
        }

        public byte[] ToByteArray()
        {
            return _extensionData.Length > 0
                   ? new List<byte>(this).ToArray()
                   : _applicationData;
        }

        public override string ToString()
        {
            return BitConverter.ToString(ToByteArray());
        }

        #endregion

        #region Explicitly Implemented Interface Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        #endregion
    }
}