httpクライアントの実装(2)
続きです。
コードをいじりました。
レスポンスをただputsするのではなくてResponseクラスのインスタンスを返すようにしました。
#response.rb class Response attr_accessor :request, :headers, :response_except_body, :status, :body def initialize(response) @response = response @body = @response.slice!(/(\n\r\n).+/m) @response_except_body = @response.slice(/.+/m) #なぜsliceしないと動かないのだろうか・・・・ @request = @response.slice!(/.+/) @status = @request.slice!(/\d{3}.+/) #ヘッダーの切り出し @headers = [] while @response != "" header = @response.slice!(/.+/) @headers.push(header) unless header.nil? @response.sub!(/(\r\n|\r|\n)/, '') end #切り出したヘッダーからインスタンス変数、 #アクセサメソッドを作成 @headers.each do |header| header_name_raw = header.slice!(/^.+: /) unless header_name_raw.nil? header_name = header_name_raw.downcase .gsub("-", "_") .gsub(":", "") .gsub(" ", "") self.instance_variable_set("@#{header_name}",header) add_accessor header_name end end end def all_response self.response_except_body end def disp_body self.body end private def add_accessor instance_variable_name self.class.send(:attr_accessor, instance_variable_name) end end
#http_client.rb require 'socket' require './response' class HttpClient attr_accessor :uri, :port, :path def initialize(options = {}) @uri = options[:uri] @path = options[:path] @port = options[:port] end [:get, :post, :put, :delete, :head, :options].each do |method| define_method(method) do |content = nil, type = "text/plain"| @socket = TCPSocket.open(uri, port) @socket << "#{method.to_s.swapcase} #{self.path} HTTP/1.1\r\n" @socket << "Host: #{self.uri}\r\n" @socket << "Content-Type: #{type}; charset=utf-8\r\n" unless content.nil? @socket << "Content-Length: #{content.length}\r\n" @socket << "\r\n#{content}" end @socket << "Connection: close\r\n" @socket << "\r\n" response = Response.new(@socket.read) return response @socket.close end end end request = HttpClient.new(uri:"example.com", path:"/", port:80) puts "====================" puts request.get.all_response puts "====================" puts HttpClient.new(uri:"example.com", path:"/", port:80).post("こんにちは").all_response puts "====================" puts HttpClient.new(uri:"www.google.com", path:"/", port:80).post("こんにちは").all_response puts "====================" puts HttpClient.new(uri:"example.com", path:"/", port:80).options.all_response puts "===================="
実行すると、
% ruby http_client.rb ==================== HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: max-age=604800 Content-Type: text/html Date: Sat, 30 Apr 2016 03:37:44 GMT Etag: "359670651" Expires: Sat, 07 May 2016 03:37:44 GMT Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT Server: ECS (rhv/818F) Vary: Accept-Encoding X-Cache: HIT x-ec-custom-error: 1 Content-Length: 1270 Connection: close ==================== HTTP/1.1 200 OK Accept-Ranges: bytes Cache-Control: max-age=604800 Content-Type: text/html Date: Sat, 30 Apr 2016 03:37:44 GMT Etag: "359670651" Expires: Sat, 07 May 2016 03:37:44 GMT Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT Server: EOS (lax004/2812) Content-Length: 1270 ==================== HTTP/1.1 405 Method Not Allowed Allow: GET, HEAD Date: Sat, 30 Apr 2016 03:37:44 GMT Content-Type: text/html; charset=UTF-8 Server: gws Content-Length: 1589 X-XSS-Protection: 1; mode=block X-Frame-Options: SAMEORIGIN ==================== HTTP/1.1 200 OK Allow: OPTIONS, GET, HEAD, POST Cache-Control: max-age=604800 Date: Sat, 30 Apr 2016 03:37:45 GMT Expires: Sat, 07 May 2016 03:37:45 GMT Server: EOS (lax004/28A4) x-ec-custom-error: 1 Content-Length: 0 Connection: close ====================
簡単にResponseクラスの説明をすると、正規表現でガリガリ削ってレスポンスのヘッダーを動的にインスタンス変数に入れて動的にアクセサメソッド付与しています。これだけです。