mirror of https://github.com/fafhrd91/actix-web
fix payload documentation
This commit is contained in:
parent
02ae28581a
commit
8c7e4cd6d5
|
@ -1,9 +1,12 @@
|
|||
//! Payload stream
|
||||
use std::cell::RefCell;
|
||||
use std::collections::VecDeque;
|
||||
use std::pin::Pin;
|
||||
use std::rc::{Rc, Weak};
|
||||
use std::task::{Context, Poll, Waker};
|
||||
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
collections::VecDeque,
|
||||
pin::Pin,
|
||||
rc::{Rc, Weak},
|
||||
task::{Context, Poll, Waker},
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use futures_core::Stream;
|
||||
|
@ -22,39 +25,32 @@ pub enum PayloadStatus {
|
|||
|
||||
/// Buffered stream of bytes chunks
|
||||
///
|
||||
/// Payload stores chunks in a vector. First chunk can be received with `.readany()` method.
|
||||
/// Payload stream is not thread safe. Payload does not notify current task when new data
|
||||
/// is available.
|
||||
/// Payload stores chunks in a vector. First chunk can be received with `poll_next`. Payload does
|
||||
/// not notify current task when new data is available.
|
||||
///
|
||||
/// Payload stream can be used as `Response` body stream.
|
||||
/// Payload can be used as `Response` body stream.
|
||||
#[derive(Debug)]
|
||||
pub struct Payload {
|
||||
inner: Rc<RefCell<Inner>>,
|
||||
}
|
||||
|
||||
impl Payload {
|
||||
/// Create payload stream.
|
||||
/// Creates a payload stream.
|
||||
///
|
||||
/// This method construct two objects responsible for bytes stream
|
||||
/// generation.
|
||||
///
|
||||
/// * `PayloadSender` - *Sender* side of the stream
|
||||
///
|
||||
/// * `Payload` - *Receiver* side of the stream
|
||||
/// This method construct two objects responsible for bytes stream generation:
|
||||
/// - `PayloadSender` - *Sender* side of the stream
|
||||
/// - `Payload` - *Receiver* side of the stream
|
||||
pub fn create(eof: bool) -> (PayloadSender, Payload) {
|
||||
let shared = Rc::new(RefCell::new(Inner::new(eof)));
|
||||
|
||||
(
|
||||
PayloadSender {
|
||||
inner: Rc::downgrade(&shared),
|
||||
},
|
||||
PayloadSender::new(Rc::downgrade(&shared)),
|
||||
Payload { inner: shared },
|
||||
)
|
||||
}
|
||||
|
||||
/// Create empty payload
|
||||
#[doc(hidden)]
|
||||
pub fn empty() -> Payload {
|
||||
/// Creates an empty payload.
|
||||
pub(crate) fn empty() -> Payload {
|
||||
Payload {
|
||||
inner: Rc::new(RefCell::new(Inner::new(true))),
|
||||
}
|
||||
|
@ -86,7 +82,7 @@ impl Stream for Payload {
|
|||
self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, PayloadError>>> {
|
||||
self.inner.borrow_mut().readany(cx)
|
||||
Pin::new(&mut *self.inner.borrow_mut()).poll_next(cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -96,6 +92,10 @@ pub struct PayloadSender {
|
|||
}
|
||||
|
||||
impl PayloadSender {
|
||||
fn new(inner: Weak<RefCell<Inner>>) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_error(&mut self, err: PayloadError) {
|
||||
if let Some(shared) = self.inner.upgrade() {
|
||||
|
@ -219,7 +219,10 @@ impl Inner {
|
|||
self.len
|
||||
}
|
||||
|
||||
fn readany(&mut self, cx: &mut Context<'_>) -> Poll<Option<Result<Bytes, PayloadError>>> {
|
||||
fn poll_next(
|
||||
mut self: Pin<&mut Self>,
|
||||
cx: &mut Context<'_>,
|
||||
) -> Poll<Option<Result<Bytes, PayloadError>>> {
|
||||
if let Some(data) = self.items.pop_front() {
|
||||
self.len -= data.len();
|
||||
self.need_read = self.len < MAX_BUFFER_SIZE;
|
||||
|
@ -249,12 +252,18 @@ impl Inner {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::panic::{RefUnwindSafe, UnwindSafe};
|
||||
|
||||
use actix_utils::future::poll_fn;
|
||||
use static_assertions::assert_impl_all;
|
||||
use static_assertions::{assert_impl_all, assert_not_impl_any};
|
||||
|
||||
use super::*;
|
||||
|
||||
assert_impl_all!(Payload: Unpin);
|
||||
assert_not_impl_any!(Payload: Send, Sync, UnwindSafe, RefUnwindSafe);
|
||||
|
||||
assert_impl_all!(Inner: Unpin, Send, Sync);
|
||||
assert_not_impl_any!(Inner: UnwindSafe, RefUnwindSafe);
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_unread_data() {
|
||||
|
|
|
@ -23,7 +23,7 @@ pin_project_lite::pin_project! {
|
|||
H1 { payload: crate::h1::Payload },
|
||||
H2 { payload: crate::h2::Payload },
|
||||
Stream { #[pin] payload: S },
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S> From<crate::h1::Payload> for Payload<S> {
|
||||
|
|
|
@ -120,7 +120,7 @@ impl TestRequest {
|
|||
}
|
||||
|
||||
/// Set request payload.
|
||||
pub fn set_payload<B: Into<Bytes>>(&mut self, data: B) -> &mut Self {
|
||||
pub fn set_payload(&mut self, data: impl Into<Bytes>) -> &mut Self {
|
||||
let mut payload = crate::h1::Payload::empty();
|
||||
payload.unread_data(data.into());
|
||||
parts(&mut self.0).payload = Some(payload.into());
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
## Unreleased - 2021-xx-xx
|
||||
- Rename `Connector::{ssl => openssl}`. [#2503]
|
||||
- Improve `Client` instantiation efficiency when using `openssl` by only building connectors once. [#2503]
|
||||
- `ClientResponse` is no longer `Unpin`. [#2545]
|
||||
- `impl Stream` for `ClientResponse` no longer requires the body type be `Unpin`. [#2545]
|
||||
|
||||
[#2503]: https://github.com/actix/actix-web/pull/2503
|
||||
[#2545]: https://github.com/actix/actix-web/pull/2545
|
||||
|
||||
|
||||
## 3.0.0-beta.14 - 2021-12-17
|
||||
|
|
|
@ -65,7 +65,7 @@ impl TestResponse {
|
|||
|
||||
/// Set response's payload
|
||||
pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
|
||||
let mut payload = h1::Payload::empty();
|
||||
let (_, mut payload) = h1::Payload::create(true);
|
||||
payload.unread_data(data.into());
|
||||
self.payload = Some(payload.into());
|
||||
self
|
||||
|
@ -90,7 +90,8 @@ impl TestResponse {
|
|||
if let Some(pl) = self.payload {
|
||||
ClientResponse::new(head, pl)
|
||||
} else {
|
||||
ClientResponse::new(head, h1::Payload::empty().into())
|
||||
let (_, payload) = h1::Payload::create(true);
|
||||
ClientResponse::new(head, payload.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -429,9 +429,12 @@ mod tests {
|
|||
use actix_http::body;
|
||||
|
||||
use super::*;
|
||||
use crate::http::{
|
||||
header::{self, HeaderValue, CONTENT_TYPE},
|
||||
StatusCode,
|
||||
use crate::{
|
||||
http::{
|
||||
header::{self, HeaderValue, CONTENT_TYPE},
|
||||
StatusCode,
|
||||
},
|
||||
test::assert_body_eq,
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
@ -472,32 +475,23 @@ mod tests {
|
|||
|
||||
#[actix_rt::test]
|
||||
async fn test_json() {
|
||||
let resp = HttpResponse::Ok().json(vec!["v1", "v2", "v3"]);
|
||||
let ct = resp.headers().get(CONTENT_TYPE).unwrap();
|
||||
let res = HttpResponse::Ok().json(vec!["v1", "v2", "v3"]);
|
||||
let ct = res.headers().get(CONTENT_TYPE).unwrap();
|
||||
assert_eq!(ct, HeaderValue::from_static("application/json"));
|
||||
assert_eq!(
|
||||
body::to_bytes(resp.into_body()).await.unwrap().as_ref(),
|
||||
br#"["v1","v2","v3"]"#
|
||||
);
|
||||
assert_body_eq!(res, br#"["v1","v2","v3"]"#);
|
||||
|
||||
let resp = HttpResponse::Ok().json(&["v1", "v2", "v3"]);
|
||||
let ct = resp.headers().get(CONTENT_TYPE).unwrap();
|
||||
let res = HttpResponse::Ok().json(&["v1", "v2", "v3"]);
|
||||
let ct = res.headers().get(CONTENT_TYPE).unwrap();
|
||||
assert_eq!(ct, HeaderValue::from_static("application/json"));
|
||||
assert_eq!(
|
||||
body::to_bytes(resp.into_body()).await.unwrap().as_ref(),
|
||||
br#"["v1","v2","v3"]"#
|
||||
);
|
||||
assert_body_eq!(res, br#"["v1","v2","v3"]"#);
|
||||
|
||||
// content type override
|
||||
let resp = HttpResponse::Ok()
|
||||
let res = HttpResponse::Ok()
|
||||
.insert_header((CONTENT_TYPE, "text/json"))
|
||||
.json(&vec!["v1", "v2", "v3"]);
|
||||
let ct = resp.headers().get(CONTENT_TYPE).unwrap();
|
||||
let ct = res.headers().get(CONTENT_TYPE).unwrap();
|
||||
assert_eq!(ct, HeaderValue::from_static("text/json"));
|
||||
assert_eq!(
|
||||
body::to_bytes(resp.into_body()).await.unwrap().as_ref(),
|
||||
br#"["v1","v2","v3"]"#
|
||||
);
|
||||
assert_body_eq!(res, br#"["v1","v2","v3"]"#);
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
|
|
@ -174,25 +174,28 @@ impl TestRequest {
|
|||
}
|
||||
|
||||
/// Set request payload.
|
||||
pub fn set_payload<B: Into<Bytes>>(mut self, data: B) -> Self {
|
||||
pub fn set_payload(mut self, data: impl Into<Bytes>) -> Self {
|
||||
self.req.set_payload(data);
|
||||
self
|
||||
}
|
||||
|
||||
/// Serialize `data` to a URL encoded form and set it as the request payload. The `Content-Type`
|
||||
/// header is set to `application/x-www-form-urlencoded`.
|
||||
pub fn set_form<T: Serialize>(mut self, data: &T) -> Self {
|
||||
let bytes = serde_urlencoded::to_string(data)
|
||||
/// Serialize `data` to a URL encoded form and set it as the request payload.
|
||||
///
|
||||
/// The `Content-Type` header is set to `application/x-www-form-urlencoded`.
|
||||
pub fn set_form(mut self, data: impl Serialize) -> Self {
|
||||
let bytes = serde_urlencoded::to_string(&data)
|
||||
.expect("Failed to serialize test data as a urlencoded form");
|
||||
self.req.set_payload(bytes);
|
||||
self.req.insert_header(ContentType::form_url_encoded());
|
||||
self
|
||||
}
|
||||
|
||||
/// Serialize `data` to JSON and set it as the request payload. The `Content-Type` header is
|
||||
/// set to `application/json`.
|
||||
pub fn set_json<T: Serialize>(mut self, data: &T) -> Self {
|
||||
let bytes = serde_json::to_string(data).expect("Failed to serialize test data to json");
|
||||
/// Serialize `data` to JSON and set it as the request payload.
|
||||
///
|
||||
/// The `Content-Type` header is set to `application/json`.
|
||||
pub fn set_json(mut self, data: impl Serialize) -> Self {
|
||||
let bytes =
|
||||
serde_json::to_string(&data).expect("Failed to serialize test data to json");
|
||||
self.req.set_payload(bytes);
|
||||
self.req.insert_header(ContentType::json());
|
||||
self
|
||||
|
|
Loading…
Reference in New Issue