Class: Camping::FastCGI

Inherits:
Object
  • Object
show all
Defined in:
lib/camping/fastcgi.rb

Overview

fast.start

Constant Summary collapse

CHUNK_SIZE =
(4 * 1024)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFastCGI

Creates a Camping::FastCGI class with empty mounts.



62
63
64
# File 'lib/camping/fastcgi.rb', line 62

def initialize
    @mounts = {}
end

Class Method Details

.serve(path, index = nil) ⇒ Object

Serve an entire directory of Camping apps. (See code.whytheluckystiff.net/camping/wiki/TheCampingServer.)

Use this method inside your FastCGI dispatcher:

#!/usr/local/bin/ruby
require 'rubygems'
require 'camping/fastcgi'
Camping::Models::Base.establish_connection :adapter => 'sqlite3', :database => "/path/to/db"
Camping::FastCGI.serve("/home/why/cvs/camping/examples")


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# File 'lib/camping/fastcgi.rb', line 161

def self.serve(path, index=nil)
    require 'camping/reloader'
    if File.directory? path
        fast = Camping::FastCGI.new
        script_load = proc do |script|
            app = Camping::Reloader.new(script)
            fast.mount("/#{app.mount}", app)
            app
        end
        Dir[File.join(path, '*.rb')].each &script_load
        fast.mount("/", index) if index

        fast.start do |dir, app|
             Dir[File.join(path, dir, '*.rb')].each do |script|
                 smount = "/" + File.basename(script, '.rb')
                 script_load[script] unless @mounts.has_key? smount
             end
        end
    else
        start(Camping::Reloader.new(path))
    end
end

.start(app) ⇒ Object

A simple single-app starter mechanism

Camping::FastCGI.start(Blog)


144
145
146
147
148
# File 'lib/camping/fastcgi.rb', line 144

def self.start(app)
    cf = Camping::FastCGI.new
    cf.mount("/", app)
    cf.start
end

Instance Method Details

#mount(dir, app) ⇒ Object

Mounts a Camping application. The dir being the name of the directory to serve as the application’s root. The app is a Camping class.



67
68
69
70
71
# File 'lib/camping/fastcgi.rb', line 67

def mount(dir, app)
    dir.gsub!(/\/{2,}/, '/')
    dir.gsub!(/\/+$/, '')
    @mounts[dir] = app
end

#startObject

Starts the FastCGI main loop.



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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/camping/fastcgi.rb', line 74

def start
    FCGI.each do |req|
        dir, app = nil
        begin
            root, path = "/"
            if ENV['FORCE_ROOT'] and ENV['FORCE_ROOT'].to_i == 1
              path = req.env['REQUEST_URI']
            else
              root = req.env['SCRIPT_NAME']
              path = req.env['PATH_INFO']
            end

            dir, app = @mounts.max { |a,b| match(path, a[0]) <=> match(path, b[0]) }
            unless dir and app
                dir, app = '/', Camping
            end
            yield dir, app if block_given?

            req.env['SERVER_SCRIPT_NAME'] = req.env['SCRIPT_NAME']
            req.env['SERVER_PATH_INFO'] = req.env['PATH_INFO']
            req.env['SCRIPT_NAME'] = File.join(root, dir)
            req.env['PATH_INFO'] = path.gsub(/^#{dir}/, '')

            controller = app.run(req.in, req.env)
            sendfile = nil
            headers = {}
            controller.headers.each do |k, v|
              if k =~ /^X-SENDFILE$/i and !ENV['SERVER_X_SENDFILE']
                sendfile = v
              else
                headers[k] = v
              end
            end

            body = controller.body
            controller.body = ""
            controller.headers = headers

            req.out << controller.to_s
            if sendfile
              File.open(sendfile, "rb") do |f|
                while chunk = f.read(CHUNK_SIZE) and chunk.length > 0
                  req.out << chunk
                end
              end
            elsif body.respond_to? :read
              while chunk = body.read(CHUNK_SIZE) and chunk.length > 0
                req.out << chunk
              end
              body.close if body.respond_to? :close
            else
              req.out << body.to_s
            end
        rescue Exception => e
            req.out << "Content-Type: text/html\r\n\r\n" +
                "<h1>Camping Problem!</h1>" +
                "<h2><strong>#{root}</strong>#{path}</h2>" + 
                "<h3>#{e.class} #{esc e.message}</h3>" +
                "<ul>" + e.backtrace.map { |bt| "<li>#{esc bt}</li>" }.join + "</ul>" +
                "<hr /><p>#{req.env.inspect}</p>"
        ensure
            req.finish
        end
    end
end