Ruby: HTTP メッセージを解析する

Node.js で使われている HTTP Parser の Ruby バインディングを利用すれば、生の HTML メッセージを解析することができる。

require "http/parser"

body = "hello world"
msg = "HTTP/1.1 200 OK\r\n" \
    + "Content-Type: text/html; charset=utf-8\r\n" \
    + ("Content-Length: %d\r\n" % body.bytesize) \
    + "Connection: Close\r\n" \
    + "\r\n" \
    + body

parser = Http::Parser.new
ret = ''
parser.on_body = proc do |chunk|
  ret += chunk
end

parser << msg

puts parser.headers
puts ret

Ruby: SSL 対応の echo サーバーをつくる

TCPServer のインスタンスを OpenSSL::SSL::SSLServer でつつむ。証明書と秘密鍵はそれぞれ、 OpenSSL::X509::Certificate、OpenSSL::PKey::RSA のインスタンスとしてあらわし、OpenSSL::SSL::SSLContext の cert および key メソッドで指定する。

require 'socket'
require 'openssl'

body = "hello world"
msg = "HTTP/1.1 200 OK\r\n" \
    + "Content-Type: text/html; charset=utf-8\r\n" \
    + ("Content-Length: %d\r\n" % body.bytesize) \
    + "Connection: Close\r\n" \
    + "\r\n" \
    + body

port = 12345
cert = 'server.crt'
key  = 'server.key'

ctx = OpenSSL::SSL::SSLContext.new
ctx.cert = OpenSSL::X509::Certificate.new File.read(cert)
ctx.key = OpenSSL::PKey::RSA.new File.read(key)

server = TCPServer.new port
sslServer = OpenSSL::SSL::SSLServer.new server, ctx

while client = sslServer.accept
  client.puts msg
  client.close
end

PHP: OpenSSL のバージョン番号を調べる

定数の OPENSSL_VERSION_TEXT から OpenSSL のバージョンを調べることができる。

var_dump(
    OPENSSL_VERSION_TEXT
);

OPENSSL_VERSION_NUMBER を使って調べる場合、バージョン番号は16進法なので、表示のために dechex などの変換関数が必要になる。OpenSSL のマニュアルによれば、0x00090605f は 0.9.6e release を意味する。

var_dump(
    dechex(OPENSSL_VERSION_NUMBER)
);

バージョン番号が 1.0.1g 以降であるかチェックするのであれば、次のように書ける。

var_dump(
    0x1000107f <= OPENSSL_VERSION_NUMBER
);

OPENSSL_VERSION_TEXT と OPENSSL_VERSION_NUMBER は crypto/opensslv.h で定義されている。

OpenSSL に付属のコマンドツールからバージョンを調べることもできる。

openssl version

Ruby: Socket、TCPServer クラスを使って echo サーバーをつくる

おそらくもっともシンプルなのは tcp_server_loop を使うやりかたであろう。RubyKaigi2009 の「ソケットライブラリの改善」の資料で知った。

require 'socket'

body = "hello world"
msg = "HTTP/1.1 200 OK\r\n" \
    + "Content-Type: text/html; charset=utf-8\r\n" \
    + ("Content-Length: %d\r\n" % body.bytesize) \
    + "Connection: Close\r\n" \
    + "\r\n" \
    + body

port = 12345

Socket.tcp_server_loop(port) { |s|
  s.puts msg
  s.close
}

似たようなメソッドとして Socket.accept_loop がある。

server = TCPServer.new port

Socket.accept_loop(server) { |s|
  s.puts msg
  s.close
}

英語の公式マニュアルにシンプルなコードサンプルが掲載されているので、echo するメッセージを HTTP に変更。Ruby では無限ループのために loop do 構文が用意されている。

server = TCPServer.new port

loop do
  client = server.accept
  client.puts msg
  client.close
end

loop の代わりに while 文を使うことができる。

server = TCPServer.new port

while client = server.accept
  client.puts msg
  client.close
end

accept の代わりに accept_nonblock を使う場合、次のように書ける。

server = TCPServer.new port

loop do
  begin
    client = server.accept_nonblock
  rescue IO::WaitReadable, Errno::EINTR
    IO.select([server])
    retry
  end

  client.puts msg
  client.close
end

TCPServer を使わずに Socket クラスを使う場合は次のようになる。

require 'socket'
include Socket::Constants

body = "hello world\000"
msg = "HTTP/1.1 200 OK\r\n" \
    + "Content-Type: text/html; charset=utf-8\r\n" \
    + ("Content-Length: %d\r\n" % body.bytesize) \
    + "Connection: Close\r\n" \
    + "\r\n" \
    + body

port = 12345
host = '0.0.0.0'

socket = Socket.new AF_INET, SOCK_STREAM
sockaddr = Socket.pack_sockaddr_in port, host
socket.bind sockaddr
socket.listen 5

loop do
  client_fd, client_addrinfo = socket.sysaccept
  client = Socket.for_fd client_fd
  client.puts msg
  client.close
end

socket.close
アーカイブ ランダム ホーム 次のページ ページ 1 / 331