Security News
New Python Packaging Proposal Aims to Solve Phantom Dependency Problem with SBOMs
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
HTTP proxy with the ability to capture requests and generate a fake response. It is not intended to use in production environments, but only in integration tests.
It is tested in Ruby MRI (1.9, 2.0, 2.1), JRuby and Rubinius. Check out the Travis page to see the current status on every platform.
Install the gem with
$ gem install cap_proxy
Or add it to your Gemfile
group :test do
gem "cap_proxy"
end
Finally, load it into your application
require "cap_proxy/server"
The main class to use the proxy is CapProxy::Server
. You have to indicate the address where the proxy will be listening, and the address of the HTTP server which receives every non-captured request.
When the proxy is initialized, you have to call to the #run!
method to start the server. This method has to be invoked when EventMachine is running.
proxy = CapProxy::Server.new("localhost:1234", "localhost:5678")
EM.run do
proxy.run!
end
You can use a logger with the proxy:
logger = Logger.new(STDOUT)
proxy = CapProxy::Server.new("localhost:1234", "localhost:5678", logger)
EM.run do
proxy.run!
end
Now, every connection to http://localhost:1234
will be forwarded to http://localhost:5678
.
For your convenience, if you are using RSpec you can use CapProxy::TestWrapper
to wrap every example.
require "cap_proxy/testkit"
# ...
around :each do |example|
CapProxy::TestWrapper.run(example, "localhost:4001", "localhost:3000") do |proxy|
@proxy = proxy
end
end
CapProxy::TestWrapper
will initialize EventMachine, creates a proxy running in it, and launch the example in a different thread. When the example is finished, the EventMachine is stopped.
With #capture
you can capture any request, and generate a dummy response for it. You have to define a filter, and a block to generate the response.
@proxy.capture(method: "get", path: "/users") do |client, request|
client.respond 404, {}, "Dummy response"
end
Details about how to capture requests, and to generate a response for it, are in the section Capturing requests.
The first step is to define a filter. If a request matches multiple filters, it will be managed by the oldest one. If no filter matches the request, it will be forwarded to the default HTTP server.
The easiest way to define a filter is with a hash, which can contain any of the following items:
:method
:path
:headers
:method
can accept any string to represent a HTTP method ("get"
and "GET"
are equivalent).
@proxy.capture(method: "get") { ... }
:path
can be defined with a string (full URI has to match), or with a regular expression (matched with the =~
operator).
@proxy.capture(path: "/users") { ... }
@proxy.capture(method: "post", path: %r{/users/\d+}) { ... }
:headers
expects a hash with the headers to be matched. The value of every header can be a string or a regular expression.
@proxy.capture(path: "/", headers: { "content-type" => /json/ }) do
...
end
If you need more control to filter the request, you can create your own filter
class MyFilter < CapProxy::Filter
def apply?(request)
# Conditions
end
end
The #apply?
method receives an instance of Http::Parser
, from the http_parser.rb gem. You can use methods like http_method
, request_url
or headers
to query info about the request.
If #apply?
returns false
or nil
, the filter will skip this request.
To use your filter, create an instance of it:
@proxy.capture(MyFilter.new) { ... }
The block of the capture
method is invoked with two arguments: the first one is an instance of CapProxy::Client
. The last one is the instance of HTTP::Parser
.
The simplest way to generate a response is calling to client.respond(status, headers, body)
.
@proxy.capture(path: "/users", method: "post") do |client, request|
client.respond 201, {"Content-Type" => "application/json"}, %q[{"id": 123}]
end
You can generate a response in multiple chunks.
First, you have to call to client.chunks_start(status, headers)
, to initialize the chunked response. Then, for every chunk, call to client.chunks_send(data)
. Finally, finish the connection with client.chunks_finish
@proxy.capture(path: "/chunks") do |client, request|
client.chunks_start 200, "content-type" => "text/plain"
EM.add_timer(0.4) { client.chunks_send("Cap") }
EM.add_timer(0.8) { client.chunks_send("Proxy\n") }
EM.add_timer(1.2) { client.chunks_finish }
end
require "cap_proxy/server"
require "cap_proxy/testkit"
describe MyApp do
around :each do |test|
CapProxy::TestWrapper.run(test, "localhost:4001", "localhost:3000") do |proxy|
@proxy = proxy
end
end
it "should do it" do
@proxy.capture(method: "get", path: "/users") do |client, request|
request.request_url.should include("foo_id")
client.respond 404, {}, "Dummy response"
end
end
end
FAQs
Unknown package
We found that cap_proxy demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
PEP 770 proposes adding SBOM support to Python packages to improve transparency and catch hidden non-Python dependencies that security tools often miss.
Security News
Socket CEO Feross Aboukhadijeh discusses open source security challenges, including zero-day attacks and supply chain risks, on the Cyber Security Council podcast.
Security News
Research
Socket researchers uncover how threat actors weaponize Out-of-Band Application Security Testing (OAST) techniques across the npm, PyPI, and RubyGems ecosystems to exfiltrate sensitive data.