From: Wakou Aoyama Date: 1998-04-17T06:35:20+09:00 Subject: [ruby-list:7597] http-lib.rb 青山です。 simple_chat_server.rb の http 部分を分離したついでに、さらにライブラリ として取り出してみました。汎用として使うにはヘッダの生成の方があまりに も貧弱(content-length しか無い)ですが、ヘッダの解釈の方はこの程度でも 使えそうです。 ついでに、これを使用したタイプの simple_chat_server.rb も付けます。(圧 縮しようかと思ったのですが、たいして変らないのでそのまま付けます。) ところで、CR, LF (できれば EOL も) という定数を用意するというのはいか がでしょうか? 便利だと思いますし、弊害も無いと思いますが。 #!/usr/local/bin/ruby # # http-lib.rb # ver0.01 1998/04/17 # Wakou Aoyama # # == HTTP header analyze # request_file_name = HTTP.header_analyze(IO) # # == add HTTP header # http_content = HTTP.add_header("string") class HTTP CR = "\015" LF = "\012" EOL = CR + LF def HTTP.header_analyze(io) # ===== header analyze head = '' head += io.read(1) while /#{EOL}#{EOL}|#{LF}#{LF}|#{CR}#{CR}/n !~ head head.gsub!(/#{EOL}|#{CR}|#{LF}/, "\n") case head when /^GET\s+([^?\s]+)\??([^\s]*)/ request_file_name = $1 ENV['REQUEST_METHOD'] = 'GET' ENV['QUERY_STRING'] = ($2 or '').to_s when /^POST\s+([^\s]+)/ request_file_name = $1 ENV['REQUEST_METHOD'] = 'POST' ENV['CONTENT_LENGTH'] = head.scan(/^Content-length: (\d+)/i)[0].to_s end head.scan(/\n([^:]+): (.*)/){|k,v| ENV['HTTP_' + k.upcase.gsub(/\-/, '_')] = v } request_file_name end def HTTP.add_header(content, options = '') # ===== add header 'HTTP/1.0 200 OK' + EOL + ('Content-length: ' + content.length.to_s + EOL if 'no-length' != options).to_s + 'Content-type: text/html' + EOL + EOL + content end end #!/usr/local/bin/ruby # # simple_chat_server.rb # ver0.20 1998/04/17 # Wakou Aoyama require 'socket' require 'thread' require 'kconv' require 'cgi-lib' require 'http-lib' CR = "\015" LF = "\012" EOL = CR + LF def send_for_all_member(member, message) # ===== send message member.each_value do |listener| # delivery for each listener begin listener['listen_window'] << message # delivery the message rescue # if listener was logouted handle = listener['handle'] member.delete(listener['no']) send_for_all_member(member, '(' + handle + " is logout.)
\n" ) end end end def new_access(sock, serial_no, member) # ===== new access member[serial_no] = {'no' => serial_no, 'handle' => 'No. ' + serial_no.to_s} sock << HTTP.add_header( %|CHAT |.gsub(/^ /, ''), 'no-cache') sock.shutdown(2) end def new_listen_window(sock, my, member) # ===== new listen window my['listen_window'] = sock sock << HTTP.add_header( %|

Welcome!
simple chat server.

Powerd by Ruby.

change handle. input like this.
/HA handle

|.gsub(/^ /, ''), 'no-length') send_for_all_member(member, '(' + my['handle'] + " is login.)
\n") # socket don't shutdown end def talk_window(sock, my, member) # ===== talk window (post message) query = CGI.new(sock) if /\/HA (.+)/i =~ query.inputs['input'] # change handle send_for_all_member(member, '(change handle. "' + my['handle'] + '" --> "' + Kconv.toeuc($1) + "\")
\n" ) my['handle'] = Kconv.toeuc($1) elsif query.inputs.include?('input') and '' != query.inputs['input'] send_for_all_member(member, my['handle'] + ' > ' + Kconv.toeuc( (query.inputs['input'] or '') ) + "
\n" ) end sock << HTTP.add_header( %|
#{my['handle']} >
|.gsub(/^ /, '')) sock.shutdown(2) end PORT = ARGV.shift || 8080 serial_no = 0 member = {} port = TCPserver.open(PORT) trap('PIPE', 'IGNORE') STDERR.print (Time.now, "\tserver is on #{port.addr[1]}\n") loop do s = port.accept # stand by for accept Thread.start do # divide the work sock = s # copy to thread-local variable case HTTP.header_analyze(sock) when %r|^/$| # ===== new access serial_no += 1 new_access(sock, serial_no, member) when %r|^/talk(\d+).html$| # ===== talk window (post message) talk_window(sock, member[$1.to_i], member) when %r|^/listen(\d+).html$| # ===== new listen window new_listen_window(sock, member[$1.to_i], member) else # ===== file not found sock << HTTP.add_header('

file not found

') sock.shutdown(2) end end end 青山 和光 Wakou Aoyama