Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in
Toggle navigation
P
pylibs
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
domotika
pylibs
Commits
85566b3b
Commit
85566b3b
authored
Jul 19, 2020
by
root
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add sockjs for python3
parent
46f2f5eb
Changes
29
Show whitespace changes
Inline
Side-by-side
Showing
29 changed files
with
2661 additions
and
0 deletions
+2661
-0
.gitattributes
sockjs-twisted-master/.gitattributes
+22
-0
.gitignore
sockjs-twisted-master/.gitignore
+34
-0
AUTHORS
sockjs-twisted-master/AUTHORS
+1
-0
CHANGELOG.rst
sockjs-twisted-master/CHANGELOG.rst
+13
-0
LICENSE
sockjs-twisted-master/LICENSE
+24
-0
MANIFEST.in
sockjs-twisted-master/MANIFEST.in
+3
-0
README.rst
sockjs-twisted-master/README.rst
+126
-0
setup.py
sockjs-twisted-master/setup.py
+28
-0
chat.html
sockjs-twisted-master/tests/chat.html
+78
-0
chat.py
sockjs-twisted-master/tests/chat.py
+48
-0
multiplex.html
sockjs-twisted-master/tests/multiplex.html
+96
-0
multiplex.py
sockjs-twisted-master/tests/multiplex.py
+43
-0
server.py
sockjs-twisted-master/tests/server.py
+40
-0
__init__.py
sockjs-twisted-master/txsockjs/__init__.py
+1
-0
factory.py
sockjs-twisted-master/txsockjs/factory.py
+132
-0
multiplex.py
sockjs-twisted-master/txsockjs/multiplex.py
+148
-0
multiplex.py.bak
sockjs-twisted-master/txsockjs/multiplex.py.bak
+148
-0
oldwebsockets.py
sockjs-twisted-master/txsockjs/oldwebsockets.py
+405
-0
__init__.py
sockjs-twisted-master/txsockjs/protocols/__init__.py
+0
-0
base.py
sockjs-twisted-master/txsockjs/protocols/base.py
+201
-0
eventsource.py
sockjs-twisted-master/txsockjs/protocols/eventsource.py
+51
-0
htmlfile.py
sockjs-twisted-master/txsockjs/protocols/htmlfile.py
+69
-0
jsonp.py
sockjs-twisted-master/txsockjs/protocols/jsonp.py
+63
-0
static.py
sockjs-twisted-master/txsockjs/protocols/static.py
+77
-0
websocket.py
sockjs-twisted-master/txsockjs/protocols/websocket.py
+114
-0
xhr.py
sockjs-twisted-master/txsockjs/protocols/xhr.py
+84
-0
utils.py
sockjs-twisted-master/txsockjs/utils.py
+44
-0
utils.py.bak
sockjs-twisted-master/txsockjs/utils.py.bak
+44
-0
websockets.py
sockjs-twisted-master/txsockjs/websockets.py
+524
-0
No files found.
sockjs-twisted-master/.gitattributes
0 → 100644
View file @
85566b3b
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
*.sln merge=union
*.csproj merge=union
*.vbproj merge=union
*.fsproj merge=union
*.dbproj merge=union
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain
sockjs-twisted-master/.gitignore
0 → 100644
View file @
85566b3b
#############
## Python
#############
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Unit test / coverage reports
.coverage
.tox
#Translations
*.mo
#Mr Developer
.mr.developer.cfg
# Mac crap
.DS_Store
sockjs-twisted-master/AUTHORS
0 → 100644
View file @
85566b3b
Christopher Gamble
\ No newline at end of file
sockjs-twisted-master/CHANGELOG.rst
0 → 100644
View file @
85566b3b
========================
SockJS-Twisted Changelog
========================
0.1
===
**0.1.1**
* Converts all text to UTF-8 (prevents crashing websockets in chrome)
* Minor bug fixes
**0.1.0**
* Initial release
sockjs-twisted-master/LICENSE
0 → 100644
View file @
85566b3b
Copyright (c) 2012, Christopher Gamble
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Christopher Gamble nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
\ No newline at end of file
sockjs-twisted-master/MANIFEST.in
0 → 100644
View file @
85566b3b
include AUTHORS
include LICENSE
include README.rst
\ No newline at end of file
sockjs-twisted-master/README.rst
0 → 100644
View file @
85566b3b
==============
SockJS-Twisted
==============
A simple library for adding SockJS support to your twisted application.
Status
======
SockJS-Twisted passes all `SockJS-Protocol v0.3.3 <https://github.com/sockjs/sockjs-protocol>`_ tests,
and all `SockJS-Client qunit <https://github.com/sockjs/sockjs-client>`_ tests. It has been used in
production environments, and should be free of any critical bugs.
Usage
=====
Use ``txsockjs.factory.SockJSFactory`` to wrap your factories. That's it!
.. code-block:: python
from txsockjs.factory import SockJSFactory
reactor.listenTCP(8080, SockJSFactory(factory_to_wrap))
There is nothing else to it, no special setup involved.
Do you want a secure connection? Use ``listenSSL()`` instead of ``listenTCP()``.
Advanced Usage
==============
For those who want to host multiple SockJS services off of one port,
``txsockjs.factory.SockJSMultiFactory`` is designed to handle routing for you.
.. code-block:: python
from txsockjs.factory import SockJSMultiFactory
f = SockJSMultiFactory()
f.addFactory(EchoFactory(), "echo")
f.addFactory(ChatFactory(), "chat")
reactor.listenTCP(8080, f)
http://localhost:8080/echo and http://localhost:8080/chat will give you access
to your EchoFactory and ChatFactory.
Integration With Websites
=========================
It is possible to offer static resources, dynamic pages, and SockJS endpoints off of
a single port by using ``txsockjs.factory.SockJSResource``.
.. code-block:: python
from txsockjs.factory import SockJSResource
root = resource.Resource()
root.putChild("echo", SockJSResource(EchoFactory()))
root.putChild("chat", SockJSResource(ChatFactory()))
site = server.Site(root)
reactor.listenTCP(8080, site)
Multiplexing [Experimental]
===========================
SockJS-Twisted also has built-in support for multiplexing. See the
`Websocket-Multiplex <https://github.com/sockjs/websocket-multiplex>`_ library
for how to integrate multiplexing client side.
.. code-block:: python
from txsockjs.multiplex import SockJSMultiplexResource
multiplex = SockJSMultiplexResource()
multiplex.addFactory("echo", EchoFactory())
multiplex.addFactory("chat", ChatFactory())
root = resource.Resource()
root.putChild("multiplex", multiplex)
site = server.Site(root)
reactor.listenTCP(8080, site)
If you want PubSub functionality, just use ``txsockjs.multiplex.SockJSPubSubResource`` instead!
Options
=======
A dictionary of options can be passed into the factory to control SockJS behavior.
.. code-block:: python
options = {
'websocket': True,
'cookie_needed': False,
'heartbeat': 25,
'timeout': 5,
'streaming_limit': 128 * 1024,
'encoding': 'cp1252', # Latin1
'sockjs_url': 'https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.js'
}
SockJSFactory(factory_to_wrap, options)
SockJSMultiFactory().addFactory(factory_to_wrap, prefix, options)
SockJSResource(factory_to_wrap, options)
SockJSMultiplexResource(options)
SockJSPubSubResource(options)
websocket :
whether websockets are supported as a protocol. Useful for proxies or load balancers that don't support websockets.
cookie_needed :
whether the JSESSIONID cookie is set. Results in less performant protocols being used, so don't require them unless your load balancer requires it.
heartbeat :
how often a heartbeat message is sent to keep the connection open. Do not increase this unless you know what you are doing.
timeout :
maximum delay between connections before the underlying protocol is disconnected
streaming_limit :
how many bytes can be sent over a streaming protocol before it is cycled. Allows browser-side garbage collection to lower RAM usage.
encoding :
All messages to and from txsockjs should be valid UTF-8. In the event that a message received by txsockjs is not UTF-8, fall back to this encoding.
sockjs_url :
The url of the SockJS library to use in iframes. By default this is served over HTTPS and therefore shouldn't need changing.
License
=======
SockJS-Twisted is (c) 2012 Christopher Gamble and is made available under the BSD license.
sockjs-twisted-master/setup.py
0 → 100644
View file @
85566b3b
from
setuptools
import
setup
import
txsockjs
import
os
setup
(
author
=
"Christopher Gamble"
,
author_email
=
"chris@chrisgamble.net"
,
name
=
"txsockjs"
,
version
=
txsockjs
.
__version__
,
description
=
"Twisted SockJS wrapper"
,
long_description
=
open
(
os
.
path
.
join
(
os
.
path
.
dirname
(
__file__
),
'README.rst'
))
.
read
(),
url
=
"http://github.com/Fugiman/sockjs-twisted"
,
license
=
'BSD License'
,
platforms
=
[
'OS Independent'
],
packages
=
[
"txsockjs"
,
"txsockjs.protocols"
],
install_requires
=
[
"Twisted"
,
],
classifiers
=
[
"Development Status :: 5 - Production/Stable"
,
"Framework :: Twisted"
,
"Intended Audience :: Developers"
,
"License :: OSI Approved :: BSD License"
,
"Operating System :: OS Independent"
,
"Programming Language :: Python"
,
"Topic :: Internet"
,
],
)
\ No newline at end of file
sockjs-twisted-master/tests/chat.html
0 → 100644
View file @
85566b3b
<!doctype html>
<html>
<head>
<title>
IRC Client Test
</title>
<script
src=
"https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"
></script>
<script
src=
"http://cdn.sockjs.org/sockjs-0.3.min.js"
></script>
<style>
#container
{
width
:
800px
;
margin
:
40px
auto
;
padding
:
0
;
}
#irc-holder
{
height
:
600px
;
width
:
800px
;
overflow
:
auto
;
border
:
2px
solid
black
;
}
#irc
{
width
:
100%
;
border-collapse
:
collapse
;
}
#irc
tr
{
border-bottom
:
1px
solid
gray
;
}
#chatter
input
[
type
=
"text"
]
{
width
:
700px
;
}
#chatter
input
[
type
=
"submit"
]
{
width
:
90px
;
}
#protocol
{
font-size
:
1.5em
;
margin
:
auto
;
width
:
300px
;
display
:
block
;
}
</style>
</head>
<body>
<div
id=
"container"
>
<div
id=
"irc-holder"
>
<table
id=
"irc"
></table>
</div>
<form
method=
"GET"
id=
"chatter"
>
<input
type=
"text"
/>
<input
type=
"submit"
value=
"Send"
/>
<br
/>
<select
id=
"protocol"
>
<option
value=
"websocket"
selected
>
Websocket
</option>
<option
value=
"xdr-streaming"
>
XDR Streaming
</option>
<option
value=
"xhr-streaming"
>
XHR Streaming
</option>
<option
value=
"iframe-eventsource"
>
Eventsource
</option>
<option
value=
"iframe-htmlfile"
>
HTMLFile
</option>
<option
value=
"xdr-polling"
>
XDR Polling
</option>
<option
value=
"xhr-polling"
>
XHR Polling
</option>
<option
value=
"iframe-xhr-polling"
>
XHR Polling (IFrame)
</option>
<option
value=
"jsonp-polling"
>
JSONP Polling
</option>
</select>
</form>
</div>
<script>
$
(
document
).
keypress
(
function
(
e
)
{
return
e
.
which
!==
0
;
});
var
url
=
'http://127.0.0.1:6672'
;
var
conn
=
false
;
function
connect
()
{
if
(
conn
)
conn
.
close
()
conn
=
false
var
protocol
=
$
(
'#protocol'
).
val
();
conn
=
new
SockJS
(
url
,
null
,{
debug
:
true
,
devel
:
true
,
protocols_whitelist
:[
protocol
]});
var
log
=
function
(
msg
)
{
$
(
'#irc'
).
append
(
$
(
'<tr>'
).
html
(
$
(
'<td>'
).
html
(
msg
)));
};
conn
.
onopen
=
function
(
evt
)
{
log
(
'<i>Connected via '
+
$
(
'#protocol'
).
val
()
+
'</i>'
);
};
conn
.
onclose
=
function
(
evt
)
{
log
(
'<i>Disconnected</i>'
);
};
conn
.
onmessage
=
function
(
evt
)
{
log
(
$
(
'<div>'
).
text
(
evt
.
data
).
html
());
};
}
$
(
'#chatter'
).
submit
(
function
()
{
var
txt
=
$
(
this
).
find
(
'input[type="text"]'
);
var
m
=
txt
.
val
();
conn
.
send
(
m
+
"
\
r
\n
"
);
txt
.
val
(
''
);
return
false
;
});
$
(
'#protocol'
).
change
(
connect
);
connect
();
</script>
</body>
</html>
sockjs-twisted-master/tests/chat.py
0 → 100644
View file @
85566b3b
from
twisted.internet.protocol
import
Factory
from
twisted.protocols.basic
import
LineReceiver
from
twisted.internet
import
reactor
from
txsockjs.factory
import
SockJSFactory
class
Chat
(
LineReceiver
):
def
__init__
(
self
,
users
):
self
.
users
=
users
self
.
name
=
None
self
.
state
=
"GETNAME"
def
connectionMade
(
self
):
print
(
"IRC Connection Made!"
)
self
.
sendLine
(
"What's your name?"
)
def
connectionLost
(
self
,
reason
):
print
(
"IRC Connection Lost!"
)
if
self
.
users
.
has_key
(
self
.
name
):
del
self
.
users
[
self
.
name
]
def
lineReceived
(
self
,
line
):
if
self
.
state
==
"GETNAME"
:
self
.
handle_GETNAME
(
line
)
else
:
self
.
handle_CHAT
(
line
)
def
handle_GETNAME
(
self
,
name
):
if
self
.
users
.
has_key
(
name
):
self
.
sendLine
(
"Name taken, please choose another."
)
return
print
(
"IRC User chose name -
%
s!"
%
name
)
self
.
sendLine
(
"Welcome,
%
s!"
%
(
name
,))
self
.
name
=
name
self
.
users
[
name
]
=
self
self
.
state
=
"CHAT"
def
handle_CHAT
(
self
,
message
):
message
=
"<
%
s>
%
s"
%
(
self
.
name
,
message
)
print
(
message
)
for
name
,
protocol
in
self
.
users
.
iteritems
():
protocol
.
sendLine
(
message
)
class
ChatFactory
(
Factory
):
def
__init__
(
self
):
self
.
users
=
{}
# maps user names to Chat instances
def
buildProtocol
(
self
,
addr
):
return
Chat
(
self
.
users
)
f
=
ChatFactory
()
s
=
SockJSFactory
(
f
)
reactor
.
listenTCP
(
6667
,
f
)
reactor
.
listenTCP
(
6672
,
s
)
reactor
.
run
()
\ No newline at end of file
sockjs-twisted-master/tests/multiplex.html
0 → 100644
View file @
85566b3b
<!doctype html>
<html><head>
<script
src=
"http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"
></script>
<script
src=
"http://cdn.sockjs.org/sockjs-0.3.min.js"
></script>
<script
src=
"http://cdn.sockjs.org/websocket-multiplex-0.1.js"
></script>
<style>
.box
{
width
:
300px
;
float
:
left
;
margin
:
0
20px
0
20px
;
}
.box
div
,
.box
input
{
border
:
1px
solid
;
-moz-border-radius
:
4px
;
border-radius
:
4px
;
width
:
100%
;
padding
:
0px
;
margin
:
5px
;
}
.box
div
{
border-color
:
grey
;
height
:
300px
;
overflow
:
auto
;
}
.box
input
{
height
:
30px
;
}
h1
{
margin-left
:
75px
;
}
body
{
background-color
:
#F0F0F0
;
font-family
:
"Arial"
;
}
</style>
</head><body
lang=
"en"
>
<h1>
SockJS Multiplex example
</h1>
<div
id=
"first"
class=
"box"
>
<div></div>
<form><input
autocomplete=
"off"
value=
"Type here..."
></input></form>
</div>
<div
id=
"second"
class=
"box"
>
<div></div>
<form><input
autocomplete=
"off"
></input></form>
</div>
<div
id=
"third"
class=
"box"
>
<div></div>
<form><input
autocomplete=
"off"
></input></form>
</div>
<script>
// Pipe - convenience wrapper to present data received from an
// object supporting WebSocket API in an html element. And the other
// direction: data typed into an input box shall be sent back.
var
pipe
=
function
(
ws
,
el_name
)
{
var
div
=
$
(
el_name
+
' div'
);
var
inp
=
$
(
el_name
+
' input'
);
var
form
=
$
(
el_name
+
' form'
);
var
print
=
function
(
m
,
p
)
{
p
=
(
p
===
undefined
)
?
''
:
JSON
.
stringify
(
p
);
div
.
append
(
$
(
"<code>"
).
text
(
m
+
' '
+
p
));
div
.
append
(
$
(
"<br>"
));
div
.
scrollTop
(
div
.
scrollTop
()
+
10000
);
};
ws
.
onopen
=
function
()
{
print
(
'[*] open'
,
ws
.
protocol
);};
ws
.
onmessage
=
function
(
e
)
{
print
(
'[.] message'
,
e
.
data
);};
ws
.
onclose
=
function
()
{
print
(
'[*] close'
);};
form
.
submit
(
function
()
{
print
(
'[ ] sending'
,
inp
.
val
());
ws
.
send
(
inp
.
val
());
inp
.
val
(
''
);
return
false
;
});
};
var
sockjs_url
=
'http://127.0.0.1:8081/multiplex'
;
var
sockjs
=
new
SockJS
(
sockjs_url
);
var
multiplexer
=
new
WebSocketMultiplex
(
sockjs
);
var
ann
=
multiplexer
.
channel
(
'ann'
);
var
bob
=
multiplexer
.
channel
(
'bob'
);
var
carl
=
multiplexer
.
channel
(
'carl'
);
pipe
(
ann
,
'#first'
);
pipe
(
bob
,
'#second'
);
pipe
(
carl
,
'#third'
);
$
(
'#first input'
).
focus
();
</script>
</body></html>
\ No newline at end of file
sockjs-twisted-master/tests/multiplex.py
0 → 100644
View file @
85566b3b
from
twisted.internet
import
reactor
,
protocol
from
twisted.web
import
server
,
resource
from
txsockjs.multiplex
import
SockJSMultiplexResource
class
AnnP
(
protocol
.
Protocol
):
def
connectionMade
(
self
):
self
.
transport
.
write
(
"Ann says hi!"
)
def
dataReceived
(
self
,
data
):
self
.
transport
.
write
(
"Ann nods: "
+
data
)
class
BobP
(
protocol
.
Protocol
):
def
connectionMade
(
self
):
self
.
transport
.
write
(
"Bob doesn't agree."
)
def
dataReceived
(
self
,
data
):
self
.
transport
.
write
(
"Bob says no to: "
+
data
)
class
CarlP
(
protocol
.
Protocol
):
def
connectionMade
(
self
):
self
.
transport
.
write
(
"Carl says goodbye!"
)
self
.
transport
.
loseConnection
()
class
AnnF
(
protocol
.
Factory
):
protocol
=
AnnP
class
BobF
(
protocol
.
Factory
):
protocol
=
BobP
class
CarlF
(
protocol
.
Factory
):
protocol
=
CarlP
multiplex
=
SockJSMultiplexResource
()
multiplex
.
addFactory
(
"ann"
,
AnnF
())
multiplex
.
addFactory
(
"bob"
,
BobF
())
multiplex
.
addFactory
(
"carl"
,
CarlF
())
root
=
resource
.
Resource
()
root
.
putChild
(
"multiplex"
,
multiplex
)
site
=
server
.
Site
(
root
)
reactor
.
listenTCP
(
8081
,
site
)
reactor
.
run
()
\ No newline at end of file
sockjs-twisted-master/tests/server.py
0 → 100644
View file @
85566b3b
from
twisted.internet
import
reactor
,
protocol
from
twisted.web
import
server
,
resource
from
txsockjs.factory
import
SockJSMultiFactory
,
SockJSResource
class
Echo
(
protocol
.
Protocol
):
def
dataReceived
(
self
,
data
):
#print ">>> %s" % data
self
.
transport
.
write
(
data
)
class
EchoFactory
(
protocol
.
Factory
):
def
buildProtocol
(
self
,
addr
):
return
Echo
()
class
Close
(
protocol
.
Protocol
):
def
connectionMade
(
self
):
self
.
transport
.
loseConnection
()
class
CloseFactory
(
protocol
.
Factory
):
def
buildProtocol
(
self
,
addr
):
return
Close
()
echo
=
EchoFactory
()
close
=
CloseFactory
()
s
=
SockJSMultiFactory
()
s
.
addFactory
(
echo
,
"echo"
,
{
'streaming_limit'
:
4
*
1024
})
s
.
addFactory
(
close
,
"close"
,
{
'streaming_limit'
:
4
*
1024
})
s
.
addFactory
(
echo
,
"disabled_websocket_echo"
,
{
'websocket'
:
False
,
'streaming_limit'
:
4
*
1024
})
s
.
addFactory
(
echo
,
"cookie_needed_echo"
,
{
'cookie_needed'
:
True
,
'streaming_limit'
:
4
*
1024
})
root
=
resource
.
Resource
()
root
.
putChild
(
"echo"
,
SockJSResource
(
echo
,
{
'streaming_limit'
:
4
*
1024
}))
root
.
putChild
(
"close"
,
SockJSResource
(
close
,
{
'streaming_limit'
:
4
*
1024
}))
root
.
putChild
(
"disabled_websocket_echo"
,
SockJSResource
(
echo
,
{
'websocket'
:
False
,
'streaming_limit'
:
4
*
1024
}))
root
.
putChild
(
"cookie_needed_echo"
,
SockJSResource
(
echo
,
{
'cookie_needed'
:
True
,
'streaming_limit'
:
4
*
1024
}))
site
=
server
.
Site
(
root
)
reactor
.
listenTCP
(
8081
,
s
)
reactor
.
listenTCP
(
8082
,
site
)
reactor
.
run
()
\ No newline at end of file
sockjs-twisted-master/txsockjs/__init__.py
0 → 100644
View file @
85566b3b
__version__
=
"0.1.1"
sockjs-twisted-master/txsockjs/factory.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
twisted.web
import
resource
,
server
from
txsockjs.protocols.base
import
Stub
from
txsockjs.protocols.eventsource
import
EventSource
from
txsockjs.protocols.htmlfile
import
HTMLFile
from
txsockjs.protocols.jsonp
import
JSONP
,
JSONPSend
from
txsockjs.protocols.static
import
Info
,
IFrame
from
txsockjs.protocols.websocket
import
RawWebSocket
,
WebSocket
from
txsockjs.protocols.xhr
import
XHR
,
XHRSend
,
XHRStream
class
SockJSFactory
(
server
.
Site
):
def
__init__
(
self
,
factory
,
options
=
None
):
server
.
Site
.
__init__
(
self
,
SockJSResource
(
factory
,
options
))
class
SockJSMultiFactory
(
server
.
Site
):
def
__init__
(
self
):
server
.
Site
.
__init__
(
self
,
resource
.
Resource
())
def
addFactory
(
self
,
factory
,
prefix
,
options
=
None
):
self
.
resource
.
putChild
(
prefix
,
SockJSResource
(
factory
,
options
))
class
SockJSResource
(
resource
.
Resource
):
def
__init__
(
self
,
factory
,
options
=
None
):
resource
.
Resource
.
__init__
(
self
)
self
.
_factory
=
factory
self
.
_sessions
=
{}
self
.
_options
=
{
'websocket'
:
True
,
'cookie_needed'
:
False
,
'heartbeat'
:
25
,
'timeout'
:
5
,
'streaming_limit'
:
128
*
1024
,
'encoding'
:
'cp1252'
,
#Latin1
'sockjs_url'
:
'https://d1fxtkz8shb9d2.cloudfront.net/sockjs-0.3.js'
}
if
options
is
not
None
:
self
.
_options
.
update
(
options
)
# Just in case somebody wants to mess with these
self
.
_methods
=
{
'xhr'
:
XHR
,
'xhr_send'
:
XHRSend
,
'xhr_streaming'
:
XHRStream
,
'eventsource'
:
EventSource
,
'htmlfile'
:
HTMLFile
,
'jsonp'
:
JSONP
,
'jsonp_send'
:
JSONPSend
,
}
self
.
_writeMethods
=
(
'xhr_send'
,
'jsonp_send'
)
# Static Resources
self
.
putChild
(
"info"
,
Info
())
self
.
putChild
(
"iframe.html"
,
IFrame
())
self
.
putChild
(
"websocket"
,
RawWebSocket
())
# Since it's constant, we can declare the websocket handler up here
self
.
_websocket
=
WebSocket
()
self
.
_websocket
.
parent
=
self
def
getChild
(
self
,
name
,
request
):
# Check if it is the greeting url
if
not
name
and
not
request
.
postpath
:
return
self
# Hacks to resove the iframe even when people are dumb
if
len
(
name
)
>
10
and
name
[:
6
]
==
"iframe"
and
name
[
-
5
:]
==
".html"
:
return
self
.
children
[
"iframe.html"
]
# Sessions must have 3 parts, name is already the first. Also, no periods in the loadbalancer
if
len
(
request
.
postpath
)
!=
2
or
"."
in
name
or
not
name
:
return
resource
.
NoResource
(
"No such child resource."
)
# Extract session & request type. Discard load balancer
session
,
name
=
request
.
postpath
# No periods in the session
if
"."
in
session
or
not
session
:
return
resource
.
NoResource
(
"No such child resource."
)
# Websockets are a special case
if
name
==
"websocket"
:
return
self
.
_websocket
# Reject invalid methods
if
name
not
in
self
.
_methods
:
return
resource
.
NoResource
(
"No such child resource."
)
# Reject writes to invalid sessions, unless just checking options
if
name
in
self
.
_writeMethods
and
session
not
in
self
.
_sessions
and
request
.
method
!=
"OPTIONS"
:
return
resource
.
NoResource
(
"No such child resource."
)
# Generate session if doesn't exist, unless just checking options
if
session
not
in
self
.
_sessions
and
request
.
method
!=
"OPTIONS"
:
self
.
_sessions
[
session
]
=
Stub
(
self
,
session
)
# Delegate request to appropriate handler
return
self
.
_methods
[
name
](
self
,
self
.
_sessions
[
session
]
if
request
.
method
!=
"OPTIONS"
else
None
)
def
putChild
(
self
,
path
,
child
):
child
.
parent
=
self
resource
.
Resource
.
putChild
(
self
,
path
,
child
)
def
setBaseHeaders
(
self
,
request
,
cookie
=
True
):
origin
=
request
.
getHeader
(
"Origin"
)
headers
=
request
.
getHeader
(
'Access-Control-Request-Headers'
)
if
origin
is
None
or
origin
==
"null"
:
origin
=
"*"
request
.
setHeader
(
'access-control-allow-origin'
,
origin
)
request
.
setHeader
(
'access-control-allow-credentials'
,
'true'
)
request
.
setHeader
(
'Cache-Control'
,
'no-store, no-cache, must-revalidate, max-age=0'
)
if
headers
is
not
None
:
request
.
setHeader
(
'Access-Control-Allow-Headers'
,
headers
)
if
self
.
_options
[
"cookie_needed"
]
and
cookie
:
cookie
=
request
.
getCookie
(
"JSESSIONID"
)
if
request
.
getCookie
(
"JSESSIONID"
)
else
"dummy"
request
.
addCookie
(
"JSESSIONID"
,
cookie
,
path
=
"/"
)
def
render_GET
(
self
,
request
):
self
.
setBaseHeaders
(
request
,
False
)
request
.
setHeader
(
'content-type'
,
'text/plain; charset=UTF-8'
)
return
"Welcome to SockJS!
\n
"
sockjs-twisted-master/txsockjs/multiplex.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
twisted.internet.protocol
import
Protocol
,
Factory
from
twisted.protocols.policies
import
ProtocolWrapper
from
txsockjs.factory
import
SockJSResource
from
txsockjs
import
utils
class
BroadcastProtocol
(
Protocol
):
def
dataReceived
(
self
,
data
):
self
.
transport
.
broadcast
(
data
)
class
BroadcastFactory
(
Factory
):
protocol
=
BroadcastProtocol
class
MultiplexProxy
(
ProtocolWrapper
):
def
__init__
(
self
,
factory
,
wrappedProtocol
,
transport
,
topic
):
ProtocolWrapper
.
__init__
(
self
,
factory
,
wrappedProtocol
)
self
.
topic
=
topic
self
.
makeConnection
(
transport
)
def
write
(
self
,
data
):
self
.
transport
.
transport
.
write
(
","
.
join
([
"msg"
,
self
.
topic
,
data
]))
def
writeSequence
(
self
,
data
):
for
d
in
data
:
self
.
write
(
d
)
def
broadcast
(
self
,
data
):
self
.
factory
.
broadcast
(
self
.
topic
,
data
)
def
loseConnection
(
self
):
self
.
transport
.
transport
.
write
(
","
.
join
([
"uns"
,
self
.
topic
]))
class
MultiplexProtocol
(
Protocol
):
def
connectionMade
(
self
):
self
.
factory
.
_connections
[
self
]
=
{}
def
dataReceived
(
self
,
message
):
type
,
chaff
,
topic
=
message
.
partition
(
","
)
if
","
in
topic
:
topic
,
chaff
,
payload
=
topic
.
partition
(
","
)
if
type
==
"sub"
:
self
.
factory
.
subscribe
(
self
,
topic
)
elif
type
==
"msg"
:
self
.
factory
.
handleMessage
(
self
,
topic
,
payload
)
elif
type
==
"uns"
:
self
.
factory
.
unsubscribe
(
self
,
topic
)
def
connectionLost
(
self
,
reason
=
None
):
for
conn
in
list
(
self
.
factory
.
_connections
[
self
]
.
values
()):
conn
.
connectionLost
(
reason
)
del
self
.
factory
.
_connections
[
self
]
class
MultiplexFactory
(
Factory
):
protocol
=
MultiplexProtocol
def
__init__
(
self
,
resource
):
self
.
_resource
=
resource
self
.
_topics
=
{}
self
.
_connections
=
{}
def
addFactory
(
self
,
name
,
factory
):
self
.
_topics
[
name
]
=
factory
def
broadcast
(
self
,
name
,
message
):
targets
=
[]
message
=
","
.
join
([
"msg"
,
name
,
message
])
for
p
,
topics
in
list
(
self
.
_connections
.
items
()):
if
name
in
topics
:
targets
.
append
(
p
)
utils
.
broadcast
(
message
,
targets
)
def
removeFactory
(
self
,
name
,
factory
):
del
self
.
_topics
[
name
]
def
subscribe
(
self
,
p
,
name
):
if
name
not
in
self
.
_topics
:
return
self
.
_connections
[
p
][
name
]
=
MultiplexProxy
(
self
,
self
.
_topics
[
name
]
.
buildProtocol
(
p
.
transport
.
getPeer
()),
p
,
name
)
def
handleMessage
(
self
,
p
,
name
,
message
):
if
p
not
in
self
.
_connections
:
return
if
name
not
in
self
.
_connections
[
p
]:
return
self
.
_connections
[
p
][
name
]
.
dataReceived
(
message
)
def
unsubscribe
(
self
,
p
,
name
):
if
p
not
in
self
.
_connections
:
return
if
name
not
in
self
.
_connections
[
p
]:
return
self
.
_connections
[
p
][
name
]
.
connectionLost
(
None
)
del
self
.
_connections
[
p
][
name
]
def
registerProtocol
(
self
,
p
):
pass
def
unregisterProtocol
(
self
,
p
):
pass
class
PubSubFactory
(
MultiplexFactory
):
broadcastFactory
=
BroadcastFactory
()
def
subscribe
(
self
,
p
,
name
):
if
name
not
in
self
.
_topics
:
self
.
_topics
[
name
]
=
self
.
broadcastFactory
MultiplexFactory
.
subscribe
(
self
,
p
,
name
)
class
SockJSMultiplexResource
(
SockJSResource
):
def
__init__
(
self
,
options
=
None
):
SockJSResource
.
__init__
(
self
,
MultiplexFactory
(
self
),
options
)
def
addFactory
(
self
,
name
,
factory
):
return
self
.
_factory
.
addFactory
(
name
,
factory
)
def
broadcast
(
self
,
name
,
message
):
return
self
.
_factory
.
broadcast
(
name
,
message
)
def
removeFactory
(
self
,
name
):
return
self
.
_factory
.
removeFactory
(
name
)
class
SockJSPubSubResource
(
SockJSMultiplexResource
):
def
__init__
(
self
,
options
=
None
):
SockJSResource
.
__init__
(
self
,
PubSubFactory
(
self
),
options
)
sockjs-twisted-master/txsockjs/multiplex.py.bak
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from twisted.internet.protocol import Protocol, Factory
from twisted.protocols.policies import ProtocolWrapper
from txsockjs.factory import SockJSResource
from txsockjs import utils
class BroadcastProtocol(Protocol):
def dataReceived(self, data):
self.transport.broadcast(data)
class BroadcastFactory(Factory):
protocol = BroadcastProtocol
class MultiplexProxy(ProtocolWrapper):
def __init__(self, factory, wrappedProtocol, transport, topic):
ProtocolWrapper.__init__(self, factory, wrappedProtocol)
self.topic = topic
self.makeConnection(transport)
def write(self, data):
self.transport.transport.write(",".join(["msg", self.topic, data]))
def writeSequence(self, data):
for d in data:
self.write(d)
def broadcast(self, data):
self.factory.broadcast(self.topic, data)
def loseConnection(self):
self.transport.transport.write(",".join(["uns", self.topic]))
class MultiplexProtocol(Protocol):
def connectionMade(self):
self.factory._connections[self] = {}
def dataReceived(self, message):
type, chaff, topic = message.partition(",")
if "," in topic:
topic, chaff, payload = topic.partition(",")
if type == "sub":
self.factory.subscribe(self, topic)
elif type == "msg":
self.factory.handleMessage(self, topic, payload)
elif type == "uns":
self.factory.unsubscribe(self, topic)
def connectionLost(self, reason=None):
for conn in self.factory._connections[self].values():
conn.connectionLost(reason)
del self.factory._connections[self]
class MultiplexFactory(Factory):
protocol = MultiplexProtocol
def __init__(self, resource):
self._resource = resource
self._topics = {}
self._connections = {}
def addFactory(self, name, factory):
self._topics[name] = factory
def broadcast(self, name, message):
targets = []
message = ",".join(["msg", name, message])
for p, topics in self._connections.items():
if name in topics:
targets.append(p)
utils.broadcast(message, targets)
def removeFactory(self, name, factory):
del self._topics[name]
def subscribe(self, p, name):
if name not in self._topics:
return
self._connections[p][name] = MultiplexProxy(self, self._topics[name].buildProtocol(p.transport.getPeer()), p, name)
def handleMessage(self, p, name, message):
if p not in self._connections:
return
if name not in self._connections[p]:
return
self._connections[p][name].dataReceived(message)
def unsubscribe(self, p, name):
if p not in self._connections:
return
if name not in self._connections[p]:
return
self._connections[p][name].connectionLost(None)
del self._connections[p][name]
def registerProtocol(self, p):
pass
def unregisterProtocol(self, p):
pass
class PubSubFactory(MultiplexFactory):
broadcastFactory = BroadcastFactory()
def subscribe(self, p, name):
if name not in self._topics:
self._topics[name] = self.broadcastFactory
MultiplexFactory.subscribe(self, p, name)
class SockJSMultiplexResource(SockJSResource):
def __init__(self, options=None):
SockJSResource.__init__(self, MultiplexFactory(self), options)
def addFactory(self, name, factory):
return self._factory.addFactory(name, factory)
def broadcast(self, name, message):
return self._factory.broadcast(name, message)
def removeFactory(self, name):
return self._factory.removeFactory(name)
class SockJSPubSubResource(SockJSMultiplexResource):
def __init__(self, options=None):
SockJSResource.__init__(self, PubSubFactory(self), options)
sockjs-twisted-master/txsockjs/oldwebsockets.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
twisted.internet
import
reactor
# ============================================================================================================
# === THIS IS A MODIFIED COPY OF twisted.web.websockets TO BE COMPATIBLE WITH OLDER VERSIONS OF WEBSOCKETS ===
# === IT WILL BE REMOVED WHEN SOCKJS STOPS NEEDING TO SUPPORT OLD, DUMB VERSIONS OF WEBSOCKETS ===
# ============================================================================================================
# Copyright (c) 2011-2012 Oregon State University Open Source Lab
# 2011-2012 Corbin Simpson
# Twisted Matrix Laboratories
#
# See LICENSE for details.
"""
The WebSockets protocol (RFC 6455), provided as a resource which wraps a
factory.
"""
__all__
=
(
"OldWebSocketsResource"
,)
from
base64
import
b64encode
,
b64decode
from
hashlib
import
md5
,
sha1
from
struct
import
pack
,
unpack
from
string
import
digits
from
zope.interface
import
implementer
from
twisted.protocols.policies
import
ProtocolWrapper
,
WrappingFactory
from
twisted.python
import
log
from
twisted.python.constants
import
NamedConstant
,
Names
from
twisted.web.resource
import
IResource
,
NoResource
from
twisted.web.server
import
NOT_DONE_YET
class
_WSException
(
Exception
):
"""
Internal exception for control flow inside the WebSockets frame parser.
"""
class
_CONTROLS
(
Names
):
"""
Control frame specifiers.
"""
NORMAL
=
NamedConstant
()
CLOSE
=
NamedConstant
()
PING
=
NamedConstant
()
PONG
=
NamedConstant
()
_opcode_types
=
{
0x0
:
_CONTROLS
.
NORMAL
,
0x1
:
_CONTROLS
.
NORMAL
,
0x2
:
_CONTROLS
.
NORMAL
,
0x8
:
_CONTROLS
.
CLOSE
,
0x9
:
_CONTROLS
.
PING
,
0xa
:
_CONTROLS
.
PONG
,
}
_opcode_for_type
=
{
_CONTROLS
.
NORMAL
:
0x1
,
_CONTROLS
.
CLOSE
:
0x8
,
_CONTROLS
.
PING
:
0x9
,
_CONTROLS
.
PONG
:
0xa
,
}
_encoders
=
{
"base64"
:
b64encode
,
}
_decoders
=
{
"base64"
:
b64decode
,
}
_WS_GUID
=
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
def
_isHixie75
(
request
):
return
request
.
getHeader
(
"Sec-WebSocket-Version"
)
is
None
and
\
request
.
getHeader
(
"Sec-WebSocket-Key1"
)
is
None
and
\
request
.
getHeader
(
"Sec-WebSocket-Key2"
)
is
None
def
_isHybi00
(
request
):
return
request
.
getHeader
(
"Sec-WebSocket-Key1"
)
is
not
None
and
\
request
.
getHeader
(
"Sec-WebSocket-Key2"
)
is
not
None
def
_challenge
(
key1
,
key2
,
challenge
):
first
=
int
(
""
.
join
(
i
for
i
in
key1
if
i
in
digits
))
/
key1
.
count
(
" "
)
second
=
int
(
""
.
join
(
i
for
i
in
key2
if
i
in
digits
))
/
key2
.
count
(
" "
)
nonce
=
md5
(
pack
(
">II8s"
,
first
,
second
,
challenge
))
.
digest
()
return
nonce
def
_makeAccept
(
key
):
return
sha1
(
"
%
s
%
s"
%
(
key
,
_WS_GUID
))
.
digest
()
.
encode
(
"base64"
)
.
strip
()
def
_mask
(
buf
,
key
):
key
=
[
ord
(
i
)
for
i
in
key
]
buf
=
list
(
buf
)
for
i
,
char
in
enumerate
(
buf
):
buf
[
i
]
=
chr
(
ord
(
char
)
^
key
[
i
%
4
])
return
""
.
join
(
buf
)
def
_makeFrame
(
buf
,
old
,
_opcode
=
_CONTROLS
.
NORMAL
):
if
old
:
if
_opcode
!=
_CONTROLS
.
NORMAL
:
return
None
return
"
\x00
{}
\xFF
"
.
format
(
buf
)
else
:
bufferLength
=
len
(
buf
)
if
bufferLength
>
0xffff
:
length
=
"
\x7f
%
s"
%
pack
(
">Q"
,
bufferLength
)
elif
bufferLength
>
0x7d
:
length
=
"
\x7e
%
s"
%
pack
(
">H"
,
bufferLength
)
else
:
length
=
chr
(
bufferLength
)
# Always make a normal packet.
header
=
chr
(
0x80
|
_opcode_for_type
[
_opcode
])
frame
=
"
%
s
%
s
%
s"
%
(
header
,
length
,
buf
)
return
frame
def
_parseFrames
(
buf
,
old
):
if
old
:
start
=
buf
.
find
(
"
\x00
"
)
tail
=
0
frames
=
[]
while
start
!=
-
1
:
end
=
buf
.
find
(
"
\xFF
"
,
start
+
1
)
if
end
==
-
1
:
break
frame
=
buf
[
start
+
1
:
end
]
frames
.
append
((
_CONTROLS
.
NORMAL
,
frame
))
tail
=
end
+
1
start
=
buf
.
find
(
"
\x00
"
,
tail
)
return
frames
,
buf
[
tail
:]
else
:
start
=
0
frames
=
[]
while
True
:
if
len
(
buf
)
-
start
<
2
:
break
header
=
ord
(
buf
[
start
])
if
header
&
0x70
:
raise
_WSException
(
"Reserved flag in frame (
%
d)"
%
header
)
opcode
=
header
&
0xf
try
:
opcode
=
_opcode_types
[
opcode
]
except
KeyError
:
raise
_WSException
(
"Unknown opcode
%
d in frame"
%
opcode
)
length
=
ord
(
buf
[
start
+
1
])
masked
=
length
&
0x80
length
&=
0x7f
offset
=
2
if
length
==
0x7e
:
if
len
(
buf
)
-
start
<
4
:
break
length
=
buf
[
start
+
2
:
start
+
4
]
length
=
unpack
(
">H"
,
length
)[
0
]
offset
+=
2
elif
length
==
0x7f
:
if
len
(
buf
)
-
start
<
10
:
break
length
=
buf
[
start
+
2
:
start
+
10
]
length
=
unpack
(
">Q"
,
length
)[
0
]
offset
+=
8
if
masked
:
if
len
(
buf
)
-
(
start
+
offset
)
<
4
:
break
key
=
buf
[
start
+
offset
:
start
+
offset
+
4
]
offset
+=
4
if
len
(
buf
)
-
(
start
+
offset
)
<
length
:
break
data
=
buf
[
start
+
offset
:
start
+
offset
+
length
]
if
masked
:
data
=
_mask
(
data
,
key
)
if
opcode
==
_CONTROLS
.
CLOSE
:
if
len
(
data
)
>=
2
:
data
=
unpack
(
">H"
,
data
[:
2
])[
0
],
data
[
2
:]
else
:
data
=
1000
,
"No reason given"
frames
.
append
((
opcode
,
data
))
start
+=
offset
+
length
return
frames
,
buf
[
start
:]
class
_WebSocketsProtocol
(
ProtocolWrapper
):
buf
=
""
codec
=
None
challenge
=
None
connected
=
False
pending_dc
=
False
def
__init__
(
self
,
*
args
,
**
kwargs
):
ProtocolWrapper
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.
_pending_frames
=
[]
def
connectionMade
(
self
):
connected
=
True
if
not
self
.
challenge
:
ProtocolWrapper
.
connectionMade
(
self
)
log
.
msg
(
"Opening connection with
%
s"
%
self
.
transport
.
getPeer
())
def
parseFrames
(
self
):
try
:
frames
,
self
.
buf
=
_parseFrames
(
self
.
buf
,
self
.
old
)
except
_WSException
:
log
.
err
()
self
.
loseConnection
()
return
for
frame
in
frames
:
opcode
,
data
=
frame
if
opcode
==
_CONTROLS
.
NORMAL
:
if
self
.
codec
:
data
=
_decoders
[
self
.
codec
](
data
)
ProtocolWrapper
.
dataReceived
(
self
,
data
)
elif
opcode
==
_CONTROLS
.
CLOSE
:
reason
,
text
=
data
log
.
msg
(
"Closing connection:
%
r (
%
d)"
%
(
text
,
reason
))
self
.
transport
.
loseConnection
()
return
elif
opcode
==
_CONTROLS
.
PING
:
self
.
transport
.
write
(
_makeFrame
(
data
,
self
.
old
,
_opcode
=
_CONTROLS
.
PONG
))
def
sendFrames
(
self
):
# Don't send anything before the challenge
if
self
.
challenge
:
return
for
frame
in
self
.
_pending_frames
:
# Encode the frame before sending it.
if
self
.
codec
:
frame
=
_encoders
[
self
.
codec
](
frame
)
packet
=
_makeFrame
(
frame
,
self
.
old
)
self
.
transport
.
write
(
packet
)
self
.
_pending_frames
=
[]
def
dataReceived
(
self
,
data
):
self
.
buf
+=
data
if
self
.
challenge
:
if
len
(
self
.
buf
)
>=
8
:
challenge
,
self
.
buf
=
self
.
buf
[:
8
],
self
.
buf
[
8
:]
nonce
=
self
.
challenge
(
challenge
)
self
.
transport
.
write
(
nonce
)
self
.
challenge
=
None
if
self
.
connected
:
ProtocolWrapper
.
connectionMade
(
self
)
self
.
dataReceived
(
""
)
# Kick it off proper
if
self
.
pending_dc
:
self
.
pending_dc
=
False
self
.
loseConnection
()
else
:
self
.
parseFrames
()
if
self
.
_pending_frames
:
self
.
sendFrames
()
def
write
(
self
,
data
):
self
.
_pending_frames
.
append
(
data
)
self
.
sendFrames
()
def
writeSequence
(
self
,
data
):
self
.
_pending_frames
.
extend
(
data
)
self
.
sendFrames
()
def
loseConnection
(
self
):
if
not
self
.
disconnecting
:
if
not
self
.
challenge
:
self
.
disconnecting
=
True
frame
=
_makeFrame
(
""
,
self
.
old
,
_opcode
=
_CONTROLS
.
CLOSE
)
if
frame
:
self
.
transport
.
write
(
frame
)
else
:
self
.
transport
.
loseConnection
()
else
:
self
.
pending_dc
=
True
class
_WebSocketsFactory
(
WrappingFactory
):
protocol
=
_WebSocketsProtocol
@
implementer
(
IResource
)
class
OldWebSocketsResource
(
object
):
isLeaf
=
True
def
__init__
(
self
,
factory
):
self
.
__factory
=
_WebSocketsFactory
(
factory
)
def
getChildWithDefault
(
self
,
name
,
request
):
return
NoResource
(
"No such child resource."
)
def
putChild
(
self
,
path
,
child
):
pass
def
render
(
self
,
request
):
"""
Render a request.
We're not actually rendering a request. We are secretly going to
handle a WebSockets connection instead.
"""
# If we fail at all, we're gonna fail with 400 and no response.
failed
=
False
if
request
.
method
!=
"GET"
:
failed
=
True
upgrade
=
request
.
getHeader
(
"Upgrade"
)
if
upgrade
is
None
or
"websocket"
not
in
upgrade
.
lower
():
failed
=
True
connection
=
request
.
getHeader
(
"Connection"
)
if
connection
is
None
or
"upgrade"
not
in
connection
.
lower
():
failed
=
True
codec
=
request
.
getHeader
(
"Sec-WebSocket-Protocol"
)
or
request
.
getHeader
(
"WebSocket-Protocol"
)
if
codec
:
if
codec
not
in
_encoders
or
codec
not
in
_decoders
:
log
.
msg
(
"Codec
%
s is not implemented"
%
codec
)
failed
=
True
## This is a big mess of setting various headers based on which version we are
## And determining whether to use "old frames" or "new frames"
if
_isHixie75
(
request
)
or
_isHybi00
(
request
):
old
=
True
host
=
request
.
getHeader
(
"Host"
)
or
"example.com"
origin
=
request
.
getHeader
(
"Origin"
)
or
"http://example.com"
location
=
"{}://{}{}"
.
format
(
"wss"
if
request
.
isSecure
()
else
"ws"
,
host
,
request
.
path
)
if
_isHixie75
(
request
):
request
.
setHeader
(
"WebSocket-Origin"
,
origin
)
request
.
setHeader
(
"WebSocket-Location"
,
location
)
if
codec
:
request
.
setHeader
(
"WebSocket-Protocol"
,
codec
)
else
:
request
.
setHeader
(
"Sec-WebSocket-Origin"
,
origin
)
request
.
setHeader
(
"Sec-WebSocket-Location"
,
location
)
if
codec
:
request
.
setHeader
(
"Sec-WebSocket-Protocol"
,
codec
)
else
:
old
=
False
key
=
request
.
getHeader
(
"Sec-WebSocket-Key"
)
if
key
is
None
:
failed
=
True
version
=
request
.
getHeader
(
"Sec-WebSocket-Version"
)
if
version
not
in
(
"7"
,
"8"
,
"13"
):
failed
=
True
request
.
setHeader
(
"Sec-WebSocket-Version"
,
"13"
)
if
not
failed
:
request
.
setHeader
(
"Sec-WebSocket-Version"
,
version
)
request
.
setHeader
(
"Sec-WebSocket-Accept"
,
_makeAccept
(
key
))
if
codec
:
request
.
setHeader
(
"Sec-WebSocket-Protocol"
,
codec
)
if
failed
:
request
.
setResponseCode
(
400
)
return
""
# We are going to finish this handshake. We will return a valid status code.
request
.
setResponseCode
(
101
)
request
.
setHeader
(
"Upgrade"
,
"WebSocket"
)
request
.
setHeader
(
"Connection"
,
"Upgrade"
)
# Create the protocol. This could fail, in which case we deliver an
# error status. Status 502 was decreed by glyph; blame him.
protocol
=
self
.
__factory
.
buildProtocol
(
request
.
transport
.
getPeer
())
if
not
protocol
:
request
.
setResponseCode
(
502
)
return
""
protocol
.
old
=
old
if
_isHybi00
(
request
):
protocol
.
challenge
=
lambda
x
:
_challenge
(
request
.
getHeader
(
"Sec-WebSocket-Key1"
),
request
.
getHeader
(
"Sec-WebSocket-Key2"
),
x
)
if
codec
:
protocol
.
codec
=
codec
## This must be first, since makeConnection will butcher our headers otherwise
request
.
write
(
""
)
## Then we wire it into the protocol wrapper
transport
,
request
.
transport
=
request
.
transport
,
None
transport
.
protocol
=
protocol
protocol
.
makeConnection
(
transport
)
## Copy the buffer
protocol
.
dataReceived
(
request
.
channel
.
clearLineBuffer
())
return
NOT_DONE_YET
sockjs-twisted-master/txsockjs/protocols/__init__.py
0 → 100644
View file @
85566b3b
sockjs-twisted-master/txsockjs/protocols/base.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
zope.interface
import
directlyProvides
,
providedBy
from
twisted.internet
import
reactor
,
protocol
from
twisted.web
import
resource
,
server
,
http
from
twisted.protocols.policies
import
ProtocolWrapper
from
txsockjs.utils
import
normalize
import
json
class
StubResource
(
resource
.
Resource
,
ProtocolWrapper
):
isLeaf
=
True
def
__init__
(
self
,
parent
,
session
):
resource
.
Resource
.
__init__
(
self
)
ProtocolWrapper
.
__init__
(
self
,
None
,
session
)
self
.
parent
=
parent
self
.
session
=
session
self
.
putChild
(
""
,
self
)
def
render_OPTIONS
(
self
,
request
):
method
=
"POST"
if
getattr
(
self
,
"render_POST"
,
None
)
is
not
None
else
"GET"
request
.
setResponseCode
(
http
.
NO_CONTENT
)
self
.
parent
.
setBaseHeaders
(
request
,
False
)
request
.
setHeader
(
'Cache-Control'
,
'public, max-age=31536000'
)
request
.
setHeader
(
'access-control-max-age'
,
'31536000'
)
request
.
setHeader
(
'Expires'
,
'Fri, 01 Jan 2500 00:00:00 GMT'
)
#Get a new library by then
request
.
setHeader
(
'Access-Control-Allow-Methods'
,
'OPTIONS, {}'
.
format
(
method
))
# Hardcoding this may be bad?
return
""
def
connect
(
self
,
request
):
if
self
.
session
.
attached
:
return
'c[2010,"Another connection still open"]
\n
'
self
.
request
=
request
directlyProvides
(
self
,
providedBy
(
request
.
transport
))
protocol
.
Protocol
.
makeConnection
(
self
,
request
.
transport
)
self
.
session
.
makeConnection
(
self
)
request
.
notifyFinish
()
.
addErrback
(
self
.
connectionLost
)
return
server
.
NOT_DONE_YET
def
disconnect
(
self
):
self
.
request
.
finish
()
self
.
session
.
transportLeft
()
def
loseConnection
(
self
):
self
.
request
.
finish
()
self
.
session
.
transportLeft
()
def
connectionLost
(
self
,
reason
=
None
):
self
.
wrappedProtocol
.
connectionLost
(
reason
)
class
Stub
(
ProtocolWrapper
):
def
__init__
(
self
,
parent
,
session
):
self
.
parent
=
parent
self
.
session
=
session
self
.
pending
=
[]
self
.
buffer
=
[]
self
.
connecting
=
True
self
.
disconnecting
=
False
self
.
attached
=
False
self
.
transport
=
None
# Upstream (SockJS)
self
.
protocol
=
None
# Downstream (Wrapped Factory)
self
.
peer
=
None
self
.
host
=
None
self
.
timeout
=
reactor
.
callLater
(
self
.
parent
.
_options
[
'timeout'
],
self
.
disconnect
)
#reactor.callLater(self.parent._options['heartbeat'], self.heartbeat)
def
makeConnection
(
self
,
transport
):
directlyProvides
(
self
,
providedBy
(
transport
))
protocol
.
Protocol
.
makeConnection
(
self
,
transport
)
self
.
attached
=
True
self
.
peer
=
self
.
transport
.
getPeer
()
self
.
host
=
self
.
transport
.
getHost
()
if
self
.
timeout
.
active
():
self
.
timeout
.
cancel
()
if
self
.
protocol
is
None
:
self
.
protocol
=
self
.
parent
.
_factory
.
buildProtocol
(
self
.
transport
.
getPeer
())
self
.
protocol
.
makeConnection
(
self
)
self
.
sendData
()
def
loseConnection
(
self
):
self
.
disconnecting
=
True
self
.
sendData
()
def
connectionLost
(
self
,
reason
=
None
):
if
self
.
attached
:
self
.
disconnecting
=
True
self
.
transport
=
None
self
.
attached
=
False
self
.
disconnect
()
def
heartbeat
(
self
):
self
.
pending
.
append
(
'h'
)
reactor
.
callLater
(
self
.
parent
.
_options
[
'heartbeat'
],
self
.
heartbeat
)
def
disconnect
(
self
):
if
self
.
protocol
:
self
.
protocol
.
connectionLost
(
None
)
del
self
.
parent
.
_sessions
[
self
.
session
]
def
transportLeft
(
self
):
self
.
transport
=
None
self
.
attached
=
False
self
.
timeout
=
reactor
.
callLater
(
self
.
parent
.
_options
[
'timeout'
],
self
.
disconnect
)
def
write
(
self
,
data
):
data
=
normalize
(
data
,
self
.
parent
.
_options
[
'encoding'
])
self
.
buffer
.
append
(
data
)
self
.
sendData
()
def
writeSequence
(
self
,
data
):
for
p
in
data
:
p
=
normalize
(
p
,
self
.
parent
.
_options
[
'encoding'
])
self
.
buffer
.
extend
(
data
)
self
.
sendData
()
def
writeRaw
(
self
,
data
):
self
.
flushData
()
self
.
pending
.
append
(
data
)
self
.
sendData
()
def
sendData
(
self
):
if
self
.
transport
:
if
self
.
connecting
:
self
.
transport
.
write
(
'o'
)
self
.
connecting
=
False
self
.
sendData
()
elif
self
.
disconnecting
:
self
.
transport
.
write
(
'c[3000,"Go away!"]'
)
if
self
.
transport
:
self
.
transport
.
loseConnection
()
else
:
self
.
flushData
()
if
self
.
pending
:
data
=
list
(
self
.
pending
)
self
.
pending
=
[]
self
.
transport
.
writeSequence
(
data
)
def
flushData
(
self
):
if
self
.
buffer
:
data
=
'a{}'
.
format
(
json
.
dumps
(
self
.
buffer
,
separators
=
(
','
,
':'
)))
self
.
buffer
=
[]
self
.
pending
.
append
(
data
)
def
requeue
(
self
,
data
):
data
.
extend
(
self
.
pending
)
self
.
pending
=
data
def
dataReceived
(
self
,
data
):
if
self
.
timeout
.
active
():
self
.
timeout
.
reset
(
5
)
if
data
==
''
:
return
"Payload expected."
try
:
packets
=
json
.
loads
(
data
)
for
p
in
packets
:
p
=
normalize
(
p
,
self
.
parent
.
_options
[
'encoding'
])
if
self
.
protocol
:
self
.
protocol
.
dataReceived
(
p
)
return
None
except
ValueError
:
return
"Broken JSON encoding."
def
getPeer
(
self
):
return
self
.
peer
def
getHost
(
self
):
return
self
.
host
def
registerProducer
(
self
,
producer
,
streaming
):
if
self
.
transport
:
self
.
transport
.
registerProducer
(
producer
,
streaming
)
def
unregisterProducer
(
self
):
if
self
.
transport
:
self
.
transport
.
unregisterProducer
()
def
stopConsuming
(
self
):
if
self
.
transport
:
self
.
transport
.
stopConsuming
()
sockjs-twisted-master/txsockjs/protocols/eventsource.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
txsockjs.protocols.base
import
StubResource
class
EventSource
(
StubResource
):
sent
=
0
done
=
False
def
render_GET
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
)
request
.
setHeader
(
'content-type'
,
'text/event-stream; charset=UTF-8'
)
request
.
write
(
"
\r\n
"
)
return
self
.
connect
(
request
)
def
write
(
self
,
data
):
if
self
.
done
:
self
.
session
.
requeue
([
data
])
return
packet
=
"data: {}
\r\n\r\n
"
.
format
(
data
)
self
.
sent
+=
len
(
packet
)
self
.
request
.
write
(
packet
)
if
self
.
sent
>
self
.
parent
.
_options
[
'streaming_limit'
]:
self
.
done
=
True
self
.
disconnect
()
def
writeSequence
(
self
,
data
):
for
d
in
data
:
self
.
write
(
d
)
sockjs-twisted-master/txsockjs/protocols/htmlfile.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
twisted.web
import
http
from
txsockjs.protocols.base
import
StubResource
class
HTMLFile
(
StubResource
):
sent
=
0
done
=
False
def
render_GET
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
)
callback
=
request
.
args
.
get
(
'c'
,[
None
])[
0
]
if
callback
is
None
:
request
.
setResponseCode
(
http
.
INTERNAL_SERVER_ERROR
)
return
'"callback" parameter required'
request
.
setHeader
(
'content-type'
,
'text/html; charset=UTF-8'
)
request
.
write
(
r'''
<!doctype html>
<html><head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head><body><h2>Don't panic!</h2>
<script>
document.domain = document.domain;
var c = parent.{};
c.start();
function p(d) {{c.message(d);}};
window.onload = function() {{c.stop();}};
</script>{}
'''
.
format
(
callback
,
' '
*
1024
))
return
self
.
connect
(
request
)
def
write
(
self
,
data
):
if
self
.
done
:
self
.
session
.
requeue
([
data
])
return
packet
=
"<script>
\n
p(
\"
{}
\"
);
\n
</script>
\r\n
"
.
format
(
data
.
replace
(
'
\\
'
,
'
\\\\
'
)
.
replace
(
'"'
,
'
\\
"'
))
self
.
sent
+=
len
(
packet
)
self
.
request
.
write
(
packet
)
if
self
.
sent
>
self
.
parent
.
_options
[
'streaming_limit'
]:
self
.
done
=
True
self
.
disconnect
()
def
writeSequence
(
self
,
data
):
for
d
in
data
:
self
.
write
(
d
)
sockjs-twisted-master/txsockjs/protocols/jsonp.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
twisted.web
import
http
from
txsockjs.protocols.base
import
StubResource
class
JSONP
(
StubResource
):
written
=
False
def
render_GET
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
)
self
.
callback
=
request
.
args
.
get
(
'c'
,[
None
])[
0
]
if
self
.
callback
is
None
:
request
.
setResponseCode
(
http
.
INTERNAL_SERVER_ERROR
)
return
'"callback" parameter required'
request
.
setHeader
(
'content-type'
,
'application/javascript; charset=UTF-8'
)
return
self
.
connect
(
request
)
def
write
(
self
,
data
):
if
self
.
written
:
self
.
session
.
requeue
([
data
])
return
self
.
written
=
True
self
.
request
.
write
(
"{}(
\"
{}
\"
);
\r\n
"
.
format
(
self
.
callback
,
data
.
replace
(
'
\\
'
,
'
\\\\
'
)
.
replace
(
'"'
,
'
\\
"'
)))
self
.
disconnect
()
def
writeSequence
(
self
,
data
):
self
.
write
(
data
.
pop
(
0
))
self
.
session
.
requeue
(
data
)
class
JSONPSend
(
StubResource
):
def
render_POST
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
)
request
.
setHeader
(
'content-type'
,
'text/plain; charset=UTF-8'
)
urlencoded
=
request
.
getHeader
(
"Content-Type"
)
==
'application/x-www-form-urlencoded'
data
=
request
.
args
.
get
(
'd'
,
[
''
])[
0
]
if
urlencoded
else
request
.
content
.
read
()
ret
=
self
.
session
.
dataReceived
(
data
)
if
not
ret
:
return
"ok"
request
.
setResponseCode
(
http
.
INTERNAL_SERVER_ERROR
)
return
"{}
\r\n
"
.
format
(
ret
)
sockjs-twisted-master/txsockjs/protocols/static.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
import
json
,
random
from
twisted.web
import
resource
,
http
class
Info
(
resource
.
Resource
):
def
render_GET
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
,
False
)
request
.
setHeader
(
'content-type'
,
'application/json; charset=UTF-8'
)
data
=
{
'websocket'
:
self
.
parent
.
_options
[
'websocket'
],
'cookie_needed'
:
self
.
parent
.
_options
[
'cookie_needed'
],
'origins'
:
[
'*:*'
],
'entropy'
:
random
.
randint
(
0
,
2
**
32
-
1
)
}
return
json
.
dumps
(
data
)
def
render_OPTIONS
(
self
,
request
):
request
.
setResponseCode
(
http
.
NO_CONTENT
)
self
.
parent
.
setBaseHeaders
(
request
,
False
)
request
.
setHeader
(
'Cache-Control'
,
'public, max-age=31536000'
)
request
.
setHeader
(
'access-control-max-age'
,
'31536000'
)
request
.
setHeader
(
'Expires'
,
'Fri, 01 Jan 2500 00:00:00 GMT'
)
#Get a new library by then
request
.
setHeader
(
'Access-Control-Allow-Methods'
,
'OPTIONS, GET'
)
# Hardcoding this may be bad?
return
""
class
IFrame
(
resource
.
Resource
):
etag
=
'00000000-0000-0000-0000-000000000000'
def
render_GET
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
,
False
)
if
request
.
setETag
(
self
.
etag
):
request
.
setResponseCode
(
http
.
NOT_MODIFIED
)
return
""
request
.
setHeader
(
'content-type'
,
'text/html; charset=UTF-8'
)
request
.
setHeader
(
'Cache-Control'
,
'public, max-age=31536000'
)
request
.
setHeader
(
'access-control-max-age'
,
'31536000'
)
request
.
setHeader
(
'Expires'
,
'Fri, 01 Jan 2500 00:00:00 GMT'
)
#Get a new library by then
return
'''
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<script>
document.domain = document.domain;
_sockjs_onload = function(){{SockJS.bootstrap_iframe();}};
</script>
<script src="{}"></script>
</head>
<body>
<h2>Don't panic!</h2>
<p>This is a SockJS hidden iframe. It's used for cross domain magic.</p>
</body>
</html>'''
.
format
(
self
.
parent
.
_options
[
"sockjs_url"
])
sockjs-twisted-master/txsockjs/protocols/websocket.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
try
:
from
twisted.web.websockets
import
WebSocketsResource
except
ImportError
:
from
txsockjs.websockets
import
WebSocketsResource
from
zope.interface
import
directlyProvides
,
providedBy
from
twisted.internet.protocol
import
Protocol
from
twisted.protocols.policies
import
WrappingFactory
,
ProtocolWrapper
from
twisted.web.server
import
NOT_DONE_YET
from
txsockjs.oldwebsockets
import
OldWebSocketsResource
from
txsockjs.utils
import
normalize
import
json
class
JsonProtocol
(
ProtocolWrapper
):
def
makeConnection
(
self
,
transport
):
directlyProvides
(
self
,
providedBy
(
transport
))
Protocol
.
makeConnection
(
self
,
transport
)
self
.
transport
.
write
(
"o"
)
self
.
factory
.
registerProtocol
(
self
)
self
.
wrappedProtocol
.
makeConnection
(
self
)
def
write
(
self
,
data
):
self
.
writeSequence
([
data
])
def
writeSequence
(
self
,
data
):
for
p
in
data
:
p
=
normalize
(
p
,
self
.
factory
.
parent
.
_options
[
'encoding'
])
self
.
transport
.
write
(
"a{}"
.
format
(
json
.
dumps
(
data
,
separators
=
(
','
,
':'
))))
def
writeRaw
(
self
,
data
):
self
.
transport
.
write
(
data
)
def
loseConnection
(
self
):
self
.
transport
.
write
(
'c[3000,"Go away!"]'
)
ProtocolWrapper
.
loseConnection
(
self
)
def
dataReceived
(
self
,
data
):
if
not
data
:
return
try
:
dat
=
json
.
loads
(
data
)
except
ValueError
:
self
.
transport
.
loseConnection
()
else
:
for
d
in
dat
:
ProtocolWrapper
.
dataReceived
(
self
,
d
)
class
JsonFactory
(
WrappingFactory
):
protocol
=
JsonProtocol
class
RawWebSocket
(
WebSocketsResource
,
OldWebSocketsResource
):
def
__init__
(
self
):
self
.
_factory
=
None
def
_makeFactory
(
self
):
WebSocketsResource
.
__init__
(
self
,
self
.
parent
.
_factory
)
OldWebSocketsResource
.
__init__
(
self
,
self
.
parent
.
_factory
)
def
render
(
self
,
request
):
# Get around .parent limitation
if
self
.
_factory
is
None
:
self
.
_makeFactory
()
# Override handling of invalid methods, returning 400 makes SockJS mad
if
request
.
method
!=
'GET'
:
request
.
setResponseCode
(
405
)
request
.
defaultContentType
=
None
# SockJS wants this gone
request
.
setHeader
(
'Allow'
,
'GET'
)
return
""
# Override handling of lack of headers, again SockJS requires non-RFC stuff
upgrade
=
request
.
getHeader
(
"Upgrade"
)
if
upgrade
is
None
or
"websocket"
not
in
upgrade
.
lower
():
request
.
setResponseCode
(
400
)
return
'Can "Upgrade" only to "WebSocket".'
connection
=
request
.
getHeader
(
"Connection"
)
if
connection
is
None
or
"upgrade"
not
in
connection
.
lower
():
request
.
setResponseCode
(
400
)
return
'"Connection" must be "Upgrade".'
# Defer to inherited methods
ret
=
WebSocketsResource
.
render
(
self
,
request
)
# For RFC versions of websockets
if
ret
is
NOT_DONE_YET
:
return
ret
return
OldWebSocketsResource
.
render
(
self
,
request
)
# For non-RFC versions of websockets
class
WebSocket
(
RawWebSocket
):
def
_makeFactory
(
self
):
f
=
JsonFactory
(
self
.
parent
.
_factory
)
f
.
parent
=
self
.
parent
WebSocketsResource
.
__init__
(
self
,
f
)
OldWebSocketsResource
.
__init__
(
self
,
f
)
sockjs-twisted-master/txsockjs/protocols/xhr.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
from
twisted.web
import
resource
,
http
from
txsockjs.protocols.base
import
StubResource
class
XHR
(
StubResource
):
written
=
False
def
render_POST
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
)
request
.
setHeader
(
'content-type'
,
'application/javascript; charset=UTF-8'
)
return
self
.
connect
(
request
)
def
write
(
self
,
data
):
if
self
.
written
:
self
.
session
.
requeue
([
data
])
return
self
.
written
=
True
self
.
request
.
write
(
"{}
\n
"
.
format
(
data
))
self
.
disconnect
()
def
writeSequence
(
self
,
data
):
if
not
self
.
written
:
self
.
write
(
data
.
pop
(
0
))
self
.
session
.
requeue
(
data
)
class
XHRSend
(
StubResource
):
def
render_POST
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
)
request
.
setResponseCode
(
http
.
NO_CONTENT
)
request
.
setHeader
(
'content-type'
,
'text/plain; charset=UTF-8'
)
ret
=
self
.
session
.
dataReceived
(
request
.
content
.
read
())
if
not
ret
:
return
""
request
.
setResponseCode
(
http
.
INTERNAL_SERVER_ERROR
)
return
"{}
\r\n
"
.
format
(
ret
)
class
XHRStream
(
StubResource
):
sent
=
0
done
=
False
def
render_POST
(
self
,
request
):
self
.
parent
.
setBaseHeaders
(
request
)
request
.
setHeader
(
'content-type'
,
'application/javascript; charset=UTF-8'
)
request
.
write
(
"{}
\n
"
.
format
(
'h'
*
2048
))
return
self
.
connect
(
request
)
def
write
(
self
,
data
):
if
self
.
done
:
self
.
session
.
requeue
([
data
])
return
packet
=
"{}
\n
"
.
format
(
data
)
self
.
sent
+=
len
(
packet
)
self
.
request
.
write
(
packet
)
if
self
.
sent
>
self
.
parent
.
_options
[
'streaming_limit'
]:
self
.
done
=
True
self
.
disconnect
()
def
writeSequence
(
self
,
data
):
for
d
in
data
:
self
.
write
(
d
)
sockjs-twisted-master/txsockjs/utils.py
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
def
normalize
(
s
,
encoding
):
if
not
isinstance
(
s
,
str
):
try
:
return
str
(
s
)
except
UnicodeEncodeError
:
return
str
(
s
)
.
encode
(
'utf-8'
,
'backslashreplace'
)
elif
isinstance
(
s
,
str
):
return
s
.
encode
(
'utf-8'
,
'backslashreplace'
)
else
:
if
s
.
decode
(
'utf-8'
,
'ignore'
)
.
encode
(
'utf-8'
,
'ignore'
)
==
s
:
# Ensure s is a valid UTF-8 string
return
s
else
:
# Otherwise assume it is Windows 1252
return
s
.
decode
(
encoding
,
'replace'
)
.
encode
(
'utf-8'
,
'backslashreplace'
)
def
broadcast
(
message
,
targets
,
encoding
=
"cp1252"
):
message
=
normalize
(
message
,
encoding
)
message
=
'a{}'
.
format
(
json
.
dumps
([
message
],
separators
=
(
','
,
':'
)))
for
t
in
targets
:
t
.
writeRaw
(
message
)
\ No newline at end of file
sockjs-twisted-master/txsockjs/utils.py.bak
0 → 100644
View file @
85566b3b
# Copyright (c) 2012, Christopher Gamble
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the Christopher Gamble nor the names of its
# contributors may be used to endorse or promote products derived
# from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
# OF THE POSSIBILITY OF SUCH DAMAGE.
def normalize(s, encoding):
if not isinstance(s, basestring):
try:
return str(s)
except UnicodeEncodeError:
return unicode(s).encode('utf-8','backslashreplace')
elif isinstance(s, unicode):
return s.encode('utf-8', 'backslashreplace')
else:
if s.decode('utf-8', 'ignore').encode('utf-8', 'ignore') == s: # Ensure s is a valid UTF-8 string
return s
else: # Otherwise assume it is Windows 1252
return s.decode(encoding, 'replace').encode('utf-8', 'backslashreplace')
def broadcast(message, targets, encoding="cp1252"):
message = normalize(message, encoding)
message = 'a{}'.format(json.dumps([message], separators=(',',':')))
for t in targets:
t.writeRaw(message)
\ No newline at end of file
sockjs-twisted-master/txsockjs/websockets.py
0 → 100644
View file @
85566b3b
# =====================================================================================
# === THIS IS A DIRECT COPY OF twisted.web.websockets AS IT IS STILL IN DEVELOPMENT ===
# === IT WILL BE REPLACED BY THE ACTUAL VERSION WHEN IT IS PUBLICLY AVAILABLE. ===
# =====================================================================================
# Copyright (c) 2011-2012 Oregon State University Open Source Lab
# 2011-2012 Corbin Simpson
# Twisted Matrix Laboratories
#
# See LICENSE for details.
"""
The WebSockets protocol (RFC 6455), provided as a resource which wraps a
factory.
"""
__all__
=
(
"WebSocketsResource"
,)
from
base64
import
b64encode
,
b64decode
from
hashlib
import
sha1
from
struct
import
pack
,
unpack
from
zope.interface
import
implementer
from
twisted.protocols.policies
import
ProtocolWrapper
,
WrappingFactory
from
twisted.python
import
log
from
twisted.python.constants
import
NamedConstant
,
Names
from
twisted.web.resource
import
IResource
,
NoResource
from
twisted.web.server
import
NOT_DONE_YET
class
_WSException
(
Exception
):
"""
Internal exception for control flow inside the WebSockets frame parser.
"""
# Control frame specifiers. Some versions of WS have control signals sent
# in-band. Adorable, right?
class
_CONTROLS
(
Names
):
"""
Control frame specifiers.
"""
NORMAL
=
NamedConstant
()
CLOSE
=
NamedConstant
()
PING
=
NamedConstant
()
PONG
=
NamedConstant
()
_opcode_types
=
{
0x0
:
_CONTROLS
.
NORMAL
,
0x1
:
_CONTROLS
.
NORMAL
,
0x2
:
_CONTROLS
.
NORMAL
,
0x8
:
_CONTROLS
.
CLOSE
,
0x9
:
_CONTROLS
.
PING
,
0xa
:
_CONTROLS
.
PONG
,
}
_opcode_for_type
=
{
_CONTROLS
.
NORMAL
:
0x1
,
_CONTROLS
.
CLOSE
:
0x8
,
_CONTROLS
.
PING
:
0x9
,
_CONTROLS
.
PONG
:
0xa
,
}
_encoders
=
{
"base64"
:
b64encode
,
}
_decoders
=
{
"base64"
:
b64decode
,
}
# Authentication for WS.
# The GUID for WebSockets, from RFC 6455.
_WS_GUID
=
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
def
_makeAccept
(
key
):
"""
Create an "accept" response for a given key.
This dance is expected to somehow magically make WebSockets secure.
@type key: C{str}
@param key: The key to respond to.
@rtype: C{str}
@return: An encoded response.
"""
return
sha1
(
"
%
s
%
s"
%
(
key
,
_WS_GUID
))
.
digest
()
.
encode
(
"base64"
)
.
strip
()
# Frame helpers.
# Separated out to make unit testing a lot easier.
# Frames are bonghits in newer WS versions, so helpers are appreciated.
def
_mask
(
buf
,
key
):
"""
Mask or unmask a buffer of bytes with a masking key.
@type buf: C{str}
@param buf: A buffer of bytes.
@type key: C{str}
@param key: The masking key. Must be exactly four bytes.
@rtype: C{str}
@return: A masked buffer of bytes.
"""
# This is super-secure, I promise~
key
=
[
ord
(
i
)
for
i
in
key
]
buf
=
list
(
buf
)
for
i
,
char
in
enumerate
(
buf
):
buf
[
i
]
=
chr
(
ord
(
char
)
^
key
[
i
%
4
])
return
""
.
join
(
buf
)
def
_makeFrame
(
buf
,
_opcode
=
_CONTROLS
.
NORMAL
):
"""
Make a frame.
This function always creates unmasked frames, and attempts to use the
smallest possible lengths.
@type buf: C{str}
@param buf: A buffer of bytes.
@type _opcode: C{_CONTROLS}
@param _opcode: Which type of frame to create.
@rtype: C{str}
@return: A packed frame.
"""
bufferLength
=
len
(
buf
)
if
bufferLength
>
0xffff
:
length
=
"
\x7f
%
s"
%
pack
(
">Q"
,
bufferLength
)
elif
bufferLength
>
0x7d
:
length
=
"
\x7e
%
s"
%
pack
(
">H"
,
bufferLength
)
else
:
length
=
chr
(
bufferLength
)
# Always make a normal packet.
header
=
chr
(
0x80
|
_opcode_for_type
[
_opcode
])
frame
=
"
%
s
%
s
%
s"
%
(
header
,
length
,
buf
)
return
frame
def
_parseFrames
(
buf
):
"""
Parse frames in a highly compliant manner.
@type buf: C{str}
@param buf: A buffer of bytes.
@rtype: C{list}
@return: A list of frames.
"""
start
=
0
frames
=
[]
while
True
:
# If there's not at least two bytes in the buffer, bail.
if
len
(
buf
)
-
start
<
2
:
break
# Grab the header. This single byte holds some flags nobody cares
# about, and an opcode which nobody cares about.
header
=
ord
(
buf
[
start
])
if
header
&
0x70
:
# At least one of the reserved flags is set. Pork chop sandwiches!
raise
_WSException
(
"Reserved flag in frame (
%
d)"
%
header
)
# Get the opcode, and translate it to a local enum which we actually
# care about.
opcode
=
header
&
0xf
try
:
opcode
=
_opcode_types
[
opcode
]
except
KeyError
:
raise
_WSException
(
"Unknown opcode
%
d in frame"
%
opcode
)
# Get the payload length and determine whether we need to look for an
# extra length.
length
=
ord
(
buf
[
start
+
1
])
masked
=
length
&
0x80
length
&=
0x7f
# The offset we're gonna be using to walk through the frame. We use
# this because the offset is variable depending on the length and
# mask.
offset
=
2
# Extra length fields.
if
length
==
0x7e
:
if
len
(
buf
)
-
start
<
4
:
break
length
=
buf
[
start
+
2
:
start
+
4
]
length
=
unpack
(
">H"
,
length
)[
0
]
offset
+=
2
elif
length
==
0x7f
:
if
len
(
buf
)
-
start
<
10
:
break
# Protocol bug: The top bit of this long long *must* be cleared;
# that is, it is expected to be interpreted as signed. That's
# fucking stupid, if you don't mind me saying so, and so we're
# interpreting it as unsigned anyway. If you wanna send exabytes
# of data down the wire, then go ahead!
length
=
buf
[
start
+
2
:
start
+
10
]
length
=
unpack
(
">Q"
,
length
)[
0
]
offset
+=
8
if
masked
:
if
len
(
buf
)
-
(
start
+
offset
)
<
4
:
# This is not strictly necessary, but it's more explicit so
# that we don't create an invalid key.
break
key
=
buf
[
start
+
offset
:
start
+
offset
+
4
]
offset
+=
4
if
len
(
buf
)
-
(
start
+
offset
)
<
length
:
break
data
=
buf
[
start
+
offset
:
start
+
offset
+
length
]
if
masked
:
data
=
_mask
(
data
,
key
)
if
opcode
==
_CONTROLS
.
CLOSE
:
if
len
(
data
)
>=
2
:
# Gotta unpack the opcode and return usable data here.
data
=
unpack
(
">H"
,
data
[:
2
])[
0
],
data
[
2
:]
else
:
# No reason given; use generic data.
data
=
1000
,
"No reason given"
frames
.
append
((
opcode
,
data
))
start
+=
offset
+
length
return
frames
,
buf
[
start
:]
class
_WebSocketsProtocol
(
ProtocolWrapper
):
"""
Protocol which wraps another protocol to provide a WebSockets transport
layer.
"""
buf
=
""
codec
=
None
def
__init__
(
self
,
*
args
,
**
kwargs
):
ProtocolWrapper
.
__init__
(
self
,
*
args
,
**
kwargs
)
self
.
_pending_frames
=
[]
def
connectionMade
(
self
):
ProtocolWrapper
.
connectionMade
(
self
)
log
.
msg
(
"Opening connection with
%
s"
%
self
.
transport
.
getPeer
())
def
parseFrames
(
self
):
"""
Find frames in incoming data and pass them to the underlying protocol.
"""
try
:
frames
,
self
.
buf
=
_parseFrames
(
self
.
buf
)
except
_WSException
:
# Couldn't parse all the frames, something went wrong, let's bail.
log
.
err
()
self
.
loseConnection
()
return
for
frame
in
frames
:
opcode
,
data
=
frame
if
opcode
==
_CONTROLS
.
NORMAL
:
# Business as usual. Decode the frame, if we have a decoder.
if
self
.
codec
:
data
=
_decoders
[
self
.
codec
](
data
)
# Pass the frame to the underlying protocol.
ProtocolWrapper
.
dataReceived
(
self
,
data
)
elif
opcode
==
_CONTROLS
.
CLOSE
:
# The other side wants us to close. I wonder why?
reason
,
text
=
data
log
.
msg
(
"Closing connection:
%
r (
%
d)"
%
(
text
,
reason
))
# Close the connection.
self
.
loseConnection
()
return
elif
opcode
==
_CONTROLS
.
PING
:
# 5.5.2 PINGs must be responded to with PONGs.
# 5.5.3 PONGs must contain the data that was sent with the
# provoking PING.
self
.
transport
.
write
(
_makeFrame
(
data
,
_opcode
=
_CONTROLS
.
PONG
))
def
sendFrames
(
self
):
"""
Send all pending frames.
"""
for
frame
in
self
.
_pending_frames
:
# Encode the frame before sending it.
if
self
.
codec
:
frame
=
_encoders
[
self
.
codec
](
frame
)
packet
=
_makeFrame
(
frame
)
self
.
transport
.
write
(
packet
)
self
.
_pending_frames
=
[]
def
dataReceived
(
self
,
data
):
self
.
buf
+=
data
self
.
parseFrames
()
# Kick any pending frames. This is needed because frames might have
# started piling up early; we can get write()s from our protocol above
# when they makeConnection() immediately, before our browser client
# actually sends any data. In those cases, we need to manually kick
# pending frames.
if
self
.
_pending_frames
:
self
.
sendFrames
()
def
write
(
self
,
data
):
"""
Write to the transport.
This method will only be called by the underlying protocol.
"""
self
.
_pending_frames
.
append
(
data
)
self
.
sendFrames
()
def
writeSequence
(
self
,
data
):
"""
Write a sequence of data to the transport.
This method will only be called by the underlying protocol.
"""
self
.
_pending_frames
.
extend
(
data
)
self
.
sendFrames
()
def
loseConnection
(
self
):
"""
Close the connection.
This includes telling the other side we're closing the connection.
If the other side didn't signal that the connection is being closed,
then we might not see their last message, but since their last message
should, according to the spec, be a simple acknowledgement, it
shouldn't be a problem.
"""
# Send a closing frame. It's only polite. (And might keep the browser
# from hanging.)
if
not
self
.
disconnecting
:
frame
=
_makeFrame
(
""
,
_opcode
=
_CONTROLS
.
CLOSE
)
self
.
transport
.
write
(
frame
)
ProtocolWrapper
.
loseConnection
(
self
)
class
_WebSocketsFactory
(
WrappingFactory
):
"""
Factory which wraps another factory to provide WebSockets frames for all
of its protocols.
This factory does not provide the HTTP headers required to perform a
WebSockets handshake; see C{WebSocketsResource}.
"""
protocol
=
_WebSocketsProtocol
@
implementer
(
IResource
)
class
WebSocketsResource
(
object
):
"""
A resource for serving a protocol through WebSockets.
This class wraps a factory and connects it to WebSockets clients. Each
connecting client will be connected to a new protocol of the factory.
Due to unresolved questions of logistics, this resource cannot have
children.
@since 12.3
"""
isLeaf
=
True
def
__init__
(
self
,
factory
):
self
.
_factory
=
_WebSocketsFactory
(
factory
)
def
getChildWithDefault
(
self
,
name
,
request
):
return
NoResource
(
"No such child resource."
)
def
putChild
(
self
,
path
,
child
):
pass
def
render
(
self
,
request
):
"""
Render a request.
We're not actually rendering a request. We are secretly going to
handle a WebSockets connection instead.
"""
# If we fail at all, we're gonna fail with 400 and no response.
# You might want to pop open the RFC and read along.
failed
=
False
if
request
.
method
!=
"GET"
:
# 4.2.1.1 GET is required.
failed
=
True
upgrade
=
request
.
getHeader
(
"Upgrade"
)
if
upgrade
is
None
or
"websocket"
not
in
upgrade
.
lower
():
# 4.2.1.3 Upgrade: WebSocket is required.
failed
=
True
connection
=
request
.
getHeader
(
"Connection"
)
if
connection
is
None
or
"upgrade"
not
in
connection
.
lower
():
# 4.2.1.4 Connection: Upgrade is required.
failed
=
True
key
=
request
.
getHeader
(
"Sec-WebSocket-Key"
)
if
key
is
None
:
# 4.2.1.5 The challenge key is required.
failed
=
True
version
=
request
.
getHeader
(
"Sec-WebSocket-Version"
)
if
version
!=
"13"
:
# 4.2.1.6 Only version 13 works.
failed
=
True
# 4.4 Forward-compatible version checking.
request
.
setHeader
(
"Sec-WebSocket-Version"
,
"13"
)
# Check whether a codec is needed. WS calls this a "protocol" for
# reasons I cannot fathom. The specification permits multiple,
# comma-separated codecs to be listed, but this functionality isn't
# used in the wild. (If that ever changes, we'll have already added
# the requisite codecs here anyway.) The main reason why we check for
# codecs at all is that older draft versions of WebSockets used base64
# encoding to work around the inability to send \x00 bytes, and those
# runtimes would request base64 encoding during the handshake. We
# stand prepared to engage that behavior should any of those runtimes
# start supporting RFC WebSockets.
#
# We probably should remove this altogether, but I'd rather leave it
# because it will prove to be a useful reference if/when extensions
# are added, and it *does* work as advertised.
codec
=
request
.
getHeader
(
"Sec-WebSocket-Protocol"
)
if
codec
:
if
codec
not
in
_encoders
or
codec
not
in
_decoders
:
log
.
msg
(
"Codec
%
s is not implemented"
%
codec
)
failed
=
True
if
failed
:
request
.
setResponseCode
(
400
)
return
""
# We are going to finish this handshake. We will return a valid status
# code.
# 4.2.2.5.1 101 Switching Protocols
request
.
setResponseCode
(
101
)
# 4.2.2.5.2 Upgrade: websocket
request
.
setHeader
(
"Upgrade"
,
"WebSocket"
)
# 4.2.2.5.3 Connection: Upgrade
request
.
setHeader
(
"Connection"
,
"Upgrade"
)
# 4.2.2.5.4 Response to the key challenge
request
.
setHeader
(
"Sec-WebSocket-Accept"
,
_makeAccept
(
key
))
# 4.2.2.5.5 Optional codec declaration
if
codec
:
request
.
setHeader
(
"Sec-WebSocket-Protocol"
,
codec
)
# Create the protocol. This could fail, in which case we deliver an
# error status. Status 502 was decreed by glyph; blame him.
protocol
=
self
.
_factory
.
buildProtocol
(
request
.
transport
.
getPeer
())
if
not
protocol
:
request
.
setResponseCode
(
502
)
return
""
if
codec
:
protocol
.
codec
=
codec
# Provoke request into flushing headers and finishing the handshake.
request
.
write
(
""
)
# And now take matters into our own hands. We shall manage the
# transport's lifecycle.
transport
,
request
.
transport
=
request
.
transport
,
None
# Connect the transport to our factory, and make things go. We need to
# do some stupid stuff here; see #3204, which could fix it.
transport
.
protocol
=
protocol
protocol
.
makeConnection
(
transport
)
return
NOT_DONE_YET
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment