ruby 1.9.3 simple GET request to unicorn through socket - ruby

Now I try to connect to my socket cretaed by unicorn with this code
require 'socket'
def foo
socket = UNIXSocket.new("path_to_socket/tmp/unicorn.sock")
data = "GET /time HTTP/1.1\n"
data << "Connection: Close\n"
data << "User-Agent: Mozilla/5.0\n"
data << "Accept: */*\n"
data << "Content-Type: application/x-www-form-urlencoded\n"
data << "\n\r\n\r"
socket.puts(data)
while(line = socket.gets) do
puts line
end
end
foo
But always get a "HTTP/1.1 400 Bad Request"
Please, can any body say what I'm do wrong???

Use net/http...
require "net/http"
require "socket"
sock = Net::BufferedIO.new(UNIXSocket.new("path_to_socket/tmp/unicorn.sock"))
request = Net::HTTP::Get.new("/time")
request.exec(sock, "1.1", "/time")
begin
response = Net::HTTPResponse.read_new(sock)
end while response.kind_of?(Net::HTTPContinue)
response.reading_body(sock, request.response_body_permitted?) { }
response.body
response.code

This is very helpful but please note that the Net::HTTP#exec method is marked for internal use only. Likely because it doesn't do resource management, etc.
The following work adapts the suggested strategy to override Net::HTTP#connect (to connect to a socket). I like to use the HTTParty gem for handling my HTTP requests. So the strategy here makes use of a custom ConnectionAdaptor for HTTParty. Now I can just change the ::default_params= call on my including class, to control whether we're using a Unix or a TCP/HTTP socket.
###########################################################
# net/socket_http.rb
###########################################################
module Net
# Overrides the connect method to simply connect to a unix domain socket.
class SocketHttp < HTTP
attr_reader :socket_path
# URI should be a relative URI giving the path on the HTTP server.
# socket_path is the filesystem path to the socket the server is listening to.
def initialize(uri, socket_path)
#socket_path = socket_path
super(uri)
end
# Create the socket object.
def connect
#socket = Net::BufferedIO.new UNIXSocket.new socket_path
on_connect
end
# Override to prevent errors concatenating relative URI objects.
def addr_port
File.basename(socket_path)
end
end
end
###########################################################
# sock_party.rb, a ConnectionAdapter class
###########################################################
require "net/http"
require "socket"
class SockParty < HTTParty::ConnectionAdapter
# Override the base class connection method.
# Only difference is that we'll create a Net::SocketHttp rather than a Net::HTTP.
# Relies on :socket_path in the
def connection
http = Net::SocketHttp.new(uri, options[:socket_path])
if options[:timeout] && (options[:timeout].is_a?(Integer) || options[:timeout].is_a?(Float))
http.open_timeout = options[:timeout]
http.read_timeout = options[:timeout]
end
if options[:debug_output]
http.set_debug_output(options[:debug_output])
end
if options[:ciphers]
http.ciphers = options[:ciphers]
end
return http
end
end
###########################################################
# class MockSockParty, a really *nix-y HTTParty
###########################################################
class MockSockParty
include HTTParty
self.default_options = {connection_adapter: SockParty, socket_path: '/tmp/thin.sock'}
def party_hard
self.class.get('/client').body
end
end
###########################################################
# sock_party_spec.rb
###########################################################
require 'spec_helper'
describe SockParty do
it "should party until its socks fall off." do
puts MockSockParty.new.party_hard
end
end

Related

web server in ruby and connection keep-alive

Web server example:
require 'rubygems'
require 'socket'
require 'thread'
class WebServer
LINE_TERMINATOR = "\r\n".freeze
def initialize(host, port)
#server = TCPServer.new(host, port)
end
def run
response_body = 'Hello World!'.freeze
response_headers = "HTTP/1.1 200 OK#{LINE_TERMINATOR}Connection: Keep-Alive#{LINE_TERMINATOR}Content-Length: #{response_body.bytesize}#{LINE_TERMINATOR}".freeze
loop do
Thread.new(#server.accept) do |socket|
puts "request #{socket}"
sleep 3
socket.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
socket.write(response_headers)
socket.write(LINE_TERMINATOR)
socket.write(response_body)
# socket.close # if this line is uncommented then it's work.
end
end
end
end
WebServer.new('localhost', 8888).run
if update browser without waiting for the end of the cycle then the following queries are not processed
How can handle incomming request which are persistent socket ?
You need to:
Keep around the sockets you get from the #server.accept call. Store them in an array (socket_array).
Use the IO.select call on the array of sockets to get the set of sockets that can be read:
ready = IO.select(socket_array)
readable = ready[0]
readable.each do |socket|
# Read from socket here
# Do the rest of processing here
Don't close the socket after you have sent the data.
If you need more details leave a comment - I can write more of the code.

Responding to HTTP Requests in Eventmachine

I have a very simple server for use in integration tests, built using eventmachine:
EM.run do
EM::start_server(server, port, HttpRecipient)
end
I can receive HTTP requests and parse them like so:
class HttpRecipient < EM::Connection
def initialize
##stored = ''
end
# Data is received in chunks, so here we wait until we've got a full web request before
# calling spool.
def receive_data(data)
##stored << data
begin
spool(##stored)
EM.stop
rescue WEBrick::HTTPStatus::BadRequest
#Not received a complete request yet
end
end
def spool(data)
#Parse the request
req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP)
req.parse(StringIO.new(##stored))
#Send a response, e.g. HTTP OK
end
end
The question is, how do I send a response? Eventmachine provides a send_data for sending responses, but that doesn't understand http. Similarly there is the em-http-request
module for sending requests, but it's not obvious that this is capable of generating responses.
I can generate HTTP messages manually and then send them using send_data, but I wonder if there is a clean way to use an existing http library, or the functionality built in to eventmachine?
If you want something easy then use Thin or Rainbows. It uses Eventmachine inside and provides Rack interface support.
# config.ru
http_server = proc do |env|
response = "Hello World!"
[200, {"Connection" => "close", "Content-Length" => response.bytesize.to_s}, [response]]
end
run http_server
And then
>> thin start -R config.ru
UPD.
If you need server to run in parallel you could run it in a Thread
require 'thin'
class ThreadedServer
def initialize(*args)
#server = Thin::Server.new(*args)
end
def start
#thread = Thread.start do
#server.start
end
end
def stop
#server.stop
if #thread
#thread.join
#thread = nil
end
end
end
http_server = proc do |env|
response = "Hello World!"
[200, {"Connection" => "close", "Content-Length" => response.bytesize.to_s}, [response]]
end
server = ThreadedServer.new http_server
server.start
# Some job with server
server.stop
# Server is down

Can I send an object via TCP using Ruby?

I'm trying to send and "message" object via TCP on Ruby and my client class simply don't see any thing comming. What am I doing wrong?
My message class (that I'm trying to send)
class Message
attr_reader :host_type, :command, :params
attr_accessor :host_type, :command, :params
def initialize(host_type, command, params)
#host_type = host_type
#command = command
#params = params
end
end
My "Server" class
require 'socket'
require_relative 'message'
class TCP_connection
def start_listening
puts "listening"
socket = TCPServer.open(2000)
loop {
Thread.start(socket.accept) do |message|
puts message.command
end
}
end
def send_message
hostname = 'localhost'
port = 2000
s = TCPSocket.open(hostname, port)
message = Message.new("PARAM A", "PARAM B", "PARAM C")
s.print(message)
s.close
end
end
Below an example of client server comunication via json. You will expect something like this RuntimeError: {"method1"=>"param1"}. Instead of raising errors, process this json with the server logic.
Server
require 'socket'
require 'json'
server = TCPServer.open(2000)
loop {
client = server.accept
params = JSON.parse(client.gets)
raise params.inspect
}
Client
require 'socket'
require 'json'
host = 'localhost'
port = 2000
s = TCPSocket.open(host, port)
request = { 'method1' => 'param1' }.to_json
s.print(request)
s.close
You need to serialize your object. The most portable way to do this is using YAML. First, require the yaml library:
require "yaml"
Than, replace s.print(message) with s.print(YAML.dump(message)).

Pipe data from HTTP GET to HTTP POST/PUT

I'd like to stream data from an HTTP GET request to an HTTP POST or PUT request. I'd prefer to use Ruby and have already made an attempt using EventMachine and EM-HTTP-Request.
Here's my attempt, to be called using:
HttpToS3Stream.new(src_url, dest_bucket, dest_key, aws_access_key_id, aws_secret_access_key)
http_to_s3_stream.rb
require 'em-http-request'
class HttpToS3Stream
def initialize(http_url, s3_bucket, s3_key, s3_access_key_id, s3_secret_access_key)
#http_url = http_url
#s3_bucket = s3_bucket
#s3_key = s3_key
#s3_access_key_id = s3_access_key_id
#s3_secret_access_key = s3_secret_access_key
go
end
private
def go
EM.run {
# initialize get stream, without listener does not start request
#get_stream = HttpGetStream.new(#http_url)
# initialize put stream, send content length, request starts
#put_stream = S3PutStream.new(#s3_bucket, #s3_key, #s3_access_key_id, #s3_secret_access_key, #get_stream.content_length)
# set listener on get stream, starts request, pipes data to put stream
#get_stream.listener = #put_stream
}
end
end
http_get_stream.rb
require 'httparty'
require 'em-http-request'
class HttpGetStream
def initialize(http_url, listener = nil)
#http_url = http_url
self.listener = listener
end
def listener=(listener)
#listener = listener
listen unless #listener.nil?
end
def content_length
response = HTTParty.head(#http_url)
response['Content-length']
end
private
def listen
http = EventMachine::HttpRequest.new(#http_url).get
http.stream do |chunk|
#listener.send_data chunk
end
http.callback do |chunk|
EventMachine.stop
end
end
end
s3_put_stream.rb
require 'em-http-request'
class S3PutStream
def initialize(s3_bucket, s3_key, s3_access_key_id, s3_secret_access_key, content_length = nil)
#s3_bucket = s3_bucket
#s3_key = s3_key
#s3_access_key_id = s3_access_key_id
#s3_secret_access_key = s3_secret_access_key
#content_length = content_length
#bytes_sent = 0
listen
end
def send_data(data)
#bytes_sent += data.length
#http.on_body_data data
end
private
def listen
raise 'ContentLengthRequired' if #content_length.nil?
#http = EventMachine::HttpRequest.new(put_url).put(
:head => {
'Content-Length' => #content_length,
'Date' => Time.now.getutc,
'Authorization' => auth_key
}
)
#http.errback { |error| puts "error: #{error}" }
end
def put_url
"http://#{#s3_bucket}.s3.amazonaws.com/#{#s3_key}"
end
def auth_key
"#{#s3_access_key_id}:#{#s3_secret_access_key}"
end
end
HttpToS3Stream.new(src_url, dest_bucket, dest_key, aws_access_key_id, aws_secret_access_key)
It seems to be working but always stops at 33468 bytes. Not sure what that's about. Now, by passing chunks directly to #listener.send_data, it is processing the entire GET body. However, the upload is not occurring successfully.
How can I get this to work? And is there a name for what I'm trying to do? I'm having trouble searching for more information.
Any help is appreciated.

Sharing DB connections across objects using class methods in ruby?

I am writing a ruby script to be used as Postfix SMTP access policy delegation. The script needs to access a Tokyo Tyrant database. I am using EventMachine to take care of network connections. EventMachine needs a EventMachine::Connection class that is instantiated by EventMachineā€˜s processing loop whenever a new connection is created. so for each connection a class is instantiated and destroyed.
I am creating a connection to Tokyo Tyrant from the post_init of the EventMachine::Connection (ie right after connection is setup) and tearing it down after connection is terminated.
My question is if this is the proper way to connect to db? ie making a connection every yime I need it and tearing it down after I am finished? Wouldn't be better to connect to DB once (when program is started) tear it down during program shutdown? If that is so how should I code that ?
My code is:
require 'rubygems'
require 'eventmachine'
require 'rufus/tokyo/tyrant'
class LineCounter < EM::Connection
ActionAllow = "action=dunno\n\n"
def post_init
puts "Received a new connection"
#tokyo = Rufus::Tokyo::Tyrant.new('server', 1978)
#data_received = ""
end
def receive_data data
#data_received << data
#data_received.lines do |line|
key = line.split('=')[0]
value = line.split('=')[1]
#reverse_client_name = value.strip() if key == 'reverse_client_name'
#client_address = value.strip() if key == 'client_address'
#tokyo[#client_address] = #reverse_client_name
end
puts #client_address, #reverse_client_name
send_data ActionAllow
end
def unbind
#tokyo.close
end
end
EventMachine::run {
host,port = "127.0.0.1", 9997
EventMachine::start_server host, port, LineCounter
puts "Now accepting connections on address #{host}, port #{port}..."
EventMachine::add_periodic_timer( 10 ) { $stderr.write "*" }
}
with regards,
raj
Surprising there's no answers to this question.
What you probably need is a connection pool where you can fetch, use, and return connections as they are required.
class ConnectionPool
def initialize(&block)
#pool = [ ]
#generator = block
end
def fetch
#pool.shift or #generator and #generator.call
end
def release(handle)
#pool.push(handle)
end
def use
if (block_given?)
handle = fetch
yield(handle)
release(handle)
end
end
end
# Declare a pool with an appropriate connection generator
tokyo_pool = ConnectionPool.new do
Rufus::Tokyo::Tyrant.new('server', 1978)
end
# Fetch/Release cycle
tokyo = tokyo_pool.fetch
tokyo[#client_address] = #reverse_client_name
tokyo_pool.release(tokyo)
# Simple block-method for use
tokyo_pool.use do |tokyo|
tokyo[#client_address] = #reverse_client_name
end

Resources