├── websocket-sharp
├── doc
│ ├── .gitignore
│ └── doc.sh
├── websocket-sharp.snk
├── AssemblyInfo.cs
├── Fin.cs
├── Rsv.cs
├── Mask.cs
├── Net
│ ├── HttpHeaderType.cs
│ ├── HttpVersion.cs
│ ├── Security
│ │ └── SslStream.cs
│ ├── HttpHeaderInfo.cs
│ ├── CookieException.cs
│ ├── ChunkStream.cs
│ ├── HttpStatusCode.cs
│ ├── CookieCollection.cs
│ └── Cookie.cs
├── ByteOrder.cs
├── CompressionMethod.cs
├── LogLevel.cs
├── WebSocketState.cs
├── Opcode.cs
├── ErrorEventArgs.cs
├── WebSocketException.cs
├── websocket-sharp.csproj
├── HandshakeBase.cs
├── CloseEventArgs.cs
├── MessageEventArgs.cs
├── LogData.cs
├── PayloadData.cs
├── HandshakeResponse.cs
├── CloseStatusCode.cs
├── HandshakeRequest.cs
├── WsStream.cs
├── Logger.cs
└── WsFrame.cs
├── websocket-sharp.png
├── .gitignore
├── EchoClient
├── Properties
│ └── AssemblyInfo.cs
├── Program.cs
└── EchoClient.csproj
├── LICENSE.txt
├── websocket-sharp.sln
└── README.md
/websocket-sharp/doc/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore MonoDevelop build results.
2 |
3 | html
4 | mdoc
5 |
--------------------------------------------------------------------------------
/websocket-sharp.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KLab/websocket-unitymobile/HEAD/websocket-sharp.png
--------------------------------------------------------------------------------
/websocket-sharp/websocket-sharp.snk:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/KLab/websocket-unitymobile/HEAD/websocket-sharp/websocket-sharp.snk
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore build results and temporary files.
2 |
3 | Backup*
4 | _UpgradeReport_Files
5 | bin
6 | obj
7 |
8 | *.mdb
9 | *.pdb
10 | *.pidb
11 | *.suo
12 | *.user
13 | *.userprefs
14 | UpgradeLog*.*
15 |
--------------------------------------------------------------------------------
/websocket-sharp/doc/doc.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | #
3 | # @(#) doc.sh ver.0.0.2 2013.01.24
4 | #
5 | # Usage:
6 | # doc.sh
7 | #
8 | # Description:
9 | # Creating documentation for websocket-sharp.
10 | #
11 | ###########################################################################
12 |
13 | SRC_DIR="../bin/Release_Ubuntu"
14 | XML="${SRC_DIR}/websocket-sharp.xml"
15 | DLL="${SRC_DIR}/websocket-sharp.dll"
16 |
17 | DOC_DIR="."
18 | MDOC_DIR="${DOC_DIR}/mdoc"
19 | HTML_DIR="${DOC_DIR}/html"
20 |
21 | createDir() {
22 | if [ ! -d $1 ]; then
23 | mkdir -p $1
24 | fi
25 | }
26 |
27 | set -e
28 | createDir ${MDOC_DIR}
29 | createDir ${HTML_DIR}
30 | mdoc update --delete -fno-assembly-versions -i ${XML} -o ${MDOC_DIR}/ ${DLL}
31 | mdoc export-html -o ${HTML_DIR}/ ${MDOC_DIR}/
32 |
--------------------------------------------------------------------------------
/EchoClient/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 |
4 | // Information about this assembly is defined by the following attributes.
5 | // Change them to the values specific to your project.
6 |
7 | [assembly: AssemblyTitle ("EchoClient")]
8 | [assembly: AssemblyDescription ("")]
9 | [assembly: AssemblyConfiguration ("")]
10 | [assembly: AssemblyCompany ("")]
11 | [assembly: AssemblyProduct ("")]
12 | [assembly: AssemblyCopyright ("inada-n")]
13 | [assembly: AssemblyTrademark ("")]
14 | [assembly: AssemblyCulture ("")]
15 |
16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
19 |
20 | [assembly: AssemblyVersion ("1.0.*")]
21 |
22 | // The following attributes are used to specify the signing key for the assembly,
23 | // if desired. See the Mono documentation for more information about signing.
24 |
25 | //[assembly: AssemblyDelaySign(false)]
26 | //[assembly: AssemblyKeyFile("")]
27 |
28 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2010-2014 sta.blockhead
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/websocket-sharp/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 |
4 | // Information about this assembly is defined by the following attributes.
5 | // Change them to the values specific to your project.
6 |
7 | [assembly: AssemblyTitle("websocket-sharp")]
8 | [assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")]
9 | [assembly: AssemblyConfiguration("")]
10 | [assembly: AssemblyCompany("")]
11 | [assembly: AssemblyProduct("websocket-sharp.dll")]
12 | [assembly: AssemblyCopyright("sta.blockhead")]
13 | [assembly: AssemblyTrademark("")]
14 | [assembly: AssemblyCulture("")]
15 |
16 | // The assembly version has the format "{Major}.{Minor}.{Build}.{Revision}".
17 | // The form "{Major}.{Minor}.*" will automatically update the build and revision,
18 | // and "{Major}.{Minor}.{Build}.*" will update just the revision.
19 |
20 | [assembly: AssemblyVersion("1.0.2.*")]
21 |
22 | // The following attributes are used to specify the signing key for the assembly,
23 | // if desired. See the Mono documentation for more information about signing.
24 |
25 | //[assembly: AssemblyDelaySign(false)]
26 | //[assembly: AssemblyKeyFile("")]
27 |
--------------------------------------------------------------------------------
/EchoClient/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using WebSocketSharp;
3 |
4 | namespace EchoClient
5 | {
6 | class MainClass
7 | {
8 | public static void Main (string[] args)
9 | {
10 | if (args.Length != 1) {
11 | Console.WriteLine ("Usage: EchoClient.exe ws://echo.websocket.org");
12 | return;
13 | }
14 |
15 | WebSocket ws = new WebSocket(args[0]);
16 | ws.OnOpen = (Object sender, EventArgs e) => {
17 | Console.WriteLine ("Connected");
18 | Console.Write("-> ");
19 | };
20 | ws.OnMessage = (Object sender, MessageEventArgs e) => {
21 | Console.WriteLine ("<- " + e.Data);
22 | Console.Write("-> ");
23 | };
24 | ws.OnError = (Object sender, ErrorEventArgs e) => {
25 | Console.WriteLine ("ERROR: " + e.Message);
26 | Console.Write("-> ");
27 | };
28 | ws.OnClose = (Object sender, CloseEventArgs e) => {
29 | Console.WriteLine ("Closed " + e.Code + e.Reason + e.WasClean);
30 | };
31 |
32 | ws.Connect ();
33 |
34 | while (true) {
35 | string line = Console.ReadLine ();
36 | ws.Send (line.TrimEnd(new char[] {'\r', '\n'}));
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/websocket-sharp/Fin.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * Fin.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp {
32 |
33 | internal enum Fin : byte
34 | {
35 | MORE = 0x0,
36 | FINAL = 0x1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/websocket-sharp/Rsv.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * Rsv.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp {
32 |
33 | internal enum Rsv : byte
34 | {
35 | OFF = 0x0,
36 | ON = 0x1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/websocket-sharp/Mask.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * Mask.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp {
32 |
33 | internal enum Mask : byte
34 | {
35 | UNMASK = 0x0,
36 | MASK = 0x1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/HttpHeaderType.cs:
--------------------------------------------------------------------------------
1 | //
2 | // HttpHeaderType.cs
3 | //
4 | // Authors:
5 | // sta (sta.blockhead@gmail.com)
6 | //
7 | // Copyright (c) 2013 sta.blockhead
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;
30 |
31 | namespace WebSocketSharp.Net {
32 |
33 | [Flags]
34 | enum HttpHeaderType
35 | {
36 | Unspecified = 0,
37 | Request = 1,
38 | Response = 1 << 1,
39 | Restricted = 1 << 2,
40 | MultiValue = 1 << 3,
41 | MultiValueInRequest = 1 << 4,
42 | MultiValueInResponse = 1 << 5
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/websocket-sharp/ByteOrder.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * ByteOrder.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp {
32 |
33 | ///
34 | /// Contains the values that indicate whether the byte order is a Little-endian or Big-endian.
35 | ///
36 | public enum ByteOrder : byte
37 | {
38 | ///
39 | /// Indicates a Little-endian.
40 | ///
41 | LITTLE,
42 | ///
43 | /// Indicates a Big-endian.
44 | ///
45 | BIG
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/HttpVersion.cs:
--------------------------------------------------------------------------------
1 | //
2 | // HttpVersion.cs
3 | // Copied from System.Net.HttpVersion.cs
4 | //
5 | // Author:
6 | // Lawrence Pit (loz@cable.a2000.nl)
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining
9 | // a copy of this software and associated documentation files (the
10 | // "Software"), to deal in the Software without restriction, including
11 | // without limitation the rights to use, copy, modify, merge, publish,
12 | // distribute, sublicense, and/or sell copies of the Software, and to
13 | // permit persons to whom the Software is furnished to do so, subject to
14 | // the following conditions:
15 | //
16 | // The above copyright notice and this permission notice shall be
17 | // included in all copies or substantial portions of the Software.
18 | //
19 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 | //
27 |
28 | using System;
29 |
30 | namespace WebSocketSharp.Net {
31 |
32 | ///
33 | /// Provides the HTTP version numbers.
34 | ///
35 | public class HttpVersion {
36 |
37 | ///
38 | /// Provides a instance for HTTP 1.0.
39 | ///
40 | public static readonly Version Version10 = new Version (1, 0);
41 |
42 | ///
43 | /// Provides a instance for HTTP 1.1.
44 | ///
45 | public static readonly Version Version11 = new Version (1, 1);
46 |
47 | ///
48 | /// Initializes a new instance of the class.
49 | ///
50 | public HttpVersion () {}
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/EchoClient/EchoClient.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.21022
7 | 2.0
8 | {3C35488A-1B9D-4E76-A1E4-BED3062E5517}
9 | Exe
10 | EchoClient
11 | EchoClient
12 | v3.5
13 |
14 |
15 | true
16 | full
17 | false
18 | bin\Debug
19 | DEBUG;
20 | prompt
21 | 4
22 | true
23 |
24 |
25 | full
26 | true
27 | bin\Release
28 | prompt
29 | 4
30 | true
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 | {B357BAC7-529E-4D81-A0D2-71041B19C8DE}
43 | websocket-sharp
44 |
45 |
46 |
--------------------------------------------------------------------------------
/websocket-sharp/CompressionMethod.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * CompressionMethod.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp {
32 |
33 | ///
34 | /// Contains the values of the compression methods used to compress the payload data of the WebSocket Data frame.
35 | ///
36 | ///
37 | /// The CompressionMethod enumeration contains the values of the compression methods defined in
38 | /// Compression Extensions for WebSocket.
39 | ///
40 | public enum CompressionMethod : byte
41 | {
42 | ///
43 | /// Indicates non compression.
44 | ///
45 | NONE,
46 | ///
47 | /// Indicates using DEFLATE.
48 | ///
49 | DEFLATE
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/websocket-sharp/LogLevel.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * LogLevel.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp
32 | {
33 | ///
34 | /// Contains the values of the logging level.
35 | ///
36 | public enum LogLevel
37 | {
38 | ///
39 | /// Indicates the bottom logging level.
40 | ///
41 | TRACE,
42 | ///
43 | /// Indicates the 2nd logging level from the bottom.
44 | ///
45 | DEBUG,
46 | ///
47 | /// Indicates the 3rd logging level from the bottom.
48 | ///
49 | INFO,
50 | ///
51 | /// Indicates the 3rd logging level from the top.
52 | ///
53 | WARN,
54 | ///
55 | /// Indicates the 2nd logging level from the top.
56 | ///
57 | ERROR,
58 | ///
59 | /// Indicates the top logging level.
60 | ///
61 | FATAL
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/websocket-sharp/WebSocketState.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * WebSocketState.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2010-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp {
32 |
33 | ///
34 | /// Contains the values of the state of the WebSocket connection.
35 | ///
36 | ///
37 | /// The WebSocketState enumeration contains the values of the state of the WebSocket connection defined in
38 | /// The WebSocket API.
39 | ///
40 | public enum WebSocketState : ushort
41 | {
42 | ///
43 | /// Equivalent to numeric value 0. Indicates that the connection has not yet been established.
44 | ///
45 | CONNECTING = 0,
46 | ///
47 | /// Equivalent to numeric value 1. Indicates that the connection is established and the communication
48 | /// is possible.
49 | ///
50 | OPEN = 1,
51 | ///
52 | /// Equivalent to numeric value 2. Indicates that the connection is going through the closing handshake,
53 | /// or the WebSocket.Close method has been invoked.
54 | ///
55 | CLOSING = 2,
56 | ///
57 | /// Equivalent to numeric value 3. Indicates that the connection has been closed or could not be opened.
58 | ///
59 | CLOSED = 3
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/websocket-sharp/Opcode.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * Opcode.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp {
32 |
33 | ///
34 | /// Contains the values of the opcodes that denotes the frame type of the WebSocket frame.
35 | ///
36 | ///
37 | /// The Opcode enumeration contains the values of the opcodes defined in
38 | /// RFC 6455 for the WebSocket protocol.
39 | ///
40 | public enum Opcode : byte
41 | {
42 | ///
43 | /// Equivalent to numeric value 0. Indicates a continuation frame.
44 | ///
45 | CONT = 0x0,
46 | ///
47 | /// Equivalent to numeric value 1. Indicates a text frame.
48 | ///
49 | TEXT = 0x1,
50 | ///
51 | /// Equivalent to numeric value 2. Indicates a binary frame.
52 | ///
53 | BINARY = 0x2,
54 | ///
55 | /// Equivalent to numeric value 8. Indicates a connection close frame.
56 | ///
57 | CLOSE = 0x8,
58 | ///
59 | /// Equivalent to numeric value 9. Indicates a ping frame.
60 | ///
61 | PING = 0x9,
62 | ///
63 | /// Equivalent to numeric value 10. Indicates a pong frame.
64 | ///
65 | PONG = 0xa
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/Security/SslStream.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * SslStream.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Net.Security;
31 | using System.Net.Sockets;
32 |
33 | namespace WebSocketSharp.Net.Security {
34 |
35 | internal class SslStream : System.Net.Security.SslStream
36 | {
37 | #region Public Constructors
38 |
39 | public SslStream(NetworkStream innerStream)
40 | : base(innerStream)
41 | {
42 | }
43 |
44 | public SslStream(NetworkStream innerStream, bool leaveInnerStreamOpen)
45 | : base(innerStream, leaveInnerStreamOpen)
46 | {
47 | }
48 |
49 | public SslStream(
50 | NetworkStream innerStream,
51 | bool leaveInnerStreamOpen,
52 | RemoteCertificateValidationCallback userCertificateValidationCallback
53 | ) : base(innerStream, leaveInnerStreamOpen, userCertificateValidationCallback)
54 | {
55 | }
56 |
57 | public SslStream(
58 | NetworkStream innerStream,
59 | bool leaveInnerStreamOpen,
60 | RemoteCertificateValidationCallback userCertificateValidationCallback,
61 | LocalCertificateSelectionCallback userCertificateSelectionCallback
62 | ) : base(
63 | innerStream,
64 | leaveInnerStreamOpen,
65 | userCertificateValidationCallback,
66 | userCertificateSelectionCallback
67 | )
68 | {
69 | }
70 |
71 | #endregion
72 |
73 | #region Public Properties
74 |
75 | public bool DataAvailable {
76 | get {
77 | return ((NetworkStream)InnerStream).DataAvailable;
78 | }
79 | }
80 |
81 | #endregion
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/HttpHeaderInfo.cs:
--------------------------------------------------------------------------------
1 | //
2 | // HttpHeaderInfo.cs
3 | //
4 | // Authors:
5 | // sta (sta.blockhead@gmail.com)
6 | //
7 | // Copyright (c) 2013 sta.blockhead
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;
30 |
31 | namespace WebSocketSharp.Net {
32 |
33 | class HttpHeaderInfo {
34 |
35 | #region Constructor
36 |
37 | public HttpHeaderInfo ()
38 | {
39 | }
40 |
41 | #endregion
42 |
43 | #region Properties
44 |
45 | public bool IsMultiValueInRequest {
46 | get {
47 | return (Type & HttpHeaderType.MultiValueInRequest) == HttpHeaderType.MultiValueInRequest;
48 | }
49 | }
50 |
51 | public bool IsMultiValueInResponse {
52 | get {
53 | return (Type & HttpHeaderType.MultiValueInResponse) == HttpHeaderType.MultiValueInResponse;
54 | }
55 | }
56 |
57 | public bool IsRequest {
58 | get {
59 | return (Type & HttpHeaderType.Request) == HttpHeaderType.Request;
60 | }
61 | }
62 |
63 | public bool IsResponse {
64 | get {
65 | return (Type & HttpHeaderType.Response) == HttpHeaderType.Response;
66 | }
67 | }
68 |
69 | public string Name { get; set; }
70 |
71 | public HttpHeaderType Type { get; set; }
72 |
73 | #endregion
74 |
75 | #region Methods
76 |
77 | public bool IsMultiValue (bool response)
78 | {
79 | return (Type & HttpHeaderType.MultiValue) != HttpHeaderType.MultiValue
80 | ? response
81 | ? IsMultiValueInResponse
82 | : IsMultiValueInRequest
83 | : response
84 | ? IsResponse
85 | : IsRequest;
86 | }
87 |
88 | public bool IsRestricted (bool response)
89 | {
90 | return (Type & HttpHeaderType.Restricted) != HttpHeaderType.Restricted
91 | ? false
92 | : response
93 | ? IsResponse
94 | : IsRequest;
95 | }
96 |
97 | #endregion
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/websocket-sharp/ErrorEventArgs.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * ErrorEventArgs.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp
32 | {
33 | ///
34 | /// Contains the event data associated with a event.
35 | ///
36 | ///
37 | /// A event occurs when the gets an error.
38 | /// If you would like to get the error message, you should access the
39 | /// property.
40 | ///
41 | public class ErrorEventArgs : EventArgs
42 | {
43 | #region Private Fields
44 |
45 | private string _message;
46 | private Exception _exception;
47 |
48 | #endregion
49 |
50 | #region Internal Constructors
51 |
52 | internal ErrorEventArgs (string message)
53 | : this (message, null)
54 | {
55 | }
56 |
57 | internal ErrorEventArgs (string message, Exception exception)
58 | {
59 | _message = message;
60 | _exception = exception;
61 | }
62 |
63 | #endregion
64 |
65 | #region Public Properties
66 |
67 | ///
68 | /// Gets the error message.
69 | ///
70 | ///
71 | /// A that represents the error message.
72 | ///
73 | public string Message {
74 | get {
75 | return _message;
76 | }
77 | }
78 |
79 | ///
80 | /// Gets the exception that caused the error.
81 | ///
82 | /// A instance that represents the cause of the error,
83 | /// or if the error isn't due to an exception.
84 | ///
85 | public Exception Exception {
86 | get {
87 | return _exception;
88 | }
89 | }
90 |
91 | #endregion
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/websocket-sharp/WebSocketException.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * WebSocketException.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2014 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp
32 | {
33 | ///
34 | /// Represents the exception that occurred when attempting to perform an
35 | /// operation on the WebSocket connection.
36 | ///
37 | public class WebSocketException : Exception
38 | {
39 | #region Internal Constructors
40 |
41 | internal WebSocketException ()
42 | : this (CloseStatusCode.ABNORMAL, null, null)
43 | {
44 | }
45 |
46 | internal WebSocketException (CloseStatusCode code)
47 | : this (code, null, null)
48 | {
49 | }
50 |
51 | internal WebSocketException (string reason)
52 | : this (CloseStatusCode.ABNORMAL, reason, null)
53 | {
54 | }
55 |
56 | internal WebSocketException (string reason, Exception innerException)
57 | : this (CloseStatusCode.ABNORMAL, reason, innerException)
58 | {
59 | }
60 |
61 | internal WebSocketException (CloseStatusCode code, string reason)
62 | : this (code, reason, null)
63 | {
64 | }
65 |
66 | internal WebSocketException (
67 | CloseStatusCode code, string reason, Exception innerException)
68 | : base (reason ?? code.GetMessage (), innerException)
69 | {
70 | Code = code;
71 | }
72 |
73 | #endregion
74 |
75 | #region Public Properties
76 |
77 | ///
78 | /// Gets the associated with the
79 | /// .
80 | ///
81 | ///
82 | /// One of the values, indicates the cause of
83 | /// the .
84 | ///
85 | public CloseStatusCode Code {
86 | get; private set;
87 | }
88 |
89 | #endregion
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/websocket-sharp/websocket-sharp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | 9.0.21022
7 | 2.0
8 | {B357BAC7-529E-4D81-A0D2-71041B19C8DE}
9 | Library
10 | WebSocketSharp
11 | websocket-sharp
12 | v3.5
13 | True
14 | websocket-sharp.snk
15 |
16 |
17 | True
18 | full
19 | False
20 | bin\Debug
21 | DEBUG
22 | prompt
23 | 4
24 | False
25 |
26 |
27 | none
28 | False
29 | bin\Release
30 | prompt
31 | 4
32 | False
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 |
--------------------------------------------------------------------------------
/websocket-sharp/HandshakeBase.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * HandshakeBase.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2014 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Collections.Specialized;
31 | using System.Text;
32 | using WebSocketSharp.Net;
33 |
34 | namespace WebSocketSharp
35 | {
36 | internal abstract class HandshakeBase
37 | {
38 | #region Private Fields
39 |
40 | private byte [] _entity;
41 | private NameValueCollection _headers;
42 | private Version _version;
43 |
44 | #endregion
45 |
46 | #region Protected Const Fields
47 |
48 | protected const string CrLf = "\r\n";
49 |
50 | #endregion
51 |
52 | #region Protected Constructors
53 |
54 | protected HandshakeBase ()
55 | {
56 | }
57 |
58 | #endregion
59 |
60 | #region Internal Properties
61 |
62 | internal byte [] EntityBodyData {
63 | get {
64 | return _entity;
65 | }
66 |
67 | set {
68 | _entity = value;
69 | }
70 | }
71 |
72 | #endregion
73 |
74 | #region Public Properties
75 |
76 | public string EntityBody {
77 | get {
78 | return _entity != null && _entity.LongLength > 0
79 | ? getEncoding (_headers ["Content-Type"]).GetString (_entity)
80 | : String.Empty;
81 | }
82 | }
83 |
84 | public NameValueCollection Headers {
85 | get {
86 | return _headers ?? (_headers = new NameValueCollection ());
87 | }
88 |
89 | protected set {
90 | _headers = value;
91 | }
92 | }
93 |
94 | public Version ProtocolVersion {
95 | get {
96 | return _version ?? (_version = HttpVersion.Version11);
97 | }
98 |
99 | protected set {
100 | _version = value;
101 | }
102 | }
103 |
104 | #endregion
105 |
106 | #region Private Methods
107 |
108 | private static Encoding getEncoding (string contentType)
109 | {
110 | if (contentType == null || contentType.Length == 0)
111 | return Encoding.UTF8;
112 |
113 | var i = contentType.IndexOf ("charset=", StringComparison.Ordinal);
114 | if (i == -1)
115 | return Encoding.UTF8;
116 |
117 | var charset = contentType.Substring (i + 8);
118 | i = charset.IndexOf (';');
119 | if (i != -1)
120 | charset = charset.Substring (0, i);
121 |
122 | return Encoding.GetEncoding (charset);
123 | }
124 |
125 | #endregion
126 |
127 | #region Public Methods
128 |
129 | public byte [] ToByteArray ()
130 | {
131 | return Encoding.UTF8.GetBytes (ToString ());
132 | }
133 |
134 | #endregion
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/websocket-sharp/CloseEventArgs.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * CloseEventArgs.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2014 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Text;
31 |
32 | namespace WebSocketSharp
33 | {
34 | ///
35 | /// Contains the event data associated with a
36 | /// event.
37 | ///
38 | ///
39 | /// A event occurs when the WebSocket connection
40 | /// has been closed. If you want to get the reason for closure, you access the
41 | /// or property.
42 | ///
43 | public class CloseEventArgs : EventArgs
44 | {
45 | #region Private Fields
46 |
47 | private bool _clean;
48 | private ushort _code;
49 | private string _reason;
50 |
51 | #endregion
52 |
53 | #region Internal Constructors
54 |
55 | internal CloseEventArgs (PayloadData payload)
56 | {
57 | var data = payload.ApplicationData;
58 | _code = getCodeFrom (data);
59 | _reason = getReasonFrom (data);
60 | _clean = false;
61 | }
62 |
63 | #endregion
64 |
65 | #region Public Properties
66 |
67 | ///
68 | /// Gets the status code for closure.
69 | ///
70 | ///
71 | /// A that indicates the status code for closure if any.
72 | ///
73 | public ushort Code {
74 | get {
75 | return _code;
76 | }
77 | }
78 |
79 | ///
80 | /// Gets the reason for closure.
81 | ///
82 | ///
83 | /// A that represents the reason for closure if any.
84 | ///
85 | public string Reason {
86 | get {
87 | return _reason;
88 | }
89 | }
90 |
91 | ///
92 | /// Gets a value indicating whether the WebSocket connection has been closed
93 | /// cleanly.
94 | ///
95 | ///
96 | /// true if the WebSocket connection has been closed cleanly;
97 | /// otherwise, false.
98 | ///
99 | public bool WasClean {
100 | get {
101 | return _clean;
102 | }
103 |
104 | internal set {
105 | _clean = value;
106 | }
107 | }
108 |
109 | #endregion
110 |
111 | #region Private Methods
112 |
113 | private static ushort getCodeFrom (byte [] data)
114 | {
115 | return data.Length > 1
116 | ? data.SubArray (0, 2).ToUInt16 (ByteOrder.BIG)
117 | : (ushort) CloseStatusCode.NO_STATUS_CODE;
118 | }
119 |
120 | private static string getReasonFrom (byte [] data)
121 | {
122 | var len = data.Length;
123 | return len > 2
124 | ? Encoding.UTF8.GetString (data.SubArray (2, len - 2))
125 | : String.Empty;
126 | }
127 |
128 | #endregion
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/websocket-sharp/MessageEventArgs.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * MessageEventArgs.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Text;
31 |
32 | namespace WebSocketSharp
33 | {
34 | ///
35 | /// Contains the event data associated with a event.
36 | ///
37 | ///
38 | /// A event occurs when the receives
39 | /// a text or binary data frame.
40 | /// If you want to get the received data, you access the or
41 | /// property.
42 | ///
43 | public class MessageEventArgs : EventArgs
44 | {
45 | #region Private Fields
46 |
47 | private string _data;
48 | private Opcode _opcode;
49 | private byte[] _rawData;
50 |
51 | #endregion
52 |
53 | #region Internal Constructors
54 |
55 | internal MessageEventArgs (Opcode opcode, byte[] data)
56 | {
57 | if ((ulong) data.LongLength > PayloadData.MaxLength)
58 | throw new WebSocketException (CloseStatusCode.TOO_BIG);
59 |
60 | _opcode = opcode;
61 | _rawData = data;
62 | }
63 |
64 | internal MessageEventArgs (Opcode opcode, PayloadData payload)
65 | {
66 | _opcode = opcode;
67 | _rawData = payload.ApplicationData;
68 | }
69 |
70 | #endregion
71 |
72 | #region Public Properties
73 |
74 | ///
75 | /// Gets the received data as a .
76 | ///
77 | ///
78 | /// A that contains the received data.
79 | ///
80 | public string Data {
81 | get {
82 | if (_data == null)
83 | {
84 | _data = convertToString (_opcode, _rawData);
85 | }
86 | return _data;
87 | }
88 | }
89 |
90 | ///
91 | /// Gets the received data as an array of .
92 | ///
93 | ///
94 | /// An array of that contains the received data.
95 | ///
96 | public byte [] RawData {
97 | get {
98 | return _rawData;
99 | }
100 | }
101 |
102 | ///
103 | /// Gets the type of the received data.
104 | ///
105 | ///
106 | /// One of the values, indicates the type of the received data.
107 | ///
108 | public Opcode Type {
109 | get {
110 | return _opcode;
111 | }
112 | }
113 |
114 | #endregion
115 |
116 | #region Private Methods
117 |
118 | private static string convertToString (Opcode opcode, byte [] data)
119 | {
120 | return data.LongLength == 0
121 | ? String.Empty
122 | : opcode == Opcode.TEXT
123 | ? Encoding.UTF8.GetString (data)
124 | : opcode.ToString ();
125 | }
126 |
127 | #endregion
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/CookieException.cs:
--------------------------------------------------------------------------------
1 | //
2 | // CookieException.cs
3 | // Copied from System.Net.CookieException.cs
4 | //
5 | // Author:
6 | // Lawrence Pit (loz@cable.a2000.nl)
7 | //
8 | // Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining
11 | // a copy of this software and associated documentation files (the
12 | // "Software"), to deal in the Software without restriction, including
13 | // without limitation the rights to use, copy, modify, merge, publish,
14 | // distribute, sublicense, and/or sell copies of the Software, and to
15 | // permit persons to whom the Software is furnished to do so, subject to
16 | // the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be
19 | // included in all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | using System;
31 | using System.Globalization;
32 | using System.Runtime.Serialization;
33 | using System.Security.Permissions;
34 |
35 | namespace WebSocketSharp.Net {
36 |
37 | ///
38 | /// The exception that is thrown when a gets an error.
39 | ///
40 | [Serializable]
41 | public class CookieException : FormatException, ISerializable
42 | {
43 | #region Internal Constructors
44 |
45 | internal CookieException (string message)
46 | : base (message)
47 | {
48 | }
49 |
50 | internal CookieException (string message, Exception innerException)
51 | : base (message, innerException)
52 | {
53 | }
54 |
55 | #endregion
56 |
57 | #region Protected Constructor
58 |
59 | ///
60 | /// Initializes a new instance of the class
61 | /// with the specified and .
62 | ///
63 | ///
64 | /// A that holds the serialized object data.
65 | ///
66 | ///
67 | /// A that contains the contextual information about the source or destination.
68 | ///
69 | protected CookieException (SerializationInfo serializationInfo, StreamingContext streamingContext)
70 | : base (serializationInfo, streamingContext)
71 | {
72 | }
73 |
74 | #endregion
75 |
76 | #region Public Constructor
77 |
78 | ///
79 | /// Initializes a new instance of the class.
80 | ///
81 | public CookieException ()
82 | : base ()
83 | {
84 | }
85 |
86 | #endregion
87 |
88 | #region Explicit Interface Implementation
89 |
90 | ///
91 | /// Populates the specified with the data needed to serialize the .
92 | ///
93 | ///
94 | /// A that holds the serialized object data.
95 | ///
96 | ///
97 | /// A that specifies the destination for the serialization.
98 | ///
99 | [SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter, SerializationFormatter = true)]
100 | void ISerializable.GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
101 | {
102 | base.GetObjectData (serializationInfo, streamingContext);
103 | }
104 |
105 | #endregion
106 |
107 | #region Public Method
108 |
109 | ///
110 | /// Populates the specified with the data needed to serialize the .
111 | ///
112 | ///
113 | /// A that holds the serialized object data.
114 | ///
115 | ///
116 | /// A that specifies the destination for the serialization.
117 | ///
118 | [SecurityPermission (SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.SerializationFormatter)]
119 | public override void GetObjectData (SerializationInfo serializationInfo, StreamingContext streamingContext)
120 | {
121 | base.GetObjectData (serializationInfo, streamingContext);
122 | }
123 |
124 | #endregion
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/websocket-sharp/LogData.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * LogData.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Diagnostics;
31 | using System.Text;
32 |
33 | namespace WebSocketSharp
34 | {
35 | ///
36 | /// Represents the log data used by the class.
37 | ///
38 | public class LogData
39 | {
40 | #region Private Fields
41 |
42 | private StackFrame _caller;
43 | private DateTime _date;
44 | private LogLevel _level;
45 | private string _message;
46 |
47 | #endregion
48 |
49 | #region Internal Constructors
50 |
51 | internal LogData (LogLevel level, StackFrame caller, string message)
52 | {
53 | _level = level;
54 | _caller = caller;
55 | _message = message;
56 | _date = DateTime.Now;
57 | }
58 |
59 | #endregion
60 |
61 | #region Public Properties
62 |
63 | ///
64 | /// Gets the information of the logging method caller.
65 | ///
66 | ///
67 | /// A that contains the information of a logging method caller.
68 | ///
69 | public StackFrame Caller {
70 | get {
71 | return _caller;
72 | }
73 | }
74 |
75 | ///
76 | /// Gets the date and time when the log data was created.
77 | ///
78 | ///
79 | /// A that contains the date and time when the log data was created.
80 | ///
81 | public DateTime Date {
82 | get {
83 | return _date;
84 | }
85 | }
86 |
87 | ///
88 | /// Gets the logging level associated with the log data.
89 | ///
90 | ///
91 | /// One of the values that indicates the logging level
92 | /// associated with the log data.
93 | ///
94 | public LogLevel Level {
95 | get {
96 | return _level;
97 | }
98 | }
99 |
100 | ///
101 | /// Gets the message of the log data.
102 | ///
103 | ///
104 | /// A that contains the message of a log data.
105 | ///
106 | public string Message {
107 | get {
108 | return _message;
109 | }
110 | }
111 |
112 | #endregion
113 |
114 | #region Public Methods
115 |
116 | ///
117 | /// Returns a that represents the current .
118 | ///
119 | ///
120 | /// A that represents the current .
121 | ///
122 | public override string ToString ()
123 | {
124 | var header = String.Format ("{0}|{1,-5}|", _date, _level);
125 | var method = _caller.GetMethod ();
126 | var type = method.DeclaringType;
127 | #if DEBUG
128 | var lineNum = _caller.GetFileLineNumber ();
129 | var headerAndCaller = String.Format ("{0}{1}.{2}:{3}|", header, type.Name, method.Name, lineNum);
130 | #else
131 | var headerAndCaller = String.Format ("{0}{1}.{2}|", header, type.Name, method.Name);
132 | #endif
133 |
134 | var messages = _message.Replace ("\r\n", "\n").TrimEnd ('\n').Split ('\n');
135 | if (messages.Length <= 1)
136 | return String.Format ("{0}{1}", headerAndCaller, _message);
137 |
138 | var output = new StringBuilder (String.Format ("{0}{1}\n", headerAndCaller, messages [0]), 64);
139 | var space = header.Length;
140 | var format = String.Format ("{{0,{0}}}{{1}}\n", space);
141 | for (var i = 1; i < messages.Length; i++)
142 | output.AppendFormat (format, "", messages [i]);
143 |
144 | output.Length--;
145 | return output.ToString ();
146 | }
147 |
148 | #endregion
149 | }
150 | }
151 |
--------------------------------------------------------------------------------
/websocket-sharp/PayloadData.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * PayloadData.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Collections;
31 | using System.Collections.Generic;
32 | using System.IO;
33 | using System.Linq;
34 | using System.Text;
35 |
36 | namespace WebSocketSharp
37 | {
38 | internal class PayloadData : IEnumerable
39 | {
40 | #region Public Const Fields
41 |
42 | public const ulong MaxLength = long.MaxValue;
43 |
44 | #endregion
45 |
46 | #region Public Constructors
47 |
48 | public PayloadData ()
49 | : this (new byte []{})
50 | {
51 | }
52 |
53 | public PayloadData (byte [] appData)
54 | : this (new byte []{}, appData)
55 | {
56 | }
57 |
58 | public PayloadData (string appData)
59 | : this (Encoding.UTF8.GetBytes (appData))
60 | {
61 | }
62 |
63 | public PayloadData (byte [] appData, bool masked)
64 | : this (new byte []{}, appData, masked)
65 | {
66 | }
67 |
68 | public PayloadData (byte [] extData, byte [] appData)
69 | : this (extData, appData, false)
70 | {
71 | }
72 |
73 | public PayloadData (byte [] extData, byte [] appData, bool masked)
74 | {
75 | if ((ulong) extData.LongLength + (ulong) appData.LongLength > MaxLength)
76 | throw new ArgumentOutOfRangeException (
77 | "The length of 'extData' plus 'appData' must be less than MaxLength.");
78 |
79 | ExtensionData = extData;
80 | ApplicationData = appData;
81 | IsMasked = masked;
82 | }
83 |
84 | #endregion
85 |
86 | #region Internal Properties
87 |
88 | internal bool ContainsReservedCloseStatusCode {
89 | get {
90 | return ApplicationData.Length > 1
91 | ? ApplicationData.SubArray (0, 2).ToUInt16 (ByteOrder.BIG).IsReserved ()
92 | : false;
93 | }
94 | }
95 |
96 | internal bool IsMasked {
97 | get; private set;
98 | }
99 |
100 | #endregion
101 |
102 | #region Public Properties
103 |
104 | public byte [] ExtensionData {
105 | get; private set;
106 | }
107 |
108 | public byte [] ApplicationData {
109 | get; private set;
110 | }
111 |
112 | public ulong Length {
113 | get {
114 | return (ulong) (ExtensionData.LongLength + ApplicationData.LongLength);
115 | }
116 | }
117 |
118 | #endregion
119 |
120 | #region Private Methods
121 |
122 | private static void mask (byte [] src, byte [] key)
123 | {
124 | for (long i = 0; i < src.LongLength; i++)
125 | src [i] = (byte) (src [i] ^ key [i % 4]);
126 | }
127 |
128 | #endregion
129 |
130 | #region Internal Methods
131 |
132 | #endregion
133 |
134 | #region Public Methods
135 |
136 | public IEnumerator GetEnumerator ()
137 | {
138 | foreach (byte b in ExtensionData)
139 | yield return b;
140 |
141 | foreach (byte b in ApplicationData)
142 | yield return b;
143 | }
144 |
145 | public void Mask (byte [] maskingKey)
146 | {
147 | if (ExtensionData.LongLength > 0)
148 | mask (ExtensionData, maskingKey);
149 |
150 | if (ApplicationData.LongLength > 0)
151 | mask (ApplicationData, maskingKey);
152 |
153 | IsMasked = !IsMasked;
154 | }
155 |
156 | public byte [] ToByteArray ()
157 | {
158 | return ExtensionData.LongLength > 0
159 | ? this.ToArray ()
160 | : ApplicationData;
161 | }
162 |
163 | public override string ToString ()
164 | {
165 | return BitConverter.ToString (ToByteArray ());
166 | }
167 |
168 | #endregion
169 |
170 | #region Explicitly Implemented Interface Members
171 |
172 | IEnumerator IEnumerable.GetEnumerator ()
173 | {
174 | return GetEnumerator ();
175 | }
176 |
177 | #endregion
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/websocket-sharp/HandshakeResponse.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * HandshakeResponse.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2014 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Collections.Specialized;
31 | using System.Text;
32 | using WebSocketSharp.Net;
33 |
34 | namespace WebSocketSharp
35 | {
36 | internal class HandshakeResponse : HandshakeBase
37 | {
38 | #region Private Fields
39 |
40 | private string _code;
41 | private string _reason;
42 |
43 | #endregion
44 |
45 | #region Private Constructors
46 |
47 | private HandshakeResponse ()
48 | {
49 | }
50 |
51 | #endregion
52 |
53 | #region Public Constructors
54 |
55 | public HandshakeResponse (HttpStatusCode code)
56 | {
57 | _code = ((int) code).ToString ();
58 | _reason = code.GetDescription ();
59 |
60 | var headers = Headers;
61 | headers ["Server"] = "websocket-sharp/1.0";
62 | if (code == HttpStatusCode.SwitchingProtocols) {
63 | headers ["Upgrade"] = "websocket";
64 | headers ["Connection"] = "Upgrade";
65 | }
66 | }
67 |
68 | #endregion
69 |
70 | #region Public Properties
71 | public CookieCollection Cookies {
72 | get {
73 | return Headers.GetCookies (true);
74 | }
75 | }
76 |
77 | public bool IsUnauthorized {
78 | get {
79 | return _code == "401";
80 | }
81 | }
82 |
83 | public bool IsWebSocketResponse {
84 | get {
85 | var headers = Headers;
86 | return ProtocolVersion >= HttpVersion.Version11 &&
87 | _code == "101" &&
88 | headers.Contains ("Upgrade", "websocket") &&
89 | headers.Contains ("Connection", "Upgrade");
90 | }
91 | }
92 |
93 | public string Reason {
94 | get {
95 | return _reason;
96 | }
97 |
98 | private set {
99 | _reason = value;
100 | }
101 | }
102 |
103 | public string StatusCode {
104 | get {
105 | return _code;
106 | }
107 |
108 | private set {
109 | _code = value;
110 | }
111 | }
112 |
113 | #endregion
114 |
115 | #region Public Methods
116 |
117 | public static HandshakeResponse CreateCloseResponse (HttpStatusCode code)
118 | {
119 | var res = new HandshakeResponse (code);
120 | res.Headers ["Connection"] = "close";
121 |
122 | return res;
123 | }
124 |
125 | public static HandshakeResponse Parse (string [] headerParts)
126 | {
127 | var statusLine = headerParts [0].Split (new char [] { ' ' }, 3);
128 | if (statusLine.Length != 3)
129 | throw new ArgumentException ("Invalid status line: " + headerParts [0]);
130 |
131 | var headers = new WebHeaderCollection ();
132 | for (int i = 1; i < headerParts.Length; i++)
133 | headers.SetInternal (headerParts [i], true);
134 |
135 | return new HandshakeResponse {
136 | Headers = headers,
137 | ProtocolVersion = new Version (statusLine [0].Substring (5)),
138 | Reason = statusLine [2],
139 | StatusCode = statusLine [1]
140 | };
141 | }
142 |
143 | public void SetCookies (CookieCollection cookies)
144 | {
145 | if (cookies == null || cookies.Count == 0)
146 | return;
147 |
148 | var headers = Headers;
149 | foreach (var cookie in cookies.Sorted)
150 | headers.Add ("Set-Cookie", cookie.ToResponseString ());
151 | }
152 |
153 | public override string ToString ()
154 | {
155 | var buffer = new StringBuilder (64);
156 | buffer.AppendFormat (
157 | "HTTP/{0} {1} {2}{3}", ProtocolVersion, _code, _reason, CrLf);
158 |
159 | var headers = Headers;
160 | foreach (var key in headers.AllKeys)
161 | buffer.AppendFormat ("{0}: {1}{2}", key, headers [key], CrLf);
162 |
163 | buffer.Append (CrLf);
164 |
165 | var entity = EntityBody;
166 | if (entity.Length > 0)
167 | buffer.Append (entity);
168 |
169 | return buffer.ToString ();
170 | }
171 |
172 | #endregion
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/websocket-sharp/CloseStatusCode.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * CloseStatusCode.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2014 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 |
31 | namespace WebSocketSharp
32 | {
33 | ///
34 | /// Contains the values of the status codes for the WebSocket connection
35 | /// closure.
36 | ///
37 | ///
38 | ///
39 | /// The CloseStatusCode enumeration contains the values of the status codes
40 | /// for the WebSocket connection closure defined in
41 | /// RFC 6455
42 | /// for the WebSocket protocol.
43 | ///
44 | ///
45 | /// "Reserved value" must not be set as a status code in a close control frame
46 | /// by an endpoint. It's designated for use in applications expecting a status
47 | /// code to indicate that the connection was closed due to a system grounds.
48 | ///
49 | ///
50 | public enum CloseStatusCode : ushort
51 | {
52 | ///
53 | /// Equivalent to close status 1000.
54 | /// Indicates a normal closure.
55 | ///
56 | NORMAL = 1000,
57 | ///
58 | /// Equivalent to close status 1001.
59 | /// Indicates that an endpoint is "going away".
60 | ///
61 | AWAY = 1001,
62 | ///
63 | /// Equivalent to close status 1002.
64 | /// Indicates that an endpoint is terminating the connection due to a protocol
65 | /// error.
66 | ///
67 | PROTOCOL_ERROR = 1002,
68 | ///
69 | /// Equivalent to close status 1003.
70 | /// Indicates that an endpoint is terminating the connection because it has
71 | /// received a type of data it cannot accept.
72 | ///
73 | INCORRECT_DATA = 1003,
74 | ///
75 | /// Equivalent to close status 1004.
76 | /// Still undefined. Reserved value.
77 | ///
78 | UNDEFINED = 1004,
79 | ///
80 | /// Equivalent to close status 1005.
81 | /// Indicates that no status code was actually present. Reserved value.
82 | ///
83 | NO_STATUS_CODE = 1005,
84 | ///
85 | /// Equivalent to close status 1006.
86 | /// Indicates that the connection was closed abnormally. Reserved value.
87 | ///
88 | ABNORMAL = 1006,
89 | ///
90 | /// Equivalent to close status 1007.
91 | /// Indicates that an endpoint is terminating the connection because it has
92 | /// received the data within a message that wasn't consistent with the type of
93 | /// the message.
94 | ///
95 | INCONSISTENT_DATA = 1007,
96 | ///
97 | /// Equivalent to close status 1008.
98 | /// Indicates that an endpoint is terminating the connection because it has
99 | /// received a message that violates its policy.
100 | ///
101 | POLICY_VIOLATION = 1008,
102 | ///
103 | /// Equivalent to close status 1009.
104 | /// Indicates that an endpoint is terminating the connection because it has
105 | /// received a message that is too big to process.
106 | ///
107 | TOO_BIG = 1009,
108 | ///
109 | /// Equivalent to close status 1010.
110 | /// Indicates that an endpoint (client) is terminating the connection because
111 | /// it has expected the server to negotiate one or more extension, but the
112 | /// server didn't return them in the response message of the WebSocket
113 | /// handshake.
114 | ///
115 | IGNORE_EXTENSION = 1010,
116 | ///
117 | /// Equivalent to close status 1011.
118 | /// Indicates that the server is terminating the connection because it has
119 | /// encountered an unexpected condition that prevented it from fulfilling the
120 | /// request.
121 | ///
122 | SERVER_ERROR = 1011,
123 | ///
124 | /// Equivalent to close status 1015.
125 | /// Indicates that the connection was closed due to a failure to perform a TLS
126 | /// handshake. Reserved value.
127 | ///
128 | TLS_HANDSHAKE_FAILURE = 1015
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/websocket-sharp/HandshakeRequest.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * HandshakeRequest.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2014 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Collections.Specialized;
31 | using System.Linq;
32 | using System.Text;
33 | using WebSocketSharp.Net;
34 |
35 | namespace WebSocketSharp
36 | {
37 | internal class HandshakeRequest : HandshakeBase
38 | {
39 | #region Private Fields
40 |
41 | private string _method;
42 | private NameValueCollection _queryString;
43 | private string _rawUrl;
44 | private Uri _uri;
45 |
46 | #endregion
47 |
48 | #region Private Constructors
49 |
50 | private HandshakeRequest ()
51 | {
52 | }
53 |
54 | #endregion
55 |
56 | #region Public Constructors
57 |
58 | public HandshakeRequest (string uriString)
59 | {
60 | _uri = uriString.ToUri ();
61 | _rawUrl = _uri.IsAbsoluteUri ? _uri.PathAndQuery : uriString;
62 | _method = "GET";
63 |
64 | var headers = Headers;
65 | headers ["User-Agent"] = "websocket-sharp/1.0";
66 | headers ["Upgrade"] = "websocket";
67 | headers ["Connection"] = "Upgrade";
68 | }
69 |
70 | #endregion
71 |
72 | #region Public Properties
73 |
74 | public CookieCollection Cookies {
75 | get {
76 | return Headers.GetCookies (false);
77 | }
78 | }
79 |
80 | public string HttpMethod {
81 | get {
82 | return _method;
83 | }
84 |
85 | private set {
86 | _method = value;
87 | }
88 | }
89 |
90 | public bool IsWebSocketRequest {
91 | get {
92 | var headers = Headers;
93 | return _method == "GET" &&
94 | ProtocolVersion >= HttpVersion.Version11 &&
95 | headers.Contains ("Upgrade", "websocket") &&
96 | headers.Contains ("Connection", "Upgrade");
97 | }
98 | }
99 |
100 | public NameValueCollection QueryString {
101 | get {
102 | if (_queryString == null) {
103 | _queryString = new NameValueCollection ();
104 |
105 | var i = RawUrl.IndexOf ('?');
106 | if (i > 0) {
107 | var query = RawUrl.Substring (i + 1);
108 | var components = query.Split ('&');
109 | foreach (var c in components) {
110 | var nv = c.GetNameAndValue ("=");
111 | if (nv.Key != null) {
112 | var name = nv.Key.UrlDecode ();
113 | var val = nv.Value.UrlDecode ();
114 | _queryString.Add (name, val);
115 | }
116 | }
117 | }
118 | }
119 |
120 | return _queryString;
121 | }
122 | }
123 |
124 | public string RawUrl {
125 | get {
126 | return _rawUrl;
127 | }
128 |
129 | private set {
130 | _rawUrl = value;
131 | }
132 | }
133 |
134 | public Uri RequestUri {
135 | get {
136 | return _uri;
137 | }
138 |
139 | private set {
140 | _uri = value;
141 | }
142 | }
143 |
144 | #endregion
145 |
146 | #region Public Methods
147 |
148 | public static HandshakeRequest Parse (string [] headerParts)
149 | {
150 | var requestLine = headerParts [0].Split (new char [] { ' ' }, 3);
151 | if (requestLine.Length != 3)
152 | throw new ArgumentException ("Invalid request line: " + headerParts [0]);
153 |
154 | var headers = new WebHeaderCollection ();
155 | for (int i = 1; i < headerParts.Length; i++)
156 | headers.SetInternal (headerParts [i], false);
157 |
158 | return new HandshakeRequest {
159 | Headers = headers,
160 | HttpMethod = requestLine [0],
161 | ProtocolVersion = new Version (requestLine [2].Substring (5)),
162 | RawUrl = requestLine [1],
163 | RequestUri = requestLine [1].ToUri ()
164 | };
165 | }
166 |
167 | public void SetCookies (CookieCollection cookies)
168 | {
169 | if (cookies == null || cookies.Count == 0)
170 | return;
171 |
172 | var sorted = cookies.Sorted.ToArray ();
173 | var header = new StringBuilder (sorted [0].ToString (), 64);
174 | for (int i = 1; i < sorted.Length; i++)
175 | if (!sorted [i].Expired)
176 | header.AppendFormat ("; {0}", sorted [i].ToString ());
177 |
178 | Headers ["Cookie"] = header.ToString ();
179 | }
180 |
181 | public override string ToString ()
182 | {
183 | var buffer = new StringBuilder (64);
184 | buffer.AppendFormat (
185 | "{0} {1} HTTP/{2}{3}", _method, _rawUrl, ProtocolVersion, CrLf);
186 |
187 | var headers = Headers;
188 | foreach (var key in headers.AllKeys)
189 | buffer.AppendFormat ("{0}: {1}{2}", key, headers [key], CrLf);
190 |
191 | buffer.Append (CrLf);
192 |
193 | var entity = EntityBody;
194 | if (entity.Length > 0)
195 | buffer.Append (entity);
196 |
197 | return buffer.ToString ();
198 | }
199 |
200 | #endregion
201 | }
202 | }
203 |
--------------------------------------------------------------------------------
/websocket-sharp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 10.00
3 | # Visual Studio 2008
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "websocket-sharp", "websocket-sharp\websocket-sharp.csproj", "{B357BAC7-529E-4D81-A0D2-71041B19C8DE}"
5 | EndProject
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EchoClient", "EchoClient\EchoClient.csproj", "{3C35488A-1B9D-4E76-A1E4-BED3062E5517}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {3C35488A-1B9D-4E76-A1E4-BED3062E5517}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {3C35488A-1B9D-4E76-A1E4-BED3062E5517}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {3C35488A-1B9D-4E76-A1E4-BED3062E5517}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {3C35488A-1B9D-4E76-A1E4-BED3062E5517}.Release|Any CPU.Build.0 = Release|Any CPU
18 | {B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {B357BAC7-529E-4D81-A0D2-71041B19C8DE}.Release|Any CPU.Build.0 = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(MonoDevelopProperties) = preSolution
24 | Policies = $0
25 | $0.TextStylePolicy = $1
26 | $1.IndentWidth = 2
27 | $1.NoTabsAfterNonTabs = True
28 | $1.EolMarker = Unix
29 | $1.inheritsSet = VisualStudio
30 | $1.inheritsScope = text/plain
31 | $1.scope = text/x-csharp
32 | $0.CSharpFormattingPolicy = $2
33 | $2.inheritsSet = Mono
34 | $2.inheritsScope = text/x-csharp
35 | $2.scope = text/x-csharp
36 | $0.DotNetNamingPolicy = $3
37 | $3.DirectoryNamespaceAssociation = None
38 | $3.ResourceNamePolicy = FileFormatDefault
39 | $0.StandardHeader = $4
40 | $4.Text =
41 | $4.IncludeInNewFiles = True
42 | $0.NameConventionPolicy = $5
43 | $5.Rules = $6
44 | $6.NamingRule = $7
45 | $7.Name = Namespaces
46 | $7.AffectedEntity = Namespace
47 | $7.VisibilityMask = VisibilityMask
48 | $7.NamingStyle = PascalCase
49 | $7.IncludeInstanceMembers = True
50 | $7.IncludeStaticEntities = True
51 | $6.NamingRule = $8
52 | $8.Name = Types
53 | $8.AffectedEntity = Class, Struct, Enum, Delegate
54 | $8.VisibilityMask = Public
55 | $8.NamingStyle = PascalCase
56 | $8.IncludeInstanceMembers = True
57 | $8.IncludeStaticEntities = True
58 | $6.NamingRule = $9
59 | $9.Name = Interfaces
60 | $9.RequiredPrefixes = $10
61 | $10.String = I
62 | $9.AffectedEntity = Interface
63 | $9.VisibilityMask = Public
64 | $9.NamingStyle = PascalCase
65 | $9.IncludeInstanceMembers = True
66 | $9.IncludeStaticEntities = True
67 | $6.NamingRule = $11
68 | $11.Name = Attributes
69 | $11.RequiredSuffixes = $12
70 | $12.String = Attribute
71 | $11.AffectedEntity = CustomAttributes
72 | $11.VisibilityMask = Public
73 | $11.NamingStyle = PascalCase
74 | $11.IncludeInstanceMembers = True
75 | $11.IncludeStaticEntities = True
76 | $6.NamingRule = $13
77 | $13.Name = Event Arguments
78 | $13.RequiredSuffixes = $14
79 | $14.String = EventArgs
80 | $13.AffectedEntity = CustomEventArgs
81 | $13.VisibilityMask = Public
82 | $13.NamingStyle = PascalCase
83 | $13.IncludeInstanceMembers = True
84 | $13.IncludeStaticEntities = True
85 | $6.NamingRule = $15
86 | $15.Name = Exceptions
87 | $15.RequiredSuffixes = $16
88 | $16.String = Exception
89 | $15.AffectedEntity = CustomExceptions
90 | $15.VisibilityMask = VisibilityMask
91 | $15.NamingStyle = PascalCase
92 | $15.IncludeInstanceMembers = True
93 | $15.IncludeStaticEntities = True
94 | $6.NamingRule = $17
95 | $17.Name = Methods
96 | $17.AffectedEntity = Methods
97 | $17.VisibilityMask = Protected, Public
98 | $17.NamingStyle = PascalCase
99 | $17.IncludeInstanceMembers = True
100 | $17.IncludeStaticEntities = True
101 | $6.NamingRule = $18
102 | $18.Name = Static Readonly Fields
103 | $18.AffectedEntity = ReadonlyField
104 | $18.VisibilityMask = Protected, Public
105 | $18.NamingStyle = PascalCase
106 | $18.IncludeInstanceMembers = False
107 | $18.IncludeStaticEntities = True
108 | $6.NamingRule = $19
109 | $19.Name = Fields
110 | $19.AffectedEntity = Field
111 | $19.VisibilityMask = Protected, Public
112 | $19.NamingStyle = PascalCase
113 | $19.IncludeInstanceMembers = True
114 | $19.IncludeStaticEntities = True
115 | $6.NamingRule = $20
116 | $20.Name = ReadOnly Fields
117 | $20.AffectedEntity = ReadonlyField
118 | $20.VisibilityMask = Protected, Public
119 | $20.NamingStyle = PascalCase
120 | $20.IncludeInstanceMembers = True
121 | $20.IncludeStaticEntities = False
122 | $6.NamingRule = $21
123 | $21.Name = Constant Fields
124 | $21.AffectedEntity = ConstantField
125 | $21.VisibilityMask = Protected, Public
126 | $21.NamingStyle = PascalCase
127 | $21.IncludeInstanceMembers = True
128 | $21.IncludeStaticEntities = True
129 | $6.NamingRule = $22
130 | $22.Name = Properties
131 | $22.AffectedEntity = Property
132 | $22.VisibilityMask = Protected, Public
133 | $22.NamingStyle = PascalCase
134 | $22.IncludeInstanceMembers = True
135 | $22.IncludeStaticEntities = True
136 | $6.NamingRule = $23
137 | $23.Name = Events
138 | $23.AffectedEntity = Event
139 | $23.VisibilityMask = Protected, Public
140 | $23.NamingStyle = PascalCase
141 | $23.IncludeInstanceMembers = True
142 | $23.IncludeStaticEntities = True
143 | $6.NamingRule = $24
144 | $24.Name = Enum Members
145 | $24.AffectedEntity = EnumMember
146 | $24.VisibilityMask = VisibilityMask
147 | $24.NamingStyle = PascalCase
148 | $24.IncludeInstanceMembers = True
149 | $24.IncludeStaticEntities = True
150 | $6.NamingRule = $25
151 | $25.Name = Parameters
152 | $25.AffectedEntity = Parameter
153 | $25.VisibilityMask = VisibilityMask
154 | $25.NamingStyle = CamelCase
155 | $25.IncludeInstanceMembers = True
156 | $25.IncludeStaticEntities = True
157 | $6.NamingRule = $26
158 | $26.Name = Type Parameters
159 | $26.RequiredPrefixes = $27
160 | $27.String = T
161 | $26.AffectedEntity = TypeParameter
162 | $26.VisibilityMask = VisibilityMask
163 | $26.NamingStyle = PascalCase
164 | $26.IncludeInstanceMembers = True
165 | $26.IncludeStaticEntities = True
166 | $0.VersionControlPolicy = $28
167 | $28.inheritsSet = Mono
168 | $0.ChangeLogPolicy = $29
169 | $29.UpdateMode = None
170 | $29.MessageStyle = $30
171 | $30.LineAlign = 0
172 | $29.inheritsSet = Mono
173 | EndGlobalSection
174 | EndGlobal
175 |
--------------------------------------------------------------------------------
/websocket-sharp/WsStream.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * WsStream.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2010-2014 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Collections.Generic;
31 | using System.IO;
32 | using System.Net.Sockets;
33 | using System.Security.Cryptography.X509Certificates;
34 | using System.Text;
35 | using System.Threading;
36 | using WebSocketSharp.Net.Security;
37 |
38 | namespace WebSocketSharp
39 | {
40 | internal class WsStream : IDisposable
41 | {
42 | #region Private Const Fields
43 |
44 | private const int _handshakeHeadersLimitLen = 8192;
45 |
46 | #endregion
47 |
48 | #region Private Fields
49 |
50 | private object _forWrite;
51 | private Stream _innerStream;
52 | private bool _secure;
53 |
54 | #endregion
55 |
56 | #region Private Constructors
57 |
58 | private WsStream (Stream innerStream, bool secure)
59 | {
60 | _innerStream = innerStream;
61 | _secure = secure;
62 | _forWrite = new object ();
63 | }
64 |
65 | #endregion
66 |
67 | #region Internal Constructors
68 |
69 | internal WsStream (NetworkStream innerStream)
70 | : this (innerStream, false)
71 | {
72 | }
73 |
74 | internal WsStream (SslStream innerStream)
75 | : this (innerStream, true)
76 | {
77 | }
78 |
79 | #endregion
80 |
81 | #region Public Properties
82 |
83 | public bool DataAvailable {
84 | get {
85 | return _secure
86 | ? ((SslStream) _innerStream).DataAvailable
87 | : ((NetworkStream) _innerStream).DataAvailable;
88 | }
89 | }
90 |
91 | public bool IsSecure {
92 | get {
93 | return _secure;
94 | }
95 | }
96 |
97 | #endregion
98 |
99 | #region Private Methods
100 |
101 | private static byte [] readHandshakeEntityBody (Stream stream, string length)
102 | {
103 | var len = Int64.Parse (length);
104 | return len > 1024
105 | ? stream.ReadBytes (len, 1024)
106 | : stream.ReadBytes ((int) len);
107 | }
108 |
109 | private static string [] readHandshakeHeaders (Stream stream)
110 | {
111 | var buffer = new List ();
112 | var count = 0;
113 | Action add = i => {
114 | buffer.Add ((byte) i);
115 | count++;
116 | };
117 |
118 | var read = false;
119 | while (count < _handshakeHeadersLimitLen) {
120 | if (stream.ReadByte ().EqualsWith ('\r', add) &&
121 | stream.ReadByte ().EqualsWith ('\n', add) &&
122 | stream.ReadByte ().EqualsWith ('\r', add) &&
123 | stream.ReadByte ().EqualsWith ('\n', add)) {
124 | read = true;
125 | break;
126 | }
127 | }
128 |
129 | if (!read)
130 | throw new WebSocketException (
131 | "The header part of a handshake is greater than the limit length.");
132 |
133 | var crlf = "\r\n";
134 | return Encoding.UTF8.GetString (buffer.ToArray ())
135 | .Replace (crlf + " ", " ")
136 | .Replace (crlf + "\t", " ")
137 | .Split (new string [] { crlf }, StringSplitOptions.RemoveEmptyEntries);
138 | }
139 |
140 | #endregion
141 |
142 | #region Internal Methods
143 |
144 | internal static WsStream CreateClientStream (
145 | TcpClient client,
146 | bool secure,
147 | string host,
148 | System.Net.Security.RemoteCertificateValidationCallback validationCallback)
149 | {
150 | var netStream = client.GetStream ();
151 | if (secure) {
152 | if (validationCallback == null)
153 | validationCallback = (sender, certificate, chain, sslPolicyErrors) => true;
154 |
155 | var sslStream = new SslStream (netStream, false, validationCallback);
156 | sslStream.AuthenticateAsClient (host);
157 |
158 | return new WsStream (sslStream);
159 | }
160 |
161 | return new WsStream (netStream);
162 | }
163 |
164 | internal static WsStream CreateServerStream (
165 | TcpClient client, X509Certificate cert, bool secure)
166 | {
167 | var netStream = client.GetStream ();
168 | if (secure) {
169 | var sslStream = new SslStream (netStream, false);
170 | sslStream.AuthenticateAsServer (cert);
171 |
172 | return new WsStream (sslStream);
173 | }
174 |
175 | return new WsStream (netStream);
176 | }
177 |
178 | internal T ReadHandshake (
179 | Func parser, int millisecondsTimeout)
180 | where T : HandshakeBase
181 | {
182 | var timeout = false;
183 | var timer = new Timer (
184 | state => {
185 | timeout = true;
186 | _innerStream.Close ();
187 | },
188 | null,
189 | millisecondsTimeout,
190 | -1);
191 |
192 | T handshake = null;
193 | Exception exception = null;
194 | try {
195 | handshake = parser (readHandshakeHeaders (_innerStream));
196 | var contentLen = handshake.Headers ["Content-Length"];
197 | if (contentLen != null && contentLen.Length > 0)
198 | handshake.EntityBodyData = readHandshakeEntityBody (
199 | _innerStream, contentLen);
200 | }
201 | catch (Exception ex) {
202 | exception = ex;
203 | }
204 | finally {
205 | timer.Change (-1, -1);
206 | timer.Dispose ();
207 | }
208 |
209 | var reason = timeout
210 | ? "A timeout has occurred while receiving a handshake."
211 | : exception != null
212 | ? "An exception has occurred while receiving a handshake."
213 | : null;
214 |
215 | if (reason != null)
216 | throw new WebSocketException (reason, exception);
217 |
218 | return handshake;
219 | }
220 |
221 | internal bool Write (byte [] data)
222 | {
223 | lock (_forWrite) {
224 | try {
225 | _innerStream.Write (data, 0, data.Length);
226 | return true;
227 | }
228 | catch {
229 | return false;
230 | }
231 | }
232 | }
233 |
234 | #endregion
235 |
236 | #region Public Methods
237 |
238 | public void Close ()
239 | {
240 | _innerStream.Close ();
241 | }
242 |
243 | public void Dispose ()
244 | {
245 | _innerStream.Dispose ();
246 | }
247 |
248 | public WsFrame ReadFrame ()
249 | {
250 | return WsFrame.Parse (_innerStream, true);
251 | }
252 |
253 | public void ReadFrameAsync (
254 | Action completed, Action error)
255 | {
256 | WsFrame.ParseAsync (_innerStream, true, completed, error);
257 | }
258 |
259 | public HandshakeRequest ReadHandshakeRequest ()
260 | {
261 | return ReadHandshake (HandshakeRequest.Parse, 90000);
262 | }
263 |
264 | public HandshakeResponse ReadHandshakeResponse ()
265 | {
266 | return ReadHandshake (HandshakeResponse.Parse, 90000);
267 | }
268 |
269 | public bool WriteFrame (WsFrame frame)
270 | {
271 | return Write (frame.ToByteArray ());
272 | }
273 |
274 | public bool WriteHandshake (HandshakeBase handshake)
275 | {
276 | return Write (handshake.ToByteArray ());
277 | }
278 |
279 | #endregion
280 | }
281 | }
282 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/ChunkStream.cs:
--------------------------------------------------------------------------------
1 | //
2 | // ChunkStream.cs
3 | // Copied from System.Net.ChunkStream.cs
4 | //
5 | // Authors:
6 | // Gonzalo Paniagua Javier (gonzalo@ximian.com)
7 | //
8 | // (C) 2003 Ximian, Inc (http://www.ximian.com)
9 | //
10 | // Permission is hereby granted, free of charge, to any person obtaining
11 | // a copy of this software and associated documentation files (the
12 | // "Software"), to deal in the Software without restriction, including
13 | // without limitation the rights to use, copy, modify, merge, publish,
14 | // distribute, sublicense, and/or sell copies of the Software, and to
15 | // permit persons to whom the Software is furnished to do so, subject to
16 | // the following conditions:
17 | //
18 | // The above copyright notice and this permission notice shall be
19 | // included in all copies or substantial portions of the Software.
20 | //
21 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 | //
29 |
30 | using System;
31 | using System.Collections.Generic;
32 | using System.Globalization;
33 | using System.IO;
34 | using System.Net;
35 | using System.Text;
36 |
37 | namespace WebSocketSharp.Net {
38 |
39 | class ChunkStream {
40 |
41 | enum State {
42 |
43 | None,
44 | Body,
45 | BodyFinished,
46 | Trailer
47 | }
48 |
49 | class Chunk {
50 |
51 | public byte [] Bytes;
52 | public int Offset;
53 |
54 | public Chunk (byte [] chunk)
55 | {
56 | this.Bytes = chunk;
57 | }
58 |
59 | public int Read (byte [] buffer, int offset, int size)
60 | {
61 | int nread = (size > Bytes.Length - Offset) ? Bytes.Length - Offset : size;
62 | Buffer.BlockCopy (Bytes, Offset, buffer, offset, nread);
63 | Offset += nread;
64 | return nread;
65 | }
66 | }
67 |
68 | #region Private Fields
69 |
70 | int chunkRead;
71 | List chunks;
72 | int chunkSize;
73 | bool gotit;
74 | StringBuilder saved;
75 | bool sawCR;
76 | State state;
77 | int trailerState;
78 |
79 | #endregion
80 |
81 | #region Internal Fields
82 |
83 | internal WebHeaderCollection headers;
84 |
85 | #endregion
86 |
87 | #region Constructors
88 |
89 | public ChunkStream (byte [] buffer, int offset, int size, WebHeaderCollection headers)
90 | : this (headers)
91 | {
92 | Write (buffer, offset, size);
93 | }
94 |
95 | public ChunkStream (WebHeaderCollection headers)
96 | {
97 | this.headers = headers;
98 | saved = new StringBuilder ();
99 | chunks = new List ();
100 | chunkSize = -1;
101 | }
102 |
103 | #endregion
104 |
105 | #region Properties
106 |
107 | public int ChunkLeft {
108 | get { return chunkSize - chunkRead; }
109 | }
110 |
111 | public bool WantMore {
112 | get { return (chunkRead != chunkSize || chunkSize != 0 || state != State.None); }
113 | }
114 |
115 | #endregion
116 |
117 | #region Private Methods
118 |
119 | State GetChunkSize (byte [] buffer, ref int offset, int size)
120 | {
121 | char c = '\0';
122 | while (offset < size) {
123 | c = (char) buffer [offset++];
124 | if (c == '\r') {
125 | if (sawCR)
126 | ThrowProtocolViolation ("2 CR found.");
127 |
128 | sawCR = true;
129 | continue;
130 | }
131 |
132 | if (sawCR && c == '\n')
133 | break;
134 |
135 | if (c == ' ')
136 | gotit = true;
137 |
138 | if (!gotit)
139 | saved.Append (c);
140 |
141 | if (saved.Length > 20)
142 | ThrowProtocolViolation ("Chunk size too long.");
143 | }
144 |
145 | if (!sawCR || c != '\n') {
146 | if (offset < size)
147 | ThrowProtocolViolation ("Missing \\n.");
148 |
149 | try {
150 | if (saved.Length > 0) {
151 | chunkSize = Int32.Parse (RemoveChunkExtension (saved.ToString ()), NumberStyles.HexNumber);
152 | }
153 | } catch (Exception) {
154 | ThrowProtocolViolation ("Cannot parse chunk size.");
155 | }
156 |
157 | return State.None;
158 | }
159 |
160 | chunkRead = 0;
161 | try {
162 | chunkSize = Int32.Parse (RemoveChunkExtension (saved.ToString ()), NumberStyles.HexNumber);
163 | } catch (Exception) {
164 | ThrowProtocolViolation ("Cannot parse chunk size.");
165 | }
166 |
167 | if (chunkSize == 0) {
168 | trailerState = 2;
169 | return State.Trailer;
170 | }
171 |
172 | return State.Body;
173 | }
174 |
175 | void InternalWrite (byte [] buffer, ref int offset, int size)
176 | {
177 | if (state == State.None) {
178 | state = GetChunkSize (buffer, ref offset, size);
179 | if (state == State.None)
180 | return;
181 |
182 | saved.Length = 0;
183 | sawCR = false;
184 | gotit = false;
185 | }
186 |
187 | if (state == State.Body && offset < size) {
188 | state = ReadBody (buffer, ref offset, size);
189 | if (state == State.Body)
190 | return;
191 | }
192 |
193 | if (state == State.BodyFinished && offset < size) {
194 | state = ReadCRLF (buffer, ref offset, size);
195 | if (state == State.BodyFinished)
196 | return;
197 |
198 | sawCR = false;
199 | }
200 |
201 | if (state == State.Trailer && offset < size) {
202 | state = ReadTrailer (buffer, ref offset, size);
203 | if (state == State.Trailer)
204 | return;
205 |
206 | saved.Length = 0;
207 | sawCR = false;
208 | gotit = false;
209 | }
210 |
211 | if (offset < size)
212 | InternalWrite (buffer, ref offset, size);
213 | }
214 |
215 | State ReadBody (byte [] buffer, ref int offset, int size)
216 | {
217 | if (chunkSize == 0)
218 | return State.BodyFinished;
219 |
220 | int diff = size - offset;
221 | if (diff + chunkRead > chunkSize)
222 | diff = chunkSize - chunkRead;
223 |
224 | byte [] chunk = new byte [diff];
225 | Buffer.BlockCopy (buffer, offset, chunk, 0, diff);
226 | chunks.Add (new Chunk (chunk));
227 | offset += diff;
228 | chunkRead += diff;
229 | return (chunkRead == chunkSize) ? State.BodyFinished : State.Body;
230 | }
231 |
232 | State ReadCRLF (byte [] buffer, ref int offset, int size)
233 | {
234 | if (!sawCR) {
235 | if ((char) buffer [offset++] != '\r')
236 | ThrowProtocolViolation ("Expecting \\r.");
237 |
238 | sawCR = true;
239 | if (offset == size)
240 | return State.BodyFinished;
241 | }
242 |
243 | if (sawCR && (char) buffer [offset++] != '\n')
244 | ThrowProtocolViolation ("Expecting \\n.");
245 |
246 | return State.None;
247 | }
248 |
249 | int ReadFromChunks (byte [] buffer, int offset, int size)
250 | {
251 | int count = chunks.Count;
252 | int nread = 0;
253 | for (int i = 0; i < count; i++) {
254 | var chunk = chunks [i];
255 | if (chunk == null)
256 | continue;
257 |
258 | if (chunk.Offset == chunk.Bytes.Length) {
259 | chunks [i] = null;
260 | continue;
261 | }
262 |
263 | nread += chunk.Read (buffer, offset + nread, size - nread);
264 | if (nread == size)
265 | break;
266 | }
267 |
268 | return nread;
269 | }
270 |
271 | State ReadTrailer (byte [] buffer, ref int offset, int size)
272 | {
273 | char c = '\0';
274 |
275 | // short path
276 | if (trailerState == 2 && (char) buffer [offset] == '\r' && saved.Length == 0) {
277 | offset++;
278 | if (offset < size && (char) buffer [offset] == '\n') {
279 | offset++;
280 | return State.None;
281 | }
282 |
283 | offset--;
284 | }
285 |
286 | int st = trailerState;
287 | string stString = "\r\n\r";
288 | while (offset < size && st < 4) {
289 | c = (char) buffer [offset++];
290 | if ((st == 0 || st == 2) && c == '\r') {
291 | st++;
292 | continue;
293 | }
294 |
295 | if ((st == 1 || st == 3) && c == '\n') {
296 | st++;
297 | continue;
298 | }
299 |
300 | if (st > 0) {
301 | saved.Append (stString.Substring (0, saved.Length == 0? st-2: st));
302 | st = 0;
303 | if (saved.Length > 4196)
304 | ThrowProtocolViolation ("Error reading trailer (too long).");
305 | }
306 | }
307 |
308 | if (st < 4) {
309 | trailerState = st;
310 | if (offset < size)
311 | ThrowProtocolViolation ("Error reading trailer.");
312 |
313 | return State.Trailer;
314 | }
315 |
316 | var reader = new StringReader (saved.ToString ());
317 | string line;
318 | while ((line = reader.ReadLine ()) != null && line != "")
319 | headers.Add (line);
320 |
321 | return State.None;
322 | }
323 |
324 | static string RemoveChunkExtension (string input)
325 | {
326 | int idx = input.IndexOf (';');
327 | if (idx == -1)
328 | return input;
329 |
330 | return input.Substring (0, idx);
331 | }
332 |
333 | static void ThrowProtocolViolation (string message)
334 | {
335 | var we = new WebException (message, null, WebExceptionStatus.ServerProtocolViolation, null);
336 | throw we;
337 | }
338 |
339 | #endregion
340 |
341 | #region Public Methods
342 |
343 | public int Read (byte [] buffer, int offset, int size)
344 | {
345 | return ReadFromChunks (buffer, offset, size);
346 | }
347 |
348 | public void ResetBuffer ()
349 | {
350 | chunkSize = -1;
351 | chunkRead = 0;
352 | chunks.Clear ();
353 | }
354 |
355 | public void Write (byte [] buffer, int offset, int size)
356 | {
357 | InternalWrite (buffer, ref offset, size);
358 | }
359 |
360 | public void WriteAndReadBack (byte [] buffer, int offset, int size, ref int read)
361 | {
362 | if (offset + read > 0)
363 | Write (buffer, offset, offset + read);
364 |
365 | read = Read (buffer, offset, size);
366 | }
367 |
368 | #endregion
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/websocket-sharp/Logger.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * Logger.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.Diagnostics;
31 |
32 |
33 | namespace WebSocketSharp
34 | {
35 | ///
36 | /// Provides the simple logging functions.
37 | ///
38 | ///
39 | ///
40 | /// The Logger class provides some methods that output the logs associated with the each
41 | /// values.
42 | /// If the value associated with a log is less than the ,
43 | /// the log can not be outputted.
44 | ///
45 | ///
46 | /// The default output action used by the output methods outputs the log data to the standard output stream.
47 | ///
48 | ///
49 | /// If you want to run custom output action, you can replace the current output action with
50 | /// your output action by using the method.
51 | ///
52 | ///
53 | public class Logger
54 | {
55 | #region Private Fields
56 |
57 | private volatile LogLevel _level;
58 | private Action _output;
59 | private object _sync;
60 |
61 | #endregion
62 |
63 | #region Public Constructors
64 |
65 | ///
66 | /// Initializes a new instance of the class.
67 | ///
68 | ///
69 | /// This constructor initializes the current logging level with the .
70 | ///
71 | public Logger ()
72 | : this (LogLevel.ERROR, null)
73 | {
74 | }
75 |
76 | ///
77 | /// Initializes a new instance of the class
78 | /// with the specified logging .
79 | ///
80 | ///
81 | /// One of the values to initialize.
82 | ///
83 | public Logger (LogLevel level)
84 | : this (level, null)
85 | {
86 | }
87 |
88 | ///
89 | /// Initializes a new instance of the class
90 | /// with the specified logging , path to the log
91 | /// and action.
92 | ///
93 | ///
94 | /// One of the values to initialize.
95 | ///
96 | ///
97 | /// A that contains a path to the log file to initialize.
98 | ///
99 | ///
100 | /// An Action<LogData> delegate that references the method(s) to initialize.
101 | ///
102 | public Logger (LogLevel level, Action output)
103 | {
104 | _level = level;
105 | _output = output ?? defaultOutput;
106 | _sync = new object ();
107 | }
108 |
109 | #endregion
110 |
111 | #region Public Properties
112 |
113 | ///
114 | /// Gets or sets the current logging level.
115 | ///
116 | ///
117 | /// A log associated with a less than the current logging level can not be outputted.
118 | ///
119 | ///
120 | /// One of the values that indicates the current logging level.
121 | ///
122 | public LogLevel Level {
123 | get {
124 | return _level;
125 | }
126 |
127 | set {
128 | _level = value;
129 | Warn (String.Format ("The current logging level has been changed to {0}.", _level));
130 | }
131 | }
132 |
133 | #endregion
134 |
135 | #region Private Methods
136 |
137 | private static void defaultOutput (LogData data)
138 | {
139 | var log = data.ToString ();
140 | Console.WriteLine (log);
141 | }
142 |
143 | private void output (string message, LogLevel level)
144 | {
145 | if (level < _level || message == null || message.Length == 0)
146 | return;
147 |
148 | lock (_sync)
149 | {
150 | LogData data = null;
151 | try {
152 | data = new LogData (level, new StackFrame (2, true), message);
153 | _output (data);
154 | }
155 | catch (Exception ex) {
156 | data = new LogData (LogLevel.FATAL, new StackFrame (0, true), ex.Message);
157 | Console.WriteLine (data.ToString ());
158 | }
159 | }
160 | }
161 |
162 | #endregion
163 |
164 | #region Public Methods
165 |
166 | ///
167 | /// Outputs the specified as a log with the .
168 | ///
169 | ///
170 | /// If the current logging level is greater than the ,
171 | /// this method does not output as a log.
172 | ///
173 | ///
174 | /// A that contains a message to output as a log.
175 | ///
176 | public void Debug (string message)
177 | {
178 | output (message, LogLevel.DEBUG);
179 | }
180 |
181 | ///
182 | /// Outputs the specified as a log with the .
183 | ///
184 | ///
185 | /// If the current logging level is greater than the ,
186 | /// this method does not output as a log.
187 | ///
188 | ///
189 | /// A that contains a message to output as a log.
190 | ///
191 | public void Error (string message)
192 | {
193 | output (message, LogLevel.ERROR);
194 | }
195 |
196 | ///
197 | /// Outputs the specified as a log with the .
198 | ///
199 | ///
200 | /// If the current logging level is greater than the ,
201 | /// this method does not output as a log.
202 | ///
203 | ///
204 | /// A that contains a message to output as a log.
205 | ///
206 | public void Fatal (string message)
207 | {
208 | output (message, LogLevel.FATAL);
209 | }
210 |
211 | ///
212 | /// Outputs the specified as a log with the .
213 | ///
214 | ///
215 | /// If the current logging level is greater than the ,
216 | /// this method does not output as a log.
217 | ///
218 | ///
219 | /// A that contains a message to output as a log.
220 | ///
221 | public void Info (string message)
222 | {
223 | output (message, LogLevel.INFO);
224 | }
225 |
226 | ///
227 | /// Replaces the current output action with the specified action.
228 | ///
229 | ///
230 | /// If is ,
231 | /// this method replaces the current output action with the default output action.
232 | ///
233 | ///
234 | /// An Action<LogData> delegate that references the method(s) to set.
235 | ///
236 | public void SetOutput (Action output)
237 | {
238 | lock (_sync)
239 | {
240 | _output = output ?? defaultOutput;
241 | Warn ("The current output action has been replaced.");
242 | }
243 | }
244 |
245 | ///
246 | /// Outputs the specified as a log with the .
247 | ///
248 | ///
249 | /// If the current logging level is greater than the ,
250 | /// this method does not output as a log.
251 | ///
252 | ///
253 | /// A that contains a message to output as a log.
254 | ///
255 | public void Trace (string message)
256 | {
257 | output (message, LogLevel.TRACE);
258 | }
259 |
260 | ///
261 | /// Outputs the specified as a log with the .
262 | ///
263 | ///
264 | /// If the current logging level is greater than the ,
265 | /// this method does not output as a log.
266 | ///
267 | ///
268 | /// A that contains a message to output as a log.
269 | ///
270 | public void Warn (string message)
271 | {
272 | output (message, LogLevel.WARN);
273 | }
274 |
275 | #endregion
276 | }
277 | }
278 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/HttpStatusCode.cs:
--------------------------------------------------------------------------------
1 | //
2 | // HttpStatusCode.cs
3 | // Copied from System.Net.HttpStatusCode.cs
4 | //
5 | // This code was automatically generated from
6 | // ECMA CLI XML Library Specification.
7 | // Generator: libgen.xsl [1.0; (C) Sergey Chaban (serge@wildwestsoftware.com)]
8 | // Created: Wed, 5 Sep 2001 06:32:05 UTC
9 | // Source file: AllTypes.xml
10 | // URL: http://msdn.microsoft.com/net/ecma/AllTypes.xml
11 | //
12 | // Copyright (C) 2001 Ximian, Inc. (http://www.ximian.com)
13 | //
14 | // Permission is hereby granted, free of charge, to any person obtaining
15 | // a copy of this software and associated documentation files (the
16 | // "Software"), to deal in the Software without restriction, including
17 | // without limitation the rights to use, copy, modify, merge, publish,
18 | // distribute, sublicense, and/or sell copies of the Software, and to
19 | // permit persons to whom the Software is furnished to do so, subject to
20 | // the following conditions:
21 | //
22 | // The above copyright notice and this permission notice shall be
23 | // included in all copies or substantial portions of the Software.
24 | //
25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 | //
33 |
34 | namespace WebSocketSharp.Net {
35 |
36 | ///
37 | /// Contains the values of the HTTP status codes.
38 | ///
39 | ///
40 | /// The HttpStatusCode enumeration contains the values of the HTTP status codes defined in
41 | /// RFC 2616 for HTTP 1.1.
42 | ///
43 | public enum HttpStatusCode {
44 |
45 | ///
46 | /// Equivalent to status code 100. Indicates that the client should continue with its request.
47 | ///
48 | Continue = 100,
49 |
50 | ///
51 | /// Equivalent to status code 101. Indicates that the server is switching the HTTP version or protocol on the connection.
52 | ///
53 | SwitchingProtocols = 101,
54 |
55 | ///
56 | /// Equivalent to status code 200. Indicates that the client's request has succeeded.
57 | ///
58 | OK = 200,
59 |
60 | ///
61 | /// Equivalent to status code 201. Indicates that the client's request has been fulfilled
62 | /// and resulted in a new resource being created.
63 | ///
64 | Created = 201,
65 |
66 | ///
67 | /// Equivalent to status code 202. Indicates that the client's request has been accepted for processing,
68 | /// but the processing has not been completed.
69 | ///
70 | Accepted = 202,
71 |
72 | ///
73 | /// Equivalent to status code 203. Indicates that the returned metainformation is from a local or a third-party copy instead of the origin server.
74 | ///
75 | NonAuthoritativeInformation = 203,
76 |
77 | ///
78 | /// Equivalent to status code 204. Indicates that the server has fulfilled the client's request
79 | /// but does not need to return an entity-body.
80 | ///
81 | NoContent = 204,
82 |
83 | ///
84 | /// Equivalent to status code 205. Indicates that the server has fulfilled the client's request
85 | /// and the user agent should reset the document view which caused the request to be sent.
86 | ///
87 | ResetContent = 205,
88 |
89 | ///
90 | /// Equivalent to status code 206. Indicates that the server has fulfilled the partial GET request for the resource.
91 | ///
92 | PartialContent = 206,
93 |
94 | ///
95 | ///
96 | /// Equivalent to status code 300. Indicates that the requested resource corresponds to
97 | /// any one of multiple representations.
98 | ///
99 | ///
100 | /// MultipleChoices is a synonym for Ambiguous.
101 | ///
102 | ///
103 | MultipleChoices = 300,
104 |
105 | ///
106 | ///
107 | /// Equivalent to status code 300. Indicates that the requested resource corresponds to
108 | /// any one of multiple representations.
109 | ///
110 | ///
111 | /// Ambiguous is a synonym for MultipleChoices.
112 | ///
113 | ///
114 | Ambiguous = 300,
115 |
116 | ///
117 | ///
118 | /// Equivalent to status code 301. Indicates that the requested resource has been assigned a new permanent URI
119 | /// and any future references to this resource should use one of the returned URIs.
120 | ///
121 | ///
122 | /// MovedPermanently is a synonym for Moved.
123 | ///
124 | ///
125 | MovedPermanently = 301,
126 |
127 | ///
128 | ///
129 | /// Equivalent to status code 301. Indicates that the requested resource has been assigned a new permanent URI
130 | /// and any future references to this resource should use one of the returned URIs.
131 | ///
132 | ///
133 | /// Moved is a synonym for MovedPermanently.
134 | ///
135 | ///
136 | Moved = 301,
137 |
138 | ///
139 | ///
140 | /// Equivalent to status code 302. Indicates that the requested resource is located temporarily
141 | /// under a different URI.
142 | ///
143 | ///
144 | /// Found is a synonym for Redirect.
145 | ///
146 | ///
147 | Found = 302,
148 |
149 | ///
150 | ///
151 | /// Equivalent to status code 302. Indicates that the requested resource is located temporarily
152 | /// under a different URI.
153 | ///
154 | ///
155 | /// Redirect is a synonym for Found.
156 | ///
157 | ///
158 | Redirect = 302,
159 |
160 | ///
161 | ///
162 | /// Equivalent to status code 303. Indicates that the response to the request can be found
163 | /// under a different URI and should be retrieved using a GET method on that resource.
164 | ///
165 | ///
166 | /// SeeOther is a synonym for RedirectMethod.
167 | ///
168 | ///
169 | SeeOther = 303,
170 |
171 | ///
172 | ///
173 | /// Equivalent to status code 303. Indicates that the response to the request can be found
174 | /// under a different URI and should be retrieved using a GET method on that resource.
175 | ///
176 | ///
177 | /// RedirectMethod is a synonym for SeeOther.
178 | ///
179 | ///
180 | RedirectMethod = 303,
181 |
182 | ///
183 | /// Equivalent to status code 304. Indicates that the client has performed a conditional GET request
184 | /// and access is allowed, but the document has not been modified.
185 | ///
186 | NotModified = 304,
187 |
188 | ///
189 | /// Equivalent to status code 305. Indicates that the requested resource must be accessed
190 | /// through the proxy given by the Location field.
191 | ///
192 | UseProxy = 305,
193 |
194 | ///
195 | /// Equivalent to status code 306. This code was used in a previous version of the specification,
196 | /// is no longer used, and is reserved for future use.
197 | ///
198 | Unused = 306,
199 |
200 | ///
201 | ///
202 | /// Equivalent to status code 307. Indicates that the requested resource is located temporarily
203 | /// under a different URI.
204 | ///
205 | ///
206 | /// TemporaryRedirect is a synonym for RedirectKeepVerb.
207 | ///
208 | ///
209 | TemporaryRedirect = 307,
210 |
211 | ///
212 | ///
213 | /// Equivalent to status code 307. Indicates that the requested resource is located temporarily
214 | /// under a different URI.
215 | ///
216 | ///
217 | /// RedirectKeepVerb is a synonym for TemporaryRedirect.
218 | ///
219 | ///
220 | RedirectKeepVerb = 307,
221 |
222 | ///
223 | /// Equivalent to status code 400. Indicates that the client's request could not be understood
224 | /// by the server due to malformed syntax.
225 | ///
226 | BadRequest = 400,
227 |
228 | ///
229 | /// Equivalent to status code 401. Indicates that the client's request requires user authentication.
230 | ///
231 | Unauthorized = 401,
232 |
233 | ///
234 | /// Equivalent to status code 402. This code is reserved for future use.
235 | ///
236 | PaymentRequired = 402,
237 |
238 | ///
239 | /// Equivalent to status code 403. Indicates that the server understood the client's request
240 | /// but is refusing to fulfill it.
241 | ///
242 | Forbidden = 403,
243 |
244 | ///
245 | /// Equivalent to status code 404. Indicates that the server has not found anything
246 | /// matching the request URI.
247 | ///
248 | NotFound = 404,
249 |
250 | ///
251 | /// Equivalent to status code 405. Indicates that the method specified in the request line
252 | /// is not allowed for the resource identified by the request URI.
253 | ///
254 | MethodNotAllowed = 405,
255 |
256 | ///
257 | /// Equivalent to status code 406. Indicates that the server does not have the appropriate resource
258 | /// to respond to the accept headers in the client's request.
259 | ///
260 | NotAcceptable = 406,
261 |
262 | ///
263 | /// Equivalent to status code 407. Indicates that the client must first authenticate itself with the proxy.
264 | ///
265 | ProxyAuthenticationRequired = 407,
266 |
267 | ///
268 | /// Equivalent to status code 408. Indicates that the client did not produce a request
269 | /// within the time that the server was prepared to wait.
270 | ///
271 | RequestTimeout = 408,
272 |
273 | ///
274 | /// Equivalent to status code 409. Indicates that the client's request could not be completed
275 | /// due to a conflict on the server.
276 | ///
277 | Conflict = 409,
278 |
279 | ///
280 | /// Equivalent to status code 410. Indicates that the requested resource is no longer available
281 | /// at the server and no forwarding address is known.
282 | ///
283 | Gone = 410,
284 |
285 | ///
286 | /// Equivalent to status code 411. Indicates that the server refuses to accept the client's request
287 | /// without a defined Content-Length.
288 | ///
289 | LengthRequired = 411,
290 |
291 | ///
292 | /// Equivalent to status code 412. Indicates that the precondition given in one or more of the request header fields
293 | /// evaluated to false when it was tested on the server.
294 | ///
295 | PreconditionFailed = 412,
296 |
297 | ///
298 | /// Equivalent to status code 413. Indicates that the client's request entity is larger
299 | /// than the server is willing or able to process.
300 | ///
301 | RequestEntityTooLarge = 413,
302 |
303 | ///
304 | /// Equivalent to status code 414. Indicates that the request URI is longer
305 | /// than the server is willing to interpret.
306 | ///
307 | RequestUriTooLong = 414,
308 |
309 | ///
310 | /// Equivalent to status code 415. Indicates that the entity of the client's request is in a format
311 | /// not supported by the requested resource for the requested method.
312 | ///
313 | UnsupportedMediaType = 415,
314 |
315 | ///
316 | /// Equivalent to status code 416. Indicates that none of the range specifier values in a Range request header field
317 | /// overlap the current extent of the selected resource.
318 | ///
319 | RequestedRangeNotSatisfiable = 416,
320 |
321 | ///
322 | /// Equivalent to status code 417. Indicates that the expectation given in an Expect request header field
323 | /// could not be met by the server.
324 | ///
325 | ExpectationFailed = 417,
326 |
327 | ///
328 | /// Equivalent to status code 500. Indicates that the server encountered an unexpected condition
329 | /// which prevented it from fulfilling the client's request.
330 | ///
331 | InternalServerError = 500,
332 |
333 | ///
334 | /// Equivalent to status code 501. Indicates that the server does not support the functionality
335 | /// required to fulfill the client's request.
336 | ///
337 | NotImplemented = 501,
338 |
339 | ///
340 | /// Equivalent to status code 502. Indicates that a gateway or proxy server received an invalid response
341 | /// from the upstream server.
342 | ///
343 | BadGateway = 502,
344 |
345 | ///
346 | /// Equivalent to status code 503. Indicates that the server is currently unable to handle the client's request
347 | /// due to a temporary overloading or maintenance of the server.
348 | ///
349 | ServiceUnavailable = 503,
350 |
351 | ///
352 | /// Equivalent to status code 504. Indicates that a gateway or proxy server did not receive a timely response
353 | /// from the upstream server or some other auxiliary server.
354 | ///
355 | GatewayTimeout = 504,
356 |
357 | ///
358 | /// Equivalent to status code 505. Indicates that the server does not support the HTTP version
359 | /// used in the client's request.
360 | ///
361 | HttpVersionNotSupported = 505,
362 | }
363 | }
364 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | ## Welcome to websocket-sharp! ##
4 |
5 | **websocket-sharp** supports the followings:
6 |
7 | - **[WebSocket Client](#websocket-client)** and **[Server](#websocket-server)**
8 | - **[RFC 6455](#supported-websocket-specifications)**
9 | - **[Per-message Compression](#per-message-compression)** extension
10 | - **[Secure Connection](#secure-connection)**
11 | - **[HTTP Authentication](#http-authentication)**
12 | - .NET **3.5** or later (includes compatible)
13 |
14 | ## Branches ##
15 |
16 | - **[master]** for production releases.
17 | - **[hybi-00]** for older [draft-ietf-hybi-thewebsocketprotocol-00]. No longer maintained.
18 | - **[draft75]** for even more old [draft-hixie-thewebsocketprotocol-75]. No longer maintained.
19 |
20 | ## Build ##
21 |
22 | websocket-sharp is built as a single assembly, **websocket-sharp.dll**.
23 |
24 | websocket-sharp is developed with **[MonoDevelop]**. So the simple way to build is to open **websocket-sharp.sln** and run build for the websocket-sharp project with any of the build configurations (e.g. Debug) in the MonoDevelop.
25 |
26 | ## Install ##
27 |
28 | ### Self Build ###
29 |
30 | You should add **websocket-sharp.dll** (e.g. /path/to/websocket-sharp/bin/Debug/websocket-sharp.dll) built yourself to the library references of your project.
31 |
32 | If you would like to use that websocket-sharp.dll in your **[Unity]** project, you should add that dll to any folder of your project (e.g. Assets/Plugins) in the **Unity Editor**.
33 |
34 | ### NuGet Gallery ###
35 |
36 | websocket-sharp is available on the **[NuGet Gallery]**, as still a **prerelease** version.
37 |
38 | - **[NuGet Gallery: websocket-sharp]**
39 |
40 | You can add websocket-sharp to your project using the **NuGet Package Manager**, the following command in the **Package Manager Console**.
41 |
42 | PM> Install-Package WebSocketSharp -Pre
43 |
44 | ### Unity Asset Store ###
45 |
46 | websocket-sharp is available on the **Unity Asset Store**.
47 |
48 | - **[WebSocket-Sharp for Unity]**
49 |
50 | It's priced at **US$15**. I think your $15 makes this project more better and accelerated, **Thank you!**
51 |
52 | ## Usage ##
53 |
54 | ### WebSocket Client ###
55 |
56 | ```cs
57 | using System;
58 | using WebSocketSharp;
59 |
60 | namespace Example
61 | {
62 | public class Program
63 | {
64 | public static void Main (string [] args)
65 | {
66 | using (var ws = new WebSocket ("ws://dragonsnest.far/Laputa")) {
67 | ws.OnMessage += (sender, e) =>
68 | Console.WriteLine ("Laputa says: " + e.Data);
69 |
70 | ws.Connect ();
71 | ws.Send ("BALUS");
72 | Console.ReadKey (true);
73 | }
74 | }
75 | }
76 | }
77 | ```
78 |
79 | #### Step 1 ####
80 |
81 | Required namespace.
82 |
83 | ```cs
84 | using WebSocketSharp;
85 | ```
86 |
87 | The `WebSocket` class exists in the `WebSocketSharp` namespace.
88 |
89 | #### Step 2 ####
90 |
91 | Creating an instance of the `WebSocket` class with the WebSocket URL to connect.
92 |
93 | ```cs
94 | using (var ws = new WebSocket ("ws://example.com")) {
95 | ...
96 | }
97 | ```
98 |
99 | The `WebSocket` class inherits the `System.IDisposable` interface, so you can use the `using` statement.
100 |
101 | #### Step 3 ####
102 |
103 | Setting the `WebSocket` events.
104 |
105 | ##### WebSocket.OnOpen Event #####
106 |
107 | A `WebSocket.OnOpen` event occurs when the WebSocket connection has been established.
108 |
109 | ```cs
110 | ws.OnOpen += (sender, e) => {
111 | ...
112 | };
113 | ```
114 |
115 | `e` has passed as the `System.EventArgs.Empty`, so you don't use `e`.
116 |
117 | ##### WebSocket.OnMessage Event #####
118 |
119 | A `WebSocket.OnMessage` event occurs when the `WebSocket` receives a WebSocket message.
120 |
121 | ```cs
122 | ws.OnMessage += (sender, e) => {
123 | ...
124 | };
125 | ```
126 |
127 | `e` has passed as a `WebSocketSharp.MessageEventArgs`.
128 |
129 | `e.Type` property returns either `WebSocketSharp.Opcode.TEXT` or `WebSocketSharp.Opcode.BINARY` that represents the type of the received message. So by checking it, you determine which item you should use.
130 |
131 | If `e.Type` is `Opcode.TEXT`, you should use `e.Data` property (returns a `string`) that represents the received **Text** message.
132 |
133 | Or if `e.Type` is `Opcode.BINARY`, you should use `e.RawData` property (returns a `byte []`) that represents the received **Binary** message.
134 |
135 | ```cs
136 | if (e.Type == Opcode.TEXT) {
137 | // Do something with e.Data
138 | return;
139 | }
140 |
141 | if (e.Type == Opcode.BINARY) {
142 | // Do something with e.RawData
143 | return;
144 | }
145 | ```
146 |
147 | ##### WebSocket.OnError Event #####
148 |
149 | A `WebSocket.OnError` event occurs when the `WebSocket` gets an error.
150 |
151 | ```cs
152 | ws.OnError += (sender, e) => {
153 | ...
154 | };
155 | ```
156 |
157 | `e` has passed as a `WebSocketSharp.ErrorEventArgs`.
158 |
159 | `e.Message` property returns a `string` that represents the error message. So you should use it to get the error message.
160 |
161 | ##### WebSocket.OnClose Event #####
162 |
163 | A `WebSocket.OnClose` event occurs when the WebSocket connection has been closed.
164 |
165 | ```cs
166 | ws.OnClose += (sender, e) => {
167 | ...
168 | };
169 | ```
170 |
171 | `e` has passed as a `WebSocketSharp.CloseEventArgs`.
172 |
173 | `e.Code` property returns a `ushort` that represents the status code that indicates the reason for closure, and `e.Reason` property returns a `string` that represents the reason for closure. So you should use them to get the reason for closure.
174 |
175 | #### Step 4 ####
176 |
177 | Connecting to the WebSocket server.
178 |
179 | ```cs
180 | ws.Connect ();
181 | ```
182 |
183 | If you would like to connect to the server asynchronously, you should use the `WebSocket.ConnectAsync ()` method.
184 |
185 | #### Step 5 ####
186 |
187 | Sending a data to the WebSocket server.
188 |
189 | ```cs
190 | ws.Send (data);
191 | ```
192 |
193 | The `WebSocket.Send` method is overloaded.
194 |
195 | You can use the `WebSocket.Send (string)`, `WebSocket.Send (byte [])`, and `WebSocket.Send (System.IO.FileInfo)` methods to send a data.
196 |
197 | If you would like to send a data asynchronously, you should use the `WebSocket.SendAsync` method.
198 |
199 | ```cs
200 | ws.SendAsync (data, completed);
201 | ```
202 |
203 | And if you would like to do something when the send is complete, you should set `completed` to any `Action`.
204 |
205 | #### Step 6 ####
206 |
207 | Closing the WebSocket connection.
208 |
209 | ```cs
210 | ws.Close (code, reason);
211 | ```
212 |
213 | If you would like to close the connection explicitly, you should use the `WebSocket.Close` method.
214 |
215 | The `WebSocket.Close` method is overloaded.
216 |
217 | You can use the `WebSocket.Close ()`, `WebSocket.Close (ushort)`, `WebSocket.Close (WebSocketSharp.CloseStatusCode)`, `WebSocket.Close (ushort, string)`, or `WebSocket.Close (WebSocketSharp.CloseStatusCode, string)` method to close the connection.
218 |
219 | If you would like to close the connection asynchronously, you should use the `WebSocket.CloseAsync` method.
220 |
221 | ### WebSocket Server ###
222 |
223 | ```cs
224 | using System;
225 | using WebSocketSharp;
226 | using WebSocketSharp.Server;
227 |
228 | namespace Example
229 | {
230 | public class Laputa : WebSocketService
231 | {
232 | protected override void OnMessage (MessageEventArgs e)
233 | {
234 | var msg = e.Data == "BALUS"
235 | ? "I've been balused already..."
236 | : "I'm not available now.";
237 |
238 | Send (msg);
239 | }
240 | }
241 |
242 | public class Program
243 | {
244 | public static void Main (string [] args)
245 | {
246 | var wssv = new WebSocketServer ("ws://dragonsnest.far");
247 | wssv.AddWebSocketService ("/Laputa");
248 | wssv.Start ();
249 | Console.ReadKey (true);
250 | wssv.Stop ();
251 | }
252 | }
253 | }
254 | ```
255 |
256 | #### Step 1 ####
257 |
258 | Required namespace.
259 |
260 | ```cs
261 | using WebSocketSharp.Server;
262 | ```
263 |
264 | The `WebSocketServer` and `WebSocketService` classes exist in the `WebSocketSharp.Server` namespace.
265 |
266 | #### Step 2 ####
267 |
268 | Creating the class that inherits the `WebSocketService` class.
269 |
270 | For example, if you would like to provide an echo service,
271 |
272 | ```cs
273 | using System;
274 | using WebSocketSharp;
275 | using WebSocketSharp.Server;
276 |
277 | public class Echo : WebSocketService
278 | {
279 | protected override void OnMessage (MessageEventArgs e)
280 | {
281 | Send (e.Data);
282 | }
283 | }
284 | ```
285 |
286 | And if you would like to provide a chat service,
287 |
288 | ```cs
289 | using System;
290 | using WebSocketSharp;
291 | using WebSocketSharp.Server;
292 |
293 | public class Chat : WebSocketService
294 | {
295 | private string _suffix;
296 |
297 | public Chat ()
298 | : this (null)
299 | {
300 | }
301 |
302 | public Chat (string suffix)
303 | {
304 | _suffix = suffix ?? String.Empty;
305 | }
306 |
307 | protected override void OnMessage (MessageEventArgs e)
308 | {
309 | Sessions.Broadcast (e.Data + _suffix);
310 | }
311 | }
312 | ```
313 |
314 | If you override the `WebSocketService.OnMessage (MessageEventArgs)` method, that overridden method is called when the `OnMessage` event of the current session's `WebSocket` occurs.
315 |
316 | And if you override the `WebSocketService.OnOpen ()`, `WebSocketService.OnError (ErrorEventArgs)`, and `WebSocketService.OnClose (CloseEventArgs)` methods, each of them is called when each event of the current session's `WebSocket` (the `OnOpen`, `OnError`, and `OnClose` events) occurs.
317 |
318 | The `WebSocketService.Send` method sends a data to the client on the current session in the WebSocket service.
319 |
320 | If you would like to access the sessions in the WebSocket service, you should use the `WebSocketService.Sessions` property (returns a `WebSocketSharp.Server.WebSocketSessionManager`).
321 |
322 | The `WebSocketService.Sessions.Broadcast` method broadcasts a data to all clients of the WebSocket service.
323 |
324 | #### Step 3 ####
325 |
326 | Creating an instance of the `WebSocketServer` class.
327 |
328 | ```cs
329 | var wssv = new WebSocketServer (4649);
330 | wssv.AddWebSocketService ("/Echo");
331 | wssv.AddWebSocketService ("/Chat");
332 | wssv.AddWebSocketService ("/ChatWithNiceBoat", () => new Chat (" Nice boat."));
333 | ```
334 |
335 | You can add any WebSocket service to your `WebSocketServer` with the specified path to the service, using the `WebSocketServer.AddWebSocketService (string)` and `WebSocketServer.AddWebSocketService (string, Func)` methods.
336 |
337 | The type of `TWithNew` must inherit the `WebSocketService` class and must have a public parameterless constructor.
338 |
339 | The type of `T` must inherit the `WebSocketService` class.
340 |
341 | So you can use the classes created in **Step 2** to add the WebSocket service.
342 |
343 | If you create an instance of the `WebSocketServer` class without a port number, the `WebSocketServer` set the port number to **80** automatically. So it's necessary to run with root permission.
344 |
345 | $ sudo mono example2.exe
346 |
347 | #### Step 4 ####
348 |
349 | Starting the WebSocket server.
350 |
351 | ```cs
352 | wssv.Start ();
353 | ```
354 |
355 | #### Step 5 ####
356 |
357 | Stopping the WebSocket server.
358 |
359 | ```cs
360 | wssv.Stop (code, reason);
361 | ```
362 |
363 | The `WebSocketServer.Stop` method is overloaded.
364 |
365 | You can use the `WebSocketServer.Stop ()`, `WebSocketServer.Stop (ushort, string)`, or `WebSocketServer.Stop (WebSocketSharp.CloseStatusCode, string)` method to stop the server.
366 |
367 | ### HTTP Server with the WebSocket ###
368 |
369 | I modified the `System.Net.HttpListener`, `System.Net.HttpListenerContext`, and some other classes of **[Mono]** to create the HTTP server that allows to accept the WebSocket connection requests.
370 |
371 | So websocket-sharp provides the `WebSocketSharp.Server.HttpServer` class.
372 |
373 | You can add any WebSocket service to your `HttpServer` with the specified path to the service, using the `HttpServer.AddWebSocketService (string)` and `HttpServer.AddWebSocketService (string, Func)` methods.
374 |
375 | ```cs
376 | var httpsv = new HttpServer (4649);
377 | httpsv.AddWebSocketService ("/Echo");
378 | httpsv.AddWebSocketService ("/Chat");
379 | httpsv.AddWebSocketService ("/ChatWithNiceBoat", () => new Chat (" Nice boat."));
380 | ```
381 |
382 | For more information, could you see **[Example3]**?
383 |
384 | ### WebSocket Extensions ###
385 |
386 | #### Per-message Compression ####
387 |
388 | websocket-sharp supports the **[Per-message Compression][compression]** extension. (But it doesn't support with the [extension parameters].)
389 |
390 | If you would like to enable this extension as a WebSocket client, you should set like the following.
391 |
392 | ```cs
393 | ws.Compression = CompressionMethod.DEFLATE;
394 | ```
395 |
396 | And then your client sends the following header with the connection request to the server.
397 |
398 | Sec-WebSocket-Extensions: permessage-deflate
399 |
400 | If the server supports this extension, it returns the same header. And when your client receives that header, it enables this extension.
401 |
402 | ### Secure Connection ###
403 |
404 | websocket-sharp supports the **Secure Connection (SSL)**.
405 |
406 | As a **WebSocket Client**, you should create an instance of the `WebSocket` class with the **wss** scheme WebSocket URL to connect.
407 |
408 | ```cs
409 | using (var ws = new WebSocket ("wss://example.com")) {
410 | ...
411 | }
412 | ```
413 |
414 | And if you would like to set the custom validation for the server certificate, you should set the `WebSocket.ServerCertificateValidationCallback` property.
415 |
416 | ```cs
417 | ws.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => {
418 | // Do something to validate the server certificate.
419 | return true; // If the server certificate is valid.
420 | };
421 | ```
422 |
423 | If you set this property to nothing, the validation does nothing with the server certificate and returns valid.
424 |
425 | As a **WebSocket Server**, you should create an instance of the `WebSocketServer` or `HttpServer` class with some settings for the secure connection. It's like the following.
426 |
427 | ```cs
428 | var wssv = new WebSocketServer (4649, true);
429 | wssv.Certificate = new X509Certificate2 ("/path/to/cert.pfx", "password for cert.pfx");
430 | ```
431 |
432 | ### HTTP Authentication ###
433 |
434 | websocket-sharp supports the **[HTTP Authentication (Basic/Digest)][rfc2617]**.
435 |
436 | As a **WebSocket Client**, you should set a pair of user name and password for the HTTP authentication, using the `WebSocket.SetCredentials (string, string, bool)` method before connecting.
437 |
438 | ```cs
439 | ws.SetCredentials (username, password, preAuth);
440 | ```
441 |
442 | If `preAuth` is `true`, the `WebSocket` sends the Basic authentication credentials with the first connection request to the server.
443 |
444 | Or if `preAuth` is `false`, the `WebSocket` sends either the Basic or Digest authentication (determined by the unauthorized response to the first connection request) credentials with the second connection request to the server.
445 |
446 | As a **WebSocket Server**, you should set an HTTP authentication scheme, a realm, and any function to find the user credentials before starting. It's like the following.
447 |
448 | ```cs
449 | wssv.AuthenticationSchemes = AuthenticationSchemes.Basic;
450 | wssv.Realm = "WebSocket Test";
451 | wssv.UserCredentialsFinder = identity => {
452 | var expected = "nobita";
453 | return identity.Name == expected
454 | ? new NetworkCredential (expected, "password", "gunfighter") // User name, password, and roles
455 | : null; // If the user credentials not found.
456 | };
457 | ```
458 |
459 | If you would like to provide the Digest authentication, you should set like the following.
460 |
461 | ```cs
462 | wssv.AuthenticationSchemes = AuthenticationSchemes.Digest;
463 | ```
464 |
465 | ### Logging ###
466 |
467 | The `WebSocket` class includes the own logging function.
468 |
469 | You can access it with the `WebSocket.Log` property (returns a `WebSocketSharp.Logger`).
470 |
471 | So if you would like to change the current logging level (`WebSocketSharp.LogLevel.ERROR` as the default), you should set the `WebSocket.Log.Level` property to any of the `LogLevel` enum values.
472 |
473 | ```cs
474 | ws.Log.Level = LogLevel.DEBUG;
475 | ```
476 |
477 | This means a log with less than `LogLevel.DEBUG` isn't outputted.
478 |
479 | And if you would like to output a log, you should use any of the output methods. The following outputs a log with `LogLevel.DEBUG`.
480 |
481 | ```cs
482 | ws.Log.Debug ("This is a debug message.");
483 | ```
484 |
485 | The `WebSocketServer` and `HttpServer` classes include the same logging function.
486 |
487 | ## Examples ##
488 |
489 | Examples using **websocket-sharp**.
490 |
491 | ### Example ###
492 |
493 | **[Example]** connects to the **[Echo server]** with the WebSocket.
494 |
495 | ### Example1 ###
496 |
497 | **[Example1]** connects to the **[Audio Data delivery server]** with the WebSocket. (But it's only implemented the chat feature, still unfinished.)
498 |
499 | And Example1 uses **[Json.NET]**.
500 |
501 | ### Example2 ###
502 |
503 | **[Example2]** starts a WebSocket server.
504 |
505 | ### Example3 ###
506 |
507 | **[Example3]** starts an HTTP server that allows to accept the WebSocket connection requests.
508 |
509 | Could you access to [http://localhost:4649](http://localhost:4649) to do **WebSocket Echo Test** with your web browser after Example3 running?
510 |
511 | ## Supported WebSocket Specifications ##
512 |
513 | websocket-sharp supports **[RFC 6455][rfc6455]** and is based on the following WebSocket references.
514 |
515 | - **[The WebSocket Protocol][rfc6455]**
516 | - **[The WebSocket API][api]**
517 | - **[Compression Extensions for WebSocket][compression]**
518 |
519 | Thanks for translating to japanese.
520 |
521 | - **[The WebSocket Protocol 日本語訳][rfc6455_ja]**
522 | - **[The WebSocket API 日本語訳][api_ja]**
523 |
524 | ## License ##
525 |
526 | websocket-sharp is provided under **[The MIT License]**.
527 |
528 |
529 | [Audio Data delivery server]: http://agektmr.node-ninja.com:3000
530 | [Echo server]: http://www.websocket.org/echo.html
531 | [Example]: https://github.com/sta/websocket-sharp/tree/master/Example
532 | [Example1]: https://github.com/sta/websocket-sharp/tree/master/Example1
533 | [Example2]: https://github.com/sta/websocket-sharp/tree/master/Example2
534 | [Example3]: https://github.com/sta/websocket-sharp/tree/master/Example3
535 | [Json.NET]: http://james.newtonking.com/projects/json-net.aspx
536 | [Mono]: http://www.mono-project.com
537 | [MonoDevelop]: http://monodevelop.com
538 | [NuGet Gallery]: http://www.nuget.org
539 | [NuGet Gallery: websocket-sharp]: http://www.nuget.org/packages/WebSocketSharp
540 | [The MIT License]: https://raw.github.com/sta/websocket-sharp/master/LICENSE.txt
541 | [Unity]: http://unity3d.com
542 | [WebSocket-Sharp for Unity]: http://u3d.as/content/sta-blockhead/websocket-sharp-for-unity
543 | [api]: http://www.w3.org/TR/websockets
544 | [api_ja]: http://www.hcn.zaq.ne.jp/___/WEB/WebSocket-ja.html
545 | [compression]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-09
546 | [draft-hixie-thewebsocketprotocol-75]: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
547 | [draft-ietf-hybi-thewebsocketprotocol-00]: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
548 | [draft75]: https://github.com/sta/websocket-sharp/tree/draft75
549 | [extension parameters]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-09#section-8.1
550 | [hybi-00]: https://github.com/sta/websocket-sharp/tree/hybi-00
551 | [master]: https://github.com/sta/websocket-sharp/tree/master
552 | [rfc2617]: http://tools.ietf.org/html/rfc2617
553 | [rfc6455]: http://tools.ietf.org/html/rfc6455
554 | [rfc6455_ja]: http://www.hcn.zaq.ne.jp/___/WEB/RFC6455-ja.html
555 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/CookieCollection.cs:
--------------------------------------------------------------------------------
1 | //
2 | // CookieCollection.cs
3 | // Copied from System.Net.CookieCollection.cs
4 | //
5 | // Authors:
6 | // Lawrence Pit (loz@cable.a2000.nl)
7 | // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 | // Sebastien Pouliot (sebastien@ximian.com)
9 | // sta (sta.blockhead@gmail.com)
10 | //
11 | // Copyright (c) 2004,2009 Novell, Inc (http://www.novell.com)
12 | // Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
13 | //
14 | // Permission is hereby granted, free of charge, to any person obtaining
15 | // a copy of this software and associated documentation files (the
16 | // "Software"), to deal in the Software without restriction, including
17 | // without limitation the rights to use, copy, modify, merge, publish,
18 | // distribute, sublicense, and/or sell copies of the Software, and to
19 | // permit persons to whom the Software is furnished to do so, subject to
20 | // the following conditions:
21 | //
22 | // The above copyright notice and this permission notice shall be
23 | // included in all copies or substantial portions of the Software.
24 | //
25 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 | //
33 |
34 | using System;
35 | using System.Collections;
36 | using System.Collections.Generic;
37 | using System.Globalization;
38 | using System.Linq;
39 | using System.Runtime.Serialization;
40 | using System.Text;
41 |
42 | namespace WebSocketSharp.Net {
43 |
44 | ///
45 | /// Provides a collection container for instances of the class.
46 | ///
47 | [Serializable]
48 | public class CookieCollection : ICollection, IEnumerable
49 | {
50 | // not 100% identical to MS implementation
51 | sealed class CookieCollectionComparer : IComparer
52 | {
53 | public int Compare (Cookie x, Cookie y)
54 | {
55 | if (x == null || y == null)
56 | return 0;
57 |
58 | int c1 = x.Name.Length + x.Value.Length;
59 | int c2 = y.Name.Length + y.Value.Length;
60 |
61 | return (c1 - c2);
62 | }
63 | }
64 |
65 | #region Private Static Fields
66 |
67 | static CookieCollectionComparer Comparer = new CookieCollectionComparer ();
68 |
69 | #endregion
70 |
71 | #region Private Fields
72 |
73 | List list;
74 | object sync;
75 |
76 | #endregion
77 |
78 | #region Public Constructors
79 |
80 | ///
81 | /// Initializes a new instance of the class.
82 | ///
83 | public CookieCollection ()
84 | {
85 | list = new List ();
86 | }
87 |
88 | #endregion
89 |
90 | #region Internal Properties
91 |
92 | internal IList List {
93 | get { return list; }
94 | }
95 |
96 | internal IEnumerable Sorted {
97 | get {
98 | return from cookie in list
99 | orderby cookie.Version,
100 | cookie.Name,
101 | cookie.Path.Length descending
102 | select cookie;
103 | }
104 | }
105 |
106 | #endregion
107 |
108 | #region Public Properties
109 |
110 | ///
111 | /// Gets the number of cookies contained in the .
112 | ///
113 | ///
114 | /// An that indicates the number of cookies contained in the .
115 | ///
116 | public int Count {
117 | get { return list.Count; }
118 | }
119 |
120 | // LAMESPEC: So how is one supposed to create a writable CookieCollection
121 | // instance?? We simply ignore this property, as this collection is always
122 | // writable.
123 | //
124 | ///
125 | /// Gets a value indicating whether the is read-only.
126 | ///
127 | ///
128 | /// true if the is read-only; otherwise, false.
129 | /// The default is true.
130 | ///
131 | public bool IsReadOnly {
132 | get { return true; }
133 | }
134 |
135 | ///
136 | /// Gets a value indicating whether access to the is thread safe.
137 | ///
138 | ///
139 | /// true if access to the is thread safe; otherwise, false.
140 | /// The default is false.
141 | ///
142 | public bool IsSynchronized {
143 | get { return false; }
144 | }
145 |
146 | ///
147 | /// Gets the with the specified from the .
148 | ///
149 | ///
150 | /// A with the specified in the .
151 | ///
152 | ///
153 | /// An is the zero-based index of the to find.
154 | ///
155 | ///
156 | /// is less than zero or is greater than or
157 | /// equal to .
158 | ///
159 | public Cookie this [int index] {
160 | get {
161 | if (index < 0 || index >= list.Count)
162 | throw new ArgumentOutOfRangeException ("index");
163 |
164 | return list [index];
165 | }
166 | }
167 |
168 | ///
169 | /// Gets the with the specified from the .
170 | ///
171 | ///
172 | /// A with the specified in the .
173 | ///
174 | ///
175 | /// A is the name of the to find.
176 | ///
177 | ///
178 | /// is .
179 | ///
180 | public Cookie this [string name] {
181 | get {
182 | if (name == null)
183 | throw new ArgumentNullException ("name");
184 |
185 | foreach (var cookie in Sorted) {
186 | if (cookie.Name.Equals (name, StringComparison.InvariantCultureIgnoreCase))
187 | return cookie;
188 | }
189 |
190 | return null;
191 | }
192 | }
193 |
194 | ///
195 | /// Gets an object to use to synchronize access to the .
196 | ///
197 | ///
198 | /// An to use to synchronize access to the .
199 | ///
200 | public Object SyncRoot {
201 | get {
202 | if (sync == null)
203 | sync = new object ();
204 |
205 | return sync;
206 | }
207 | }
208 |
209 | #endregion
210 |
211 | #region Private Methods
212 |
213 | static CookieCollection ParseRequest (string value)
214 | {
215 | var cookies = new CookieCollection ();
216 |
217 | Cookie cookie = null;
218 | int version = 0;
219 | string [] pairs = Split(value).ToArray();
220 | for (int i = 0; i < pairs.Length; i++) {
221 | string pair = pairs [i].Trim ();
222 | if (pair.Length == 0)
223 | continue;
224 |
225 | if (pair.StartsWith ("$version", StringComparison.InvariantCultureIgnoreCase)) {
226 | version = Int32.Parse (pair.GetValueInternal ("=").Trim ('"'));
227 | }
228 | else if (pair.StartsWith ("$path", StringComparison.InvariantCultureIgnoreCase)) {
229 | if (cookie != null)
230 | cookie.Path = pair.GetValueInternal ("=");
231 | }
232 | else if (pair.StartsWith ("$domain", StringComparison.InvariantCultureIgnoreCase)) {
233 | if (cookie != null)
234 | cookie.Domain = pair.GetValueInternal ("=");
235 | }
236 | else if (pair.StartsWith ("$port", StringComparison.InvariantCultureIgnoreCase)) {
237 | var port = pair.Equals ("$port", StringComparison.InvariantCultureIgnoreCase)
238 | ? "\"\""
239 | : pair.GetValueInternal ("=");
240 |
241 | if (cookie != null)
242 | cookie.Port = port;
243 | }
244 | else {
245 | if (cookie != null)
246 | cookies.Add (cookie);
247 |
248 | string name;
249 | string val = String.Empty;
250 | int pos = pair.IndexOf ('=');
251 | if (pos == -1) {
252 | name = pair;
253 | }
254 | else if (pos == pair.Length - 1) {
255 | name = pair.Substring (0, pos).TrimEnd (' ');
256 | }
257 | else {
258 | name = pair.Substring (0, pos).TrimEnd (' ');
259 | val = pair.Substring (pos + 1).TrimStart (' ');
260 | }
261 |
262 | cookie = new Cookie (name, val);
263 | if (version != 0)
264 | cookie.Version = version;
265 | }
266 | }
267 |
268 | if (cookie != null)
269 | cookies.Add (cookie);
270 |
271 | return cookies;
272 | }
273 |
274 | static CookieCollection ParseResponse (string value)
275 | {
276 | var cookies = new CookieCollection ();
277 |
278 | Cookie cookie = null;
279 | string [] pairs = Split(value).ToArray();
280 | for (int i = 0; i < pairs.Length; i++) {
281 | string pair = pairs [i].Trim ();
282 | if (pair.Length == 0)
283 | continue;
284 |
285 | if (pair.StartsWith ("version", StringComparison.InvariantCultureIgnoreCase)) {
286 | if (cookie != null)
287 | cookie.Version = Int32.Parse (pair.GetValueInternal ("=").Trim ('"'));
288 | }
289 | else if (pair.StartsWith ("expires", StringComparison.InvariantCultureIgnoreCase)) {
290 | var buffer = new StringBuilder (pair.GetValueInternal ("="), 32);
291 | if (i < pairs.Length - 1)
292 | buffer.AppendFormat (", {0}", pairs [++i].Trim ());
293 |
294 | DateTime expires;
295 | if (!DateTime.TryParseExact (buffer.ToString (),
296 | new string [] { "ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'", "r" },
297 | CultureInfo.CreateSpecificCulture("en-US"),
298 | DateTimeStyles.AdjustToUniversal | DateTimeStyles.AssumeUniversal,
299 | out expires))
300 | expires = DateTime.Now;
301 |
302 | if (cookie != null && cookie.Expires == DateTime.MinValue)
303 | cookie.Expires = expires.ToLocalTime ();
304 | }
305 | else if (pair.StartsWith ("max-age", StringComparison.InvariantCultureIgnoreCase)) {
306 | int max = Int32.Parse (pair.GetValueInternal ("=").Trim ('"'));
307 | var expires = DateTime.Now.AddSeconds ((double) max);
308 | if (cookie != null)
309 | cookie.Expires = expires;
310 | }
311 | else if (pair.StartsWith ("path", StringComparison.InvariantCultureIgnoreCase)) {
312 | if (cookie != null)
313 | cookie.Path = pair.GetValueInternal ("=");
314 | }
315 | else if (pair.StartsWith ("domain", StringComparison.InvariantCultureIgnoreCase)) {
316 | if (cookie != null)
317 | cookie.Domain = pair.GetValueInternal ("=");
318 | }
319 | else if (pair.StartsWith ("port", StringComparison.InvariantCultureIgnoreCase)) {
320 | var port = pair.Equals ("port", StringComparison.InvariantCultureIgnoreCase)
321 | ? "\"\""
322 | : pair.GetValueInternal ("=");
323 |
324 | if (cookie != null)
325 | cookie.Port = port;
326 | }
327 | else if (pair.StartsWith ("comment", StringComparison.InvariantCultureIgnoreCase)) {
328 | if (cookie != null)
329 | cookie.Comment = pair.GetValueInternal ("=").UrlDecode ();
330 | }
331 | else if (pair.StartsWith ("commenturl", StringComparison.InvariantCultureIgnoreCase)) {
332 | if (cookie != null)
333 | cookie.CommentUri = pair.GetValueInternal ("=").Trim ('"').ToUri ();
334 | }
335 | else if (pair.StartsWith ("discard", StringComparison.InvariantCultureIgnoreCase)) {
336 | if (cookie != null)
337 | cookie.Discard = true;
338 | }
339 | else if (pair.StartsWith ("secure", StringComparison.InvariantCultureIgnoreCase)) {
340 | if (cookie != null)
341 | cookie.Secure = true;
342 | }
343 | else if (pair.StartsWith ("httponly", StringComparison.InvariantCultureIgnoreCase)) {
344 | if (cookie != null)
345 | cookie.HttpOnly = true;
346 | }
347 | else {
348 | if (cookie != null)
349 | cookies.Add (cookie);
350 |
351 | string name;
352 | string val = String.Empty;
353 | int pos = pair.IndexOf ('=');
354 | if (pos == -1) {
355 | name = pair;
356 | }
357 | else if (pos == pair.Length - 1) {
358 | name = pair.Substring (0, pos).TrimEnd (' ');
359 | }
360 | else {
361 | name = pair.Substring (0, pos).TrimEnd (' ');
362 | val = pair.Substring (pos + 1).TrimStart (' ');
363 | }
364 |
365 | cookie = new Cookie (name, val);
366 | }
367 | }
368 |
369 | if (cookie != null)
370 | cookies.Add (cookie);
371 |
372 | return cookies;
373 | }
374 |
375 | int SearchCookie (Cookie cookie)
376 | {
377 | string name = cookie.Name;
378 | string path = cookie.Path;
379 | string domain = cookie.Domain;
380 | int version = cookie.Version;
381 |
382 | for (int i = list.Count - 1; i >= 0; i--) {
383 | Cookie c = list [i];
384 | if (!c.Name.Equals (name, StringComparison.InvariantCultureIgnoreCase))
385 | continue;
386 |
387 | if (!c.Path.Equals (path, StringComparison.InvariantCulture))
388 | continue;
389 |
390 | if (!c.Domain.Equals (domain, StringComparison.InvariantCultureIgnoreCase))
391 | continue;
392 |
393 | if (c.Version != version)
394 | continue;
395 |
396 | return i;
397 | }
398 |
399 | return -1;
400 | }
401 |
402 | static IEnumerable Split (string value)
403 | {
404 | return value.SplitHeaderValue (',', ';');
405 | }
406 |
407 | #endregion
408 |
409 | #region Internal Methods
410 |
411 | internal static CookieCollection Parse (string value, bool response)
412 | {
413 | return response
414 | ? ParseResponse (value)
415 | : ParseRequest (value);
416 | }
417 |
418 | internal void SetOrRemove (Cookie cookie)
419 | {
420 | int pos = SearchCookie (cookie);
421 | if (pos == -1) {
422 | if (!cookie.Expired)
423 | list.Add (cookie);
424 | }
425 | else {
426 | if (!cookie.Expired)
427 | list [pos] = cookie;
428 | else
429 | list.RemoveAt (pos);
430 | }
431 | }
432 |
433 | internal void SetOrRemove (CookieCollection cookies)
434 | {
435 | foreach (Cookie cookie in cookies)
436 | SetOrRemove (cookie);
437 | }
438 |
439 | internal void Sort ()
440 | {
441 | if (list.Count > 0)
442 | list.Sort (Comparer);
443 | }
444 |
445 | #endregion
446 |
447 | #region Public Methods
448 |
449 | ///
450 | /// Add the specified to the .
451 | ///
452 | ///
453 | /// A to add to the .
454 | ///
455 | ///
456 | /// is .
457 | ///
458 | public void Add (Cookie cookie)
459 | {
460 | if (cookie == null)
461 | throw new ArgumentNullException ("cookie");
462 |
463 | int pos = SearchCookie (cookie);
464 | if (pos == -1)
465 | list.Add (cookie);
466 | else
467 | list [pos] = cookie;
468 | }
469 |
470 | ///
471 | /// Add the elements of the specified to the current .
472 | ///
473 | ///
474 | /// A to add to the current .
475 | ///
476 | ///
477 | /// is .
478 | ///
479 | public void Add (CookieCollection cookies)
480 | {
481 | if (cookies == null)
482 | throw new ArgumentNullException ("cookies");
483 |
484 | foreach (Cookie cookie in cookies)
485 | Add (cookie);
486 | }
487 |
488 | ///
489 | /// Copies the elements of the to the specified ,
490 | /// starting at the specified in the .
491 | ///
492 | ///
493 | /// An is the destination of the elements copied from the .
494 | ///
495 | ///
496 | /// An that indicates the zero-based index in at which copying begins.
497 | ///
498 | ///
499 | /// is .
500 | ///
501 | ///
502 | /// is less than zero.
503 | ///
504 | ///
505 | ///
506 | /// is multidimensional.
507 | ///
508 | ///
509 | /// -or-
510 | ///
511 | ///
512 | /// The number of elements in the is greater than the available space
513 | /// from index to the end of the destination .
514 | ///
515 | ///
516 | ///
517 | /// The elements in the cannot be cast automatically
518 | /// to the type of the destination .
519 | ///
520 | public void CopyTo (Array array, int index)
521 | {
522 | if (array == null)
523 | throw new ArgumentNullException ("array");
524 |
525 | if (index < 0)
526 | throw new ArgumentOutOfRangeException ("index", "Must not be less than zero.");
527 |
528 | if (array.Rank > 1)
529 | throw new ArgumentException ("Must not be multidimensional.", "array");
530 |
531 | if (array.Length - index < list.Count)
532 | throw new ArgumentException (
533 | "The number of elements in this collection is greater than the available space of the destination array.");
534 |
535 | if (!array.GetType ().GetElementType ().IsAssignableFrom (typeof (Cookie)))
536 | throw new InvalidCastException (
537 | "The elements in this collection cannot be cast automatically to the type of the destination array.");
538 |
539 | (list as IList).CopyTo (array, index);
540 | }
541 |
542 | ///
543 | /// Copies the elements of the to the specified array of ,
544 | /// starting at the specified in the .
545 | ///
546 | ///
547 | /// An array of is the destination of the elements copied from the .
548 | ///
549 | ///
550 | /// An that indicates the zero-based index in at which copying begins.
551 | ///
552 | ///
553 | /// is .
554 | ///
555 | ///
556 | /// is less than zero.
557 | ///
558 | ///
559 | /// The number of elements in the is greater than the available space
560 | /// from index to the end of the destination .
561 | ///
562 | public void CopyTo (Cookie [] array, int index)
563 | {
564 | if (array == null)
565 | throw new ArgumentNullException ("array");
566 |
567 | if (index < 0)
568 | throw new ArgumentOutOfRangeException ("index", "Must not be less than zero.");
569 |
570 | if (array.Length - index < list.Count)
571 | throw new ArgumentException (
572 | "The number of elements in this collection is greater than the available space of the destination array.");
573 |
574 | list.CopyTo (array, index);
575 | }
576 |
577 | ///
578 | /// Gets the enumerator to use to iterate through the .
579 | ///
580 | ///
581 | /// An instance of an implementation of the interface
582 | /// to use to iterate through the .
583 | ///
584 | public IEnumerator GetEnumerator ()
585 | {
586 | return list.GetEnumerator ();
587 | }
588 |
589 | #endregion
590 | }
591 | }
592 |
--------------------------------------------------------------------------------
/websocket-sharp/WsFrame.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | * WsFrame.cs
4 | *
5 | * The MIT License
6 | *
7 | * Copyright (c) 2012-2013 sta.blockhead
8 | *
9 | * Permission is hereby granted, free of charge, to any person obtaining a copy
10 | * of this software and associated documentation files (the "Software"), to deal
11 | * in the Software without restriction, including without limitation the rights
12 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | * copies of the Software, and to permit persons to whom the Software is
14 | * furnished to do so, subject to the following conditions:
15 | *
16 | * The above copyright notice and this permission notice shall be included in
17 | * all copies or substantial portions of the Software.
18 | *
19 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | * THE SOFTWARE.
26 | */
27 | #endregion
28 |
29 | using System;
30 | using System.IO;
31 | using System.Collections;
32 | using System.Collections.Generic;
33 | using System.Text;
34 |
35 | namespace WebSocketSharp
36 | {
37 | internal class WsFrame : IEnumerable
38 | {
39 | #region Internal Static Fields
40 |
41 | internal static readonly byte [] EmptyUnmaskPingData;
42 |
43 | #endregion
44 |
45 | #region Static Constructor
46 |
47 | static WsFrame ()
48 | {
49 | EmptyUnmaskPingData = CreatePingFrame (Mask.UNMASK).ToByteArray ();
50 | }
51 |
52 | #endregion
53 |
54 | #region Private Constructors
55 |
56 | private WsFrame ()
57 | {
58 | }
59 |
60 | #endregion
61 |
62 | #region Public Constructors
63 |
64 | public WsFrame (Opcode opcode, PayloadData payload)
65 | : this (opcode, Mask.MASK, payload)
66 | {
67 | }
68 |
69 | public WsFrame (Opcode opcode, Mask mask, PayloadData payload)
70 | : this (Fin.FINAL, opcode, mask, payload)
71 | {
72 | }
73 |
74 | public WsFrame (Fin fin, Opcode opcode, Mask mask, PayloadData payload)
75 | : this (fin, opcode, mask, payload, false)
76 | {
77 | }
78 |
79 | public WsFrame (
80 | Fin fin, Opcode opcode, Mask mask, PayloadData payload, bool compressed)
81 | {
82 | Fin = fin;
83 | Rsv1 = isData (opcode) && compressed ? Rsv.ON : Rsv.OFF;
84 | Rsv2 = Rsv.OFF;
85 | Rsv3 = Rsv.OFF;
86 | Opcode = opcode;
87 | Mask = mask;
88 |
89 | /* PayloadLen */
90 |
91 | var dataLen = payload.Length;
92 | var payloadLen = dataLen < 126
93 | ? (byte) dataLen
94 | : dataLen < 0x010000
95 | ? (byte) 126
96 | : (byte) 127;
97 |
98 | PayloadLen = payloadLen;
99 |
100 | /* ExtPayloadLen */
101 |
102 | ExtPayloadLen = payloadLen < 126
103 | ? new byte []{}
104 | : payloadLen == 126
105 | ? ((ushort) dataLen).ToByteArrayInternally (ByteOrder.BIG)
106 | : dataLen.ToByteArrayInternally (ByteOrder.BIG);
107 |
108 | /* MaskingKey */
109 |
110 | var masking = mask == Mask.MASK;
111 | var maskingKey = masking
112 | ? createMaskingKey ()
113 | : new byte []{};
114 |
115 | MaskingKey = maskingKey;
116 |
117 | /* PayloadData */
118 |
119 | if (masking)
120 | payload.Mask (maskingKey);
121 |
122 | PayloadData = payload;
123 | }
124 |
125 | #endregion
126 |
127 | #region Internal Properties
128 |
129 | internal bool IsBinary {
130 | get {
131 | return Opcode == Opcode.BINARY;
132 | }
133 | }
134 |
135 | internal bool IsClose {
136 | get {
137 | return Opcode == Opcode.CLOSE;
138 | }
139 | }
140 |
141 | internal bool IsCompressed {
142 | get {
143 | return Rsv1 == Rsv.ON;
144 | }
145 | }
146 |
147 | internal bool IsContinuation {
148 | get {
149 | return Opcode == Opcode.CONT;
150 | }
151 | }
152 |
153 | internal bool IsControl {
154 | get {
155 | var opcode = Opcode;
156 | return opcode == Opcode.CLOSE || opcode == Opcode.PING || opcode == Opcode.PONG;
157 | }
158 | }
159 |
160 | internal bool IsData {
161 | get {
162 | var opcode = Opcode;
163 | return opcode == Opcode.BINARY || opcode == Opcode.TEXT;
164 | }
165 | }
166 |
167 | internal bool IsFinal {
168 | get {
169 | return Fin == Fin.FINAL;
170 | }
171 | }
172 |
173 | internal bool IsFragmented {
174 | get {
175 | return Fin == Fin.MORE || Opcode == Opcode.CONT;
176 | }
177 | }
178 |
179 | internal bool IsMasked {
180 | get {
181 | return Mask == Mask.MASK;
182 | }
183 | }
184 |
185 | internal bool IsPerMessageCompressed {
186 | get {
187 | var opcode = Opcode;
188 | return (opcode == Opcode.BINARY || opcode == Opcode.TEXT) && Rsv1 == Rsv.ON;
189 | }
190 | }
191 |
192 | internal bool IsPing {
193 | get {
194 | return Opcode == Opcode.PING;
195 | }
196 | }
197 |
198 | internal bool IsPong {
199 | get {
200 | return Opcode == Opcode.PONG;
201 | }
202 | }
203 |
204 | internal bool IsText {
205 | get {
206 | return Opcode == Opcode.TEXT;
207 | }
208 | }
209 |
210 | internal ulong Length {
211 | get {
212 | return 2 + (ulong) (ExtPayloadLen.Length + MaskingKey.Length) + PayloadData.Length;
213 | }
214 | }
215 |
216 | #endregion
217 |
218 | #region Public Properties
219 |
220 | public Fin Fin { get; private set; }
221 |
222 | public Rsv Rsv1 { get; private set; }
223 |
224 | public Rsv Rsv2 { get; private set; }
225 |
226 | public Rsv Rsv3 { get; private set; }
227 |
228 | public Opcode Opcode { get; private set; }
229 |
230 | public Mask Mask { get; private set; }
231 |
232 | public byte PayloadLen { get; private set; }
233 |
234 | public byte [] ExtPayloadLen { get; private set; }
235 |
236 | public byte [] MaskingKey { get; private set; }
237 |
238 | public PayloadData PayloadData { get; private set; }
239 |
240 | #endregion
241 |
242 | #region Private Methods
243 |
244 | private static byte [] createMaskingKey ()
245 | {
246 | var key = new byte [4];
247 | var rand = new Random ();
248 | rand.NextBytes (key);
249 |
250 | return key;
251 | }
252 |
253 | private static string dump (WsFrame frame)
254 | {
255 | var len = frame.Length;
256 | var count = (long) (len / 4);
257 | var rem = (int) (len % 4);
258 |
259 | int countDigit;
260 | string countFmt;
261 | if (count < 10000)
262 | {
263 | countDigit = 4;
264 | countFmt = "{0,4}";
265 | }
266 | else if (count < 0x010000)
267 | {
268 | countDigit = 4;
269 | countFmt = "{0,4:X}";
270 | }
271 | else if (count < 0x0100000000)
272 | {
273 | countDigit = 8;
274 | countFmt = "{0,8:X}";
275 | }
276 | else
277 | {
278 | countDigit = 16;
279 | countFmt = "{0,16:X}";
280 | }
281 |
282 | var spFmt = String.Format ("{{0,{0}}}", countDigit);
283 | var headerFmt = String.Format (
284 | @"{0} 01234567 89ABCDEF 01234567 89ABCDEF
285 | {0}+--------+--------+--------+--------+\n", spFmt);
286 | var footerFmt = String.Format ("{0}+--------+--------+--------+--------+", spFmt);
287 |
288 | var buffer = new StringBuilder (64);
289 | Func> linePrinter = () =>
290 | {
291 | long lineCount = 0;
292 | var lineFmt = String.Format ("{0}|{{1,8}} {{2,8}} {{3,8}} {{4,8}}|\n", countFmt);
293 | return (arg1, arg2, arg3, arg4) =>
294 | buffer.AppendFormat (lineFmt, ++lineCount, arg1, arg2, arg3, arg4);
295 | };
296 | var printLine = linePrinter ();
297 |
298 | buffer.AppendFormat (headerFmt, String.Empty);
299 |
300 | var frameAsBytes = frame.ToByteArray ();
301 | int i, j;
302 | for (i = 0; i <= count; i++)
303 | {
304 | j = i * 4;
305 | if (i < count)
306 | printLine (
307 | Convert.ToString (frameAsBytes [j], 2).PadLeft (8, '0'),
308 | Convert.ToString (frameAsBytes [j + 1], 2).PadLeft (8, '0'),
309 | Convert.ToString (frameAsBytes [j + 2], 2).PadLeft (8, '0'),
310 | Convert.ToString (frameAsBytes [j + 3], 2).PadLeft (8, '0'));
311 | else if (rem > 0)
312 | printLine (
313 | Convert.ToString (frameAsBytes [j], 2).PadLeft (8, '0'),
314 | rem >= 2 ? Convert.ToString (frameAsBytes [j + 1], 2).PadLeft (8, '0') : String.Empty,
315 | rem == 3 ? Convert.ToString (frameAsBytes [j + 2], 2).PadLeft (8, '0') : String.Empty,
316 | String.Empty);
317 | }
318 |
319 | buffer.AppendFormat (footerFmt, String.Empty);
320 | return buffer.ToString ();
321 | }
322 |
323 | private static bool isBinary (Opcode opcode)
324 | {
325 | return opcode == Opcode.BINARY;
326 | }
327 |
328 | private static bool isClose (Opcode opcode)
329 | {
330 | return opcode == Opcode.CLOSE;
331 | }
332 |
333 | private static bool isContinuation (Opcode opcode)
334 | {
335 | return opcode == Opcode.CONT;
336 | }
337 |
338 | private static bool isControl (Opcode opcode)
339 | {
340 | return opcode == Opcode.CLOSE || opcode == Opcode.PING || opcode == Opcode.PONG;
341 | }
342 |
343 | private static bool isData (Opcode opcode)
344 | {
345 | return opcode == Opcode.TEXT || opcode == Opcode.BINARY;
346 | }
347 |
348 | private static bool isFinal (Fin fin)
349 | {
350 | return fin == Fin.FINAL;
351 | }
352 |
353 | private static bool isMasked (Mask mask)
354 | {
355 | return mask == Mask.MASK;
356 | }
357 |
358 | private static bool isPing (Opcode opcode)
359 | {
360 | return opcode == Opcode.PING;
361 | }
362 |
363 | private static bool isPong (Opcode opcode)
364 | {
365 | return opcode == Opcode.PONG;
366 | }
367 |
368 | private static bool isText (Opcode opcode)
369 | {
370 | return opcode == Opcode.TEXT;
371 | }
372 |
373 | private static WsFrame parse (byte [] header, Stream stream, bool unmask)
374 | {
375 | /* Header */
376 |
377 | // FIN
378 | var fin = (header [0] & 0x80) == 0x80 ? Fin.FINAL : Fin.MORE;
379 | // RSV1
380 | var rsv1 = (header [0] & 0x40) == 0x40 ? Rsv.ON : Rsv.OFF;
381 | // RSV2
382 | var rsv2 = (header [0] & 0x20) == 0x20 ? Rsv.ON : Rsv.OFF;
383 | // RSV3
384 | var rsv3 = (header [0] & 0x10) == 0x10 ? Rsv.ON : Rsv.OFF;
385 | // Opcode
386 | var opcode = (Opcode) (header [0] & 0x0f);
387 | // MASK
388 | var mask = (header [1] & 0x80) == 0x80 ? Mask.MASK : Mask.UNMASK;
389 | // Payload len
390 | var payloadLen = (byte) (header [1] & 0x7f);
391 |
392 | // Check if correct frame.
393 | var incorrect = isControl (opcode) && fin == Fin.MORE
394 | ? "A control frame is fragmented."
395 | : !isData (opcode) && rsv1 == Rsv.ON
396 | ? "A non data frame is compressed."
397 | : null;
398 |
399 | if (incorrect != null)
400 | throw new WebSocketException (CloseStatusCode.INCORRECT_DATA, incorrect);
401 |
402 | // Check if consistent frame.
403 | if (isControl (opcode) && payloadLen > 125)
404 | throw new WebSocketException (
405 | CloseStatusCode.INCONSISTENT_DATA,
406 | "The payload data length of a control frame is greater than 125 bytes.");
407 |
408 | var frame = new WsFrame {
409 | Fin = fin,
410 | Rsv1 = rsv1,
411 | Rsv2 = rsv2,
412 | Rsv3 = rsv3,
413 | Opcode = opcode,
414 | Mask = mask,
415 | PayloadLen = payloadLen
416 | };
417 |
418 | /* Extended Payload Length */
419 |
420 | var extLen = payloadLen < 126
421 | ? 0
422 | : payloadLen == 126
423 | ? 2
424 | : 8;
425 |
426 | var extPayloadLen = extLen > 0
427 | ? stream.ReadBytes (extLen)
428 | : new byte []{};
429 |
430 | if (extLen > 0 && extPayloadLen.Length != extLen)
431 | throw new WebSocketException (
432 | "The 'Extended Payload Length' of a frame cannot be read from the data source.");
433 |
434 | frame.ExtPayloadLen = extPayloadLen;
435 |
436 | /* Masking Key */
437 |
438 | var masked = mask == Mask.MASK;
439 | var maskingKey = masked
440 | ? stream.ReadBytes (4)
441 | : new byte []{};
442 |
443 | if (masked && maskingKey.Length != 4)
444 | throw new WebSocketException (
445 | "The 'Masking Key' of a frame cannot be read from the data source.");
446 |
447 | frame.MaskingKey = maskingKey;
448 |
449 | /* Payload Data */
450 |
451 | ulong dataLen = payloadLen < 126
452 | ? payloadLen
453 | : payloadLen == 126
454 | ? extPayloadLen.ToUInt16 (ByteOrder.BIG)
455 | : extPayloadLen.ToUInt64 (ByteOrder.BIG);
456 |
457 | byte [] data = null;
458 | if (dataLen > 0)
459 | {
460 | // Check if allowable payload data length.
461 | if (payloadLen > 126 && dataLen > PayloadData.MaxLength)
462 | throw new WebSocketException (
463 | CloseStatusCode.TOO_BIG, "The 'Payload Data' length is greater than the allowable length.");
464 |
465 | data = payloadLen > 126
466 | ? stream.ReadBytes ((long) dataLen, 1024)
467 | : stream.ReadBytes ((int) dataLen);
468 |
469 | if (data.LongLength != (long) dataLen)
470 | throw new WebSocketException (
471 | "The 'Payload Data' of a frame cannot be read from the data source.");
472 | }
473 | else
474 | {
475 | data = new byte []{};
476 | }
477 |
478 | var payload = new PayloadData (data, masked);
479 | if (masked && unmask)
480 | {
481 | payload.Mask (maskingKey);
482 | frame.Mask = Mask.UNMASK;
483 | frame.MaskingKey = new byte []{};
484 | }
485 |
486 | frame.PayloadData = payload;
487 | return frame;
488 | }
489 |
490 | private static string print (WsFrame frame)
491 | {
492 | /* Opcode */
493 |
494 | var opcode = frame.Opcode.ToString ();
495 |
496 | /* Payload Len */
497 |
498 | var payloadLen = frame.PayloadLen;
499 |
500 | /* Extended Payload Len */
501 |
502 | var ext = frame.ExtPayloadLen;
503 | var size = ext.Length;
504 | var extLen = size == 2
505 | ? ext.ToUInt16 (ByteOrder.BIG).ToString ()
506 | : size == 8
507 | ? ext.ToUInt64 (ByteOrder.BIG).ToString ()
508 | : String.Empty;
509 |
510 | /* Masking Key */
511 |
512 | var masked = frame.IsMasked;
513 | var key = masked
514 | ? BitConverter.ToString (frame.MaskingKey)
515 | : String.Empty;
516 |
517 | /* Payload Data */
518 |
519 | var data = payloadLen == 0
520 | ? String.Empty
521 | : size > 0
522 | ? String.Format ("A {0} data with {1} bytes.", opcode.ToLower (), extLen)
523 | : masked || frame.IsFragmented || frame.IsBinary || frame.IsClose
524 | ? BitConverter.ToString (frame.PayloadData.ToByteArray ())
525 | : Encoding.UTF8.GetString (frame.PayloadData.ApplicationData);
526 |
527 | var format =
528 | @" FIN: {0}
529 | RSV1: {1}
530 | RSV2: {2}
531 | RSV3: {3}
532 | Opcode: {4}
533 | MASK: {5}
534 | Payload Len: {6}
535 | Extended Payload Len: {7}
536 | Masking Key: {8}
537 | Payload Data: {9}";
538 |
539 | return String.Format (
540 | format,
541 | frame.Fin,
542 | frame.Rsv1,
543 | frame.Rsv2,
544 | frame.Rsv3,
545 | opcode,
546 | frame.Mask,
547 | payloadLen,
548 | extLen,
549 | key,
550 | data);
551 | }
552 |
553 | #endregion
554 |
555 | #region Internal Methods
556 |
557 | internal static WsFrame CreateCloseFrame (Mask mask, PayloadData payload)
558 | {
559 | return new WsFrame (Opcode.CLOSE, mask, payload);
560 | }
561 |
562 | internal static WsFrame CreatePongFrame (Mask mask, PayloadData payload)
563 | {
564 | return new WsFrame (Opcode.PONG, mask, payload);
565 | }
566 |
567 | #endregion
568 |
569 | #region Public Methods
570 |
571 | public static WsFrame CreateCloseFrame (Mask mask, byte [] data)
572 | {
573 | return new WsFrame (Opcode.CLOSE, mask, new PayloadData (data));
574 | }
575 |
576 | public static WsFrame CreateCloseFrame (Mask mask, CloseStatusCode code, string reason)
577 | {
578 | return new WsFrame (Opcode.CLOSE, mask, new PayloadData (((ushort) code).Append (reason)));
579 | }
580 |
581 | public static WsFrame CreateFrame (
582 | Fin fin, Opcode opcode, Mask mask, byte [] data, bool compressed)
583 | {
584 | return new WsFrame (fin, opcode, mask, new PayloadData (data), compressed);
585 | }
586 |
587 | public static WsFrame CreatePingFrame (Mask mask)
588 | {
589 | return new WsFrame (Opcode.PING, mask, new PayloadData ());
590 | }
591 |
592 | public static WsFrame CreatePingFrame (Mask mask, byte [] data)
593 | {
594 | return new WsFrame (Opcode.PING, mask, new PayloadData (data));
595 | }
596 |
597 | public IEnumerator GetEnumerator ()
598 | {
599 | foreach (byte b in ToByteArray ())
600 | yield return b;
601 | }
602 |
603 | public static WsFrame Parse (byte [] src)
604 | {
605 | return Parse (src, true);
606 | }
607 |
608 | public static WsFrame Parse (Stream stream)
609 | {
610 | return Parse (stream, true);
611 | }
612 |
613 | public static WsFrame Parse (byte [] src, bool unmask)
614 | {
615 | using (var stream = new MemoryStream (src))
616 | {
617 | return Parse (stream, unmask);
618 | }
619 | }
620 |
621 | public static WsFrame Parse (Stream stream, bool unmask)
622 | {
623 | var header = stream.ReadBytes (2);
624 | if (header.Length != 2)
625 | throw new WebSocketException (
626 | "The header part of a frame cannot be read from the data source.");
627 |
628 | return parse (header, stream, unmask);
629 | }
630 |
631 | public static void ParseAsync (Stream stream, Action completed)
632 | {
633 | ParseAsync (stream, true, completed, null);
634 | }
635 |
636 | public static void ParseAsync (Stream stream, Action completed, Action error)
637 | {
638 | ParseAsync (stream, true, completed, error);
639 | }
640 |
641 | public static void ParseAsync (
642 | Stream stream, bool unmask, Action completed, Action error)
643 | {
644 | stream.ReadBytesAsync (
645 | 2,
646 | header =>
647 | {
648 | if (header.Length != 2)
649 | throw new WebSocketException (
650 | "The header part of a frame cannot be read from the data source.");
651 |
652 | var frame = parse (header, stream, unmask);
653 | if (completed != null)
654 | completed (frame);
655 | },
656 | error);
657 | }
658 |
659 | public void Print (bool dumped)
660 | {
661 | Console.WriteLine (dumped ? dump (this) : print (this));
662 | }
663 |
664 | public string PrintToString (bool dumped)
665 | {
666 | return dumped ? dump (this) : print (this);
667 | }
668 |
669 | public byte [] ToByteArray()
670 | {
671 | using (var buffer = new MemoryStream ())
672 | {
673 | int header = (int) Fin;
674 | header = (header << 1) + (int) Rsv1;
675 | header = (header << 1) + (int) Rsv2;
676 | header = (header << 1) + (int) Rsv3;
677 | header = (header << 4) + (int) Opcode;
678 | header = (header << 1) + (int) Mask;
679 | header = (header << 7) + (int) PayloadLen;
680 | buffer.Write (((ushort) header).ToByteArrayInternally (ByteOrder.BIG), 0, 2);
681 |
682 | if (PayloadLen > 125)
683 | buffer.Write (ExtPayloadLen, 0, ExtPayloadLen.Length);
684 |
685 | if (Mask == Mask.MASK)
686 | buffer.Write (MaskingKey, 0, MaskingKey.Length);
687 |
688 | if (PayloadLen > 0)
689 | {
690 | var payload = PayloadData.ToByteArray ();
691 | if (PayloadLen < 127)
692 | buffer.Write (payload, 0, payload.Length);
693 | else
694 | buffer.WriteBytes (payload);
695 | }
696 |
697 | buffer.Close ();
698 | return buffer.ToArray ();
699 | }
700 | }
701 |
702 | public override string ToString ()
703 | {
704 | return BitConverter.ToString (ToByteArray ());
705 | }
706 |
707 | #endregion
708 |
709 | #region Explicitly Implemented Interface Members
710 |
711 | IEnumerator IEnumerable.GetEnumerator ()
712 | {
713 | return GetEnumerator ();
714 | }
715 |
716 | #endregion
717 | }
718 | }
719 |
--------------------------------------------------------------------------------
/websocket-sharp/Net/Cookie.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Cookie.cs
3 | // Copied from System.Net.Cookie.cs
4 | //
5 | // Authors:
6 | // Lawrence Pit (loz@cable.a2000.nl)
7 | // Gonzalo Paniagua Javier (gonzalo@ximian.com)
8 | // Daniel Nauck (dna@mono-project.de)
9 | // Sebastien Pouliot (sebastien@ximian.com)
10 | // sta (sta.blockhead@gmail.com)
11 | //
12 | // Copyright (c) 2004,2009 Novell, Inc (http://www.novell.com)
13 | // Copyright (c) 2012-2013 sta.blockhead (sta.blockhead@gmail.com)
14 | //
15 | // Permission is hereby granted, free of charge, to any person obtaining
16 | // a copy of this software and associated documentation files (the
17 | // "Software"), to deal in the Software without restriction, including
18 | // without limitation the rights to use, copy, modify, merge, publish,
19 | // distribute, sublicense, and/or sell copies of the Software, and to
20 | // permit persons to whom the Software is furnished to do so, subject to
21 | // the following conditions:
22 | //
23 | // The above copyright notice and this permission notice shall be
24 | // included in all copies or substantial portions of the Software.
25 | //
26 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 | // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 | // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 | // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 | // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 | //
34 |
35 | using System;
36 | using System.Text;
37 | using System.Globalization;
38 | using System.Collections;
39 |
40 | namespace WebSocketSharp.Net
41 | {
42 | ///
43 | /// Provides a set of properties and methods used to manage an HTTP Cookie.
44 | ///
45 | ///
46 | ///
47 | /// The Cookie class supports the following cookie formats:
48 | /// Netscape specification,
49 | /// RFC 2109 and
50 | /// RFC 2965.
51 | ///
52 | ///
53 | /// The Cookie class cannot be inherited.
54 | ///
55 | ///
56 | [Serializable]
57 | public sealed class Cookie
58 | {
59 | #region Static Private Fields
60 |
61 | static char [] reservedCharsForName = new char [] {' ', '=', ';', ',', '\n', '\r', '\t'};
62 | static char [] reservedCharsForValue = new char [] {';', ','};
63 |
64 | #endregion
65 |
66 | #region Private Fields
67 |
68 | string comment;
69 | Uri commentUri;
70 | bool discard;
71 | string domain;
72 | DateTime expires;
73 | bool httpOnly;
74 | string name;
75 | string path;
76 | string port;
77 | int [] ports;
78 | bool secure;
79 | DateTime timestamp;
80 | string val;
81 | int version;
82 |
83 | #endregion
84 |
85 | #region Public Constructors
86 |
87 | ///
88 | /// Initializes a new instance of the class.
89 | ///
90 | public Cookie ()
91 | {
92 | comment = String.Empty;
93 | domain = String.Empty;
94 | expires = DateTime.MinValue;
95 | name = String.Empty;
96 | path = String.Empty;
97 | port = String.Empty;
98 | ports = new int [] {};
99 | timestamp = DateTime.Now;
100 | val = String.Empty;
101 | version = 0;
102 | }
103 |
104 | ///
105 | /// Initializes a new instance of the class
106 | /// with the specified and .
107 | ///
108 | ///
109 | /// A that contains the Name of the cookie.
110 | ///
111 | ///
112 | /// A that contains the Value of the cookie.
113 | ///
114 | ///
115 | ///
116 | /// is or .
117 | ///
118 | ///
119 | /// - or -
120 | ///
121 | ///
122 | /// contains an invalid character.
123 | ///
124 | ///
125 | /// - or -
126 | ///
127 | ///
128 | /// is .
129 | ///
130 | ///
131 | /// - or -
132 | ///
133 | ///
134 | /// contains a string not enclosed in double quotes
135 | /// that contains an invalid character.
136 | ///
137 | ///
138 | public Cookie (string name, string value)
139 | : this ()
140 | {
141 | Name = name;
142 | Value = value;
143 | }
144 |
145 | ///
146 | /// Initializes a new instance of the class
147 | /// with the specified , and .
148 | ///
149 | ///
150 | /// A that contains the Name of the cookie.
151 | ///
152 | ///
153 | /// A that contains the Value of the cookie.
154 | ///
155 | ///
156 | /// A that contains the value of the Path attribute of the cookie.
157 | ///
158 | ///
159 | ///
160 | /// is or .
161 | ///
162 | ///
163 | /// - or -
164 | ///
165 | ///
166 | /// contains an invalid character.
167 | ///
168 | ///
169 | /// - or -
170 | ///
171 | ///
172 | /// is .
173 | ///
174 | ///
175 | /// - or -
176 | ///
177 | ///
178 | /// contains a string not enclosed in double quotes
179 | /// that contains an invalid character.
180 | ///
181 | ///
182 | public Cookie (string name, string value, string path)
183 | : this (name, value)
184 | {
185 | Path = path;
186 | }
187 |
188 | ///
189 | /// Initializes a new instance of the class
190 | /// with the specified , ,
191 | /// and .
192 | ///
193 | ///
194 | /// A that contains the Name of the cookie.
195 | ///
196 | ///
197 | /// A that contains the Value of the cookie.
198 | ///
199 | ///
200 | /// A that contains the value of the Path attribute of the cookie.
201 | ///
202 | ///
203 | /// A that contains the value of the Domain attribute of the cookie.
204 | ///
205 | ///
206 | ///
207 | /// is or .
208 | ///
209 | ///
210 | /// - or -
211 | ///
212 | ///
213 | /// contains an invalid character.
214 | ///
215 | ///
216 | /// - or -
217 | ///
218 | ///
219 | /// is .
220 | ///
221 | ///
222 | /// - or -
223 | ///
224 | ///
225 | /// contains a string not enclosed in double quotes
226 | /// that contains an invalid character.
227 | ///
228 | ///
229 | public Cookie (string name, string value, string path, string domain)
230 | : this (name, value, path)
231 | {
232 | Domain = domain;
233 | }
234 |
235 | #endregion
236 |
237 | #region Internal Properties
238 |
239 | internal bool ExactDomain { get; set; }
240 |
241 | internal int MaxAge {
242 | get {
243 | if (expires == DateTime.MinValue || Expired)
244 | return 0;
245 |
246 | var tmp = expires.Kind == DateTimeKind.Local
247 | ? expires
248 | : expires.ToLocalTime ();
249 |
250 | var span = tmp - DateTime.Now;
251 | return span <= TimeSpan.Zero
252 | ? 0
253 | : (int) span.TotalSeconds;
254 | }
255 | }
256 |
257 | internal int [] Ports {
258 | get { return ports; }
259 | }
260 |
261 | #endregion
262 |
263 | #region Public Properties
264 |
265 | ///
266 | /// Gets or sets the value of the Comment attribute of the cookie.
267 | ///
268 | ///
269 | /// A that contains a comment to document intended use of the cookie.
270 | ///
271 | public string Comment {
272 | get { return comment; }
273 | set { comment = value ?? String.Empty; }
274 | }
275 |
276 | ///
277 | /// Gets or sets the value of the CommentURL attribute of the cookie.
278 | ///
279 | ///
280 | /// A that contains a URI that provides the comment
281 | /// to document intended use of the cookie.
282 | ///
283 | public Uri CommentUri {
284 | get { return commentUri; }
285 | set { commentUri = value; }
286 | }
287 |
288 | ///
289 | /// Gets or sets a value indicating whether the client discards the cookie unconditionally
290 | /// when the client terminates.
291 | ///
292 | ///
293 | /// true if the client discards the cookie unconditionally when the client terminates;
294 | /// otherwise, false. The default is false.
295 | ///
296 | public bool Discard {
297 | get { return discard; }
298 | set { discard = value; }
299 | }
300 |
301 | ///
302 | /// Gets or sets the value of the Domain attribute of the cookie.
303 | ///
304 | ///
305 | /// A that contains a URI for which the cookie is valid.
306 | ///
307 | public string Domain {
308 | get { return domain; }
309 | set {
310 | if (value.IsNullOrEmpty ()) {
311 | domain = String.Empty;
312 | ExactDomain = true;
313 | } else {
314 | domain = value;
315 | ExactDomain = value [0] != '.';
316 | }
317 | }
318 | }
319 |
320 | ///
321 | /// Gets or sets a value indicating whether the cookie has expired.
322 | ///
323 | ///
324 | /// true if the cookie has expired; otherwise, false. The default is false.
325 | ///
326 | public bool Expired {
327 | get {
328 | return expires <= DateTime.Now &&
329 | expires != DateTime.MinValue;
330 | }
331 | set {
332 | expires = value
333 | ? DateTime.Now
334 | : DateTime.MinValue;
335 | }
336 | }
337 |
338 | ///
339 | /// Gets or sets the value of the Expires attribute of the cookie.
340 | ///
341 | ///
342 | /// A that contains the date and time at which the cookie expires.
343 | /// The default is .
344 | ///
345 | public DateTime Expires {
346 | get { return expires; }
347 | set { expires = value; }
348 | }
349 |
350 | ///
351 | /// Gets or sets a value indicating non-HTTP APIs can access the cookie.
352 | ///
353 | ///
354 | /// true if non-HTTP APIs can not access the cookie; otherwise, false.
355 | ///
356 | public bool HttpOnly {
357 | get { return httpOnly; }
358 | set { httpOnly = value; }
359 | }
360 |
361 | ///
362 | /// Gets or sets the Name of the cookie.
363 | ///
364 | ///
365 | /// A that contains the Name of the cookie.
366 | ///
367 | ///
368 | ///
369 | /// The value specified for a set operation is or .
370 | ///
371 | ///
372 | /// - or -
373 | ///
374 | ///
375 | /// The value specified for a set operation contains an invalid character.
376 | ///
377 | ///
378 | public string Name {
379 | get { return name; }
380 | set {
381 | string msg;
382 | if (!CanSetName (value, out msg))
383 | throw new CookieException (msg);
384 |
385 | name = value;
386 | }
387 | }
388 |
389 | ///
390 | /// Gets or sets the value of the Path attribute of the cookie.
391 | ///
392 | ///
393 | /// A that contains a subset of URI on the origin server
394 | /// to which the cookie applies.
395 | ///
396 | public string Path {
397 | get { return path; }
398 | set { path = value ?? String.Empty; }
399 | }
400 |
401 | ///
402 | /// Gets or sets the value of the Port attribute of the cookie.
403 | ///
404 | ///
405 | /// A that contains a list of the TCP ports to which the cookie applies.
406 | ///
407 | ///
408 | /// The value specified for a set operation is not enclosed in double quotes or could not be parsed.
409 | ///
410 | public string Port {
411 | get { return port; }
412 | set {
413 | if (value.IsNullOrEmpty ()) {
414 | port = String.Empty;
415 | ports = new int [] {};
416 | return;
417 | }
418 |
419 | if (!value.IsEnclosedIn ('"'))
420 | throw new CookieException (String.Format (
421 | "The 'Port={0}' attribute of the cookie is invalid. The value must be enclosed in double quotes.", value));
422 |
423 | string error;
424 | if (!TryCreatePorts (value, out ports, out error))
425 | throw new CookieException (String.Format (
426 | "The 'Port={0}' attribute of the cookie is invalid. Invalid value: {1}", value, error));
427 |
428 | port = value;
429 | }
430 | }
431 |
432 | ///
433 | /// Gets or sets a value indicating whether the security level of the cookie is secure.
434 | ///
435 | ///
436 | /// When this property is true, the cookie may be included in the HTTP request
437 | /// only if the request is transmitted over the HTTPS.
438 | ///
439 | ///
440 | /// true if the security level of the cookie is secure; otherwise, false.
441 | /// The default is false.
442 | ///
443 | public bool Secure {
444 | get { return secure; }
445 | set { secure = value; }
446 | }
447 |
448 | ///
449 | /// Gets the time when the cookie was issued.
450 | ///
451 | ///
452 | /// A that contains the time when the cookie was issued.
453 | ///
454 | public DateTime TimeStamp {
455 | get { return timestamp; }
456 | }
457 |
458 | ///
459 | /// Gets or sets the Value of the cookie.
460 | ///
461 | ///
462 | /// A that contains the Value of the cookie.
463 | ///
464 | ///
465 | ///
466 | /// The value specified for a set operation is .
467 | ///
468 | ///
469 | /// - or -
470 | ///
471 | ///
472 | /// The value specified for a set operation contains a string not enclosed in double quotes
473 | /// that contains an invalid character.
474 | ///
475 | ///
476 | public string Value {
477 | get { return val; }
478 | set {
479 | string msg;
480 | if (!CanSetValue (value, out msg))
481 | throw new CookieException (msg);
482 |
483 | val = value.Length == 0 ? "\"\"" : value;
484 | }
485 | }
486 |
487 | ///
488 | /// Gets or sets the value of the Version attribute of the cookie.
489 | ///
490 | ///
491 | /// An that contains the version of the HTTP state management
492 | /// to which the cookie conforms.
493 | ///
494 | ///
495 | /// The value specified for a set operation is not allowed. The value must be 0 or 1.
496 | ///
497 | public int Version {
498 | get { return version; }
499 | set {
500 | if (value < 0 || value > 1)
501 | throw new ArgumentOutOfRangeException ("value", "Must be 0 or 1.");
502 | else
503 | version = value;
504 | }
505 | }
506 |
507 | #endregion
508 |
509 | #region Private Methods
510 |
511 | static bool CanSetName (string name, out string message)
512 | {
513 | if (name.IsNullOrEmpty ()) {
514 | message = "Name must not be null or empty.";
515 | return false;
516 | }
517 |
518 | if (name [0] == '$' || name.Contains (reservedCharsForName)) {
519 | message = "Name contains an invalid character.";
520 | return false;
521 | }
522 |
523 | message = String.Empty;
524 | return true;
525 | }
526 |
527 | static bool CanSetValue (string value, out string message)
528 | {
529 | if (value == null) {
530 | message = "Value must not be null.";
531 | return false;
532 | }
533 |
534 | if (value.Contains (reservedCharsForValue)) {
535 | if (!value.IsEnclosedIn ('"')) {
536 | message = "Value contains an invalid character.";
537 | return false;
538 | }
539 | }
540 |
541 | message = String.Empty;
542 | return true;
543 | }
544 |
545 | static int Hash (int i, int j, int k, int l, int m)
546 | {
547 | return i ^ (j << 13 | j >> 19) ^ (k << 26 | k >> 6) ^ (l << 7 | l >> 25) ^ (m << 20 | m >> 12);
548 | }
549 |
550 | string ToResponseStringVersion0 ()
551 | {
552 | var result = new StringBuilder (64);
553 | result.AppendFormat ("{0}={1}", name, val);
554 | if (expires != DateTime.MinValue)
555 | result.AppendFormat ("; Expires={0}",
556 | expires.ToUniversalTime ().ToString ("ddd, dd'-'MMM'-'yyyy HH':'mm':'ss 'GMT'",
557 | CultureInfo.CreateSpecificCulture("en-US")));
558 |
559 | if (!path.IsNullOrEmpty ())
560 | result.AppendFormat ("; Path={0}", path);
561 |
562 | if (!domain.IsNullOrEmpty ())
563 | result.AppendFormat ("; Domain={0}", domain);
564 |
565 | if (secure)
566 | result.Append ("; Secure");
567 |
568 | if (httpOnly)
569 | result.Append ("; HttpOnly");
570 |
571 | return result.ToString ();
572 | }
573 |
574 | string ToResponseStringVersion1 ()
575 | {
576 | var result = new StringBuilder (64);
577 | result.AppendFormat ("{0}={1}; Version={2}", name, val, version);
578 | if (expires != DateTime.MinValue)
579 | result.AppendFormat ("; Max-Age={0}", MaxAge);
580 |
581 | if (!path.IsNullOrEmpty ())
582 | result.AppendFormat ("; Path={0}", path);
583 |
584 | if (!domain.IsNullOrEmpty ())
585 | result.AppendFormat ("; Domain={0}", domain);
586 |
587 | if (!port.IsNullOrEmpty ())
588 | if (port == "\"\"")
589 | result.Append ("; Port");
590 | else
591 | result.AppendFormat ("; Port={0}", port);
592 |
593 | if (!comment.IsNullOrEmpty ())
594 | result.AppendFormat ("; Comment={0}", comment.UrlEncode ());
595 |
596 | if (commentUri != null)
597 | result.AppendFormat ("; CommentURL={0}", commentUri.OriginalString.Quote ());
598 |
599 | if (discard)
600 | result.Append ("; Discard");
601 |
602 | if (secure)
603 | result.Append ("; Secure");
604 |
605 | return result.ToString ();
606 | }
607 |
608 | static bool TryCreatePorts (string value, out int [] result, out string parseError)
609 | {
610 | var values = value.Trim ('"').Split (',');
611 | var tmp = new int [values.Length];
612 | for (int i = 0; i < values.Length; i++) {
613 | tmp [i] = int.MinValue;
614 | var v = values [i].Trim ();
615 | if (v.Length == 0)
616 | continue;
617 |
618 | if (!int.TryParse (v, out tmp [i])) {
619 | result = new int [] {};
620 | parseError = v;
621 | return false;
622 | }
623 | }
624 |
625 | result = tmp;
626 | parseError = String.Empty;
627 | return true;
628 | }
629 |
630 | #endregion
631 |
632 | #region Internal Methods
633 |
634 | // From client to server
635 | internal string ToRequestString (Uri uri)
636 | {
637 | if (name.Length == 0)
638 | return String.Empty;
639 |
640 | if (version == 0)
641 | return String.Format ("{0}={1}", name, val);
642 |
643 | var result = new StringBuilder (64);
644 | result.AppendFormat ("$Version={0}; {1}={2}", version, name, val);
645 | if (!path.IsNullOrEmpty ())
646 | result.AppendFormat ("; $Path={0}", path);
647 | else if (uri != null)
648 | result.AppendFormat ("; $Path={0}", uri.GetAbsolutePath ());
649 | else
650 | result.Append ("; $Path=/");
651 |
652 | bool append_domain = uri == null || uri.Host != domain;
653 | if (append_domain && !domain.IsNullOrEmpty ())
654 | result.AppendFormat ("; $Domain={0}", domain);
655 |
656 | if (!port.IsNullOrEmpty ())
657 | if (port == "\"\"")
658 | result.Append ("; $Port");
659 | else
660 | result.AppendFormat ("; $Port={0}", port);
661 |
662 | return result.ToString ();
663 | }
664 |
665 | // From server to client
666 | internal string ToResponseString ()
667 | {
668 | return name.Length == 0
669 | ? String.Empty
670 | : version == 0
671 | ? ToResponseStringVersion0 ()
672 | : ToResponseStringVersion1 ();
673 | }
674 |
675 | #endregion
676 |
677 | #region Public Methods
678 |
679 | ///
680 | /// Determines whether the specified is equal to the current .
681 | ///
682 | ///
683 | /// An to compare with the current .
684 | ///
685 | ///
686 | /// true if the specified is equal to the current ;
687 | /// otherwise, false.
688 | ///
689 | public override bool Equals (Object comparand)
690 | {
691 | var cookie = comparand as Cookie;
692 | return cookie != null &&
693 | name.Equals (cookie.Name, StringComparison.InvariantCultureIgnoreCase) &&
694 | val.Equals (cookie.Value, StringComparison.InvariantCulture) &&
695 | path.Equals (cookie.Path, StringComparison.InvariantCulture) &&
696 | domain.Equals (cookie.Domain, StringComparison.InvariantCultureIgnoreCase) &&
697 | version == cookie.Version;
698 | }
699 |
700 | ///
701 | /// Serves as a hash function for a object.
702 | ///
703 | ///
704 | /// An that contains a hash code for this instance.
705 | ///
706 | public override int GetHashCode ()
707 | {
708 | return Hash (
709 | StringComparer.InvariantCultureIgnoreCase.GetHashCode (name),
710 | val.GetHashCode (),
711 | path.GetHashCode (),
712 | StringComparer.InvariantCultureIgnoreCase.GetHashCode (domain),
713 | version);
714 | }
715 |
716 | ///
717 | /// Returns a that represents the current .
718 | ///
719 | ///
720 | /// This method returns a to use to send an HTTP Cookie to an origin server.
721 | ///
722 | ///
723 | /// A that represents the current .
724 | ///
725 | public override string ToString ()
726 | {
727 | // i.e., only used for clients
728 | // see para 4.2.2 of RFC 2109 and para 3.3.4 of RFC 2965
729 | // see also bug #316017
730 | return ToRequestString (null);
731 | }
732 |
733 | #endregion
734 | }
735 | }
736 |
--------------------------------------------------------------------------------