How to capture POST data from a simple Ruby server - ruby

I have a basic Ruby server that I'd like to listen to a specific port, read incoming POST data and do blah...
I have this:
require 'socket' # Get sockets from stdlib
server = TCPServer.open(2000) # Socket to listen on port 2000
loop { # Servers run forever
client = server.accept # Wait for a client to connect
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
}
How would I go about capturing the POST data?
Thanks for any help.

It's possible to do this without adding much to your server:
require 'socket' # Get sockets from stdlib
server = TCPServer.open(2000) # Socket to listen on port 2000
loop { # Servers run forever
client = server.accept # Wait for a client to connect
method, path = client.gets.split # In this case, method = "POST" and path = "/"
headers = {}
while line = client.gets.split(' ', 2) # Collect HTTP headers
break if line[0] == "" # Blank line means no more headers
headers[line[0].chop] = line[1].strip # Hash headers by type
end
data = client.read(headers["Content-Length"].to_i) # Read the POST data as specified in the header
puts data # Do what you want with the POST data
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
}

For really simple apps you probably want to write something using Sinatra which is about as basic as you can get.
post('/') do
# Do stuff with post data stored in params
puts params[:example]
end
Then you can stick this in a Rack script, config.ru, and host it easily using any Rack-compliant server.

client.read(length) # length is length of request header content

Related

Read data both ways TCPServer Ruby

im new in Ruby and Im trying to set up a TCPServer and a Client, but Im having trouble getting the data from the client to the server because for some reason when the client connects, the connection is freezed inside the while loop.
Here is the code:
server.rb
require "socket"
server = TCPServer.new 1234
test = ""
loop do
session = server.accept
puts "Entering enter code herewhile loop."
while line = session.gets
puts "Inside while loop"
test << line
end
puts "Finished reading data"
puts "Data recieved - #{test}" # Read data from client
session.write "Time is #{Time.now}" # Send data to clent
session.close
end
client.rb
require "socket"
socket = TCPSocket.open("localhost", 1234)
socket.puts "Sending data.." # Send data to server
while(line = socket.gets)
puts line
end # Print sever response
socket.close
The server prints "Inside while loop" one time, and then for some reason it never prints "Finished reading data" until I manually end the client connection, after the client ends the connection the server prints everything OK. How can I make this code work? Thanks!
IO#gets is a blocking call. It waits for either a new line from the underlying I/O stream, or the end of the stream. (in which case it returns nil)
In server.rb you have
while line = session.gets
puts "Inside while loop"
test << line
end
session.gets reads one line from your client, prints some debug info and appends the line to test. It then attempts to read another line from the client.
Your client.rb however never sends a seconds line, nor does it close the stream. It sends a single line:
socket.puts "Sending data.." # Send data to server
and then waits for a response:
while(line = socket.gets)
puts line
end
which never comes because the server is sitting in the while loop, waiting for more data from the client.
You can solve this by calling close_write after all data has been sent:
socket.puts "Sending data.." # Send data to server
socket.close_write # Close socket for further writing
Calling close_write instead of close allows you to still read from the socket. It will also cause the server's session.gets to return nil, so it can get out of its loop.

Ruby send and receive custom TCP packets using PacketFu

I have a server running on port 3000 and a simple ruby program that reads lines from the server
require 'socket'
require 'packetfu'
s = TCPSocket.open('localhost', 3000)
config = PacketFu::Config.new(:iface=> "wlan0").config
pkt = PacketFu::TCPPacket.new(:config => $config , :flavor => "Linux")
while line = s.gets
puts line.chop
end
s.close
Server
require 'socket'
server = TCPServer.open('localhost', 3000)
loop {
client = server.accept
client.close
}
I want to build a simple TCP packet using packetfu that sends a WAKE-UP call and receive ACK from the server. What changes should i make to build this packet and receive the response?

Extract uri parameters from a HTTP connection on a Ruby TCPSocket

My first question here... so be gentle :D
I have the following code:
server = TCPServer.new('localhost', 8080)
loop do
socket = server.accept
# Do something with the URL parameters
response = "Hello world";
socket.print response
socket.close
end
The point is that I want to be able to retrieve if any parameters have been sent in URL of the HTTP request.
Example:
From this request:
curl http://localhost:8080/?id=1&content=test
I want to be able to retrieve something like this:
{id => "1", content => "test"}
I've been looking for CGI::Parse[1] or similar solutions but I haven't found a way to extract that data from a TCPSocket.
[1] http://www.ruby-doc.org/stdlib-1.9.3/libdoc/cgi/rdoc/CGI.html#method-c-parse
FYI: My need is to have a minimal http server in order to receive a couple of parameters and wanted to avoid the use of gems and/or full HTTP wrappers/helpers like Rack.
Needless to say... but thanks in advance.
If you want to see a very minimal server, here is one. It handles exactly two parameters, and puts the strings in an array. You'll need to do more to handle variable numbers of parameters.
There is a fuller explanation of the server code at https://practicingruby.com/articles/implementing-an-http-file-server.
require "socket"
server = TCPServer.new('localhost', 8080)
loop do
socket = server.accept
request = socket.gets
# Here is the first line of the request. There are others.
# Your parsing code will need to figure out which are
# the ones you need, and extract what you want. Rack will do
# this for you and give you everything in a nice standard form.
paramstring = request.split('?')[1] # chop off the verb
paramstring = paramstring.split(' ')[0] # chop off the HTTP version
paramarray = paramstring.split('&') # only handles two parameters
# Do something with the URL parameters which are in the parameter array
# Build a response!
# you need to include the Content-Type and Content-Length headers
# to let the client know the size and type of data
# contained in the response. Note that HTTP is whitespace
# sensitive and expects each header line to end with CRLF (i.e. "\r\n")
response = "Hello world!"
socket.print "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/plain\r\n" +
"Content-Length: #{response.bytesize}\r\n" +
"Connection: close\r\n"
# Print a blank line to separate the header from the response body,
# as required by the protocol.
socket.print "\r\n"
socket.print response
socket.close
end

how to use the ruby analytical receive binary stream from the TCP

I'm going to the receiving device over the data, but these data are binary stream, I put these data storage, then read to display them correctly, is there a better way?
require 'socket'
server = TCPServer.open(2000)
loop {
Thread.start(server.accept) do |client|
File.open("tmp","w") { |file| file.write(client.gets)}
File.open("tmp").each do |f|
puts f.unpack('H*')
end
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close # Disconnect from the client
end
}
the received data like this: xx^Q^A^Hb0# <90>26 2^B^#<83>ev
I want like this: 787811010862304020903236202032020001c26c0d0a
sorry about my poor English!
Using a temporary file with a name will cause a problem if there are multiple clients sending data; the temporary file will be overwritten.
You don't need to use a temporary file.
require 'socket'
server = TCPServer.open(2000)
loop {
Thread.start(server.accept) do |client|
puts client.gets.unpack('H*')
client.puts(Time.now.ctime) # Send the time to the client
client.puts "Closing the connection. Bye!"
client.close
end
}

HTTP Server in Ruby with multiple roles

I am struggling to write a script in ruby which should act as a server and initiate further requests to outside party and serve as a server for this party.
I came up with the following:
require 'socket'
require 'net/http'
require 'uri'
server = TCPServer.new('local_ip', 8081)
loop do
# start accepting connections
Thread.start(server.accept) do |client|
request_line = client.gets
request_uri = request_line.split(" ")[1]
path = URI.unescape(URI(request_uri).path)
conn_id = path[-2,2]
sessionID = path[-8,6]
uri = URI("somehost:8000/#{sessionID}/}")
# start another server for accepting communication with server X
mServer = Thread.new {
server = TCPServer.new('local_ip', 8082)
loop do
client = server.accept
response = ""
client.print "HTTP/1.1 200 OK\r\n"
client.print "\r\n"
client.print response
client.close
end
}
# send post request to server X
res = Net::HTTP.post_form(uri, 'connectionid' => conn_id, 'some_param' ==> 'par')
# Here Server X sends me some post data which would be responded
# send subsequent post request to server X
res2 = Net::HTTP.post_form(uri, 'connectionid' => conn_id, 'some_param' ==> 'par2')
client.print "HTTP/1.1 200 OK\r\n"
client.print "\r\n"
client.print response
client.close
end
end
Between two post requests to server X, server X should send post request of its own and when script sends 200 response to server X the subsequent post request to server X should be sent.
I am not entirely sure how to approach synchronization here, I assume I should pause main thread and resume main thread from mServer.
What would be the most optimal approach here? Ideally I would like to separate script into two parts: one accepting connections and sending http requests and second one playing role of mServer. But the synchronization issue remains and I wonder if eventmachine or drb would be appropriate solution.

Resources