Synopsis
--------
The `Env` that gets stored on the `Response` does not contain
a reference to that response. This env is a copy of the env that
was passed through the middleware stack. Thus if the env
passed to `app.call` is used, it has the response, but if the one
from the `Response` is used, then it does not. This happens when,
for example, you invoke the `on_complete` hook on the response,
after it has finished.
Fixes Longstanding VCR issue
----------------------------
Fixes https://github.com/vcr/vcr/issues/386
A longstanding issue in VCR's integration with v0.9.x
It was worked around in this commit: https://github.com/vcr/vcr/pull/439
And is merged into master, but is not released.
Merging this will fix the issue, without the changes to VCR needing to
be released.
The old code, which is currently released, and gets its env from the
Request can be seen
[here](cb9696c44d%5E/lib/vcr/middleware/faraday.rb#L99-105)
Fixes Faraday Issue
-------------------
Fixes https://github.com/lostisland/faraday/issues/441
which identifies this same problem.
Closes Faraday PR
-----------------
I'm going to recommend closing https://github.com/lostisland/faraday/pull/360/files
as the issue was probably introduced
[here](04a8514cba (diff-fc9726b31994223d11a212b5169100fdL68))
when `Response#finish` changed from storing the `env` directly,
to storing a copy:
```
- @env = env
+ @env = Env.from(env)
```
Presumably this behaviour is still desired, but the mentioned pull
essentially undoes this by returning the same `env` from `Env.from`
The commit that introduced the issue is probably good, but is called by
the app in the middleware stack that creates the response, before it
sets the rsponse onto the env. This means that the copy does not have
the link to the response.
81f16593a0/lib/faraday/rack_builder.rb (L152-155)
Not sure about the test name/location
-------------------------------------
I had difficulty figuring out where to put this test, and what to name
it. I eventually went with the test on the `middleware_stack_test.rb`,
because it deals with the `RackBuilder`, but if there's a better place,
or a better name, let me know and I'll update it.
One other weird thing
---------------------
Depending on when the `Request#on_complete` callback is invoked,
you're either getting the original env, or the copy:
81f16593a0/lib/faraday/response.rb (L64-65)
Allows 3rd-party libraries to register named shortcuts to resolve to
fully qualified constant names for specific middleware.
Usage:
Faraday.register_middleware :aloha => MyModule::Aloha
Faraday.register_middleware :response, :boom => MyModule::Boom
Faraday.register_middleware :lazy => lambda { MyModule::LazyLoaded }
Those shortcuts are then available in Builder:
builder.use :aloha
builder.response :boom
The downside is, middleware can't be modified after making the first request:
conn.use MyMiddleware # => OK
conn.get('/')
conn.use AnotherMiddleware # => raises a Builder::StackLocked error
On the plus side, the middleware stack is built only once and then cached as
the Connection#app object.
The Connection instance can always be "forked off" with the `dup` method and
modified as if it were fresh.
Changes:
- there is no `env[:response]` during the request phase
- middleware should attach `on_complete` handlers to the response object
returned from `@app.call(env)` call
- `on_complete` handlers execute immediately if the request is finished
- Builder doesn't have the `run` method anymore
- the default stack is now setup as soon as the Builder object has been initialized
- the inner app for the stack is set when creating the request
The problem with the old builder is that it was hard to see which middleware
is on the stack (it was stored in lambdas) and even harder to add new middleware
at arbitrary positions.
Incompatible changes:
- `Builder.create` shouldn't be called without a block anymore
- `Builder#run` doesn't push middleware to the stack anymore.
Instead, it sets the inner app (overrides the default).
- `Builder#handlers` are now stored in natural order
- Handlers are no longer stored as lambdas. Instead, they are
stored as lightweight `Handler` objects for easier inspection.
- Inner app is no longer present among handlers.
Enhancements:
- It's easy to see what's on the stack: `builder.handlers.inspect`
- It's possible to edit the stack:
- builder.insert_before(ExistingHandler, NewHandler)
- builder.insert_after(...)
- builder.swap(HandlerToReplace, NewHandler)
- builder.delete(HandlerToDelete)