Skip to content

Commit

Permalink
initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
stve committed Nov 11, 2011
0 parents commit 888adb6
Show file tree
Hide file tree
Showing 14 changed files with 272 additions and 0 deletions.
Empty file added .gemtest
Empty file.
17 changes: 17 additions & 0 deletions .gitignore
@@ -0,0 +1,17 @@
*.gem
*.rbc
.bundle
.config
.yardoc
Gemfile.lock
InstalledFiles
_yardoc
coverage
doc/
lib/bundler/man
pkg
rdoc
spec/reports
test/tmp
test/version_tmp
tmp
3 changes: 3 additions & 0 deletions .rspec
@@ -0,0 +1,3 @@
--color
--format=nested
--backtrace
1 change: 1 addition & 0 deletions .simplecov
@@ -0,0 +1 @@
SimpleCov.start
3 changes: 3 additions & 0 deletions .yardopts
@@ -0,0 +1,3 @@
--markup markdown
-
LICENSE.md
4 changes: 4 additions & 0 deletions Gemfile
@@ -0,0 +1,4 @@
source 'http://rubygems.org'

# Specify your gem's dependencies in pow_proxy.gemspec
gemspec
20 changes: 20 additions & 0 deletions LICENSE.md
@@ -0,0 +1,20 @@
Copyright (c) 2010 Steve Agalloco, Assaf Arkin

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
18 changes: 18 additions & 0 deletions Rakefile
@@ -0,0 +1,18 @@
#!/usr/bin/env rake

require 'bundler'
Bundler::GemHelper.install_tasks

require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)

task :default => :spec
task :test => :spec

require 'yard'
namespace :doc do
YARD::Rake::YardocTask.new do |task|
task.files = ['LICENSE.md', 'lib/**/*.rb']
task.options = ['--markup', 'markdown']
end
end
32 changes: 32 additions & 0 deletions Readme.md
@@ -0,0 +1,32 @@
PowProxy
========

PowProxy is a simple rack-based proxy that allows you to run your node apps through [Pow](http://pow.cx).

PowProxy is based on a blog post by [Assaf Arkin](/assaf). It's super easy to use. You really should just read [Assaf's blog post](http://labnotes.org/2011/08/09/using-pow-with-your-node-js-project/) to get the full explanation.

Usage
-----

Create a `config.ru` file in your project's root with the following:

```ruby
require 'pow_proxy'
run PowProxy.new
```

By default, it assumes the host to be `localhost` and the port to be `3000` however you can configure that to be anything you'd like:

```ruby
require 'pow_proxy'
run PowProxy.new(:host => '127.0.0.1', :port => 8080)
```

You can also set the host and port by exporting the `HOST` and `PORT` environment variables in your `.powenv`.

Make sure your node app is running, symlink your app so that Pow knows about it and you'll be all set.

Copyright
---------

Copyright (c) 2011 Steve Agalloco, Assaf Arkin. See [LICENSE](LICENSE.md) for details.
39 changes: 39 additions & 0 deletions lib/pow_proxy.rb
@@ -0,0 +1,39 @@
require "net/http"
require "rack"

class PowProxy
DEFAULT_HOST = "127.0.0.1"
DEFAULT_PORT = 3000

attr_reader :host, :port

def initialize(options = {})
@host = options.delete(:host) || ENV['HOST'] || DEFAULT_HOST
@port = options.delete(:port) || ENV['PORT'] || DEFAULT_PORT
end

def call(env)
begin
request = Rack::Request.new(env)
headers = {}
env.each do |key, value|
if key =~ /^http_(.*)/i
headers[$1] = value
end
end

headers["Content-Type"] = request.content_type if request.content_type
headers["Content-Length"] = request.content_length if request.content_length

http = Net::HTTP.new(@host, @port)
http.start do |http|
response = http.send_request(request.request_method, request.fullpath, request.body.read, headers)
headers = response.to_hash
headers.delete "transfer-encoding"
[response.code, headers, [response.body]]
end
rescue Errno::ECONNREFUSED
[500, {}, ["Could not establish a connection to #{@host}:#{@port}, make sure your node process is running."]]
end
end
end
3 changes: 3 additions & 0 deletions lib/pow_proxy/version.rb
@@ -0,0 +1,3 @@
class PowProxy
VERSION = "0.0.1"
end
26 changes: 26 additions & 0 deletions pow_proxy.gemspec
@@ -0,0 +1,26 @@
# -*- encoding: utf-8 -*-
require File.expand_path('../lib/pow_proxy/version', __FILE__)

Gem::Specification.new do |gem|
gem.name = "pow_proxy"
gem.version = PowProxy::VERSION

gem.authors = ["Steve Agalloco"]
gem.email = ["steve.agalloco@gmail.com"]
gem.description = 'A simple rack-based proxy that allows you to run your node apps through Pow.'
gem.summary = gem.description
gem.homepage = "https://github.com/spagalloco/pow_proxy"

gem.add_dependency 'rack'
gem.add_development_dependency 'rake', '~> 0.9'
gem.add_development_dependency 'rdiscount', '~> 1.6'
gem.add_development_dependency 'rspec', '~> 2.7'
gem.add_development_dependency 'simplecov', '~> 0.5'
gem.add_development_dependency 'yard', '~> 0.7'
gem.add_development_dependency 'webmock', '~> 1.7'

gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
gem.files = `git ls-files`.split("\n")
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
gem.require_paths = ["lib"]
end
100 changes: 100 additions & 0 deletions spec/pow_proxy_spec.rb
@@ -0,0 +1,100 @@
require 'spec_helper'

describe PowProxy do

describe '.new' do
context 'defaults' do
before do
@proxy = PowProxy.new
end

it 'defaults the host to "127.0.0.1"' do
@proxy.host.should eq('127.0.0.1')
end

it 'defaults the port to 3000' do
@proxy.port.should eq(3000)
end
end

context 'options' do
before do
@proxy = PowProxy.new(:host => 'localhost2', :port => 4242)
end

it 'sets the host to "localhost2"' do
@proxy.host.should eq('localhost2')
end

it 'sets the port to 4242' do
@proxy.port.should eq(4242)
end
end

context 'ENV' do
before do
ENV['HOST'] = 'monk.local'
ENV['PORT'] = '8080'
@proxy = PowProxy.new
end

it 'defaults the host to "monk.local"' do
@proxy.host.should eq('monk.local')
end

it 'defaults the port to 8080' do
@proxy.port.should eq('8080')
end
end
end

describe 'integration' do
before do
@proxy = PowProxy.new(:host => 'app.local', :port => 2121)
end

it 'returns the requested content' do
stub_request(:get, "http://app.local:2121/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "abcdefg", :headers => {})

env = { "REQUEST_METHOD"=>"GET", "PATH_INFO"=>"/", "rack.input" => StringIO.new }
response = @proxy.call(env)
body = response.last.shift
body.should eq('abcdefg')
end

it 'removes the transfer-encoding header from the response' do
stub_request(:get, "http://app.local:2121/").
with(:headers => {'Accept'=>'*/*', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "abcdefg", :headers => { 'Transfer-Encoding' => 'chunked'})

env = { "REQUEST_METHOD"=>"GET", "PATH_INFO"=>"/", "rack.input" => StringIO.new }
response = @proxy.call(env)
headers = response[1]
headers.should_not have_key('transfer-encoding')
end

it 'passes headers to the node server' do
stub_request(:get, "http://app.local:2121/").
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip,deflate,sdch', 'User-Agent'=>'Ruby'}).
to_return(:status => 200, :body => "abcdefg", :headers => {})

env = { "REQUEST_METHOD"=>"GET", "PATH_INFO"=>"/", "rack.input" => StringIO.new, 'HTTP_ACCEPT_ENCODING' => "gzip,deflate,sdch" }
response = @proxy.call(env)
body = response.last.shift
body.should eq('abcdefg')
end

it 'reports an error when it cannot request to the node server' do
Rack::Request.stub(:new).and_raise(Errno::ECONNREFUSED)

env = { "REQUEST_METHOD"=>"GET", "PATH_INFO"=>"/", "rack.input" => StringIO.new }
response = @proxy.call(env)
response.first.should eq(500)
body = response.last.shift
body.should match(/Could not establish a connection/)
end
end

end
6 changes: 6 additions & 0 deletions spec/spec_helper.rb
@@ -0,0 +1,6 @@
$:.unshift File.expand_path('..', __FILE__)
$:.unshift File.expand_path('../../lib', __FILE__)
require 'simplecov'
require 'pow_proxy'
require 'rspec'
require 'webmock/rspec'

0 comments on commit 888adb6

Please sign in to comment.