Adding a little script to run benchmarks. it save the data in a marshalled
[ebb.git] / ruby_binding / ebb.rb
blob493324860d90eaed0ed6f170e543ad3857673faa
1 # A ruby binding to the ebb web server
2 # Copyright (c) 2007 Ry Dahl <ry.d4hl@gmail.com>
3 # This software is released under the "MIT License". See README file for details.
4 $: << File.expand_path(File.dirname(__FILE__))
5 require 'ebb_ext'
7 module Ebb
8   class Server
9     def self.run(app, options={})
10       # port must be an integer
11       server = self.new(app, options)
12       yield server if block_given?
13       server.start
14     end
15     
16     def initialize(app, options={})
17       @host = options[:Host] || '0.0.0.0'
18       @port = (options[:Port] || 4001).to_i
19       @app = app
20     end
21     
22     # Called by the C library on each request.
23     # env is a hash containing all the variables of the request
24     # client is a TCPSocket
25     # XXX: push this code to C?
26     def process_client(client)
27       status, headers, body = @app.call(client.env)
28       
29       out = "HTTP/1.1 %d %s\r\n" % [status, HTTP_STATUS_CODES[status]]
30       
31       if body.respond_to? :length and status != 304
32         out += "Connection: close\r\n"
33         headers['Content-Length'] = body.length
34       end
35       
36       headers.each { |k, v| out += "#{k}: #{v}\r\n" }
37       out += "\r\n"
38       body.each { |part| out += part }
39       client.write out
40     ensure
41       body.close if body and body.respond_to? :close
42       client.close
43     end
44     
45     # TODO:
46     # problem here. this should be a nonblocking call that starts the server
47     # in a seperate thread. We don't want to sit in libev's loop and ignore
48     # all the ruby related things going on.
49     # Better to start a new thread (do i do this in ebb_ext.c?)
50     def start
51       trap('INT')  { puts "got INT"; stop }
52       trap('TERM') { puts "got TERM"; stop }
53       
54       start_listening
55       while process_connections
56         unless @waiting_clients.empty?
57           client = @waiting_clients.shift
58           process_client(client)
59         end
60       end
61     end
62   end
63   
64   HTTP_STATUS_CODES = {  
65     100  => 'Continue', 
66     101  => 'Switching Protocols', 
67     200  => 'OK', 
68     201  => 'Created', 
69     202  => 'Accepted', 
70     203  => 'Non-Authoritative Information', 
71     204  => 'No Content', 
72     205  => 'Reset Content', 
73     206  => 'Partial Content', 
74     300  => 'Multiple Choices', 
75     301  => 'Moved Permanently', 
76     302  => 'Moved Temporarily', 
77     303  => 'See Other', 
78     304  => 'Not Modified', 
79     305  => 'Use Proxy', 
80     400  => 'Bad Request', 
81     401  => 'Unauthorized', 
82     402  => 'Payment Required', 
83     403  => 'Forbidden', 
84     404  => 'Not Found', 
85     405  => 'Method Not Allowed', 
86     406  => 'Not Acceptable', 
87     407  => 'Proxy Authentication Required', 
88     408  => 'Request Time-out', 
89     409  => 'Conflict', 
90     410  => 'Gone', 
91     411  => 'Length Required', 
92     412  => 'Precondition Failed', 
93     413  => 'Request Entity Too Large', 
94     414  => 'Request-URI Too Large', 
95     415  => 'Unsupported Media Type', 
96     500  => 'Internal Server Error', 
97     501  => 'Not Implemented', 
98     502  => 'Bad Gateway', 
99     503  => 'Service Unavailable', 
100     504  => 'Gateway Time-out', 
101     505  => 'HTTP Version not supported'
102   }