Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
N
nghttp2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Libraries
nghttp2
Commits
7ce24fc1
Commit
7ce24fc1
authored
Aug 24, 2012
by
Tatsuhiro Tsujikawa
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
python: rewritten simple SPDY server. Add npn_get_version() helper function.
parent
dbe7cda7
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
423 additions
and
143 deletions
+423
-143
doc/python.rst
doc/python.rst
+14
-0
python/cspdylay.pxd
python/cspdylay.pxd
+3
-0
python/spdylay.pyx
python/spdylay.pyx
+388
-0
python/spdyserv.py
python/spdyserv.py
+18
-143
No files found.
doc/python.rst
View file @
7ce24fc1
...
...
@@ -543,6 +543,20 @@ Session Objects
:py:class:`StreamClosedError` will be raised if the stream is
already closed or does not exist.
Helper Functions
----------------
.. py:function:: npn_get_version(proto)
Returns SPDY version which spdylay library supports from the given
protocol name. The *proto* is the unicode string to the protocol
name. Currently, ``spdy/2`` and ``spdy/3`` are supported. The
returned nonzero SPDY version can be passed as the version
argument in :py:class:`Session` constructor.
This function returns nonzero SPDY version if it succeeds, or 0.
Data Provider Objects
---------------------
...
...
python/cspdylay.pxd
View file @
7ce24fc1
...
...
@@ -322,3 +322,6 @@ cdef extern from 'spdylay/spdylay.h':
int
spdylay_submit_window_update
(
spdylay_session
*
session
,
int32_t
stream_id
,
int32_t
delta_window_size
)
uint16_t
spdylay_npn_get_version
(
unsigned
char
*
proto
,
size_t
protolen
)
python/spdylay.pyx
View file @
7ce24fc1
...
...
@@ -976,6 +976,14 @@ cdef class Session:
elif
rv
==
cspdylay
.
SPDYLAY_ERR_NOMEM
:
raise
MemoryError
()
cpdef
int
npn_get_version
(
proto
):
cdef
char
*
cproto
if
proto
==
None
:
return
0
proto
=
proto
.
encode
(
'UTF-8'
)
cproto
=
proto
return
cspdylay
.
spdylay_npn_get_version
(
<
unsigned
char
*>
cproto
,
len
(
proto
))
# Side
CLIENT
=
1
SERVER
=
2
...
...
@@ -1076,3 +1084,383 @@ SETTINGS_INITIAL_WINDOW_SIZE = cspdylay.SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE
SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE
=
\
cspdylay
.
SPDYLAY_SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE
SETTINGS_MAX
=
cspdylay
.
SPDYLAY_SETTINGS_MAX
try
:
# Simple SPDY Server implementation. We mimics the methods and
# attributes of http.server.BaseHTTPRequestHandler. Since this
# implementation uses TLS NPN, Python 3.3.0 or later is required.
import
socket
import
threading
import
socketserver
import
ssl
import
io
import
select
import
sys
import
time
from
xml.sax.saxutils
import
escape
def
send_cb
(
session
,
data
):
ssctrl
=
session
.
user_data
wlen
=
ssctrl
.
sock
.
send
(
data
)
return
wlen
def
read_cb
(
session
,
stream_id
,
length
,
read_ctrl
,
source
):
data
=
source
.
read
(
length
)
if
not
data
:
read_ctrl
.
flags
=
READ_EOF
return
data
def
on_ctrl_recv_cb
(
session
,
frame
):
ssctrl
=
session
.
user_data
if
frame
.
frame_type
==
SYN_STREAM
:
stream
=
Stream
(
frame
.
stream_id
)
ssctrl
.
streams
[
frame
.
stream_id
]
=
stream
stream
.
process_headers
(
frame
.
nv
)
elif
frame
.
frame_type
==
HEADERS
:
if
frame
.
stream_id
in
ssctrl
.
streams
:
stream
=
ssctrl
.
streams
[
frame
.
stream_id
]
stream
.
process_headers
(
frame
.
nv
)
def
on_data_chunk_recv_cb
(
session
,
flags
,
stream_id
,
data
):
ssctrl
=
session
.
user_data
if
stream_id
in
ssctrl
.
streams
:
stream
=
ssctrl
.
streams
[
stream_id
]
if
stream
.
method
==
'POST'
:
if
not
stream
.
rfile
:
stream
.
rfile
=
io
.
BytesIO
()
stream
.
rfile
.
write
(
data
)
else
:
# We don't allow request body if method is not POST
session
.
submit_rst_stream
(
stream_id
,
PROTOCOL_ERROR
)
def
on_stream_close_cb
(
session
,
stream_id
,
status_code
):
ssctrl
=
session
.
user_data
if
stream_id
in
ssctrl
.
streams
:
del
ssctrl
.
streams
[
stream_id
]
def
on_request_recv_cb
(
session
,
stream_id
):
ssctrl
=
session
.
user_data
if
stream_id
in
ssctrl
.
streams
:
stream
=
ssctrl
.
streams
[
stream_id
]
ssctrl
.
handler
.
handle_one_request
(
stream
)
class
Stream
:
def
__init__
(
self
,
stream_id
):
self
.
stream_id
=
stream_id
self
.
data_prd
=
None
self
.
method
=
None
self
.
path
=
None
self
.
version
=
None
self
.
scheme
=
None
self
.
host
=
None
self
.
headers
=
[]
self
.
rfile
=
None
self
.
wfile
=
None
def
process_headers
(
self
,
headers
):
for
k
,
v
in
headers
:
if
k
==
':method'
:
self
.
method
=
v
elif
k
==
':scheme'
:
self
.
scheme
=
v
elif
k
==
':path'
:
self
.
path
=
v
elif
k
==
':version'
:
self
.
version
=
v
elif
k
==
':host'
:
self
.
host
=
v
else
:
self
.
headers
.
extend
(
headers
)
class
SessionCtrl
:
def
__init__
(
self
,
handler
,
sock
):
self
.
handler
=
handler
self
.
sock
=
sock
self
.
streams
=
{}
class
BaseSPDYRequestHandler
(
socketserver
.
BaseRequestHandler
):
server_version
=
'Python-spdylay'
error_content_type
=
'text/html'
error_message_format
=
'''
\
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>{code} {reason}</title>
</head><body>
<h1>{reason}</h1>
<p>{explain}</p>
<hr>
<address>{server} at {hostname} Port {port}</address>
</body></html>
'''
def
send_error
(
self
,
code
,
message
=
None
):
# Make sure that code is really int
code
=
int
(
code
)
try
:
shortmsg
,
longmsg
=
self
.
responses
[
code
]
except
KeyError
:
shortmsg
,
longmsg
=
'???'
,
'???'
if
message
is
None
:
message
=
shortmsg
explain
=
longmsg
content
=
self
.
error_message_format
.
format
(
\
code
=
code
,
reason
=
escape
(
message
),
explain
=
explain
,
server
=
self
.
server_version
,
hostname
=
socket
.
getfqdn
(),
port
=
self
.
server
.
server_address
[
1
]).
encode
(
'UTF-8'
)
self
.
send_response
(
code
,
message
)
self
.
send_header
(
'content-type'
,
self
.
error_content_type
)
self
.
send_header
(
'content-length'
,
str
(
len
(
content
)))
self
.
wfile
.
write
(
content
)
def
send_response
(
self
,
code
,
message
=
None
):
if
message
is
None
:
try
:
shortmsg
,
_
=
self
.
responses
[
code
]
except
KeyError
:
shortmsg
=
'???'
message
=
shortmsg
self
.
_response_headers
.
append
((
':status'
,
'{} {}'
.
format
(
code
,
message
)))
def
send_header
(
self
,
keyword
,
value
):
self
.
_response_headers
.
append
((
keyword
,
value
))
def
version_string
(
self
):
return
self
.
server_version
+
' '
+
self
.
sys_version
def
handle_one_request
(
self
,
stream
):
self
.
stream
=
stream
stream
.
wfile
=
io
.
BytesIO
()
self
.
command
=
stream
.
method
self
.
path
=
stream
.
path
self
.
request_version
=
stream
.
version
self
.
headers
=
stream
.
headers
self
.
rfile
=
stream
.
rfile
self
.
wfile
=
stream
.
wfile
self
.
_response_headers
=
[]
if
stream
.
method
is
None
:
self
.
send_error
(
400
)
else
:
mname
=
'do_'
+
stream
.
method
if
hasattr
(
self
,
mname
):
method
=
getattr
(
self
,
mname
)
if
self
.
rfile
is
not
None
:
self
.
rfile
.
seek
(
0
)
method
()
else
:
self
.
send_error
(
501
,
'Unsupported method ({})'
\
.
format
(
stream
.
method
))
self
.
wfile
.
seek
(
0
)
data_prd
=
DataProvider
(
self
.
wfile
,
read_cb
)
stream
.
data_prd
=
data_prd
self
.
send_header
(
':version'
,
'HTTP/1.1'
)
self
.
send_header
(
'server'
,
self
.
version_string
())
self
.
send_header
(
'date'
,
self
.
date_time_string
())
self
.
session
.
submit_response
(
stream
.
stream_id
,
self
.
_response_headers
,
data_prd
)
def
handle
(
self
):
# TODO We need to call handshake manually because 3.3.0b2
# crashes if do_handshake_on_connect=True
sock
=
self
.
server
.
ctx
.
wrap_socket
(
self
.
request
,
server_side
=
True
,
do_handshake_on_connect
=
False
)
sock
.
setblocking
(
False
)
while
True
:
try
:
sock
.
do_handshake
()
break
except
ssl
.
SSLWantReadError
as
e
:
select
.
select
([
sock
],
[],
[])
except
ssl
.
SSLWantWriteError
as
e
:
select
.
select
([],
[
sock
],
[])
version
=
npn_get_version
(
sock
.
selected_npn_protocol
())
if
version
==
0
:
return
ssctrl
=
SessionCtrl
(
self
,
sock
)
self
.
session
=
Session
(
\
SERVER
,
version
,
send_cb
=
send_cb
,
on_ctrl_recv_cb
=
on_ctrl_recv_cb
,
on_data_chunk_recv_cb
=
on_data_chunk_recv_cb
,
on_stream_close_cb
=
on_stream_close_cb
,
on_request_recv_cb
=
on_request_recv_cb
,
user_data
=
ssctrl
)
self
.
session
.
submit_settings
(
\
FLAG_SETTINGS_NONE
,
[(
SETTINGS_MAX_CONCURRENT_STREAMS
,
ID_FLAG_SETTINGS_NONE
,
100
)]
)
while
self
.
session
.
want_read
()
or
self
.
session
.
want_write
():
want_read
=
want_write
=
False
try
:
data
=
sock
.
recv
(
4096
)
if
data
:
self
.
session
.
recv
(
data
)
else
:
break
except
ssl
.
SSLWantReadError
:
want_read
=
True
except
ssl
.
SSLWantWriteError
:
want_write
=
True
try
:
self
.
session
.
send
()
except
ssl
.
SSLWantReadError
:
want_read
=
True
except
ssl
.
SSLWantWriteError
:
want_write
=
True
if
want_read
or
want_write
:
select
.
select
([
sock
]
if
want_read
else
[],
[
sock
]
if
want_write
else
[],
[])
# The following methods and attributes are copied from
# Lib/http/server.py of cpython source code
def
date_time_string
(
self
,
timestamp
=
None
):
"""Return the current date and time formatted for a
message header."""
if
timestamp
is
None
:
timestamp
=
time
.
time
()
year
,
month
,
day
,
hh
,
mm
,
ss
,
wd
,
y
,
z
=
time
.
gmtime
(
timestamp
)
s
=
"%s, %02d %3s %4d %02d:%02d:%02d GMT"
%
(
self
.
weekdayname
[
wd
],
day
,
self
.
monthname
[
month
],
year
,
hh
,
mm
,
ss
)
return
s
weekdayname
=
[
'Mon'
,
'Tue'
,
'Wed'
,
'Thu'
,
'Fri'
,
'Sat'
,
'Sun'
]
monthname
=
[
None
,
'Jan'
,
'Feb'
,
'Mar'
,
'Apr'
,
'May'
,
'Jun'
,
'Jul'
,
'Aug'
,
'Sep'
,
'Oct'
,
'Nov'
,
'Dec'
]
# The Python system version, truncated to its first component.
sys_version
=
"Python/"
+
sys
.
version
.
split
()[
0
]
# Table mapping response codes to messages; entries have the
# form {code: (shortmessage, longmessage)}.
# See RFC 2616 and 6585.
responses
=
{
100
:
(
'Continue'
,
'Request received, please continue'
),
101
:
(
'Switching Protocols'
,
'Switching to new protocol; obey Upgrade header'
),
200
:
(
'OK'
,
'Request fulfilled, document follows'
),
201
:
(
'Created'
,
'Document created, URL follows'
),
202
:
(
'Accepted'
,
'Request accepted, processing continues off-line'
),
203
:
(
'Non-Authoritative Information'
,
'Request fulfilled from cache'
),
204
:
(
'No Content'
,
'Request fulfilled, nothing follows'
),
205
:
(
'Reset Content'
,
'Clear input form for further input.'
),
206
:
(
'Partial Content'
,
'Partial content follows.'
),
300
:
(
'Multiple Choices'
,
'Object has several resources -- see URI list'
),
301
:
(
'Moved Permanently'
,
'Object moved permanently -- see URI list'
),
302
:
(
'Found'
,
'Object moved temporarily -- see URI list'
),
303
:
(
'See Other'
,
'Object moved -- see Method and URL list'
),
304
:
(
'Not Modified'
,
'Document has not changed since given time'
),
305
:
(
'Use Proxy'
,
'You must use proxy specified in Location to access this '
'resource.'
),
307
:
(
'Temporary Redirect'
,
'Object moved temporarily -- see URI list'
),
400
:
(
'Bad Request'
,
'Bad request syntax or unsupported method'
),
401
:
(
'Unauthorized'
,
'No permission -- see authorization schemes'
),
402
:
(
'Payment Required'
,
'No payment -- see charging schemes'
),
403
:
(
'Forbidden'
,
'Request forbidden -- authorization will not help'
),
404
:
(
'Not Found'
,
'Nothing matches the given URI'
),
405
:
(
'Method Not Allowed'
,
'Specified method is invalid for this resource.'
),
406
:
(
'Not Acceptable'
,
'URI not available in preferred format.'
),
407
:
(
'Proxy Authentication Required'
,
'You must authenticate with '
'this proxy before proceeding.'
),
408
:
(
'Request Timeout'
,
'Request timed out; try again later.'
),
409
:
(
'Conflict'
,
'Request conflict.'
),
410
:
(
'Gone'
,
'URI no longer exists and has been permanently removed.'
),
411
:
(
'Length Required'
,
'Client must specify Content-Length.'
),
412
:
(
'Precondition Failed'
,
'Precondition in headers is false.'
),
413
:
(
'Request Entity Too Large'
,
'Entity is too large.'
),
414
:
(
'Request-URI Too Long'
,
'URI is too long.'
),
415
:
(
'Unsupported Media Type'
,
'Entity body in unsupported format.'
),
416
:
(
'Requested Range Not Satisfiable'
,
'Cannot satisfy request range.'
),
417
:
(
'Expectation Failed'
,
'Expect condition could not be satisfied.'
),
428
:
(
'Precondition Required'
,
'The origin server requires the request to be conditional.'
),
429
:
(
'Too Many Requests'
,
'The user has sent too many requests '
'in a given amount of time ("rate limiting").'
),
431
:
(
'Request Header Fields Too Large'
,
'The server is unwilling to process '
'the request because its header fields are too large.'
),
500
:
(
'Internal Server Error'
,
'Server got itself in trouble'
),
501
:
(
'Not Implemented'
,
'Server does not support this operation'
),
502
:
(
'Bad Gateway'
,
'Invalid responses from another server/proxy.'
),
503
:
(
'Service Unavailable'
,
'The server cannot process the request due to a high load'
),
504
:
(
'Gateway Timeout'
,
'The gateway server did not receive a timely response'
),
505
:
(
'HTTP Version Not Supported'
,
'Cannot fulfill request.'
),
511
:
(
'Network Authentication Required'
,
'The client needs to authenticate to gain network access.'
),
}
class
ThreadedSPDYServer
(
socketserver
.
ThreadingMixIn
,
socketserver
.
TCPServer
):
def
__init__
(
self
,
svaddr
,
handler
,
cert_file
,
key_file
):
self
.
allow_reuse_address
=
True
self
.
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv23
)
# TODO Add SSL option here
self
.
ctx
.
load_cert_chain
(
cert_file
,
key_file
)
self
.
ctx
.
set_npn_protocols
([
'spdy/3'
,
'spdy/2'
])
socketserver
.
TCPServer
.
__init__
(
self
,
svaddr
,
handler
)
def
start
(
self
,
daemon
=
False
):
server_thread
=
threading
.
Thread
(
target
=
self
.
serve_forever
)
server_thread
.
daemon
=
daemon
server_thread
.
start
()
except
ImportError
:
# No server for 2.x because they lack TLS NPN.
pass
python/spdyserv.py
View file @
7ce24fc1
#!/usr/bin/env python
# The example SPDY server. You need Python 3.3 or later because we
# use TLS NPN. Put private key and certificate file in the current
# working directory.
import
socket
import
threading
import
socketserver
import
ssl
import
io
import
select
# The example SPDY server. Python 3.3 or later is required because TLS
# NPN is used in spdylay.ThreadedSPDYServer. Put private key and
# certificate file in the current working directory.
import
spdylay
...
...
@@ -18,150 +11,32 @@ KEY_FILE='server.key'
# certificate file
CERT_FILE
=
'server.crt'
def
send_cb
(
session
,
data
):
ssctrl
=
session
.
user_data
wlen
=
ssctrl
.
sock
.
send
(
data
)
return
wlen
def
read_cb
(
session
,
stream_id
,
length
,
read_ctrl
,
source
):
data
=
source
.
read
(
length
)
if
not
data
:
read_ctrl
.
flags
=
spdylay
.
READ_EOF
return
data
class
MySPDYRequestHandler
(
spdylay
.
BaseSPDYRequestHandler
):
def
on_ctrl_recv_cb
(
session
,
frame
):
ssctrl
=
session
.
user_data
if
frame
.
frame_type
==
spdylay
.
SYN_STREAM
:
stctrl
=
StreamCtrl
(
frame
.
stream_id
)
stctrl
.
headers
.
extend
(
frame
.
nv
)
ssctrl
.
streams
[
frame
.
stream_id
]
=
stctrl
def
do_GET
(
self
):
if
self
.
path
==
'/notfound'
:
self
.
send_error
(
404
)
return
def
on_stream_close_cb
(
session
,
stream_id
,
status_code
):
ssctrl
=
session
.
user_data
if
stream_id
in
ssctrl
.
streams
:
del
ssctrl
.
streams
[
stream_id
]
self
.
send_response
(
200
)
self
.
send_header
(
'conten-type'
,
'text/html; charset=UTF-8'
)
def
on_request_recv_cb
(
session
,
stream_id
):
ssctrl
=
session
.
user_data
if
stream_id
in
ssctrl
.
streams
:
stctrl
=
ssctrl
.
streams
[
stream_id
]
for
name
,
value
in
stctrl
.
headers
:
if
name
==
'user-agent'
:
user_agent
=
value
break
else
:
user_agent
=
''
html
=
'''
\
content
=
'''
\
<html>
<head><title>SPDY FTW</title></head>
<body>
<h1>SPDY FTW</h1>
<p>The age of HTTP/1.1 is over. The time of SPDY has come.</p>
<p>Your browser {} supports SPDY.</p>
</body>
</html>
'''
.
format
(
user_agent
)
data_prd
=
spdylay
.
DataProvider
(
io
.
BytesIO
(
bytes
(
html
,
'utf-8'
)),
read_cb
)
stctrl
.
data_prd
=
data_prd
nv
=
[(
':status'
,
'200 OK'
),
(
':version'
,
'HTTP/1.1'
),
(
'server'
,
'python-spdylay'
)]
session
.
submit_response
(
stream_id
,
nv
,
data_prd
)
class
StreamCtrl
:
def
__init__
(
self
,
stream_id
):
self
.
stream_id
=
stream_id
self
.
data_prd
=
None
self
.
headers
=
[]
class
SessionCtrl
:
def
__init__
(
self
,
sock
):
self
.
sock
=
sock
self
.
streams
=
{}
class
ThreadedSPDYRequestHandler
(
socketserver
.
BaseRequestHandler
):
def
handle
(
self
):
ctx
=
ssl
.
SSLContext
(
ssl
.
PROTOCOL_SSLv23
)
ctx
.
load_cert_chain
(
CERT_FILE
,
KEY_FILE
)
ctx
.
set_npn_protocols
([
'spdy/3'
,
'spdy/2'
])
sock
=
ctx
.
wrap_socket
(
self
.
request
,
server_side
=
True
,
do_handshake_on_connect
=
False
)
sock
.
setblocking
(
False
)
</html>'''
.
encode
(
'UTF-8'
)
while
True
:
try
:
sock
.
do_handshake
()
break
except
ssl
.
SSLWantReadError
as
e
:
select
.
select
([
sock
],
[],
[])
except
ssl
.
SSLWantWriteError
as
e
:
select
.
select
([],
[
sock
],
[])
if
sock
.
selected_npn_protocol
()
==
'spdy/3'
:
version
=
spdylay
.
PROTO_SPDY3
elif
sock
.
selected_npn_protocol
()
==
'spdy/2'
:
version
=
spdylay
.
PROTO_SPDY2
else
:
return
ssctrl
=
SessionCtrl
(
sock
)
session
=
spdylay
.
Session
(
spdylay
.
SERVER
,
version
,
send_cb
=
send_cb
,
on_ctrl_recv_cb
=
on_ctrl_recv_cb
,
on_stream_close_cb
=
on_stream_close_cb
,
on_request_recv_cb
=
on_request_recv_cb
,
user_data
=
ssctrl
)
session
.
submit_settings
(
\
spdylay
.
FLAG_SETTINGS_NONE
,
[(
spdylay
.
SETTINGS_MAX_CONCURRENT_STREAMS
,
spdylay
.
ID_FLAG_SETTINGS_NONE
,
100
)])
while
session
.
want_read
()
or
session
.
want_write
():
want_read
=
want_write
=
False
try
:
data
=
sock
.
recv
(
4096
)
if
data
:
session
.
recv
(
data
)
else
:
break
except
ssl
.
SSLWantReadError
:
want_read
=
True
except
ssl
.
SSLWantWriteError
:
want_write
=
True
try
:
session
.
send
()
except
ssl
.
SSLWantReadError
:
want_read
=
True
except
ssl
.
SSLWantWriteError
:
want_write
=
True
if
want_read
or
want_write
:
select
.
select
([
sock
]
if
want_read
else
[],
[
sock
]
if
want_write
else
[],
[])
class
ThreadedSPDYServer
(
socketserver
.
ThreadingMixIn
,
socketserver
.
TCPServer
):
def
__init__
(
self
,
svaddr
,
handler
):
self
.
allow_reuse_address
=
True
socketserver
.
TCPServer
.
__init__
(
self
,
svaddr
,
handler
)
self
.
wfile
.
write
(
content
)
if
__name__
==
"__main__"
:
# Port 0 means to select an arbitrary unused port
HOST
,
PORT
=
"localhost"
,
3000
server
=
ThreadedSPDYServer
((
HOST
,
PORT
),
ThreadedSPDYRequestHandler
)
ip
,
port
=
server
.
server_address
# Start a thread with the server -- that thread will then start one
# more thread for each request
server_thread
=
threading
.
Thread
(
target
=
server
.
serve_forever
)
# Exit the server thread when the main thread terminates
#server_thread.daemon = True
server_thread
.
start
()
server
=
spdylay
.
ThreadedSPDYServer
((
HOST
,
PORT
),
MySPDYRequestHandler
,
cert_file
=
CERT_FILE
,
key_file
=
KEY_FILE
)
server
.
start
()
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