class Knjappserver::Httpsession
This class handels the HTTP-sessions.
Attributes
active[R]
alert_sent[RW]
browser[R]
cgroup[R]
data[RW]
debug[R]
eruby[R]
get[R]
handler[R]
headers[R]
httpsession_var[R]
kas[R]
meta[R]
out[R]
page_path[R]
post[R]
resp[R]
session[R]
session_hash[R]
session_id[R]
working[R]
Public Class Methods
const_missing(name)
click to toggle source
Autoloader for subclasses.
# File lib/include/class_httpsession.rb, line 7 def self.const_missing(name) require "#{File.dirname(__FILE__)}/class_httpsession_#{name.to_s.downcase}.rb" return Knjappserver::Httpsession.const_get(name.to_s.to_sym) end
finalize(id)
click to toggle source
# File lib/include/class_httpsession.rb, line 182 def self.finalize(id) STDOUT.print "Httpsession finalize #{id}.\n" if @debug end
new(httpserver, socket)
click to toggle source
# File lib/include/class_httpsession.rb, line 12 def initialize(httpserver, socket) @data = {} @socket = socket @httpserver = httpserver @kas = httpserver.kas @types = @kas.types @config = @kas.config @active = true @debug = @kas.debug @handlers_cache = @config[:handlers_cache] @httpsession_var = {} @eruby = Knj::Eruby.new( :cache_hash => @kas.eruby_cache, :binding_callback => self.method(:create_binding) ) #Set socket stuff. if RUBY_PLATFORM == "java" or RUBY_ENGINE == "rbx" if @kas.config[:peeraddr_static] addr_peer = [0, 0, @kas.config[:peeraddr_static]] else addr_peer = @socket.peeraddr end addr = @socket.addr else addr = @socket.addr(false) addr_peer = @socket.peeraddr(false) end @socket_meta = { "REMOTE_ADDR" => addr[2], "REMOTE_PORT" => addr[1], "SERVER_ADDR" => addr_peer[2], "SERVER_PORT" => addr_peer[1] } @resp = Knjappserver::Httpsession::Http_response.new(:socket => @socket) @handler = Knjappserver::Httpsession::Http_request.new(:kas => @kas, :httpsession => self) @cgroup = Knjappserver::Httpsession::Contentgroup.new(:socket => @socket, :kas => @kas, :resp => @resp, :httpsession => self) @resp.cgroup = @cgroup Dir.chdir(@config[:doc_root]) ObjectSpace.define_finalizer(self, self.class.method(:finalize).to_proc) if @debug STDOUT.print "New httpsession #{self.__id__} (total: #{@httpserver.http_sessions.count}).\n" if @debug @thread_request = Thread.new(&self.method(:thread_request_run)) end
Public Instance Methods
add_size(size)
click to toggle source
Is called when content is added and begings to write the output if it goes above the limit.
# File lib/include/class_httpsession.rb, line 142 def add_size(size) @written_size += size @cgroup.write_output if @written_size >= @size_send end
create_binding()
click to toggle source
Creates a new Knjappserver::Binding-object and returns the binding for that object.
# File lib/include/class_httpsession.rb, line 136 def create_binding binding_obj = Knjappserver::Httpsession::Page_environment.new(:httpsession => self, :kas => @kas) return binding_obj.get_binding end
destruct()
click to toggle source
# File lib/include/class_httpsession.rb, line 186 def destruct STDOUT.print "Httpsession destruct (#{@httpserver.http_sessions.length})\n" if @debug and @httpserver and @httpserver.http_sessions begin @socket.close if !@socket.closed? rescue => e STDOUT.puts e.inspect STDOUT.puts e.backtrace #ignore if it fails... end @httpserver.http_sessions.delete(self) if @httpserver and @httpserver.http_sessions @eruby.destroy if @eruby @thread_request.kill if @thread_request.alive? end
force_content(newcont)
click to toggle source
Forces the content to be the input - nothing else can be added after calling this.
# File lib/include/class_httpsession.rb, line 204 def force_content(newcont) @cgroup.force_content(newcont) end
init_thread()
click to toggle source
# File lib/include/class_httpsession.rb, line 171 def init_thread Thread.current[:knjappserver] = {} if !Thread.current[:knjappserver] Thread.current[:knjappserver][:kas] = @kas Thread.current[:knjappserver][:httpsession] = self Thread.current[:knjappserver][:session] = @session Thread.current[:knjappserver][:get] = @get Thread.current[:knjappserver][:post] = @post Thread.current[:knjappserver][:meta] = @meta Thread.current[:knjappserver][:cookie] = @cookie end
serve()
click to toggle source
# File lib/include/class_httpsession.rb, line 208 def serve STDOUT.print "Generating meta, cookie, get, post and headers.\n" if @debug @meta = @handler.meta.merge(@socket_meta) @cookie = @handler.cookie @get = @handler.get @post = @handler.post @headers = @handler.headers close = true if @meta["HTTP_CONNECTION"] == "close" @resp.reset( :http_version => @handler.http_version, :close => close ) if @handler.http_version == "1.1" @cgroup.chunked = true @resp.chunked = true else @cgroup.chunked = false @resp.chunked = false end @page_path = @handler.page_path @ext = File.extname(@page_path).downcase[1..-1].to_s @ctype = @types[@ext.to_sym] if @ext.length > 0 and @types.key?(@ext.to_sym) @ctype = @config[:default_filetype] if !@ctype and @config.key?(:default_filetype) @resp.header("Content-Type", @ctype) @browser = Knj::Web.browser(@meta) if @meta["HTTP_X_FORWARDED_FOR"] @ip = @meta["HTTP_X_FORWARDED_FOR"].split(",")[0].strip elsif @meta["REMOTE_ADDR"] @ip = @meta["REMOTE_ADDR"] else raise "Could not figure out the IP of the session." end STDOUT.print "Figuring out session-ID, session-object and more.\n" if @debug if @cookie["KnjappserverSession"].to_s.length > 0 @session_id = @cookie["KnjappserverSession"] elsif @browser["browser"] == "bot" @session_id = "bot" else @session_id = @kas.session_generate_id(@meta) send_cookie = true end begin @session, @session_hash = @kas.session_fromid(@ip, @session_id, @meta) rescue ArgumentError => e #User should not have the session he asked for because of invalid user-agent or invalid IP. @session_id = @kas.session_generate_id(@meta) @session, @session_hash = @kas.session_fromid(@ip, @session_id, @meta) send_cookie = true end if send_cookie @resp.cookie( "name" => "KnjappserverSession", "value" => @session_id, "path" => "/", "expires" => Time.now + 32140800 #add around 12 months ) end if @config.key?(:logging) and @config[:logging][:access_db] STDOUT.print "Doing access-logging.\n" if @debug @ips = [@meta["REMOTE_ADDR"]] @ips << @meta["HTTP_X_FORWARDED_FOR"].split(",")[0].strip if @meta["HTTP_X_FORWARDED_FOR"] @kas.logs_access_pending << { :session_id => @session.id, :date_request => Time.now, :ips => @ips, :get => @get, :post => @post, :meta => @meta, :cookie => @cookie } end STDOUT.print "Initializing thread and content-group.\n" if @debug self.init_thread Thread.current[:knjappserver][:contentgroup] = @cgroup time_start = Time.now.to_f if @debug begin @kas.events.call(:request_begin, :httpsession => self) if @kas.events Timeout.timeout(@kas.config[:timeout]) do if @handlers_cache.key?(@ext) STDOUT.print "Calling handler.\n" if @debug @handlers_cache[@ext].call(self) else #check if we should use a handler for this request. @config[:handlers].each do |handler_info| if handler_info.key?(:file_ext) and handler_info[:file_ext] == @ext return handler_info[:callback].call(self) elsif handler_info.key?(:path) and handler_info[:mount] and @meta["SCRIPT_NAME"].slice(0, handler_info[:path].length) == handler_info[:path] @page_path = "#{handler_info[:mount]}#{@meta["SCRIPT_NAME"].slice(handler_info[:path].length, @meta["SCRIPT_NAME"].length)}" break end end if !File.exists?(@page_path) @resp.status = 404 @resp.header("Content-Type", "text/html") @cgroup.write("File you are looking for was not found: '#{@meta["REQUEST_URI"]}'.") else if @headers["cache-control"] and @headers["cache-control"][0] cache_control = {} @headers["cache-control"][0].scan(/(.+)=(.+)/) do |match| cache_control[match[1]] = match[2] end end cache_dont = true if cache_control and cache_control.key?("max-age") and cache_control["max-age"].to_i <= 0 lastmod = File.mtime(@page_path) @resp.header("Last-Modified", lastmod.httpdate) @resp.header("Expires", (Time.now + 86400).httpdate) #next day. if !cache_dont and @headers["if-modified-since"] and @headers["if-modified-since"][0] request_mod = Datet.in(@headers["if-modified-since"].first).time if request_mod == lastmod @resp.status = 304 return nil end end @cgroup.new_io(:type => :file, :path => @page_path) end end end rescue SystemExit #do nothing - ignore. rescue Timeout::Error @resp.status = 500 print "The request timed out." end @cgroup.mark_done @cgroup.write_output STDOUT.print "#{__id__} - Served '#{@meta["REQUEST_URI"]}' in #{Time.now.to_f - time_start} secs (#{@resp.status}).\n" if @debug @cgroup.join @kas.events.call(:request_done, { :httpsession => self }) if @kas.events @httpsession_var = {} end
thread_request_run()
click to toggle source
# File lib/include/class_httpsession.rb, line 62 def thread_request_run Thread.current[:knjappserver] = {} if !Thread.current[:knjappserver] Thread.current[:type] = :httpsession if @config.key?(:max_requests_working) max_requests_working = @config[:max_requests_working].to_i else max_requests_working = false end begin while @active begin @cgroup.reset @written_size = 0 @size_send = @config[:size_send] @alert_sent = false @working = false break if @kas.should_restart STDOUT.print "#{__id__} - Waiting to parse from socket.\n" if @debug Timeout.timeout(1800) do @handler.socket_parse(@socket) end STDOUT.print "#{__id__} - Done parsing from socket.\n" if @debug while @kas.paused? #Check if we should be waiting with executing the pending request. STDOUT.print "#{__id__} - Paused! (#{@kas.paused}) - sleeping.\n" if @debug sleep 0.1 end break if @kas.should_restart if max_requests_working and @httpserver while @httpserver.working_count.to_i >= max_requests_working STDOUT.print "#{__id__} - Maximum amounts of requests are working (#{@httpserver.working_count}, #{max_requests_working}) - sleeping.\n" if @debug sleep 0.1 end end #Reserve database connections. @kas.db_handler.get_and_register_thread if @kas.db_handler.opts[:threadsafe] @kas.ob.db.get_and_register_thread if @kas.ob.db.opts[:threadsafe] @working = true STDOUT.print "#{__id__} - Serving.\n" if @debug @httpserver.count_block do self.serve end ensure STDOUT.print "#{__id__} - Closing request.\n" if @debug @working = false #Free reserved database-connections. @kas.db_handler.free_thread if @kas and @kas.db_handler.opts[:threadsafe] @kas.ob.db.free_thread if @kas and @kas.ob.db.opts[:threadsafe] end end rescue Timeout::Error STDOUT.print "#{__id__} - Closing httpsession because of timeout.\n" if @debug rescue Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPIPE => e STDOUT.print "#{__id__} - Connection error (#{e.inspect})...\n" if @debug rescue Interrupt => e raise e rescue Exception => e STDOUT.puts Knj::Errors.error_str(e) ensure self.destruct end end
threadded_content(block)
click to toggle source
# File lib/include/class_httpsession.rb, line 147 def threadded_content(block) raise "No block was given." if !block cgroup = Thread.current[:knjappserver][:contentgroup].new_thread Thread.new do begin self.init_thread cgroup.register_thread @kas.db_handler.get_and_register_thread if @kas and @kas.db_handler.opts[:threadsafe] @kas.ob.db.get_and_register_thread if @kas and @kas.ob.db.opts[:threadsafe] block.call rescue Exception => e Thread.current[:knjappserver][:contentgroup].write Knj::Errors.error_str(e, {:html => true}) _kas.handle_error(e) ensure Thread.current[:knjappserver][:contentgroup].mark_done @kas.ob.db.free_thread if @kas and @kas.ob.db.opts[:threadsafe] @kas.db_handler.free_thread if @kas and @kas.db_handler.opts[:threadsafe] end end end