class Knjappserver::Httpsession::Contentgroup

This class handels the adding of content and writing to socket. Since this can be done with multiple threads and multiple IO's it can get complicated.

Constants

NL

Attributes

chunked[RW]
cur_data[R]
done[R]
socket[RW]

Public Class Methods

new(args = {}) click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 9
def initialize(args = {})
  @socket = args[:socket]
  @chunked = args[:chunked]
  @resp = args[:resp]
  @httpsession = args[:httpsession]
  @mutex = Mutex.new
  @debug = false
end

Public Instance Methods

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_contentgroup.rb, line 48
def force_content(newcont)
  @ios = [{:str => newcont, :done => true}]
end
init() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 18
def init
  @done = false
  @thread = nil
  @cur_data = {
    :str => "",
    :done => false
  }
  @ios = [@cur_data]
end
join() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 111
def join
  return nil if @forced
  sleep 0.1 while !@thread
  @thread.join
end
mark_done() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 106
def mark_done
  @cur_data[:done] = true
  @done = true
end
new_io(obj = "") click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 41
def new_io(obj = "")
  @cur_data[:done] = true if @cur_data
  @cur_data = {:str => obj, :done => false}
  @ios << @cur_data
end
new_thread() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 57
def new_thread
  cgroup = Knjappserver::Httpsession::Contentgroup.new(:socket => @socket, :chunked => @chunked)
  cgroup.init
  
  @mutex.synchronize do
    @ios << cgroup
    self.new_io
  end
  
  self.register_thread
  return cgroup
end
register_thread() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 52
def register_thread
  Thread.current[:knjappserver] = {} if !Thread.current[:knjappserver]
  Thread.current[:knjappserver][:contentgroup] = self
end
reset() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 28
def reset
  @ios = []
  @done = false
  @thread = nil
  @forced = false
  
  @mutex.synchronize do
    self.new_io
  end
  
  self.register_thread
end
write(cont) click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 78
def write(cont)
  @mutex.synchronize do
    @cur_data[:str] << cont
  end
end
write_begin() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 70
def write_begin
  begin
    @resp.write if @httpsession.meta["METHOD"] != "HEAD"
  rescue Errno::ECONNRESET, Errno::ENOTCONN, Errno::EPIPE
    #Ignore - the user probaly left.
  end
end
write_force() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 94
def write_force
  @mutex.synchronize do
    @forced = true if !@thread
  end
  
  if @thread
    @thread.join
  else
    self.write_begin
  end
end
write_output() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 84
def write_output
  return nil if @thread
  
  @mutex.synchronize do
    @thread = Thread.new do
      self.write_begin
    end
  end
end
write_to_socket() click to toggle source
# File lib/include/class_httpsession_contentgroup.rb, line 117
def write_to_socket
  count = 0
  
  @ios.each do |data|
    if data.is_a?(Knjappserver::Httpsession::Contentgroup)
      data.write_to_socket
    elsif data.key?(:str)
      if data[:str].is_a?(Hash) and data[:str][:type] == :file
        File.open(data[:str][:path], "r") do |file|
          loop do
            begin
              buf = file.sysread(16384)
            rescue EOFError
              break
            end
            
            if @chunked
              @socket.write("#{buf.length.to_s(16)}#{NL}#{buf}#{NL}")
            else
              @socket.write(buf)
            end
          end
        end
      else
        loop do
          break if data[:done] and data[:str].size <= 0 
          sleep 0.1 while data[:str].size < 512 and !data[:done]
          
          str = nil
          @mutex.synchronize do
            str = data[:str].bytes
            data[:str] = ""
          end
          
          #512 could take a long time for big pages. 16384 seems to be an optimal number.
          str.each_slice(16384) do |slice|
            buf = slice.pack("C*")
            
            if @chunked
              @socket.write("#{buf.length.to_s(16)}#{NL}#{buf}#{NL}")
            else
              @socket.write(buf)
            end
          end
        end
      end
    else
      raise "Unknown object: '#{data.class.name}'."
    end
  end
  
  count += 1
end