Class: Thin::FunEmbed
- Inherits:
-
EM::Connection
- Object
- EM::Connection
- Thin::FunEmbed
- Includes:
- Constants
- Defined in:
- lib/thin/fun_embed.rb,
lib/thin/fun_embed/version.rb,
lib/thin/fun_embed/constants.rb
Overview
minimalistic HTTP server for embedding into EventMachine’d applications
Method #handle_http_request accept fully formed Rack environment and should call send http status+headers+body using one of #send_200_ok, #send_status_body, #send_raw_string and #send_rack_response methods or manually. If you send response manually, then you should call #consider_keep_alive method with your wish: whether you want to try keep-alive connection or not.
require 'thin/fun_embed.rb'
class Simple200ok < Thin::FunEmbed
def handle_http_request(env)
if rand(2) == 1
send_200_ok('{"hello":"world"}', 'application/javascript')
else
send_200_ok('hello world')
end
end
end
EM.run do
EM.start_server '0.0.0.0', 8080, Simple200ok
end
Direct Known Subclasses
Defined Under Namespace
Modules: Constants
Constant Summary collapse
- FULL_KEEP_ALIVE =
"Connection: keep-alive\r\n".freeze
- RN =
"\r\n".freeze
- RNRN =
"\r\n\r\n".freeze
- NL =
"\n".freeze
- CONTENT_LENGTH =
"Content-Length".freeze
- CONTENT_LENGTH_DT =
"\r\nContent-Length: ".freeze
- CONNECTION =
'Connection'.freeze
- KEEP_ALIVE =
'keep-alive'.freeze
- CLOSE =
'close'.freeze
- TEXT_PLAIN =
'text/plain'.freeze
- HTTP_STATUS_CODES =
Thin::HTTP_STATUS_CODES
- VERSION =
"0.0.7"
Constants included from Constants
Constants::DELETE, Constants::GET, Constants::PATH_INFO, Constants::POST, Constants::PUT, Constants::QUERY_STRING, Constants::REQUEST_METHOD, Constants::SCRIPT_NAME, Constants::SERVER_NAME, Constants::SERVER_PORT
Instance Attribute Summary collapse
-
#keep_alive ⇒ Object
readonly
signals if client may accept keep-alive connection.
-
#unbind_callback ⇒ Object
callback, which called from
#unbind
.
Instance Method Summary collapse
-
#consider_keep_alive(try_keep_alive = true) ⇒ Object
call this when you fully send response.
- #force_close! ⇒ Object
-
#handle_http_request(env) ⇒ Object
main method for override you ought to put your application logic here.
- #post_init ⇒ Object
- #receive_data(data) ⇒ Object
-
#send_200_ok(body = '', type = TEXT_PLAIN, try_keep_alive = true) ⇒ Object
send simple ‘200 OK’ response with a body.
-
#send_rack_response(status, headers, body, try_keep_alive = true) ⇒ Object
send Rack like response (status, headers, body).
-
#send_raw_string(string, try_keep_alive = true) ⇒ Object
send fully formatted HTTP response.
-
#send_status_body(status, body = '', type = TEXT_PLAIN, try_keep_alive = true) ⇒ Object
send simple response with status, body and type.
-
#unbind ⇒ Object
:nodoc:.
Instance Attribute Details
#keep_alive ⇒ Object (readonly)
signals if client may accept keep-alive connection
59 60 61 |
# File 'lib/thin/fun_embed.rb', line 59 def keep_alive @keep_alive end |
#unbind_callback ⇒ Object
callback, which called from #unbind
. Could be used for monitoring connections.
56 57 58 |
# File 'lib/thin/fun_embed.rb', line 56 def unbind_callback @unbind_callback end |
Instance Method Details
#consider_keep_alive(try_keep_alive = true) ⇒ Object
call this when you fully send response
180 181 182 183 184 185 186 187 |
# File 'lib/thin/fun_embed.rb', line 180 def consider_keep_alive(try_keep_alive = true) @parser.close rescue nil if @keep_alive && try_keep_alive && !@force_close post_init else close_connection_after_writing end end |
#force_close! ⇒ Object
193 194 195 |
# File 'lib/thin/fun_embed.rb', line 193 def force_close! @force_close = true end |
#handle_http_request(env) ⇒ Object
main method for override you ought to put your application logic here
76 77 78 |
# File 'lib/thin/fun_embed.rb', line 76 def handle_http_request(env) send_200_ok "you should override #handle_http_request" end |
#post_init ⇒ Object
61 62 63 64 65 |
# File 'lib/thin/fun_embed.rb', line 61 def post_init @keep_alive = nil @force_close = false @parser = Thin::Request.new end |
#receive_data(data) ⇒ Object
67 68 69 70 71 72 |
# File 'lib/thin/fun_embed.rb', line 67 def receive_data(data) if @parser.parse(data) @keep_alive = @parser.persistent? handle_http_request(@parser.env) end end |
#send_200_ok(body = '', type = TEXT_PLAIN, try_keep_alive = true) ⇒ Object
send simple ‘200 OK’ response with a body
81 82 83 84 85 86 87 |
# File 'lib/thin/fun_embed.rb', line 81 def send_200_ok(body = '', type = TEXT_PLAIN, try_keep_alive = true) send_data("HTTP/1.1 200 OK\r\nContent-Type: #{type}\r\n"\ "Content-Length: #{body.bytesize}\r\n"\ "#{keep_alive ? FULL_KEEP_ALIVE : nil}\r\n") send_data(body) consider_keep_alive(try_keep_alive) end |
#send_rack_response(status, headers, body, try_keep_alive = true) ⇒ Object
send Rack like response (status, headers, body)
This method tries to implement as much of Rack as it progmatically needed, but not more. Test it before use
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 |
# File 'lib/thin/fun_embed.rb', line 120 def send_rack_response(status, headers, body, try_keep_alive = true) status = status.to_i out = "HTTP/1.1 #{status} #{HTTP_STATUS_CODES[status]}\r\n" if String === headers try_keep_alive &&= headers.index(CONTENT_LENGTH_DT) && headers.index(FULL_KEEP_ALIVE) out << headers else content_length = connection = nil headers.each do |k, v| if k == CONTENT_LENGTH content_length = v elsif k == CONNECTION connection = v end if String === v unless v.index(NL) out << "#{k}: #{v}\r\n" else v.each_line{|l| out << "#{k}: #{l}\r\n"} end elsif v.respond_to?(:each) v.each{|l| out << "#{k}: #{l}\r\n"} else unless (v=v.to_s).index(NL) out << "#{k}: #{v}\r\n" else v.each_line{|l| out << "#{k}: #{l}\r\n"} end end end if content_length.nil? if String === body content_length = body.bytesize elsif Array === body && body.all?{|b| String === body} content_length = 0 body.each{|s| content_length += s.bytesize} end unless content_length.nil? out << "Content-Length: #{content_length}\r\n" end end try_keep_alive &&= @keep_alive && content_length && (!connection || connection == KEEP_ALIVE) out << FULL_KEEP_ALIVE if try_keep_alive && !connection end out << RN send_data out if String === body send_data(body) else body.each{|s| send_data(s)} end consider_keep_alive(try_keep_alive) end |
#send_raw_string(string, try_keep_alive = true) ⇒ Object
send fully formatted HTTP response
106 107 108 109 110 111 112 113 114 |
# File 'lib/thin/fun_embed.rb', line 106 def send_raw_string(string, try_keep_alive = true) send_data(string) try_keep_alive &&= @keep_alive && (cl = string.index(CONTENT_LENGTH_DT)) && (kai = string.index(FULL_KEEP_ALIVE)) && kai < (rn = string.index(RNRN)) && cl < rn consider_keep_alive(try_keep_alive) end |
#send_status_body(status, body = '', type = TEXT_PLAIN, try_keep_alive = true) ⇒ Object
send simple response with status, body and type
90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/thin/fun_embed.rb', line 90 def send_status_body(status, body = '', type = TEXT_PLAIN, try_keep_alive = true) status = status.to_i if status < 200 || status == 204 || status == 304 send_data("HTTP/1.1 #{status} #{HTTP_STATUS_CODES[status]}\r\n"\ "#{keep_alive ? FULL_KEEP_ALIVE : nil}\r\n") else send_data("HTTP/1.1 #{status} #{HTTP_STATUS_CODES[status]}\r\n"\ "Content-Type: #{type}\r\n"\ "Content-Length: #{body.bytesize}\r\n"\ "#{keep_alive ? FULL_KEEP_ALIVE : nil}\r\n") send_data(body) end consider_keep_alive(try_keep_alive) end |
#unbind ⇒ Object
:nodoc:
189 190 191 |
# File 'lib/thin/fun_embed.rb', line 189 def unbind # :nodoc: @unbind_callback && @unbind_callback.call(self) end |