|
|
# Iowa::Client encapsulates the methods necessary to make a connection
# to an Iowa servlet, receive the response back from the servlet, and to
# deliver that response.
require 'socket'
require 'iowa/Request'
module Iowa
class Client
# When an Iowa::Client is created, it takes as its argument a
# socket definition. It uses that definition to establish either
# a TCPSocket or a UNIXSocket to the servlet.
#
# The socket defenition can be either in the form of:
# hostname:port
# or it can be a filesystem path. If one uses the hostname:port
# form, then a TCPSocket will be used. Otherwise, a UNIXSocket
# will be used.
def initialize(sp)
socket_path = sp.dup
socket_path.untaint
tcp_pattern = Regexp.new('^([^:]*):(\d+)')
tcp_match = tcp_pattern.match(socket_path)
if tcp_match
# Connect to a TCP socket.
socket_host = tcp_match[1]
socket_port = tcp_match[2]
TCPSocket.do_not_reverse_lookup = true
@socket = TCPSocket.new(socket_host,socket_port)
else
@socket = UNIXSocket.new(socket_path)
end
end
# One calls initiate() to send the request off to the servlet.
# The method wants to receive an Apache::Request object.
# If it receives one, it will construct the Iowa::Request object
# that is used to encapsulate the request to the servlet using
# the provided Apache::Request object.
def initiate(request=nil)
ir = Iowa::Request.new(request)
m = Marshal.dump(ir)
@socket.write(m)
@socket.flush
@socket.shutdown(1)
end
# This receives the response back from the servlet.
def receive
m = ''
@request = ''
while (recv = @socket.recv(1024)) != ""
m << recv
end
@socket.close
@socket = nil
@request = Marshal.load(m)
@request.content_type = 'text/html' unless @request.content_type
end
# Prints/sends the HTTP headers for the response.
def printHeaders(ios=nil)
if ENV['MOD_RUBY']
r = Apache.request
r.content_type = @request.content_type
@request.headers_out.each do |key,value|
r.headers_out.set(key,value.to_s)
end
r.headers_out.set('Pragma','no-cache')
r.headers_out.set('Content-Length',@request.content.length.to_s)
r.send_http_header
elsif ios
ios.print "Date: #{Time.now.asctime}\n"
ios.print "Server: #{ENV['SERVER_SOFTWARE']}\n"
ios.print "Pragma: no-cache\n"
ios.print "Connection: close\n"
ios.print "Content-Type: #{@request.content_type}\n"
ios.print "Content-Length: #{@request.content.length}\n"
@request.headers_out.each do |key, value|
ios.print "#{key}: #{value}\n"
end
ios.print "\n"
else
puts "Date: #{Time.now.asctime}"
puts "Server: #{ENV['SERVER_SOFTWARE']}"
puts "Pragma: no-cache"
puts "Connection: close"
puts "Content-Type: #{@request.content_type}"
puts "Content-Length: #{@request.content.length}"
@request.headers_out.each do |key, value|
puts "#{key}: #{value}"
end
puts ""
end
end
# Deliver the content of the request.
def printBody(ios=nil)
if ios
ios.print @request.content.to_s
else
puts @request.content.to_s
end
end
def clearOld
@socket = nil
@request = nil
end
# Deliver both the header and the content of the request, then clear
# the client.
def print(ios = nil)
printHeaders(ios)
printBody(ios)
clearOld
end
def handle_request(ios = nil)
initiate
receive
print(ios)
end
end
end
|