Ruby TCP server basics - ruby

Can someone explain to me what each part of this code is doing?
It would be helpful if someone could give me a step by step explanation.
Also, how could I upload files?
How do I manipulate a ruby server in general?
#!/usr/bin/env ruby
require 'socket'
require 'cgi'
server = TCPServer.new('127.0.0.1', 8888)
puts 'Listening on 127.0.0.1:8888'
loop {
client = server.accept
first_request_header = client.gets
resp = first_request_header
headers = ['http/1.1 200 ok',
"date: #{CGI.rfc1123_date(Time.now)}",
'server: ruby',
'content-type: text/html; charset=iso-8859-1',
"content-length: #{resp.length}\r\n\r\n"].join("\r\n")
client.puts headers # send the time to the client
client.puts resp
client.close
}

#required gems
require 'socket'
require 'cgi'
#creating new connection to a local host on port 8888
server = TCPServer.new('127.0.0.1', 8888)
puts 'Listening on 127.0.0.1:8888'
loop {
#looks like a client method call to open the connection
client = server.accept
first_request_header = client.gets
resp = first_request_header
#setting the request headers
headers = ['http/1.1 200 ok',
"date: #{CGI.rfc1123_date(Time.now)}",
'server: ruby',
'content-type: text/html; charset=iso-8859-1',
"content-length: #{resp.length}\r\n\r\n"].join("\r\n")
#inserts custom client headers into request
client.puts headers
client.puts resp
#closes client connection to local host
client.close
}

Related

how to enable CORS in standalone ruby file

`
http_server.rb
require 'socket'
require 'json'
server = TCPServer.new 5678
while session = server.accept
request = session.gets
puts request
session.print "HTTP/1.1 200\r\n" # 1
session.print "Content-Type: text/html\r\n" # 2
session.print "\r\n" # 3
output = {
"error" => false,
"total_marks" => "0"
}
session.puts(output.to_json);
session.close
end
`
So this standalone ruby http server file works perfectly locally , I would prefer not to have to use rails because I also need to make it a docker container . is there any way to enable cors solely inside this file for this simple server ?
I'm new to docker and ruby so the less complex the better.
CORS is just an Access-Control-Allow-Origin header (see the documentation here https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS) so it's easy to add it to your example.
session.print "Access-Control-Allow-Origin: something.com\r\n"

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.

How do I read a in incoming POST Multipart request using ruby and tcpserver

I have created a very simple server:
#!/bin/ruby
require 'socket'
server = TCPServer.open 2000
puts "Listening on port 2000"
loop {
client = server.accept
client.puts "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"
response = "My super slim ruby http server"
client.puts response
received = client.recv(1024)
puts received
puts "\n"
client.close
}
So far, it serves my purpose, which is to print out the requests that might come from a given client. However, if I use, for example, the following curl command to create a request:
curl -F "data=someData" http://localhost:2000
My ruby server only prints out the HTTP headers, but not the body of the request.
Is there a way to do this?
Looks like you have to call recv again to get the body:
#!/bin/ruby
require 'socket'
server = TCPServer.open 2000
puts "Listening on port 2000"
loop {
client = server.accept
client.puts "HTTP/1.1 200/OK\r\nContent-type:text/html\r\n\r\n"
response = "My super slim ruby http server"
client.puts response
headers = client.recv(1024)
headers =~ /Content-Length: (\d+)/ # get content length
body = $1 ? client.recv($1.to_i) : '' # <- call again to get body if there is one
puts headers + body
client.close
}
Thanks bundacia, I ended up mixing what you sent and some other findings and this is the result:
#!/bin/ruby
require 'socket'
server = TCPServer.open 2000
puts "Listening on port 2000"
loop {
client = server.accept
client.puts "HTTP/1.1 200/OK\r\nContent-type:text/xml\r\n\r\n"
response = "My super slim ruby http server"
client.puts response
all_data = []
i = 1024
firstrun = "yes"
while i > 0
partial_data = client.recv(i)
if (firstrun == "no")
i = 0
end
if (firstrun == "yes")
partial_data =~ /Content-Length: (\d+)/ # get content length
length = $1
if (nil != length && !length.empty?)
i = length.to_i
firstrun = "no"
end
end
all_data << partial_data
end
puts all_data.join()
client.close
}

Ruby TCPSocket / HTTP request

I just started with TCPSockets. I am simply trying to get the google home page. This is my code:
require 'socket'
host = 'http://www.google.com'
port = 80
s = TCPSocket.open host, port
s.puts "GET / HTTP/1.1\r\n"
s.puts "Host: Firefox"
s.puts "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
s.puts "Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7"
s.puts "\r\n"
while line = s.gets
puts line.chop
end
s.close
This returns:
HTTP/1.1 302 Document has moved
Location: http://92.242.140.29/?nxdomain=http%3A%2F%2Ffirefox&AddInType=2&PlatformInfo=pbrgen
Why? My goal is to get the contents of google home page. Thanks
require 'socket'
host = 'www.google.com'
port = 80
s = TCPSocket.open host, port
s.puts "GET / HTTP/1.1\r\n"
s.puts "\r\n"
while line = s.gets
puts line.chop
end
s.close
Also, using a real HTTP client will make your life much, much easier. I like Typhoeus.
A 302 status is a type of HTTP redirect, but here you're working with TCP, a network layer below HTTP, which doesn't understand redirects (or anything else HTTP). As this SO post shows, howerver, there are other ways to request a web page, namely using the OpenURI library instead of sockets.

SOAP + SSL + Ruby Savon - HTTPClient::ConnectTimeoutError: execution expired

I am trying to get a simple ruby script to send requests to a SOAP API but I am not able to get responses back.
This is what I am trying to do:
require 'date'
require 'savon'
# Create the client
client = Savon::Client.new do
wsdl.document = File.expand_path("path to wsdl document", __FILE__)
end
# Setup namespaces and credentials
client.wsdl.namespace = "http://www.example.com"
client.wsse.credentials "[USERNAME]", "[PASSWORD]"
# Setup ssl configuration
client.http.auth.ssl.cert_key_file = "path to key pem file"
client.http.auth.ssl.cert_file = "path to cert pem file"
client.http.auth.ssl.verify_mode=:peer
# execute request
response = client.request :sub, :get_data do
soap.body = {"sub:id" => "123456"}
end
This request finishes with:
D, [2011-05-05T10:21:45.014588 #22136] DEBUG -- : SOAP request: "http://www.example.com"
D, [2011-05-05T10:21:45.014743 #22136] DEBUG -- : Content-Type: text/xml;charset=UTF-8, SOAPAction: "getData"
D, [2011-05-05T10:21:45.014787 #22136] DEBUG -- : <?xml version="1.0" encoding="UTF-8"?><env:Envelope ...(XML request)... </env:Body></env:Envelope>
D, [2011-05-05T10:21:45.014864 #22136] DEBUG -- : HTTPI executes HTTP POST using the httpclient adapter
HTTPClient::ConnectTimeoutError: execution expired
However, when I try to send the same request via curl, it works (copying the xml request above to the soap-request.xml file):
curl -k -v --header "Content-Type: text/xml;charset=UTF-8, SOAPAction: 'getData'" https://www.example.com -d#soap-request.xml --cert-type PEM --cert path_to_pem_file_with_both_key_and_cert
Any ideas about what I'm missing in the ruby script?
Thanks in advance.
UPDATE:
The code above works if the WSDL document is correct. However, in case there isn't one or in case it is erroneous, just replace the client declaration with this:
# Create the client
client = Savon::Client.new do
wsdl.endpoint = "https://whateverendpoint.com"
wsdl.namespace = "http://whatevernamespace.com"
end
Finally, it is also a good idea to catch possible faults as described in Savon's documentation:
begin
# execute request
response = client.request :sub, :get_data do
soap.body = {"sub:id" => "123456"}
end
rescue Savon::SOAP::Fault => fault
puts fault.to_s
end
Have you tried to extend the http timeout? I had the same problem with some of my SOAP call that took very long on the server side. What I did was this
jira = Savon::Client.new do
wsdl.document = 'http://jira.xxx.com/rpc/soap/jirasoapservice-v2?wsdl'
end
jira.http.read_timeout = 300
done = 0
dotPrinter = Thread.new do
sec = 0
while(done==0) do
sleep 1
$STDERR.print "\b\b\b%03i" % sec
sec += 1
end
end
resp = jira.request :get_issues_from_filter do
soap.body = {:in0 => jira_token, :in1 => 18579}
end
done = 1

Resources