python: add Session.submit_data()

This commit is contained in:
Tatsuhiro Tsujikawa 2012-08-22 01:28:05 +09:00
parent 78f6119196
commit 7580c9f671
4 changed files with 83 additions and 22 deletions

View File

@ -262,10 +262,14 @@ Session objects
request message bodies request message bodies
(http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9) must (http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9) must
be specified with ``:method`` key in nv (e.g. ``POST``). The type be specified with ``:method`` key in nv (e.g. ``POST``). The type
of *data_prd* is expected to be :py:class:`DataProvider`. This of *data_prd* is expected to be :py:class:`DataProvider`. If
method does not increase reference count of *data_prd*, so the *data_prd* is ``None``, SYN_STREAM have FLAG_FIN set.
application must hold the reference to it until the stream is
closed. If *data_prd* is ``None``, SYN_STREAM have FLAG_FIN set. .. note::
This method does not increase reference count of *data_prd*,
so the application must hold the reference to it until the
stream is closed.
The *stream_user_data* is data associated to the stream opened by The *stream_user_data* is data associated to the stream opened by
this request and can be an arbitrary object, which can be this request and can be an arbitrary object, which can be
@ -309,10 +313,14 @@ Session objects
If *data_prd* is not ``None``, it provides data which will be sent If *data_prd* is not ``None``, it provides data which will be sent
in subsequent DATA frames. The type of *data_prd* is expected to in subsequent DATA frames. The type of *data_prd* is expected to
be :py:class:`DataProvider`. This method does not increase be :py:class:`DataProvider`. If *data_prd* is ``None``, SYN_REPLY
reference count of *data_prd*, so the application must hold the have FLAG_FIN set.
reference to it until the stream is closed. If *data_prd* is
``None``, SYN_REPLY have FLAG_FIN set. .. note::
This method does not increase reference count of *data_prd*,
so the application must hold the reference to it until the
stream is closed.
The :py:class:`InvalidArgumentError` will be raised if the *nv* The :py:class:`InvalidArgumentError` will be raised if the *nv*
includes empty name or ``None`` value. includes empty name or ``None`` value.
@ -376,6 +384,20 @@ Session objects
The :py:class:`InvalidArgumentError` will be raised if the *nv* The :py:class:`InvalidArgumentError` will be raised if the *nv*
includes empty name or ``None`` value. includes empty name or ``None`` value.
.. py:method:: Session.submit_data(stream_id, flags, data_prd)
Submits one or more DATA frames to the stream *stream_id*. The
data to be sent are provided by *data_prd*. The type of
*data_prd* is expected to be :py:class:`DataProvider`. If *flags*
contains :py:const:`DATA_FLAG_FIN`, the last DATA frame has
FLAG_FIN set.
.. note::
This method does not increase reference count of *data_prd*,
so the application must hold the reference to it until the
stream is closed.
.. py:method:: Session.submit_rst_stream(stream_id, status_code) .. py:method:: Session.submit_rst_stream(stream_id, status_code)
Submits RST_STREAM frame to cancel/reject the stream *stream_id* Submits RST_STREAM frame to cancel/reject the stream *stream_id*

View File

@ -233,6 +233,9 @@ cdef extern from 'spdylay/spdylay.h':
int spdylay_submit_syn_reply(spdylay_session *session, uint8_t flags, int spdylay_submit_syn_reply(spdylay_session *session, uint8_t flags,
int32_t stream_id, char **nv) int32_t stream_id, char **nv)
int spdylay_submit_data(spdylay_session *session, int32_t stream_id,
uint8_t flags, spdylay_data_provider *data_prd)
int spdylay_submit_rst_stream(spdylay_session *session, int spdylay_submit_rst_stream(spdylay_session *session,
int32_t stream_id, uint32_t status_code) int32_t stream_id, uint32_t status_code)

View File

@ -644,6 +644,23 @@ cdef class Session:
elif rv == cspdylay.SPDYLAY_ERR_NOMEM: elif rv == cspdylay.SPDYLAY_ERR_NOMEM:
raise MemoryError() raise MemoryError()
cpdef submit_data(self, stream_id, flags, data_prd):
cdef cspdylay.spdylay_data_provider c_data_prd
cdef cspdylay.spdylay_data_provider *c_data_prd_ptr
cpdef int rv
if data_prd:
create_c_data_prd(&c_data_prd, data_prd)
c_data_prd_ptr = &c_data_prd
else:
c_data_prd_ptr = NULL
rv = cspdylay.spdylay_submit_data(self._c_session, stream_id,
flags, c_data_prd_ptr)
if rv == 0:
return
elif rv == cspdylay.SPDYLAY_ERR_NOMEM:
raise MemoryError()
cpdef submit_rst_stream(self, stream_id, status_code): cpdef submit_rst_stream(self, stream_id, status_code):
cdef int rv cdef int rv
rv = cspdylay.spdylay_submit_rst_stream(self._c_session, stream_id, rv = cspdylay.spdylay_submit_rst_stream(self._c_session, stream_id,

View File

@ -121,9 +121,9 @@ class SpdylayTests(unittest.TestCase):
def test_submit_syn_stream_and_syn_stream(self): def test_submit_syn_stream_and_syn_stream(self):
self.client_session.submit_syn_stream(spdylay.CTRL_FLAG_FIN, 0, 2, self.client_session.submit_syn_stream(spdylay.CTRL_FLAG_FIN, 0, 2,
[(b':path', b'/')], None); [(b':path', b'/')], None)
self.client_session.send(); self.client_session.send()
self.server_session.recv(); self.server_session.recv()
self.assertEqual(1, len(self.server_streams.recv_frames)) self.assertEqual(1, len(self.server_streams.recv_frames))
frame = self.server_streams.recv_frames[0] frame = self.server_streams.recv_frames[0]
@ -135,8 +135,8 @@ class SpdylayTests(unittest.TestCase):
self.server_session.submit_syn_reply(spdylay.CTRL_FLAG_FIN, 1, self.server_session.submit_syn_reply(spdylay.CTRL_FLAG_FIN, 1,
[(b':version', b'HTTP/1.1')]) [(b':version', b'HTTP/1.1')])
self.server_session.send(); self.server_session.send()
self.client_session.recv(); self.client_session.recv()
self.assertEqual(1, len(self.client_streams.recv_frames)) self.assertEqual(1, len(self.client_streams.recv_frames))
frame = self.client_streams.recv_frames[0] frame = self.client_streams.recv_frames[0]
@ -146,13 +146,13 @@ class SpdylayTests(unittest.TestCase):
def test_submit_rst_stream(self): def test_submit_rst_stream(self):
self.client_session.submit_syn_stream(spdylay.CTRL_FLAG_FIN, 0, 2, self.client_session.submit_syn_stream(spdylay.CTRL_FLAG_FIN, 0, 2,
[(b':path', b'/')], None); [(b':path', b'/')], None)
self.client_session.send(); self.client_session.send()
self.server_session.recv(); self.server_session.recv()
self.server_session.submit_rst_stream(1, spdylay.PROTOCOL_ERROR) self.server_session.submit_rst_stream(1, spdylay.PROTOCOL_ERROR)
self.server_session.send(); self.server_session.send()
self.client_session.recv(); self.client_session.recv()
self.assertEqual(1, len(self.client_streams.recv_frames)) self.assertEqual(1, len(self.client_streams.recv_frames))
frame = self.client_streams.recv_frames[0] frame = self.client_streams.recv_frames[0]
@ -162,8 +162,8 @@ class SpdylayTests(unittest.TestCase):
def test_submit_goaway(self): def test_submit_goaway(self):
self.client_session.submit_goaway(spdylay.GOAWAY_PROTOCOL_ERROR) self.client_session.submit_goaway(spdylay.GOAWAY_PROTOCOL_ERROR)
self.client_session.send(); self.client_session.send()
self.server_session.recv(); self.server_session.recv()
self.assertEqual(1, len(self.server_streams.recv_frames)) self.assertEqual(1, len(self.server_streams.recv_frames))
frame = self.server_streams.recv_frames[0] frame = self.server_streams.recv_frames[0]
@ -179,8 +179,8 @@ class SpdylayTests(unittest.TestCase):
def test_fail_session(self): def test_fail_session(self):
self.client_session.fail_session(spdylay.GOAWAY_PROTOCOL_ERROR) self.client_session.fail_session(spdylay.GOAWAY_PROTOCOL_ERROR)
self.client_session.send(); self.client_session.send()
self.server_session.recv(); self.server_session.recv()
self.assertEqual(1, len(self.server_streams.recv_frames)) self.assertEqual(1, len(self.server_streams.recv_frames))
frame = self.server_streams.recv_frames[0] frame = self.server_streams.recv_frames[0]
@ -263,5 +263,24 @@ class SpdylayTests(unittest.TestCase):
with self.assertRaises(spdylay.CallbackFailureError): with self.assertRaises(spdylay.CallbackFailureError):
self.client_session.send() self.client_session.send()
def test_submit_data(self):
self.client_session.submit_syn_stream(spdylay.CTRL_FLAG_NONE, 0, 2,
[(b':path', b'/')], None)
self.client_session.send()
self.server_session.recv()
self.assertEqual(1, len(self.server_streams.recv_frames))
frame = self.server_streams.recv_frames[0]
self.assertEqual(spdylay.SYN_STREAM, frame.frame_type)
self.assertEqual(1, frame.stream_id)
data_prd = spdylay.DataProvider(io.BytesIO(b'Hello World'), read_cb)
self.client_session.submit_data(1, spdylay.DATA_FLAG_FIN, data_prd)
self.client_session.send()
self.server_session.recv()
self.assertEqual(b'Hello World',
self.server_streams.recv_data.getvalue())
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()