Class: Soba::Server
Constant Summary
Constants included from Const
Const::CGI_VER, Const::CHUNKED, Const::CHUNK_SIZE, Const::CLOSE, Const::CLOSE_CHUNKED, Const::COLON, Const::CONNECTION_CLOSE, Const::CONNECTION_KEEP_ALIVE, Const::CONTENT_LENGTH, Const::CONTENT_LENGTH2, Const::CONTENT_LENGTH_S, Const::CONTINUE, Const::EARLY_HINTS, Const::ERROR_400_RESPONSE, Const::ERROR_404_RESPONSE, Const::ERROR_408_RESPONSE, Const::ERROR_500_RESPONSE, Const::ERROR_503_RESPONSE, Const::FAST_TRACK_KA_TIMEOUT, Const::FIRST_DATA_TIMEOUT, Const::GATEWAY_INTERFACE, Const::HALT_COMMAND, Const::HEAD, Const::HIJACK, Const::HIJACK_IO, Const::HIJACK_P, Const::HTTP, Const::HTTPS, Const::HTTPS_KEY, Const::HTTP_10_200, Const::HTTP_11, Const::HTTP_11_100, Const::HTTP_11_200, Const::HTTP_CONNECTION, Const::HTTP_EXPECT, Const::HTTP_HOST, Const::HTTP_VERSION, Const::HTTP_X_FORWARDED_FOR, Const::KEEP_ALIVE, Const::LINE_END, Const::LOCALHOST, Const::LOCALHOST_ADDR, Const::LOCALHOST_IP, Const::MAX_BODY, Const::MAX_HEADER, Const::NEWLINE, Const::PATH_INFO, Const::PERSISTENT_TIMEOUT, Const::PORT_443, Const::PORT_80, Const::QUERY_STRING, Const::RACK_AFTER_REPLY, Const::RACK_INPUT, Const::RACK_URL_SCHEME, Const::REMOTE_ADDR, Const::REQUEST_METHOD, Const::REQUEST_PATH, Const::REQUEST_URI, Const::RESTART_COMMAND, Const::SERVER_NAME, Const::SERVER_PORT, Const::SERVER_PROTOCOL, Const::SERVER_SOFTWARE, Const::SOBA_VERSION, Const::STOP_COMMAND, Const::TRANSFER_ENCODING, Const::TRANSFER_ENCODING2, Const::TRANSFER_ENCODING_CHUNKED, Const::WRITE_TIMEOUT
Instance Attribute Summary collapse
-
#app ⇒ Object
readonly
Returns the value of attribute app.
-
#host ⇒ Object
readonly
Returns the value of attribute host.
-
#logger ⇒ Object
readonly
Returns the value of attribute logger.
-
#port ⇒ Object
readonly
Returns the value of attribute port.
Instance Method Summary collapse
- #error_stream ⇒ Object
-
#initialize(app, host:, port:, **options) ⇒ Server
constructor
A new instance of Server.
- #process_request(socket) ⇒ Object
- #rack_env ⇒ Object
- #run ⇒ Object
Constructor Details
#initialize(app, host:, port:, **options) ⇒ Server
Returns a new instance of Server.
16 17 18 19 20 21 22 |
# File 'lib/soba/server.rb', line 16 def initialize(app, host:, port:, **) @app = app @host, @port = host, port @server = nil @logger = Logger.new(STDOUT, level: is_true?([:debug]) ? Logger::DEBUG : Logger::INFO) @options = end |
Instance Attribute Details
#app ⇒ Object (readonly)
Returns the value of attribute app.
8 9 10 |
# File 'lib/soba/server.rb', line 8 def app @app end |
#host ⇒ Object (readonly)
Returns the value of attribute host.
8 9 10 |
# File 'lib/soba/server.rb', line 8 def host @host end |
#logger ⇒ Object (readonly)
Returns the value of attribute logger.
8 9 10 |
# File 'lib/soba/server.rb', line 8 def logger @logger end |
#port ⇒ Object (readonly)
Returns the value of attribute port.
8 9 10 |
# File 'lib/soba/server.rb', line 8 def port @port end |
Instance Method Details
#error_stream ⇒ Object
10 11 12 |
# File 'lib/soba/server.rb', line 10 def error_stream STDERR end |
#process_request(socket) ⇒ Object
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
# File 'lib/soba/server.rb', line 55 def process_request(socket) parser = Parser.new(socket) env = parser.env.merge(rack_env) env["rack.url_scheme"] = parser.request_schema env["rack.input"] = parser.body env["rack.errors"] = error_stream env["SERVER_NAME"] = env[HTTP_HOST].split(":")[0] keep_alive = env[HTTP_CONNECTION].to_s.downcase == KEEP_ALIVE begin status, headers, res_body = app.call(env) logger.debug("response: #{status} #{headers.inspect} #{res_body.inspect}") rescue Exception => e status = 500 headers = {'Content-Type' => 'text/plain'} logger.error("Internal Server Error: #{e}:\n#{e.backtrace.join("\n")}") end nobody = parser.env[REQUEST_METHOD] == HEAD || STATUS_WITH_NO_ENTITY_BODY[status] outbuf = '' status_line = "#{parser.server_protocol} #{status} #{status_text(status)}\n" outbuf << status_line set_content_length = false headers.each do |header, vs| case header.downcase when CONTENT_LENGTH2, CONTENT_LENGTH set_content_length = true end outbuf << "#{header}#{COLON}#{vs}#{LINE_END}" end chunked = !set_content_length outbuf << TRANSFER_ENCODING_CHUNKED if chunked connection_header = keep_alive ? CONNECTION_KEEP_ALIVE : CONNECTION_CLOSE outbuf << connection_header outbuf << "\n" if nobody socket << outbuf socket.flush return end res_body.each do |part| if chunked next if part.bytesize.zero? outbuf << part.bytesize.to_s(16) outbuf << LINE_END outbuf << part outbuf << LINE_END else outbuf << part end end if chunked outbuf << CLOSE_CHUNKED end # write is very slow, don't know why socket << outbuf socket.flush res_body.close if res_body.respond_to?(:close) ensure socket.close unless socket.closed? || keep_alive end |
#rack_env ⇒ Object
41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/soba/server.rb', line 41 def rack_env @rack_env ||= { "rack.version" => Rack::VERSION, "rack.multithread" => true, "rack.multiprocess" => false, "rack.run_once" => false, "rack.hijack?" => false, "rack.hijack" => nil, "rack.hijack_io" => nil, "rack.logger" => logger, "SERVER_PORT" => port.to_s, } end |
#run ⇒ Object
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/soba/server.rb', line 24 def run setup while (socket = @server.accept) _, port, host = socket.peeraddr logger.debug "accept connection from #{host}:#{port}" LightIO::Beam.new(socket) do |socket| begin process_request(socket) until socket.closed? rescue StandardError => e logger.info("Exception: #{e}") raise end end end end |