Modified WebSocket.cs

This commit is contained in:
sta 2013-05-01 14:27:24 +09:00
parent 2a816ef0c8
commit 585686f401
22 changed files with 120 additions and 79 deletions

Binary file not shown.

Binary file not shown.

View File

@ -346,7 +346,7 @@ Examples of using **websocket-sharp**.
Please access [http://localhost:4649](http://localhost:4649) to do WebSocket Echo Test with your web browser after [Example3] running.
## Supported WebSocket Protocols ##
## Supported WebSocket Specifications ##
**websocket-sharp** supports **[RFC 6455]**.
@ -357,7 +357,7 @@ Please access [http://localhost:4649](http://localhost:4649) to do WebSocket Ech
### Per-message Compression ###
**websocket-sharp** supports **[Per-message Compression]**.
**websocket-sharp** supports **[Per-message Compression][compression]** extension. (But, does not support with [extension parameters].)
If you want to enable this extension as a WebSocket client, you should do like the following.
@ -368,7 +368,7 @@ ws.Compression = CompressionMethod.DEFLATE;
And then your client sends the following header in the opening handshake to a WebSocket server.
```
Sec-WebSocket-Extensions: permessage-compress; method=deflate
Sec-WebSocket-Extensions: permessage-deflate
```
If the server supports this extension, responds the same header. And when your client receives the header, enables this extension.
@ -377,7 +377,7 @@ If the server supports this extension, responds the same header. And when your c
- **[The WebSocket Protocol]**
- **[The WebSocket API]**
- **[Per-message Compression]**
- **[Compression Extensions for WebSocket][compression]**
Thanks for translating to japanese.
@ -394,17 +394,18 @@ Licensed under the **[MIT License]**.
[Audio Data delivery server]: http://agektmr.node-ninja.com:3000/
[branch: draft75]: https://github.com/sta/websocket-sharp/tree/draft75
[branch: hybi-00]: https://github.com/sta/websocket-sharp/tree/hybi-00
[compression]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-09
[Echo server]: http://www.websocket.org/echo.html
[Example]: https://github.com/sta/websocket-sharp/tree/master/Example
[Example1]: https://github.com/sta/websocket-sharp/tree/master/Example1
[Example2]: https://github.com/sta/websocket-sharp/tree/master/Example2
[Example3]: https://github.com/sta/websocket-sharp/tree/master/Example3
[extension parameters]: http://tools.ietf.org/html/draft-ietf-hybi-permessage-compression-09#section-8.1
[hixie-75]: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75
[hybi-00]: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotocol-00
[Json.NET]: http://james.newtonking.com/projects/json-net.aspx
[MIT License]: http://www.opensource.org/licenses/mit-license.php
[Mono]: http://www.mono-project.com/
[Per-message Compression]: http://tools.ietf.org/html/draft-tyoshino-hybi-permessage-compression-00
[RFC 6455]: http://tools.ietf.org/html/rfc6455
[The WebSocket API]: http://www.w3.org/TR/websockets/
[The WebSocket API 日本語訳]: http://www.hcn.zaq.ne.jp/___/WEB/WebSocket-ja.html

View File

@ -548,6 +548,56 @@ namespace WebSocketSharp {
}
}
private bool concatenateFragments(Stream dest)
{
Func<WsFrame, bool> processContinuation = contFrame =>
{
if (!contFrame.IsContinuation)
return false;
dest.WriteBytes(contFrame.PayloadData.ApplicationData);
return true;
};
while (true)
{
var frame = readFrame();
if (processAbnormal(frame))
return false;
if (!frame.IsFinal)
{
// MORE & CONT
if (processContinuation(frame))
continue;
}
else
{
// FINAL & CONT
if (processContinuation(frame))
break;
// FINAL & PING
if (processPing(frame))
continue;
// FINAL & PONG
if (processPong(frame))
continue;
// FINAL & CLOSE
if (processClose(frame))
return false;
}
// ?
processIncorrectFrame();
return false;
}
return true;
}
private bool connect()
{
return _client
@ -565,11 +615,9 @@ namespace WebSocketSharp {
return Convert.ToBase64String(src);
}
private static string createCompressExtension(CompressionMethod method)
private static string createCompressionExtension(CompressionMethod method)
{
return method != CompressionMethod.NONE
? String.Format("permessage-compress; method={0}", method.ToString().ToLower())
: String.Empty;
return createCurrentCompressionExtension(method);
}
private static WsFrame createControlFrame(Opcode opcode, PayloadData payloadData, bool client)
@ -577,6 +625,20 @@ namespace WebSocketSharp {
return createFrame(Fin.FINAL, opcode, payloadData, false, client);
}
private static string createCurrentCompressionExtension(CompressionMethod method)
{
return method != CompressionMethod.NONE
? String.Format("permessage-{0}", method.ToString().ToLower())
: String.Empty;
}
private static string createDeprecatedCompressionExtension(CompressionMethod method)
{
return method != CompressionMethod.NONE
? String.Format("permessage-compress; method={0}", method.ToString().ToLower())
: String.Empty;
}
private static WsFrame createFrame(
Fin fin, Opcode opcode, PayloadData payloadData, bool compressed, bool client)
{
@ -590,9 +652,9 @@ namespace WebSocketSharp {
private string createRequestExtensions()
{
var extensions = new StringBuilder(64);
var compress = createCompressExtension(_compression);
if (!compress.IsEmpty())
extensions.Append(compress);
var comp = createCompressionExtension(_compression);
if (!comp.IsEmpty())
extensions.Append(comp);
return extensions.Length > 0
? extensions.ToString()
@ -671,6 +733,19 @@ namespace WebSocketSharp {
return processResponseHandshake();
}
private static CompressionMethod getCompressionMethod(string value)
{
var deprecated = createDeprecatedCompressionExtension(CompressionMethod.DEFLATE);
if (value.Equals(deprecated))
return CompressionMethod.DEFLATE;
foreach (CompressionMethod method in Enum.GetValues(typeof(CompressionMethod)))
if (isCompressionExtension(value, method))
return method;
return CompressionMethod.NONE;
}
// As client
private void init()
{
@ -691,9 +766,14 @@ namespace WebSocketSharp {
_client = false;
}
private static bool isCompressExtension(string value, CompressionMethod method)
private static bool isCompressionExtension(string value)
{
var expected = createCompressExtension(method);
return value.StartsWith("permessage-");
}
private static bool isCompressionExtension(string value, CompressionMethod method)
{
var expected = createCompressionExtension(method);
return !expected.IsEmpty()
? value.Equals(expected)
: false;
@ -751,56 +831,6 @@ namespace WebSocketSharp {
response.HeaderExists("Sec-WebSocket-Version", _version);
}
private bool mergeFragments(Stream dest)
{
Func<WsFrame, bool> processContinuation = contFrame =>
{
if (!contFrame.IsContinuation)
return false;
dest.WriteBytes(contFrame.PayloadData.ApplicationData);
return true;
};
while (true)
{
var frame = readFrame();
if (processAbnormal(frame))
return false;
if (!frame.IsFinal)
{
// MORE & CONT
if (processContinuation(frame))
continue;
}
else
{
// FINAL & CONT
if (processContinuation(frame))
break;
// FINAL & PING
if (processPing(frame))
continue;
// FINAL & PONG
if (processPong(frame))
continue;
// FINAL & CLOSE
if (processClose(frame))
return false;
}
// ?
processIncorrectFrame();
return false;
}
return true;
}
private void onClose(CloseEventArgs eventArgs)
{
if (!Thread.CurrentThread.IsBackground)
@ -931,21 +961,21 @@ namespace WebSocketSharp {
private void processFragments(WsFrame first)
{
using (var merge = new MemoryStream())
using (var concatenated = new MemoryStream())
{
merge.WriteBytes(first.PayloadData.ApplicationData);
if (!mergeFragments(merge))
concatenated.WriteBytes(first.PayloadData.ApplicationData);
if (!concatenateFragments(concatenated))
return;
byte[] data;
if (_compression != CompressionMethod.NONE)
{
data = merge.DecompressToArray(_compression);
data = concatenated.DecompressToArray(_compression);
}
else
{
merge.Close();
data = merge.ToArray();
concatenated.Close();
data = concatenated.ToArray();
}
onMessage(new MessageEventArgs(first.Opcode, data));
@ -1005,17 +1035,21 @@ namespace WebSocketSharp {
if (extensions.IsNullOrEmpty())
return;
var compress = false;
var comp = false;
var buffer = new List<string>();
foreach (var extension in extensions.SplitHeaderValue(','))
{
var e = extension.Trim();
var tmp = e.RemovePrefix("x-webkit-");
if (!compress && isCompressExtension(tmp, CompressionMethod.DEFLATE))
if (!comp && isCompressionExtension(tmp))
{
_compression = CompressionMethod.DEFLATE;
compress = true;
buffer.Add(e);
var method = getCompressionMethod(tmp);
if (method != CompressionMethod.NONE)
{
_compression = method;
comp = true;
buffer.Add(e);
}
}
}
@ -1062,20 +1096,26 @@ namespace WebSocketSharp {
// As client
private void processResponseExtensions(string extensions)
{
var compress = false;
var checkComp = _compression != CompressionMethod.NONE
? true
: false;
var comp = false;
if (!extensions.IsNullOrEmpty())
{
foreach (var extension in extensions.SplitHeaderValue(','))
{
var e = extension.Trim();
if (!compress && isCompressExtension(e, _compression))
compress = true;
if (checkComp &&
!comp &&
isCompressionExtension(e, _compression))
comp = true;
}
_extensions = extensions;
}
if (!compress)
if (checkComp && !comp)
_compression = CompressionMethod.NONE;
}

Binary file not shown.