mirror of
https://github.com/clearlinux/uwsgi.git
synced 2026-08-18 11:39:05 +00:00
@@ -412,6 +412,12 @@ static int uwsgi_proto_check_11(struct wsgi_request *wsgi_req, char *key, char *
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!uwsgi_proto_key("HTTP_ORIGIN", 11)) {
|
||||
wsgi_req->http_origin = buf;
|
||||
wsgi_req->http_origin_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -589,9 +595,28 @@ static int uwsgi_proto_check_22(struct wsgi_request *wsgi_req, char *key, char *
|
||||
wsgi_req->if_modified_since_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_KEY", 22)) {
|
||||
wsgi_req->http_sec_websocket_key = buf;
|
||||
wsgi_req->http_sec_websocket_key_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uwsgi_proto_check_27(struct wsgi_request *wsgi_req, char *key, char *buf, uint16_t len) {
|
||||
|
||||
if (!uwsgi_proto_key("HTTP_SEC_WEBSOCKET_PROTOCOL", 27)) {
|
||||
wsgi_req->http_sec_websocket_protocol = buf;
|
||||
wsgi_req->http_sec_websocket_protocol_len = len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void uwsgi_proto_hooks_setup() {
|
||||
int i = 0;
|
||||
for(i=0;i<UWSGI_PROTO_MAX_CHECK;i++) {
|
||||
@@ -609,6 +634,7 @@ void uwsgi_proto_hooks_setup() {
|
||||
uwsgi.proto_hooks[18] = uwsgi_proto_check_18;
|
||||
uwsgi.proto_hooks[20] = uwsgi_proto_check_20;
|
||||
uwsgi.proto_hooks[22] = uwsgi_proto_check_22;
|
||||
uwsgi.proto_hooks[27] = uwsgi_proto_check_27;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+23
-2
@@ -367,18 +367,39 @@ ssize_t uwsgi_websockets_simple_send(struct wsgi_request *wsgi_req, struct uwsgi
|
||||
return len;
|
||||
}
|
||||
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len) {
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *origin, uint16_t origin_len, char *proto, uint16_t proto_len) {
|
||||
#ifdef UWSGI_SSL
|
||||
if (!key_len) {
|
||||
key = wsgi_req->http_sec_websocket_key;
|
||||
key_len = wsgi_req->http_sec_websocket_key_len;
|
||||
}
|
||||
if (key_len == 0) return -1;
|
||||
|
||||
char sha1[20];
|
||||
if (uwsgi_response_prepare_headers(wsgi_req, "101 Web Socket Protocol Handshake", 33)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Upgrade", 7, "WebSocket", 9)) return -1;
|
||||
if (uwsgi_response_add_header(wsgi_req, "Connection", 10, "Upgrade", 7)) return -1;
|
||||
if (origin_len > 0) {
|
||||
|
||||
// if origin was requested or proto_len is specified, send it back
|
||||
if (wsgi_req->http_origin_len > 0 || origin_len > 0) {
|
||||
if (!origin_len) {
|
||||
origin = wsgi_req->http_origin;
|
||||
origin_len = wsgi_req->http_origin_len;
|
||||
}
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, origin, origin_len)) return -1;
|
||||
}
|
||||
else {
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Origin", 20, "*", 1)) return -1;
|
||||
}
|
||||
|
||||
// if protocol was requested or proto_len is specified, send it back
|
||||
if (wsgi_req->http_sec_websocket_protocol_len > 0 || proto_len > 0) {
|
||||
if (!proto_len) {
|
||||
proto = wsgi_req->http_sec_websocket_protocol;
|
||||
proto_len = wsgi_req->http_sec_websocket_protocol_len;
|
||||
}
|
||||
if (uwsgi_response_add_header(wsgi_req, "Sec-WebSocket-Protocol", 22, proto, proto_len)) return -1;
|
||||
}
|
||||
// generate websockets sha1 and encode it to base64
|
||||
if (!uwsgi_sha1_2n(key, key_len, "258EAFA5-E914-47DA-95CA-C5AB0DC85B11", 36, sha1)) return -1;
|
||||
size_t b64_len = 0;
|
||||
|
||||
@@ -376,18 +376,22 @@ static int uwsgi_api_ready_fd(lua_State *L) {
|
||||
|
||||
static int uwsgi_api_websocket_handshake(lua_State *L) {
|
||||
uint8_t argc = lua_gettop(L);
|
||||
if (argc == 0) goto error;
|
||||
|
||||
const char *key = NULL, *origin = NULL;
|
||||
size_t key_len = 0, origin_len = 0;
|
||||
const char *key = NULL, *origin = NULL, *proto = NULL;
|
||||
size_t key_len = 0, origin_len = 0, proto_len = 0;
|
||||
|
||||
key = lua_tolstring(L, 1, &key_len);
|
||||
if (argc > 1) {
|
||||
origin = lua_tolstring(L, 2, &origin_len);
|
||||
if (argc > 0) {
|
||||
key = lua_tolstring(L, 1, &key_len);
|
||||
if (argc > 1) {
|
||||
origin = lua_tolstring(L, 2, &origin_len);
|
||||
if (argc > 2) {
|
||||
proto = lua_tolstring(L, 3, &proto_len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
if (uwsgi_websocket_handshake(wsgi_req, (char *)key, key_len, (char *)origin, origin_len)) {
|
||||
if (uwsgi_websocket_handshake(wsgi_req, (char *)key, key_len, (char *)origin, origin_len, (char *) proto, proto_len)) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
@@ -786,7 +790,7 @@ static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
uwsgi_log("%s\n", lua_tostring(L, -1));
|
||||
lua_pop(L, 1);
|
||||
lua_pushvalue(L, -1);
|
||||
goto clear;
|
||||
goto clear2;
|
||||
}
|
||||
|
||||
//uwsgi_log("%d %s %s %s\n",i,lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) , lua_typename(L, lua_type(L, -1)));
|
||||
@@ -827,6 +831,7 @@ static int uwsgi_lua_request(struct wsgi_request *wsgi_req) {
|
||||
}
|
||||
clear:
|
||||
lua_pop(L, 4);
|
||||
clear2:
|
||||
// set frequency
|
||||
if (!ulua.gc_freq || uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].requests % ulua.gc_freq == 0) {
|
||||
lua_gc(L, LUA_GCCOLLECT, 0);
|
||||
|
||||
@@ -473,16 +473,24 @@ XS(XS_websocket_handshake) {
|
||||
char *origin = NULL;
|
||||
STRLEN origin_len = 0;
|
||||
|
||||
psgi_check_args(1);
|
||||
|
||||
key = SvPV(ST(0), key_len);
|
||||
char *proto = NULL;
|
||||
STRLEN proto_len = 0;
|
||||
|
||||
if (items > 1) {
|
||||
origin = SvPV(ST(0), origin_len);
|
||||
psgi_check_args(0);
|
||||
|
||||
if (items > 0) {
|
||||
key = SvPV(ST(0), key_len);
|
||||
if (items > 1) {
|
||||
origin = SvPV(ST(1), origin_len);
|
||||
if (items > 2) {
|
||||
proto = SvPV(ST(2), proto_len);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len)) {
|
||||
if (uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len, proto, proto_len)) {
|
||||
croak("unable to complete websocket handshake");
|
||||
}
|
||||
|
||||
|
||||
@@ -224,7 +224,7 @@ int async_add_fd_write(struct wsgi_request *, int, int);
|
||||
int async_add_fd_read(struct wsgi_request *, int, int);
|
||||
int uwsgi_connect(char *, int, int);
|
||||
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, uint16_t, char *, uint16_t);
|
||||
int uwsgi_websocket_send(struct wsgi_request *, char *, size_t);
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv(struct wsgi_request *);
|
||||
struct uwsgi_buffer *uwsgi_websocket_recv_nb(struct wsgi_request *);
|
||||
@@ -839,9 +839,12 @@ uwsgi.websocket_recv_nb = uwsgi_pypy_websocket_recv_nb
|
||||
"""
|
||||
uwsgi.websocket_handshake(key, origin)
|
||||
"""
|
||||
def uwsgi_pypy_websocket_handshake(key, origin=''):
|
||||
def uwsgi_pypy_websocket_handshake(key='', origin='', proto=''):
|
||||
wsgi_req = uwsgi_pypy_current_wsgi_req();
|
||||
if lib.uwsgi_websocket_handshake(wsgi_req, ffi.new('char[]', key), len(key), ffi.new('char[]',origin), len(origin)) < 0:
|
||||
c_key = ffi.new('char[]', key)
|
||||
c_origin = ffi.new('char[]', origin)
|
||||
c_proto = ffi.new('char[]', proto)
|
||||
if lib.uwsgi_websocket_handshake(wsgi_req, c_key, len(key), c_origin, len(origin), c_proto, len(proto)) < 0:
|
||||
raise IOError("unable to complete websocket handshake")
|
||||
uwsgi.websocket_handshake = uwsgi_pypy_websocket_handshake
|
||||
|
||||
|
||||
@@ -965,14 +965,17 @@ PyObject *py_uwsgi_websocket_handshake(PyObject * self, PyObject * args) {
|
||||
char *origin = NULL;
|
||||
Py_ssize_t origin_len = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s#|s#:websocket_handshake", &key, &key_len, &origin, &origin_len)) {
|
||||
char *proto = NULL;
|
||||
Py_ssize_t proto_len = 0;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "|s#s#s#:websocket_handshake", &key, &key_len, &origin, &origin_len, &proto, &proto_len)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct wsgi_request *wsgi_req = py_current_wsgi_req();
|
||||
|
||||
UWSGI_RELEASE_GIL
|
||||
int ret = uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len);
|
||||
int ret = uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len, proto, proto_len);
|
||||
UWSGI_GET_GIL
|
||||
|
||||
if (ret) {
|
||||
|
||||
+18
-17
@@ -1048,25 +1048,26 @@ static VALUE uwsgi_ruby_websocket_handshake(int argc, VALUE *argv, VALUE *class)
|
||||
|
||||
struct wsgi_request *wsgi_req = current_wsgi_req();
|
||||
|
||||
if (argc < 1) {
|
||||
rb_raise(rb_eRuntimeError, "you neeto specify a valid websocket key");
|
||||
return Qnil;
|
||||
char *key = NULL, *origin = NULL, *proto = NULL;
|
||||
size_t key_len = 0, origin_len = 0, proto_len = 0;
|
||||
|
||||
if (argc > 0) {
|
||||
Check_Type(argv[0], T_STRING);
|
||||
key = RSTRING_PTR(argv[0]);
|
||||
key_len = RSTRING_LEN(argv[0]);
|
||||
if (argc > 1) {
|
||||
Check_Type(argv[1], T_STRING);
|
||||
origin = RSTRING_PTR(argv[1]);
|
||||
origin_len = RSTRING_LEN(argv[1]);
|
||||
if (argc > 2) {
|
||||
Check_Type(argv[2], T_STRING);
|
||||
proto = RSTRING_PTR(argv[2]);
|
||||
proto_len = RSTRING_LEN(argv[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Check_Type(argv[0], T_STRING);
|
||||
char *key = RSTRING_PTR(argv[0]);
|
||||
size_t key_len = RSTRING_LEN(argv[0]);
|
||||
|
||||
char *origin = NULL;
|
||||
size_t origin_len = 0;
|
||||
|
||||
if (argc > 1) {
|
||||
Check_Type(argv[1], T_STRING);
|
||||
origin = RSTRING_PTR(argv[1]);
|
||||
origin_len = RSTRING_LEN(argv[1]);
|
||||
}
|
||||
|
||||
if (uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len)) {
|
||||
if (uwsgi_websocket_handshake(wsgi_req, key, key_len, origin, origin_len, proto, proto_len)) {
|
||||
rb_raise(rb_eRuntimeError, "unable to complete websocket handshake");
|
||||
}
|
||||
return Qnil;
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
#!./uwsgi --https :8443,foobar.crt,foobar.key --http-modifier1 6 --http-raw-body --threads 100 --lua tests/websocket_echo.lua
|
||||
|
||||
function app(env)
|
||||
local function html()
|
||||
coroutine.yield(string.format([[
|
||||
<html>
|
||||
<head>
|
||||
<script language="Javascript">
|
||||
var s = new WebSocket("%s://%s/foobar/", ["echo","foo","bar"]);
|
||||
s.onopen = function() {
|
||||
alert("connected !!!");
|
||||
s.send("ciao");
|
||||
};
|
||||
s.onmessage = function(e) {
|
||||
var bb = document.getElementById('blackboard')
|
||||
var html = bb.innerHTML;
|
||||
bb.innerHTML = html + '<br/>' + e.data;
|
||||
};
|
||||
|
||||
s.onerror = function(e) {
|
||||
alert(e);
|
||||
}
|
||||
|
||||
s.onclose = function(e) {
|
||||
alert("connection closed");
|
||||
}
|
||||
|
||||
function invia() {
|
||||
var value = document.getElementById('testo').value;
|
||||
s.send(value);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>WebSocket</h1>
|
||||
<input type="text" id="testo"/>
|
||||
<input type="button" value="invia" onClick="invia();"/>
|
||||
<div id="blackboard" style="width:640px;height:480px;background-color:black;color:white;border: solid 2px red;overflow:auto">
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
]], ws_scheme, env['HTTP_HOST']))
|
||||
end
|
||||
|
||||
ws_scheme = 'ws'
|
||||
if env['HTTPS'] ~= nil then
|
||||
ws_scheme = 'wss'
|
||||
end
|
||||
|
||||
if env['PATH_INFO'] == '/' then
|
||||
return 200, { ["Content-type"] = "text/html" }, coroutine.wrap(html)
|
||||
|
||||
elseif env['PATH_INFO'] == '/foobar/' then
|
||||
uwsgi.websocket_handshake(nil, nil, 'echo')
|
||||
print("websockets...")
|
||||
while 1 do
|
||||
msg = uwsgi.websocket_recv()
|
||||
uwsgi.websocket_send(string.format("[%s] %s", os.time(), msg))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return app
|
||||
@@ -4,13 +4,13 @@ class WebsocketEcho
|
||||
|
||||
def call(env)
|
||||
|
||||
ws_scheme = 'ws';
|
||||
ws_scheme = 'ws'
|
||||
if env.has_key?('HTTPS') or env['rack.url_scheme'] == 'https'
|
||||
ws_scheme = 'wss';
|
||||
ws_scheme = 'wss'
|
||||
end
|
||||
|
||||
if env['PATH_INFO'] == '/'
|
||||
body = <<EOF;
|
||||
body = <<EOF
|
||||
<html>
|
||||
<head>
|
||||
<script language="Javascript">
|
||||
@@ -51,7 +51,7 @@ class WebsocketEcho
|
||||
EOF
|
||||
|
||||
return [200, { 'Content-Type' => 'text/html'}, [body]]
|
||||
else if env['PATH_INFO'] == '/foobar/'
|
||||
elsif env['PATH_INFO'] == '/foobar/'
|
||||
UWSGI::websocket_handshake(env['HTTP_SEC_WEBSOCKET_KEY'], env['HTTP_ORIGIN'])
|
||||
puts "websockets..."
|
||||
loop do
|
||||
|
||||
@@ -1515,6 +1515,14 @@ struct wsgi_request {
|
||||
time_t websocket_last_ping;
|
||||
time_t websocket_last_pong;
|
||||
int websocket_closed;
|
||||
// websocket specific headers
|
||||
char *http_sec_websocket_key;
|
||||
uint16_t http_sec_websocket_key_len;
|
||||
char *http_origin;
|
||||
uint16_t http_origin_len;
|
||||
char *http_sec_websocket_protocol;
|
||||
uint16_t http_sec_websocket_protocol_len;
|
||||
|
||||
|
||||
struct uwsgi_buffer *chunked_input_buf;
|
||||
uint8_t chunked_input_parser_status;
|
||||
@@ -1610,7 +1618,7 @@ struct uwsgi_stats_pusher;
|
||||
struct uwsgi_stats_pusher_instance;
|
||||
|
||||
#define UWSGI_PROTO_MIN_CHECK 4
|
||||
#define UWSGI_PROTO_MAX_CHECK 23
|
||||
#define UWSGI_PROTO_MAX_CHECK 28
|
||||
|
||||
struct uwsgi_offload_engine;
|
||||
|
||||
@@ -4196,7 +4204,7 @@ uint16_t uwsgi_be16(char *);
|
||||
uint32_t uwsgi_be32(char *);
|
||||
uint64_t uwsgi_be64(char *);
|
||||
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, uint16_t);
|
||||
int uwsgi_websocket_handshake(struct wsgi_request *, char *, uint16_t, char *, uint16_t, char *, uint16_t);
|
||||
|
||||
int uwsgi_response_prepare_headers(struct wsgi_request *, char *, uint16_t);
|
||||
int uwsgi_response_prepare_headers_int(struct wsgi_request *, int);
|
||||
|
||||
Reference in New Issue
Block a user