How to establish a SSL enabled TCP/IP Connection in Ruby
require 'socket'
require 'openssl'
myXML = 'my_sample_data'
host = 'my_host.com'
port = my_port
socket = TCPSocket.open(host,port)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.cert = OpenSSL::X509::Certificate.new(File.open("certificate.crt"))
ssl_context.key = OpenSSL::PKey::RSA.new(File.open("certificate.key"))
ssl_context.ssl_version = :SSLv23
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
ssl_socket.sync_close = true
ssl_socket.connect
ssl_socket.puts(myXML)
while line = ssl_socket.gets
p line
end
ssl_socket.close
TCPSocket connection reset by peer
First thing, you should replace the string '443' by an integer :
TCPSocket.open('stream-api.betfair.com', 443)
Anyway, it seems to be related with the SSL negociation : the following Stackoverflow post gives a quick idea about what would work : How to establish a SSL enabled TCP/IP Connection in Ruby. Using this method, I works.
require 'socket'
require 'openssl'
host = 'stream-api.betfair.com'
port = 443
socket = TCPSocket.open(host,port)
ssl_context = OpenSSL::SSL::SSLContext.new()
ssl_context.ssl_version = :SSLv23
ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ssl_context)
ssl_socket.sync_close = true
ssl_socket.connect
while line = ssl_socket.gets
p line
end
ssl_socket.close
Result :
"{\"op\":\"connection\",\"connectionId\":\"001-151118094105-259478\"}\r\n"
Dealing with SSL/TLS protected connection is sometime quite verbose with Ruby. In the example you gave, in NodeJS, the hint is the first line :
var tls = require('tls');
Why is this Ruby SSL-enabled server/client test working?
Depending on the version of Ruby you are using, the default verify mode for the SSLContext object may not be enforcing certificate verification. You can force the verify mode with:
context = OpenSSL::SSL::SSLContext.new
context.verify_mode = OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
This should cause the client's connection attempt to fail, as expected.
How to make a secure HTTP/2 connection to Ruby server with Chrome and Firefox?
It seems that Chrome insists on using ephemeral ECDH key exchange for HTTP/2, and to get that to work you need to set tmp_ecdh_callback
:
ctx.tmp_ecdh_callback = lambda do |*args|
OpenSSL::PKey::EC.new 'prime256v1'
end
I’ve based this on the example code from the Ruby http-2 gem, which I think is where you’ve got your code from too. Note that in that code it uses lambda do |_args|
, (with the underscore but no *
) and this causes problems because the number of args is wrong and lambda
is strict about passing the right number, so you get errors. I’ve changed it back to the original *args
here, it appears to have been changed to fix Rubocop warnings. As you seem to be active in that repo, you might want to change it to something like |*_args|
.
Socket timeout in Ruby
I have tested and my ISP has something to do with the time limitation issues of my longer connections.
Why isn't my Sinatra app working with SSL?
Generally you don't want any ruby webservers actually handling SSL. You make them serve plain HTTP (that is accessible only via localhost). Then you install a reverse proxy that handles all of the SSL communicate.
For example
- Install nginx (reverse proxy) and configure it to listen on port 443.
- Set your
ruby app server to listen on port 127.0.0.1:80 (accept local
connections only) - All requests hit nginx, which strips the SSL,
and send the plain HTTP request to your ruby webserver.
A very simple nginx config to get you started:
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/your.key;
ssl on;
add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";
server {
listen 443 ssl;
server_name you.example.com;
location / {
proxy_pass http://localhost:8080; # your ruby appserver
}
}
Using Net::HTTP.get for an https url
Original answer:
uri = URI.parse("https://example.com/some/path")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
@data = http.get(uri.request_uri)
As pointed out in the comments, this is more elegant:
require "open-uri"
@data = URI.parse("https://example.com/some/path").read
Ruby HTTP2 GET request
Public servers like google.com do not support HTTP/2 in clear text.
You are trying to connect to http://google.com, while you should really connect to https://google.com (note the https
scheme).
In order to do that, you may need to wrap the TCP socket using TLS (see for example here), if http-2
does not do it for you.
Note also that HTTP/2 requires strong TLS ciphers and ALPN, so make sure that you have an updated version of OpenSSL (at least 1.0.2).
Given that the author of http-2
is a strong HTTP/2 supporter, I am guessing that your only problem is the fact that you tried clear-text http
rather than https
, and I expect that TLS cipher strength and ALPN are taken care of by the http-2
library.
Related Topics
Ruby: "&& Return" VS "And Return"
Ruby $Stdin.Gets Without Showing Chars on Screen
Ruby: How to Generate CSV Files That Has Excel-Friendly Encoding
Clarification on the Ruby << Operator
Ruby: How to "Require" a File from the Current Working Dir
How to Get the Version from a Gemspec File
Changing Active Model Serializers Default Adapter
How to Recursively Require All Files in a Directory in Ruby
Rails: Why Images Are Not Showing in My Rails Basic App
Using Nokogiri HTML Builder to Create Fragment with Multiple Root Nodes
Sudo Gem Install Pg Won't Work
Rendering Haml Partials from Within Haml Outside of Rails
Convert a String Date Format from "17-Nov-2011" to "11/17/11"