|
ferencd@0
|
1 require 'net/http/server/parser'
|
|
ferencd@0
|
2 require 'net/http/server/requests'
|
|
ferencd@0
|
3 require 'net/http/server/responses'
|
|
ferencd@0
|
4 require 'net/http/server/stream'
|
|
ferencd@0
|
5 require 'net/http/server/chunked_stream'
|
|
ferencd@0
|
6
|
|
ferencd@0
|
7 require 'net/protocol'
|
|
ferencd@0
|
8 require 'gserver'
|
|
ferencd@0
|
9
|
|
ferencd@0
|
10 module Net
|
|
ferencd@0
|
11 class HTTP < Protocol
|
|
ferencd@0
|
12 module Server
|
|
ferencd@0
|
13 class Daemon < GServer
|
|
ferencd@0
|
14
|
|
ferencd@0
|
15 include Requests
|
|
ferencd@0
|
16 include Responses
|
|
ferencd@0
|
17
|
|
ferencd@0
|
18 # Default host to bind to.
|
|
ferencd@0
|
19 DEFAULT_HOST = '0.0.0.0'
|
|
ferencd@0
|
20
|
|
ferencd@0
|
21 # Default port to listen on.
|
|
ferencd@0
|
22 DEFAULT_PORT = 8080
|
|
ferencd@0
|
23
|
|
ferencd@0
|
24 # Maximum number of simultaneous connections.
|
|
ferencd@0
|
25 MAX_CONNECTIONS = 256
|
|
ferencd@0
|
26
|
|
ferencd@0
|
27 # Creates a new HTTP Daemon.
|
|
ferencd@0
|
28 #
|
|
ferencd@0
|
29 # @param [Hash] options
|
|
ferencd@0
|
30 # Options for the daemon.
|
|
ferencd@0
|
31 #
|
|
ferencd@0
|
32 # @option options [String] :host (DEFAULT_HOST)
|
|
ferencd@0
|
33 # The host to run on.
|
|
ferencd@0
|
34 #
|
|
ferencd@0
|
35 # @option options [String] :port (DEFAULT_PORT)
|
|
ferencd@0
|
36 # The port to listen on.
|
|
ferencd@0
|
37 #
|
|
ferencd@0
|
38 # @option options [Integer] :max_connections (MAX_CONNECTIONS)
|
|
ferencd@0
|
39 # The maximum number of simultaneous connections.
|
|
ferencd@0
|
40 #
|
|
ferencd@0
|
41 # @option options [IO] :log ($stderr)
|
|
ferencd@0
|
42 # The log to write errors to.
|
|
ferencd@0
|
43 #
|
|
ferencd@0
|
44 # @option options [#call] :handler
|
|
ferencd@0
|
45 # The HTTP Request Handler object.
|
|
ferencd@0
|
46 #
|
|
ferencd@0
|
47 # @yield [request, socket]
|
|
ferencd@0
|
48 # If a block is given, it will be used to process HTTP Requests.
|
|
ferencd@0
|
49 #
|
|
ferencd@0
|
50 # @yieldparam [Hash{Symbol => String,Array,Hash}] request
|
|
ferencd@0
|
51 # The HTTP Request.
|
|
ferencd@0
|
52 #
|
|
ferencd@0
|
53 # @yieldparam [TCPSocket] socket
|
|
ferencd@0
|
54 # The TCP socket of the client.
|
|
ferencd@0
|
55 #
|
|
ferencd@0
|
56 def initialize(options={},&block)
|
|
ferencd@0
|
57 host = options.fetch(:host,DEFAULT_HOST)
|
|
ferencd@0
|
58 port = options.fetch(:port,DEFAULT_PORT).to_i
|
|
ferencd@0
|
59 max_connections = options.fetch(:max_connections,MAX_CONNECTIONS)
|
|
ferencd@0
|
60 log = options.fetch(:log,$stderr)
|
|
ferencd@0
|
61
|
|
ferencd@0
|
62 super(port,host,max_connections,log,false,true)
|
|
ferencd@0
|
63
|
|
ferencd@0
|
64 handler(options[:handler],&block)
|
|
ferencd@0
|
65 end
|
|
ferencd@0
|
66
|
|
ferencd@0
|
67 #
|
|
ferencd@0
|
68 # Sets the HTTP Request Handler.
|
|
ferencd@0
|
69 #
|
|
ferencd@0
|
70 # @param [#call, nil] object
|
|
ferencd@0
|
71 # The HTTP Request Handler object.
|
|
ferencd@0
|
72 #
|
|
ferencd@0
|
73 # @yield [request, stream]
|
|
ferencd@0
|
74 # If a block is given, it will be used to process HTTP Requests.
|
|
ferencd@0
|
75 #
|
|
ferencd@0
|
76 # @yieldparam [Hash{Symbol => String,Array,Hash}] request
|
|
ferencd@0
|
77 # The HTTP Request.
|
|
ferencd@0
|
78 #
|
|
ferencd@0
|
79 # @yieldparam [Stream, ChunkedStream] stream
|
|
ferencd@0
|
80 # The stream of the HTTP Request body.
|
|
ferencd@0
|
81 #
|
|
ferencd@0
|
82 # @raise [ArgumentError]
|
|
ferencd@0
|
83 # The HTTP Request Handler must respond to `#call`.
|
|
ferencd@0
|
84 #
|
|
ferencd@0
|
85 def handler(object=nil,&block)
|
|
ferencd@0
|
86 if object
|
|
ferencd@0
|
87 unless object.respond_to?(:call)
|
|
ferencd@0
|
88 raise(ArgumentError,"HTTP Request Handler must respond to #call")
|
|
ferencd@0
|
89 end
|
|
ferencd@0
|
90 elsif block.nil?
|
|
ferencd@0
|
91 raise(ArgumentError,"no HTTP Request Handler block given")
|
|
ferencd@0
|
92 end
|
|
ferencd@0
|
93
|
|
ferencd@0
|
94 @handler = (object || block)
|
|
ferencd@0
|
95 end
|
|
ferencd@0
|
96
|
|
ferencd@0
|
97 #
|
|
ferencd@0
|
98 # Receives HTTP Requests and handles them.
|
|
ferencd@0
|
99 #
|
|
ferencd@0
|
100 # @param [TCPSocket] socket
|
|
ferencd@0
|
101 # A new TCP connection.
|
|
ferencd@0
|
102 #
|
|
ferencd@0
|
103 def serve(socket)
|
|
ferencd@0
|
104 if (raw_request = read_request(socket))
|
|
ferencd@0
|
105 parser = Parser.new
|
|
ferencd@0
|
106
|
|
ferencd@0
|
107 begin
|
|
ferencd@0
|
108 request = parser.parse(raw_request)
|
|
ferencd@0
|
109 rescue Parslet::ParseFailed
|
|
ferencd@0
|
110 return Responses::BAD_REQUEST
|
|
ferencd@0
|
111 end
|
|
ferencd@0
|
112
|
|
ferencd@0
|
113 normalize_request(request)
|
|
ferencd@0
|
114
|
|
ferencd@0
|
115 stream = if request[:headers]['Transfer-Encoding'] == 'chunked'
|
|
ferencd@0
|
116 ChunkedStream.new(socket)
|
|
ferencd@0
|
117 else
|
|
ferencd@0
|
118 Stream.new(socket)
|
|
ferencd@0
|
119 end
|
|
ferencd@0
|
120
|
|
ferencd@0
|
121 # rack compliant
|
|
ferencd@0
|
122 status, headers, body = @handler.call(request,stream)
|
|
ferencd@0
|
123
|
|
ferencd@0
|
124 write_response(socket,status,headers,body)
|
|
ferencd@0
|
125 end
|
|
ferencd@0
|
126 end
|
|
ferencd@0
|
127
|
|
ferencd@0
|
128 end
|
|
ferencd@0
|
129 end
|
|
ferencd@0
|
130 end
|
|
ferencd@0
|
131 end
|