Commit Graph

103 Commits

Author SHA1 Message Date
Jacob Hoffman-Andrews
4cb856196e Rename some call sites for read_headers.
Fixes tests.
2020-11-15 22:35:42 +01:00
Jacob Hoffman-Andrews
ec8dace1af Turn Unit into a built Request (#223)
This involved removing the Request reference from Unit, and adding an
Agent, a method, and headers.

Also, move is_retryable to Unit.
2020-11-14 01:12:01 -08:00
Jacob Hoffman-Andrews
acc36ac370 Add support for using testserver in doctests. (#218)
Doctests run against a normally-built copy of the crate, i.e. one
without #[cfg(test)] set, so we can't use the conditional compilation
feature.

Instead, define a static var that indicates whether the library is
running in test mode or not. For each doctest, insert a hidden call that
sets this var to true. Then, when ureq::agent() is called, it returns a
test_agent instead.

This required moving testserver out of the test mod and into src/, so
that it can be included unconditionally (i.e. when cfg(test) is false).

This PR converts one doctest as an example. If we land this PR, I'll
send a followup to convert the rest.
2020-11-13 10:40:16 -08:00
Jacob Hoffman-Andrews
a0b901f35b Remove qstring dependency. (#221)
Instead, rely on Url's built-in query parameter handling. A Request now
accumulates a list of query param pairs, and joins them with a parsed
URL at the time do_call is called.

In the process, remove some getters that rely on parsing the URL.
Adapting these getters was going to be awkward, and they mostly
duplicate things people can readily get by parsing the URL.
2020-11-13 00:02:52 -08:00
Martin Algesten
e37acc85b2 Remove AgentBuilder::set headers
The headers are not scoped by host, which means using them for
something like `Authorization` would effectively "leak" to all
requests using the agent.

Context:
https://github.com/algesten/ureq/issues/203#issuecomment-716385310
2020-11-08 11:31:49 +01:00
Jacob Hoffman-Andrews
a52c6021cf Merge branch 'master' into release-2.0 2020-10-25 14:07:32 -07:00
Martin Algesten
1369c32351 API changes for 2.0
* Remove Request::build
* All mutations on Request follow builder pattern

The previous `build()` on request was necessary because mutating
functions did not follow a proper builder pattern (taking `&mut self`
instead of `mut self`). With a proper builder pattern, the need for
`.build()` goes away.

* All Request body and call methods consume self

Anything which "executes" the request will now consume the `Request`
to produce a `Result<Response>`.

* Move all config from request to agent builder

Timeouts, redirect config, proxy settings and TLS config are now on
`AgentBuilder`.

* Rename max_pool_connections -> max_idle_connections
* Rename max_pool_connections_per_host ->  max_idle_connections_per_host

Consistent internal and external naming.

* Introduce new AgentConfig for static config created by builder.

`Agent` can be seen as having two parts. Static config and a mutable
shared state between all states. The static config goes into
`AgentConfig` and the mutable shared state into `AgentState`.

* Replace all use of `Default` for `new`.

Deriving or implementing `Default` makes for a secondary instantiation
API.  It is useful in some cases, but gets very confusing when there
is both `new` _and_ a `Default`. It's especially devious for derived
values where a reasonable default is not `0`, `false` or `None`.

* Remove feature native_tls, we want only native rustls.

This feature made for very clunky handling throughout the code. From a
security point of view, it's better to stick with one single TLS API.
Rustls recently got an official audit (very positive).

https://github.com/ctz/rustls/tree/master/audit

Rustls deliberately omits support for older, insecure TLS such as TLS
1.1 or RC4. This might be a problem for a user of ureq, but on balance
not considered important enough to keep native_tls.

* Remove auth and support for basic auth.

The API just wasn't enough. A future reintroduction should at least
also provide a `Bearer` mechanism and possibly more.

* Rename jar -> cookie_store
* Rename jar -> cookie_tin

Just make some field names sync up with the type.

* Drop "cookies" as default feature

The need for handling cookies is probably rare, let's not enable it by
default.

* Change all feature checks for "cookie" to "cookies"

The outward facing feature is "cookies" and I think it's better form
that the code uses the official feature name instead of the optional
library "cookies".

* Keep `set` on Agent level as well as AgentBuilder.

The idea is that an auth exchange might result in a header that need
to be set _after_ the agent has been built.
2020-10-25 11:47:38 +01:00
Jacob Hoffman-Andrews
2bf9362eff Reinstate read timeouts on body.
This feature was broken in #67, which reset timeouts on the
stream before passing it to set_stream.

As part of this change, refactor the internal storage of
timeouts on the Request object to use Option<Duration>.

Remove the deadline field on Response. It wasn't used. The
deadline field on unit was used instead.

Add a unittest.
2020-10-24 12:12:07 +02:00
Jacob Hoffman-Andrews
32f9ebc04a Separate overall_timeout checks. 2020-10-24 12:08:27 +02:00
Jacob Hoffman-Andrews
1f5f65877a Update overall_timeout_during_headers test. 2020-10-24 12:08:27 +02:00
Jacob Hoffman-Andrews
14475cb5c7 Add test for read_timeout during headers. 2020-10-24 12:08:27 +02:00
Jacob Hoffman-Andrews
703ca41960 Push mutexes down into pool and cookie store. (#193)
Previously, Agent stored most of its state in one big
Arc<Mutex<AgentState>>. This separates the Arc from the Mutexes.
Now, Agent is a thin wrapper around an Arc<AgentState>. The individual
components that need locking, ConnectionPool and CookieStore, now are
responsible for their own locking.

There were a couple of reasons for this. Internal components that needed
an Agent were often instead carrying around an Arc<Mutex<AgentState>>.
This felt like the components were too intertwined: those other
components shouldn't have to care quite so much about how Agent is
implemented. Also, this led to compromises of convenience: the Proxy on
Agent wound up stored inside the `Arc<Mutex<AgentState>>` even though it
didn't need locking. It was more convenient that way because that was
what Request and Unit had access too.

The other reason to push things down like this is that it can reduce
lock contention. Mutations to the cookie store don't need to lock the
connection pool, and vice versa. This was a secondary concern, since I
haven't actually profiled these things and found them to be a problem,
but it's a happy result of the refactoring.

Now all the components outside of Agent take an Agent instead of
AgentState.

In the process I removed `Agent.cookie()`. Its API was hard to use
correctly, since it didn't distinguish between cookies on different
hosts. And it would have required updates as part of this refactoring.
I'm open to reinstating some similar functionality with a refreshed API.

I kept `Agent.set_cookie`, but updated its method signature to take a
URL as well as a cookie.

Many of ConnectionPool's methods went from `&mut self` to `&self`,
because ConnectionPool is now using interior mutability.
2020-10-20 00:03:45 -07:00
Jacob Hoffman-Andrews
75bc803cf1 Use a testserver in tests. (#194)
This is a step towards allowing our tests to run without network access,
which will make them more resilient and faster.

Replace the URL in one instance of an HTTPS test that didn't need HTTPS.
2020-10-19 00:27:40 -07:00
Jacob Hoffman-Andrews
30162bf3bb Move Agent construction to new AgentBuilder.
In the process, rename set_foo methods to just foo, since methods on the
builder will always be setters.

Adds a new() method on ConnectionPool so it can be constructed directly
with the desired limits. Removes the setter methods on ConnectionPool
for those limits. This means that connection limits can only be set when
an Agent is built.

There were two tests that verify Send and Sync implementations, one for
Agent and one for Request. This PR moves the Request test to request.rs,
and changes both tests to more directly verify the traits. There may be
another way to do this, I'm not sure.
2020-10-18 12:12:07 +02:00
Jacob Hoffman-Andrews
044f25b02a Add more header validation (#188)
This adds validation of header values on receive, and of both header
names and header values on send. This doesn't change the return
type of set to be a Result, it just validates when the request is
sent. Also removes the section in the README describing handling
of invalid headers, and updates a test that verified acceptance of
non-ASCII headers so that it verifies rejection of them instead.
2020-10-17 17:59:29 -07:00
Jacob Hoffman-Andrews
e36c1c2aa1 Switch to Result-based API. (#132)
Gets rid of synthetic_error, and makes the various send_* methods return `Result<Response, Error>`.
Introduces a new error type "HTTP", which represents an error due to status codes 4xx or 5xx.
The HTTP error type contains a boxed Response, so users can read the actual response if they want.
Adds an `error_for_status` setting to disable the functionality of treating 4xx and 5xx as errors.
Adds .unwrap() to a lot of tests.

Fixes #128.
2020-10-17 00:40:48 -07:00
Jacob Hoffman-Andrews
5b75deccef Use correct host on redirect. (#180) 2020-10-06 00:10:56 -07:00
Jacob Hoffman-Andrews
2d4b42e298 Use cookie_store crate instead of cookie::CookieJar (#169)
CookieJar doesn't support the path-match and domain-match algorithms from [RFC 6265](https://tools.ietf.org/html/rfc6265#section-5.1.3), while cookie_store does.

This fixes some issues with the cookie matching algorithm currently in ureq. For instance,
the domain-match uses substring matching rather than the RFC 6265 algorithm.

This deletes two tests:

match_cookies_returns_nothing_when_no_cookies didn't test much
agent_cookies was failing because cookie_store rejects cookies on the `test:` scheme.
  The way around this is to set up a testserver - but it turns out cookies_on_redirect already
  does that, and covers the same cases and more.

This changes some cookie-related behavior:

 - Cookies could previously be sent to a wrong domain - e.g. a cookie set on `example.com`
  could go to `example.com.evil.com` or `evilexample.com`. Probably no one was relying on
  this, since it's quite broken.
 - A cookie with a path of `/foo` could be sent on a request to `/foobar`, but now it can't.
 - Cookies could previously be set on IP addresses, but now they can't.
 - Cookies could previously be set for domains other than the one on the request (or its
  parents), but now they can't.
 - When a cookie had no domain attribute, it would previously get the domain from the
  request, and subsequently be sent to that domain and all subdomains. Now, it will only
  be sent to that exact domain (host-only).

That last one is probably the most likely to break people, since someone could depend
on it without realizing it was broken behavior.
2020-10-04 10:21:09 -07:00
Martin Algesten
0bf981031b Replace lazy_static! with once_cell Lazy (#176)
Modern rust code bases prefer once_cell::sync::Lazy over the older
macro based lazy_static.
2020-10-04 09:35:31 -07:00
Jacob Hoffman-Andrews
9b39e55d1c Use cookie_store 2020-09-29 00:34:29 -07:00
Jacob Hoffman-Andrews
db0c6fb1b0 Print better errors 2020-09-27 10:42:05 +02:00
Jacob Hoffman-Andrews
786047629a bugfix: Don't re-pool streams on drop.
We only want streams in the pool that are ready for the next request,
and don't have any remaining bytes of the previous request. That's the
case when we return a stream due to EOF on the underlying `Read`.

However, there was also an `impl Drop` that returned the stream to the
pool on drop of a PoolReturnRead. That resulted in a bug: If a user
called `response.into_reader()`, but did not read the entire body,
a dirty stream would be returned to the pool. The next time a request
was made to the same host, that stream would be reused, and instead of
reading off "HTTP/1.1 200 OK", ureq would read a remnant of the previous
request, resulting in a BadStatus error.
2020-09-27 10:42:05 +02:00
Ulrik Mikaelsson
11413726cd Implement Pluggable Name-resolution (#148)
This defines a new trait `Resolver`, which turns an address into a
Vec<SocketAddr>. It also provides an implementation of Resolver for
`Fn(&str)` so it's easy to define simple resolvers with a closure.


Fixes #82

Co-authored-by: Ulrik <ulrikm@spotify.com>
2020-09-26 16:35:13 -07:00
Daniel Rivas
8bba07a9af Add req field to Unit and remove cloned parts from request (#158)
Instead of cloning most of `Request`'s fields individually when
creating a `Unit`, this PR switches to just cloning `Request` and
stuffing it in `Unit`, and changes references to `unit.[field]` to
`unit.req.[field]` where appropriate.

Fixes #155
2020-09-26 10:22:10 -07:00
Martin Algesten
155edeef19 cargo fmt (#151) 2020-09-19 00:28:39 -07:00
Martin Algesten
05ffe53e4c CI: error on dead/unused code for features (#146)
By using `RUSTFLAGS="-D dead_code -D unused-variables -D unused"`, we tell
the compiler to upgrade warnings for unused code to errors. This combined
with a more elaborate test matrix means we can have the CI catch feature
flag combos that cause warnings.
2020-09-18 13:55:23 -07:00
Ulrik Mikaelsson
f599828c6d Turn Option<AgentState> into AgentState (#149)
`Some(AgentState)` seem to be assumed pretty much everywhere. I could not
find any test or piece of code hinting at how `None` should be interpreted,
or even see how a state of `None` could even be constructed.

Co-authored-by: Ulrik <ulrikm@spotify.com>
2020-09-18 13:47:11 -07:00
Jacob Hoffman-Andrews
c343587afb Use #[cfg(feature = "cookie")] for some functions.
Some helper functions introduced as part of the cookies_on_redirect
test are only used by that test, which means they are only used when the
cookie feature is enabled. This causes clippy warnings for some of the
other feature combinations in CI.
2020-09-14 08:58:02 +02:00
Jacob Hoffman-Andrews
f38c203215 Fix cookies_on_redirect unittest.
Previously this test relied on a specific ordering of cookies, which was
not guaranteed. This makes the test robust to random ordering.

Also, fix the check for the `second` cookie to actually check the right
cookie.
2020-09-13 21:14:40 +02:00
Jacob Hoffman-Andrews
99cdff7519 Add unittest for cookie handling on redirects. 2020-09-13 14:12:17 +02:00
Martin Algesten
a198ba0a65 Test case for preserving io::Error timed out 2020-08-07 21:51:35 +02:00
Martin Algesten
db4cc90956 Normalize timeout ErrorKind::WouldBlock to be TimedOut (#131)
`set_read_timeout` and `set_write_timeout` can cause `ErrorKind::WouldBlock` on unix-y platforms.

This PR normalizes those cases to `ErrorKind::TimedOut`. This will make it simpler higher up in the
stack to deal with timeouts.
2020-08-07 10:06:56 -07:00
Jacob Hoffman-Andrews
7fce93d1c8 Fix tests. 2020-07-02 23:07:53 -07:00
Jacob Hoffman-Andrews
b47f90e773 Factor out TestServer. (#98)
This creates a struct that encapsulates the test server setup, and adds
a shutdown method to clean up the thread when done.
2020-06-30 19:16:34 -07:00
Jacob Hoffman-Andrews
3014f58a28 Add scheme to PoolKey and let port be None. (#84)
PoolKey calls unwrap() on an option that can be None. Specifically, the
local variable `port` can be None when PoolKey is constructed with a Url
whose scheme is unrecognized in url.port_or_known_default().

To fix that, make port an Option. Also, make scheme part of the PoolKey.
This prevents, for instance, a stream opened for `https://example.com:9999`
being reused on a request for `http://example.com:9999`.

Remove the test-only pool.get() accessor. This was used in only one test,
agent_pool in range.rs. This seemed like it was testing the agent more
than it was testing ranges, so I moved it to agent.rs and edited to
remove the range-testing parts.

Also, reject unrecognized URLs earlier in connect_socket so they don't
reach try_get_connection.
2020-06-22 23:23:39 -07:00
Jacob Hoffman-Andrews
00461fb5bd Only retry idempotent requests. (#80)
This also reverts a change to send_body that was originally added to
return the number of bytes written. It's no longer needed now that we
check the size of the reader in advance.

Fixes #76.
2020-06-22 09:40:55 -07:00
Jacob Hoffman-Andrews
7adbd57308 Fix up cargo test --no-default-features. (#75)
Adds some feature guards, and removes an unnecessary feature guard
around a call to connect_https (there's an implementation available for
non-TLS that returns UnknownScheme).

Also, remove unnecessary agent.state() method that was only available in
TLS builds. The state field is directly accessible within the crate, and
can be used in both TLS and non-TLS builds.

Co-authored-by: Martin Algesten <martin@algesten.se>
2020-06-21 09:54:03 +02:00
Jacob Hoffman-Andrews
57be414d97 Add overall timeout for requests. (#67)
This deprecates timeout_read() and timeout_write() in favor of
timeout(). The new timeout method on Request takes a Duration instead
of a number of milliseconds, and is measured against overall request
time, not per-read time.

Once a request is started, the timeout is turned into a deadline
specific to that call. The deadline is used in conjunction with the
new DeadlineStream class, which sets a timeout on each read according
to the remaining time for the request. Once the request is done,
the DeadlineStream is unwrapped via .into::<Stream>() to become
an undecorated Stream again for return to the pool. Timeouts on the
stream are unset at this point.

Still to be done:

Add a setting on Agent for default timeout.
Change header-writing code to apply overall deadline rather than
per-write timeout.
Fixes #28.
2020-06-21 09:47:35 +02:00
k3d3
9f7f712dde Add optional native-tls support, clear up warnings for flag configurations 2020-06-15 09:25:49 +02:00
Jacob Hoffman-Andrews
8a05241eac Move test server into its own function 2020-06-15 09:15:36 +02:00
Jacob Hoffman-Andrews
c1d7dbcfe9 Remove no-longer needed feature=tls 2020-06-15 09:15:36 +02:00
Jacob Hoffman-Andrews
64ef337c0b Fix connection_reuse test.
This test was making requests to a server on the Internet. That has the
potential to make the test flaky. Also, the test was relying on a
specific behavior from that server (timing out after 2s), which it no
longer exhibits.

This sets up a local test server that exhibits the specific properties
needed for this test.
2020-06-15 09:15:36 +02:00
Martin Algesten
deb2002f6f port in host header. close #63 2020-06-12 22:00:30 +02:00
Martin Algesten
4196eeff40 remove curlies warnings 2020-06-12 21:03:49 +02:00
Martin Algesten
1e93f17a58 fix test problem 2020-05-20 21:22:35 +02:00
Paolo Barbolini
4e744f87c1 Keep the old Response::into_json around and call this Response::into_json_deserialize 2020-05-06 13:47:37 +02:00
Paolo Barbolini
0b69c595b6 Make Response::into_json deserialize into a serde DeserializeOwned
This removes the necessity to take the result of Response::into_json and
having to convert it into a struct by using serde_json::from_value

This adds no new dependencies since serde_json already depends on serde.
Users of ureq will have to include `serde_derive` either by importing it
directly or by using serde with the `derive` feature, unless they want to
manually implement `Deserialize` on their structs.
2020-05-06 13:47:37 +02:00
Rob Young
28bdb89175 Set a default content type for JSON requests
When sending a JSON request a Content-Type of application/json is
usually wanted. This is often set as a default for JSON methods by HTTP
clients so can be confusing when it is not set. However, we do not want
to prevent the user from setting their own Content-Type.
2020-02-06 07:57:00 +01:00
Tom Forbes
594340a096 Fix compilation errors with the cookies feature (#22)
* Fix compilation errors with the cookies feature
2019-10-30 11:51:06 +01:00
Martin Algesten
753d61b454 Retry some pooled connections failing when server closes. Close #10
This is not a perfect solution. It works as long as we are not sending
any body bytes. We discover the error first when attempting to read
the response status line. That means we discover the error after
sending body bytes. To be able to re-send the body, we would need to
introduce a buffer to be able to replay the body on the next
request. We don't currently do that.
2019-10-20 21:36:38 +02:00