Skip to content
This repository has been archived by the owner on Oct 18, 2022. It is now read-only.

Don't use reqwest::blocking resolves #60 #78

Closed
wants to merge 11 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

## Unreleased

No changes.
* Updated to Rust 2021 Syntax
* Updated `reqwest`to 0.11.10
* Added `tokio` dependency for async runtime (feature rt-multi-thread)

- Refactored to not use `reqwest::blocking`, all interfaces stay stable

## 0.15.1 - 2021-11-02

Expand Down
18 changes: 14 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ categories = ["network-programming", "encoding"]
readme = "README.md"
license = "CC0-1.0"
name = "xmlrpc"
version = "0.15.1"
version = "0.16.0"
edition = "2021"

# cargo-release configuration
[package.metadata.release]
Expand Down Expand Up @@ -40,12 +41,21 @@ maintenance = { status = "actively-developed" }

[dependencies]
# public
iso8601 = "0.4.0"
reqwest = { version = "0.11.0", features = [ "blocking" ], default-features = false, optional = true }
iso8601 = "0.5.0"
# private
mime = { version = "0.3", optional = true }
base64 = "0.13.0"
xml-rs = "0.8.0"
xml-rs = "0.8.4"
futures = "0.3.21"

[dependencies.reqwest]
version = "0.11.10"
default-features = false
optional = true

[dependencies.tokio]
version = "1.17.0"
features = ["rt-multi-thread"]

[dev-dependencies]
version-sync = "0.9"
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ Start by adding an entry to your `Cargo.toml`:

```toml
[dependencies]
xmlrpc = "0.15.1"
xmlrpc = "0.16.0"
```

Then import the crate into your Rust code:
Expand Down
19 changes: 13 additions & 6 deletions examples/custom-header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,41 @@
extern crate reqwest;
extern crate xmlrpc;

use futures::executor::block_on;
use xmlrpc::http::{build_headers, check_response};
use xmlrpc::{Request, Transport};

use reqwest::blocking::{Client, RequestBuilder, Response};
use reqwest::{Client, RequestBuilder};
use reqwest::header::COOKIE;

use std::error::Error;
use std::io::Cursor;

/// Custom transport that adds a cookie header.
struct MyTransport(RequestBuilder);

impl Transport for MyTransport {
type Stream = Response;
type Stream = Cursor<String>;

fn transmit(self, request: &Request) -> Result<Self::Stream, Box<dyn Error + Send + Sync>> {
let mut body = Vec::new();
request
.write_as_xml(&mut body)
.expect("could not write request to buffer (this should never happen)");

let response = build_headers(self.0, body.len() as u64)
let response = async move {build_headers(self.0, body.len() as u64)
.header(COOKIE, "SESSION=123abc") // Our custom header will be a `Cookie` header
.body(body)
.send()?;
.send().await.unwrap()};

let resp = block_on(response);

check_response(&response)?;
check_response(&resp)?;

Ok(response)
let rs = async move {resp.text().await.unwrap()};
let rv = Cursor::new(block_on(rs));

Ok(rv)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/error.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Defines error types used by this library.

use Value;
use crate::value::Value;

use xml::common::TextPosition;
use xml::reader::Error as XmlError;
Expand Down
3 changes: 1 addition & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@
//!
//! [XML-RPC specification]: http://xmlrpc.scripting.com/spec.html

#![doc(html_root_url = "https://docs.rs/xmlrpc/0.15.1")]
#![doc(html_root_url = "https://docs.rs/xmlrpc/0.16.0")]
#![warn(missing_debug_implementations)]
#![warn(rust_2018_idioms)]
#![warn(missing_docs)]

extern crate base64;
Expand Down
6 changes: 3 additions & 3 deletions src/parser.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! XML-RPC response parser.

use error::ParseError;
use {Fault, Value};
use crate::error::{ParseError, Fault};
use crate::value::Value;

use base64;
use iso8601::datetime;
Expand Down Expand Up @@ -353,7 +353,7 @@ pub fn parse_response<R: Read>(reader: &mut R) -> ParseResult<Response> {
mod tests {
use super::*;

use error::Fault;
use crate::error::Fault;
use Value;

use std::fmt::Debug;
Expand Down
14 changes: 8 additions & 6 deletions src/request.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#[cfg(feature = "http")]
extern crate reqwest;

use error::{Error, RequestErrorKind};
use parser::parse_response;
use transport::Transport;
use utils::escape_xml;
use Value;
use crate::error::{Error, RequestErrorKind};
use crate::parser::parse_response;
use crate::transport::Transport;
use crate::utils::escape_xml;
use crate::value::Value;

use std::collections::BTreeMap;
use std::io::{self, Write};
Expand Down Expand Up @@ -81,6 +81,8 @@ impl<'a> Request<'a> {
.transmit(self)
.map_err(RequestErrorKind::TransportError)?;

//let mut reader = tr.as_bytes();

let response = parse_response(&mut reader).map_err(RequestErrorKind::ParseError)?;

let value = response.map_err(RequestErrorKind::Fault)?;
Expand Down Expand Up @@ -111,7 +113,7 @@ impl<'a> Request<'a> {
// While we could implement `Transport` for `T: IntoUrl`, such an impl might not be
// completely obvious (as it applies to `&str`), so I've added this method instead.
// Might want to reconsider if someone has an objection.
self.call(reqwest::blocking::Client::new().post(url))
self.call(reqwest::Client::new().post(url))
}

/// Formats this `Request` as a UTF-8 encoded XML document.
Expand Down
42 changes: 29 additions & 13 deletions src/transport.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use Request;

use crate::request::Request;
use std::error::Error;
use std::io::Read;

Expand Down Expand Up @@ -35,7 +34,7 @@ pub trait Transport {
/// return an appropriate [`Error`] to the caller.
///
/// [`Error`]: struct.Error.html
fn transmit(self, request: &Request<'_>) -> Result<Self::Stream, Box<dyn Error + Send + Sync>>;
fn transmit(self, request: &Request<'_>) -> std::result::Result<Self::Stream, Box<dyn Error + Send + Sync + 'static>>;
}

// FIXME: Link to `Transport` and `RequestBuilder` using intra-rustdoc links. Relative links break
Expand Down Expand Up @@ -65,10 +64,13 @@ pub mod http {
extern crate mime;
extern crate reqwest;

use std::io::Cursor;
use self::mime::Mime;
use self::reqwest::blocking::RequestBuilder;
use self::reqwest::RequestBuilder;
use self::reqwest::header::{CONTENT_LENGTH, CONTENT_TYPE, USER_AGENT};
use {Request, Transport};
use crate::request::Request;
use crate::transport::Transport;
use tokio::runtime::Runtime;

use std::error::Error;
use std::str::FromStr;
Expand All @@ -95,7 +97,7 @@ pub mod http {
/// Checks that a reqwest `Response` has a status code indicating success and verifies certain
/// headers.
pub fn check_response(
response: &reqwest::blocking::Response,
response: &reqwest::Response,
) -> Result<(), Box<dyn Error + Send + Sync>> {
// This is essentially an open-coded version of `Response::error_for_status` that does not
// consume the response.
Expand Down Expand Up @@ -133,23 +135,37 @@ pub mod http {
/// The request will be sent as specified in the XML-RPC specification: A default `User-Agent`
/// will be set, along with the correct `Content-Type` and `Content-Length`.
impl Transport for RequestBuilder {
type Stream = reqwest::blocking::Response;
//Chose Cursor<String> as Cursor implements the Read Trait and has ownership
type Stream = Cursor<String>;

fn transmit(
self,
request: &Request<'_>,
) -> Result<Self::Stream, Box<dyn Error + Send + Sync>> {
) -> Result<Self::Stream, Box<(dyn Error + Send + Sync + 'static)>> {
// First, build the body XML
let mut body = Vec::new();
// This unwrap never panics as we are using `Vec<u8>` as a `Write` implementor,
// and not doing anything else that could return an `Err` in `write_as_xml()`.
request.write_as_xml(&mut body).unwrap();

// async part needs to go to separate thread because of interference with caller
let async_transport = async move {
let rv = build_headers(self, body.len() as u64).body(body).send().await?;
check_response(&rv).expect("No valid response");
rv.text().await
};

// execute the async transport in an own thread, to the blocking async execution can be used
let rs = std::thread::spawn( || {Runtime::new().unwrap().block_on(async_transport)}).join().expect("Expected result from async thread");

// error handling of the return value
match rs {
Ok(o) => Ok(Cursor::new(o)),
Err(err) => Err(Box::new(err) as Box<dyn Error + Send + Sync>),
}

let response = build_headers(self, body.len() as u64).body(body).send()?;

check_response(&response)?;
//let rs = std::thread::spawn( || {Runtime::new().unwrap().block_on(async_transport)}).join().unwrap().map_err(|error| Box::new(error) as Box<dyn Error + Send + Sync>);

Ok(response)
}
}
}
}
2 changes: 1 addition & 1 deletion src/value.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Contains the different types of values understood by XML-RPC.

use utils::{escape_xml, format_datetime};
use crate::utils::{escape_xml, format_datetime};

use base64::encode;
use iso8601::DateTime;
Expand Down
1 change: 1 addition & 0 deletions tests/python.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ fn run_tests() {
Fault::from_value(&results[2]).expect("expected fault as third result");
}


fn main() {
let mut reaper = match setup() {
Ok(reap) => reap,
Expand Down