iodine 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cbb450cc38cab2612710d70cff54bc0bea8685b0
4
- data.tar.gz: 5165d905229eb83143eb0c2fde06a91b8223069d
3
+ metadata.gz: 9451f837296bd4fecf60df42fd3cfee80d80ef0f
4
+ data.tar.gz: af0d8bf95137d229b23ee74aef4825f50a9aafa0
5
5
  SHA512:
6
- metadata.gz: fa8b08cd218f03436b2a82ec5adf5df579108393b51dc5cf199ab11328e55717575102aa7c048d54aaffa2ad2a4f7ba2ed0a2e561630328c783b3fc4e041b704
7
- data.tar.gz: c1d9d2a99ca9132a82ddb28df1747fdc2f532b033f344373406b466d99eda0055c753deca2bc9e2802d99416abbc00bd6a3c1caa0532e5ed02d0554682743a26
6
+ metadata.gz: 6039e844f9b6658326a70fbadc12ebd61007b466a546100670382ce119d2d0bbf193497fc2c40a4fc36945352ad94e2f83f3a1c4f5f1a6a3c88f6c0719bf3dd1
7
+ data.tar.gz: 608df34266557cb59300dd08321c3dcef74a67c7f7f0eec343ae77ac823f440d2108b40008e8c744fd753199ca73b0dffdfb96fc9bad4a2ce1aaac362319d093
@@ -68,14 +68,15 @@ module Iodine
68
68
  #
69
69
  # See {Iodine::Http::WebsocketHandler} for a good starting point or inherit {Iodine::Http::WebsocketHandler} in your handler.
70
70
  #
71
- class Http < Iodine::Protocol
71
+ module Http
72
+ public
72
73
  # Sets or gets the Http callback.
73
74
  #
74
75
  # An Http callback is a Proc like object that answers to `call(request, response)` and returns either:
75
76
  # `true`:: the response has been set by the callback and can be managed (including any streaming) by the server.
76
77
  # `false`:: the request shouldn't be answered or resource not found (error 404 will be sent as a response).
77
78
  # String:: the String will be appended to the response and the response sent.
78
- def self.on_http handler = nil, &block
79
+ def on_http handler = nil, &block
79
80
  @http_app = handler || block if handler || block
80
81
  @http_app
81
82
  end
@@ -84,29 +85,38 @@ module Iodine
84
85
  # A Websockets callback is a Proc like object that answers to `call(request)` and returns either:
85
86
  # `false`:: the request shouldn't be answered or resource not found (error 404 will be sent as a response).
86
87
  # Websocket Handler:: a Websocket handler is an object that is expected to answer `on_message(data)` and `on_close`. See {} for more data.
87
- def self.on_websocket handler = nil, &block
88
+ def on_websocket handler = nil, &block
88
89
  @websocket_app = handler || block if handler || block
89
90
  @websocket_app
90
91
  end
91
92
 
92
93
  # Sets the session token for the Http server (String). Defaults to the name of the script + '_id'.
93
- def self.session_token= token
94
+ def session_token= token
94
95
  @session_token = token
95
96
  end
96
97
  # Sets the session token for the Http server (String). Defaults to the name of the script.
97
- def self.session_token
98
+ def session_token
98
99
  @session_token
99
100
  end
100
101
 
101
102
  # Sets whether Iodine will allow connections to the experiemntal Http2 protocol. Defaults to false unless the `http2` command line flag is present.
102
- def self.http2= allow
103
+ def http2= allow
103
104
  @http2 = allow && true
104
105
  end
105
106
  # Returns true if Iodine will require that new connection be encrypted.
106
- def self.http2
107
+ def http2
107
108
  @http2
108
109
  end
109
110
 
111
+ # # Sets whether Iodine will allow connections to the experiemntal Http2 protocol. Defaults to false unless the `http2` command line flag is present.
112
+ # def self.message_buffer_size= size
113
+ # @message_buffer_size = size
114
+ # end
115
+ # # Returns true if Iodine will require that new connection be encrypted.
116
+ # def self.message_buffer_size
117
+ # @message_buffer_size
118
+ # end
119
+
110
120
  # Creates a websocket client within a new task (non-blocking).
111
121
  #
112
122
  # Make sure to setup all the callbacks (as needed) prior to starting the connection. See {::Iodine::Http::WebsocketClient.connect}
@@ -132,22 +142,25 @@ module Iodine
132
142
  # #if running from irb:
133
143
  # exit
134
144
  #
135
- def self.ws_connect url, options={}, &block
145
+ def ws_connect url, options={}, &block
136
146
  ::Iodine.run { ::Iodine::Http::WebsocketClient.connect url, options, &block }
137
147
  end
138
148
 
149
+ protected
150
+
139
151
  @http2 = (ARGV.index('http2') && true)
140
152
 
141
153
  @websocket_app = @http_app = NOT_IMPLEMENTED = Proc.new { |i,o| false }
142
154
  @session_token = "#{File.basename($0, '.*')}_uuid"
155
+ extend self
143
156
  end
144
157
 
145
158
  @queue.tap do |q|
146
159
  arr =[];
147
160
  arr << q.pop until q.empty?;
148
- run { Iodine.ssl_protocols = { 'h2' => Iodine::Http::Http2, 'http/1.1' => Iodine::Http } if @ssl && @ssl_protocols.empty? && ::Iodine::Http.http2 }
161
+ run { ::Iodine.ssl_protocols = { 'h2' => ::Iodine::Http::Http2, 'http/1.1' => ::Iodine::Http::Http1 } if @ssl && @ssl_protocols.empty? && ::Iodine::Http.http2 }
149
162
  run do
150
- if Iodine.protocol == ::Iodine::Http && ::Iodine::Http.on_http == ::Iodine::Http::NOT_IMPLEMENTED && ::Iodine::Http.on_websocket == ::Iodine::Http::NOT_IMPLEMENTED
163
+ if Iodine.protocol == ::Iodine::Http::Http1 && ::Iodine::Http.on_http == ::Iodine::Http::NOT_IMPLEMENTED && ::Iodine::Http.on_websocket == ::Iodine::Http::NOT_IMPLEMENTED
151
164
  ::Iodine.protocol = :http_not_initialized
152
165
  q << arr.shift until arr.empty?
153
166
  run { Process.kill("INT", 0) }
@@ -156,4 +169,4 @@ module Iodine
156
169
  q << arr.shift until arr.empty?
157
170
  end
158
171
  end
159
- Iodine.protocol = ::Iodine::Http
172
+ Iodine.protocol = ::Iodine::Http::Http1
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  module Iodine
4
- class Http < ::Iodine::Protocol
4
+ module Http
5
5
  class Http2 < ::Iodine::Protocol
6
6
  class HPACK
7
7
  class IndexTable
@@ -145,10 +145,10 @@ module Iodine
145
145
  buffer
146
146
  rescue
147
147
  puts "HPACK failure data dump:"
148
- puts "buffer: #{buffer} - #{buffer.encoding}"
149
- puts "value: #{value} - #{value.encoding}"
150
- puts "packed #{pack_string(value)} - #{pack_string(value)}"
151
- puts "packed #{pack_string(value)} - #{pack_string(value)}"
148
+ puts "buffer: #{buffer} - #{buffer.encoding}" if buffer
149
+ puts "name: #{name} - #{name.encoding}" if name.is_a? String
150
+ puts "value: #{value} - #{value.encoding}" if value.is_a? String
151
+ puts "packed #{pack_string(name)} - #{pack_string(value)}" if value
152
152
  raise
153
153
  end
154
154
  def extract_number data, prefix, prefix_length
@@ -1,195 +1,198 @@
1
1
  module Iodine
2
- class Http < ::Iodine::Protocol
3
- def on_open
4
- set_timeout 1
5
- @refuse_requests = false
6
- @bytes_sent = 0
7
- @parser = {}
8
- end
9
- def on_message data
10
- return if @refuse_requests
11
- @http2_pri_review ||= ( ::Iodine::Http.http2 && ::Iodine::Http::Http2.pre_handshake(self, data) && (return true) ) || true
12
-
13
- data = ::StringIO.new data
14
- until data.eof?
15
- request = (@request ||= ::Iodine::Http::Request.new(self))
16
- unless request[:method]
17
- l = data.gets.strip
18
- next if l.empty?
19
- request[:method], request[:query], request[:version] = l.split(/[\s]+/, 3)
20
- return (Iodine.warn('Protocol Error, closing connection.') && close) unless request[:method] =~ HTTP_METHODS_REGEXP
21
- request[:version] = (request[:version] || '1.1'.freeze).match(/[\d\.]+/)[0]
22
- request[:time_recieved] = Time.now
23
- end
24
- until request[:headers_complete] || (l = data.gets).nil?
25
- if l.include? ':'
26
- # n = l.slice!(0, l.index(':')); l.slice! 0
27
- # n.strip! ; n.downcase!; n.freeze
28
- # request[n] ? (request[n].is_a?(Array) ? (request[n] << l) : request[n] = [request[n], l ]) : (request[n] = l)
29
- l = l.strip.split(/:[\s]?/, 2)
30
- l[0].strip! ; l[0].downcase!;
31
- request[l[0]] ? (request[l[0]].is_a?(Array) ? (request[l[0]] << l[1]) : request[l[0]] = [request[l[0]], l[1] ]) : (request[l[0]] = l[1])
32
- elsif l =~ /^[\r]?\n/
33
- request[:headers_complete] = true
34
- else
35
- #protocol error
36
- Iodine.warn 'Protocol Error, closing connection.'
37
- return close
2
+ module Http
3
+ class Http1 < ::Iodine::Protocol
4
+ def on_open
5
+ set_timeout 1
6
+ @refuse_requests = false
7
+ @bytes_sent = 0
8
+ @parser = {}
9
+ end
10
+ def on_message data
11
+ return if @refuse_requests
12
+ @http2_pri_review ||= ( ::Iodine::Http.http2 && ::Iodine::Http::Http2.pre_handshake(self, data) && (return true) ) || true
13
+
14
+ data = ::StringIO.new data
15
+ until data.eof?
16
+ request = (@request ||= ::Iodine::Http::Request.new(self))
17
+ unless request[:method]
18
+ l = data.gets.strip
19
+ next if l.empty?
20
+ request[:method], request[:query], request[:version] = l.split(/[\s]+/, 3)
21
+ return (Iodine.warn('Protocol Error, closing connection.') && close) unless request[:method] =~ HTTP_METHODS_REGEXP
22
+ request[:version] = (request[:version] || '1.1'.freeze).match(/[\d\.]+/)[0]
23
+ request[:time_recieved] = Time.now
38
24
  end
39
- end
40
- until request[:body_complete] && request[:headers_complete]
41
- if request['transfer-coding'.freeze] == 'chunked'.freeze
42
- # ad mid chunk logic here
43
- if @parser[:length].to_i == 0
44
- chunk = data.gets
25
+ until request[:headers_complete] || (l = data.gets).nil?
26
+ if l.include? ':'
27
+ # n = l.slice!(0, l.index(':')); l.slice! 0
28
+ # n.strip! ; n.downcase!; n.freeze
29
+ # request[n] ? (request[n].is_a?(Array) ? (request[n] << l) : request[n] = [request[n], l ]) : (request[n] = l)
30
+ l = l.strip.split(/:[\s]?/, 2)
31
+ l[0].strip! ; l[0].downcase!;
32
+ request[l[0]] ? (request[l[0]].is_a?(Array) ? (request[l[0]] << l[1]) : request[l[0]] = [request[l[0]], l[1] ]) : (request[l[0]] = l[1])
33
+ elsif l =~ /^[\r]?\n/
34
+ request[:headers_complete] = true
35
+ else
36
+ #protocol error
37
+ Iodine.warn 'Protocol Error, closing connection.'
38
+ return close
39
+ end
40
+ end
41
+ until request[:body_complete] && request[:headers_complete]
42
+ if request['transfer-coding'.freeze] == 'chunked'.freeze
43
+ # ad mid chunk logic here
44
+ if @parser[:length].to_i == 0
45
+ chunk = data.gets
46
+ return false unless chunk
47
+ @parser[:length] = chunk.to_i(16)
48
+ return (Iodine.warn('Protocol Error, closing connection.') && close) unless @parser[:length]
49
+ request[:body_complete] = true && break if @parser[:length] == 0
50
+ @parser[:act_length] = 0
51
+ request[:body] ||= ''
52
+ end
53
+ chunk = data.read(@parser[:length] - @parser[:act_length])
45
54
  return false unless chunk
46
- @parser[:length] = chunk.to_i(16)
47
- return (Iodine.warn('Protocol Error, closing connection.') && close) unless @parser[:length]
48
- request[:body_complete] = true && break if @parser[:length] == 0
49
- @parser[:act_length] = 0
55
+ request[:body] << chunk
56
+ @parser[:act_length] += chunk.bytesize
57
+ (@parser[:act_length] = @parser[:length] = 0) && (data.gets) if @parser[:act_length] >= @parser[:length]
58
+ elsif request['content-length'.freeze] && request['content-length'.freeze].to_i != 0
50
59
  request[:body] ||= ''
60
+ packet = data.read(request['content-length'.freeze].to_i - request[:body].bytesize)
61
+ return false unless packet
62
+ request[:body] << packet
63
+ request[:body_complete] = true if request['content-length'.freeze].to_i - request[:body].bytesize <= 0
64
+ elsif request['content-type'.freeze]
65
+ Iodine.warn 'Body type protocol error.' unless request[:body]
66
+ line = data.gets
67
+ return false unless line
68
+ (request[:body] ||= '') << line
69
+ request[:body_complete] = true if line =~ EOHEADERS
70
+ else
71
+ request[:body_complete] = true
51
72
  end
52
- chunk = data.read(@parser[:length] - @parser[:act_length])
53
- return false unless chunk
54
- request[:body] << chunk
55
- @parser[:act_length] += chunk.bytesize
56
- (@parser[:act_length] = @parser[:length] = 0) && (data.gets) if @parser[:act_length] >= @parser[:length]
57
- elsif request['content-length'.freeze] && request['content-length'.freeze].to_i != 0
58
- request[:body] ||= ''
59
- packet = data.read(request['content-length'.freeze].to_i - request[:body].bytesize)
60
- return false unless packet
61
- request[:body] << packet
62
- request[:body_complete] = true if request['content-length'.freeze].to_i - request[:body].bytesize <= 0
63
- elsif request['content-type'.freeze]
64
- Iodine.warn 'Body type protocol error.' unless request[:body]
65
- line = data.gets
66
- return false unless line
67
- (request[:body] ||= '') << line
68
- request[:body_complete] = true if line =~ EOHEADERS
69
- else
70
- request[:body_complete] = true
71
73
  end
74
+ (@request = ::Iodine::Http::Request.new(self)) && ( (::Iodine::Http.http2 && ::Iodine::Http::Http2.handshake(request, self, data)) || dispatch(request, data) ) if request.delete :body_complete
72
75
  end
73
- (@request = ::Iodine::Http::Request.new(self)) && ( (::Iodine::Http.http2 && ::Iodine::Http::Http2.handshake(request, self, data)) || dispatch(request, data) ) if request.delete :body_complete
74
- end
75
- end
76
+ end
76
77
 
77
- def send_response response
78
- return false if response.headers.frozen?
78
+ def send_response response
79
+ return false if response.headers.frozen?
79
80
 
80
- request = response.request
81
- headers = response.headers
82
- body = response.extract_body
81
+ request = response.request
82
+ headers = response.headers
83
+ body = response.extract_body
83
84
 
84
- headers['content-length'.freeze] ||= body.to_s.bytesize
85
+ headers['content-length'.freeze] ||= body.to_s.bytesize
85
86
 
86
- keep_alive = response.keep_alive
87
- if (request[:version].to_f > 1 && request['connection'.freeze].nil?) || request['connection'.freeze].to_s =~ /ke/i || (headers['connection'.freeze] && headers['connection'.freeze] =~ /^ke/i)
88
- keep_alive = true
89
- headers['connection'.freeze] ||= 'Keep-Alive'.freeze
90
- headers['keep-alive'.freeze] ||= "timeout=#{(@timeout ||= 3).to_s}"
91
- else
92
- headers['connection'.freeze] ||= 'close'.freeze
93
- end
87
+ keep_alive = response.keep_alive
88
+ if (request[:version].to_f > 1 && request['connection'.freeze].nil?) || request['connection'.freeze].to_s =~ /ke/i || (headers['connection'.freeze] && headers['connection'.freeze] =~ /^ke/i)
89
+ keep_alive = true
90
+ headers['connection'.freeze] ||= 'keep-alive'.freeze
91
+ headers['keep-alive'.freeze] ||= "timeout=#{(@timeout ||= 3).to_s}"
92
+ else
93
+ headers['connection'.freeze] ||= 'close'.freeze
94
+ end
94
95
 
95
- send_headers response
96
- return log_finished(response) if request.head?
97
- (response.bytes_written += (write(body) || 0)) && (body.frozen? || body.clear) if body
98
- close unless keep_alive
99
- log_finished response
100
- end
101
- def stream_response response, finish = false
102
- unless response.headers.frozen?
103
- response['transfer-encoding'.freeze] = 'chunked'
104
- response.headers['connection'.freeze] = 'close'.freeze
105
96
  send_headers response
106
- @refuse_requests = true
107
- end
108
- return if response.request.head?
109
- body = response.extract_body
110
- response.bytes_written += stream_data(body) if body || finish
111
- if finish
112
- response.bytes_written += stream_data('') unless body.nil?
97
+ return log_finished(response) if request.head?
98
+ (response.bytes_written += (write(body) || 0)) && (body.frozen? || body.clear) if body
99
+ close unless keep_alive
113
100
  log_finished response
114
101
  end
115
- (body.frozen? || body.clear) if body
116
- true
117
- end
102
+ def stream_response response, finish = false
103
+ unless response.headers.frozen?
104
+ response['transfer-encoding'.freeze] = 'chunked'
105
+ response.headers['connection'.freeze] = 'close'.freeze
106
+ send_headers response
107
+ @refuse_requests = true
108
+ end
109
+ return if response.request.head?
110
+ body = response.extract_body
111
+ response.bytes_written += stream_data(body) if body || finish
112
+ if finish
113
+ response.bytes_written += stream_data('') unless body.nil?
114
+ log_finished response
115
+ close unless response.keep_alive
116
+ end
117
+ (body.frozen? || body.clear) if body
118
+ true
119
+ end
118
120
 
119
- protected
120
-
121
- HTTP_METHODS = %w{GET HEAD POST PUT DELETE TRACE OPTIONS CONNECT PATCH}
122
- HTTP_METHODS_REGEXP = /\A#{HTTP_METHODS.join('|')}/i
123
-
124
- def dispatch request, data
125
- return data.string.clear if @io.closed? || @refuse_requests
126
- ::Iodine::Http::Request.parse request
127
- #check for server-responses
128
- case request[:method]
129
- when 'TRACE'.freeze
130
- close
131
- data.string.clear
132
- return false
133
- when 'OPTIONS'.freeze
121
+ protected
122
+
123
+ HTTP_METHODS = %w{GET HEAD POST PUT DELETE TRACE OPTIONS CONNECT PATCH}
124
+ HTTP_METHODS_REGEXP = /\A#{HTTP_METHODS.join('|')}/i
125
+
126
+ def dispatch request, data
127
+ return data.string.clear if @io.closed? || @refuse_requests
128
+ ::Iodine::Http::Request.parse request
129
+ #check for server-responses
130
+ case request[:method]
131
+ when 'TRACE'.freeze
132
+ close
133
+ data.string.clear
134
+ return false
135
+ when 'OPTIONS'.freeze
136
+ response = ::Iodine::Http::Response.new request
137
+ response[:Allow] = 'GET,HEAD,POST,PUT,DELETE,OPTIONS'.freeze
138
+ response['access-control-allow-origin'.freeze] = '*'
139
+ response['content-length'.freeze] = 0
140
+ send_response response
141
+ return false
142
+ end
134
143
  response = ::Iodine::Http::Response.new request
135
- response[:Allow] = 'GET,HEAD,POST,PUT,DELETE,OPTIONS'.freeze
136
- response['access-control-allow-origin'.freeze] = '*'
137
- response['content-length'.freeze] = 0
138
- send_response response
139
- return false
140
- end
141
- response = ::Iodine::Http::Response.new request
142
- begin
143
- if request.websocket?
144
- @refuse_requests = true
145
- ::Iodine::Http::Websockets.handshake request, response, self.class.on_websocket.call(request, response)
146
- else
147
- ret = self.class.on_http.call(request, response)
148
- if ret.is_a?(String)
149
- response << ret
150
- elsif ret == false
151
- response.clear && (response.status = 404) && (response << ::Iodine::Http::Response::STATUS_CODES[404])
144
+ begin
145
+ if request.websocket?
146
+ @refuse_requests = true
147
+ ::Iodine::Http::Websockets.handshake request, response, ::Iodine::Http.on_websocket.call(request, response)
148
+ else
149
+ ret = ::Iodine::Http.on_http.call(request, response)
150
+ if ret.is_a?(String)
151
+ response << ret
152
+ elsif ret == false
153
+ response.clear && (response.status = 404) && (response << ::Iodine::Http::Response::STATUS_CODES[404])
154
+ end
152
155
  end
156
+ send_response response
157
+ rescue => e
158
+ Iodine.error e
159
+ send_response ::Iodine::Http::Response.new(request, 500, {}, ::Iodine::Http::Response::STATUS_CODES[500])
153
160
  end
154
- send_response response
155
- rescue => e
156
- Iodine.error e
157
- send_response ::Iodine::Http::Response.new(request, 500, {}, ::Iodine::Http::Response::STATUS_CODES[500])
158
161
  end
159
- end
160
162
 
161
- def send_headers response
162
- return false if response.headers.frozen?
163
- request = response.request
164
- headers = response.headers
163
+ def send_headers response
164
+ return false if response.headers.frozen?
165
+ request = response.request
166
+ headers = response.headers
165
167
 
166
- # response['date'.freeze] ||= request[:time_recieved].httpdate
168
+ # response['date'.freeze] ||= request[:time_recieved].httpdate
167
169
 
168
- out = "HTTP/#{request[:version]} #{response.status} #{::Iodine::Http::Response::STATUS_CODES[response.status] || 'unknown'}\r\n"
170
+ out = "HTTP/#{request[:version]} #{response.status} #{::Iodine::Http::Response::STATUS_CODES[response.status] || 'unknown'}\r\n"
169
171
 
170
- out << request[:time_recieved].utc.strftime("Date: %a, %d %b %Y %H:%M:%S GMT\r\n".freeze) unless headers['date'.freeze]
172
+ out << request[:time_recieved].utc.strftime("Date: %a, %d %b %Y %H:%M:%S GMT\r\n".freeze) unless headers['date'.freeze]
171
173
 
172
- # unless @headers['connection'] || (@request[:version].to_f <= 1 && (@request['connection'].nil? || !@request['connection'].match(/^k/i))) || (@request['connection'] && @request['connection'].match(/^c/i))
173
- headers.each {|k,v| out << "#{k.to_s}: #{v}\r\n"}
174
- out << "Cache-Control: max-age=0, no-cache\r\n".freeze unless headers['cache-control'.freeze]
175
- response.extract_cookies.each {|cookie| out << "Set-Cookie: #{cookie}\r\n"}
176
- out << "\r\n"
174
+ # unless @headers['connection'] || (@request[:version].to_f <= 1 && (@request['connection'].nil? || !@request['connection'].match(/^k/i))) || (@request['connection'] && @request['connection'].match(/^c/i))
175
+ headers.each {|k,v| out << "#{k.to_s}: #{v}\r\n"}
176
+ out << "cache-control: max-age=0, no-cache\r\n".freeze unless headers['cache-control'.freeze]
177
+ response.extract_cookies.each {|cookie| out << "set-cookie: #{cookie}\r\n"}
178
+ out << "\r\n"
177
179
 
178
- response.bytes_written += (write(out) || 0)
179
- out.clear
180
- headers.freeze
181
- response.raw_cookies.freeze
182
- end
183
- def stream_data data = nil
184
- write("#{data.to_s.bytesize.to_s(16)}\r\n#{data.to_s}\r\n") || 0
185
- end
180
+ response.bytes_written += (write(out) || 0)
181
+ out.clear
182
+ headers.freeze
183
+ response.raw_cookies.freeze
184
+ end
185
+ def stream_data data = nil
186
+ write("#{data.to_s.bytesize.to_s(16)}\r\n#{data.to_s}\r\n") || 0
187
+ end
186
188
 
187
- def log_finished response
188
- @bytes_sent = 0
189
- request = response.request
190
- return if Iodine.logger.nil? || request[:no_log]
191
- t_n = Time.now
192
- Iodine.log("#{request[:client_ip]} [#{t_n.utc}] \"#{request[:method]} #{request[:original_path]} #{request[:scheme]}\/#{request[:version]}\" #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n").clear
189
+ def log_finished response
190
+ @bytes_sent = 0
191
+ request = response.request
192
+ return if Iodine.logger.nil? || request[:no_log]
193
+ t_n = Time.now
194
+ Iodine.log("#{request[:client_ip]} [#{t_n.utc}] \"#{request[:method]} #{request[:original_path]} #{request[:scheme]}\/#{request[:version]}\" #{response.status} #{response.bytes_written.to_s} #{((t_n - request[:time_recieved])*1000).round(2)}ms\n").clear
195
+ end
193
196
  end
194
197
  end
195
198
  end
@@ -1,5 +1,5 @@
1
1
  module Iodine
2
- class Http < Iodine::Protocol
2
+ module Http
3
3
  class Http2 < ::Iodine::Protocol
4
4
  def initialize io, original_request = nil
5
5
  super(io)
@@ -1,16 +1,17 @@
1
1
  module Iodine
2
2
 
3
- class Http < ::Iodine::Protocol
3
+ module Http
4
4
  # This (will be) a Rack handler for the Iodine HTTP server.
5
5
  module Rack
6
6
  module_function
7
7
  def run(app, options = {})
8
8
  @app = app
9
9
 
10
- Iodine.protocol ||= Iodine::HTTP
11
10
  Iodine.threads = 18
12
- @pre_rack_handler = Iodine.protocol.on_http
13
- Iodine.protocol.on_http self
11
+ Iodine.port = options[:Port]
12
+ Iodine.protocol ||= Iodine::Http::Http1
13
+ @pre_rack_handler = Iodine::Http.on_http
14
+ Iodine::Http.on_http self
14
15
  true
15
16
  end
16
17
  def call request, response
@@ -23,10 +24,10 @@ module Iodine
23
24
  raise "Rack app returned an unexpected value: #{res.to_s}" unless res && res.is_a?(Array)
24
25
  response.status = res[0]
25
26
  response.headers.clear
26
- response.headers.update res[1]
27
+ res[1].each {|k, v| response.headers[k.to_s.downcase] = v }
27
28
  response.body = res[2]
28
29
  response.raw_cookies.clear
29
- response.headers['Set-Cookie'] = response.headers.delete('Set-Cookie').split("\n").join("\r\nSet-Cookie: ") if response.headers['Set-Cookie']
30
+ response.headers['set-cookie'] = response.headers.delete('set-cookie').split("\n").join("\r\nset-cookie: ") if request[:io].is_a?(Iodine::Http::Http1) && response.headers['set-cookie']
30
31
  response.request[:no_log] = true
31
32
  true
32
33
  end
@@ -1,6 +1,6 @@
1
1
  module Iodine
2
2
 
3
- class Http < ::Iodine::Protocol
3
+ module Http
4
4
 
5
5
  # This class is the part of the Iodine server.
6
6
  # The request object is a Hash and the Request provides
@@ -1,7 +1,5 @@
1
1
  module Iodine
2
-
3
- class Http < ::Iodine::Protocol
4
-
2
+ module Http
5
3
  # this class handles Http responses.
6
4
  #
7
5
  # The response can be sent in stages but should complete within the scope of the connecton's message. Please notice that headers and status cannot be changed once the response started sending data.
@@ -1,5 +1,6 @@
1
1
  module Iodine
2
- class Http < ::Iodine::Protocol
2
+ module Http
3
+ # session management for Iodine's Http Server
3
4
  module SessionManager
4
5
 
5
6
  module MemSessionStorage
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Iodine
3
- class Http < Iodine::Protocol
3
+ module Http
4
4
  # Create a simple Websocket Client(!).
5
5
  #
6
6
  # This should be done from within an Iodine task, or the callbacks will not be called.
@@ -1,6 +1,6 @@
1
1
 
2
2
  module Iodine
3
- class Http < Iodine::Protocol
3
+ module Http
4
4
 
5
5
  # This class is a good demonstration for creating a Websocket handler with the Iodine API.
6
6
  #
@@ -1,5 +1,5 @@
1
1
  module Iodine
2
- class Http < Iodine::Protocol
2
+ module Http
3
3
  class Websockets < ::Iodine::Protocol
4
4
  # initialize the websocket protocol.
5
5
  def initialize io, handler, request, ws_extentions = nil
@@ -159,7 +159,7 @@ module Iodine
159
159
  else
160
160
  ws_extentions = nil
161
161
  end
162
- response['Sec-WebSocket-Accept'.freeze] = Digest::SHA1.base64digest(request['sec-websocket-key'.freeze] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'.freeze)
162
+ response['sec-websocket-accept'.freeze] = Digest::SHA1.base64digest(request['sec-websocket-key'.freeze] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'.freeze)
163
163
  response.session
164
164
  # Iodine.log "#{@request[:client_ip]} [#{Time.now.utc}] - #{@connection.object_id} Upgraded HTTP to WebSockets.\n"
165
165
  response.finish
@@ -26,7 +26,7 @@ module Iodine
26
26
 
27
27
  protected
28
28
 
29
- @port = (ARGV.index('-p') && ARGV[ARGV.index('-p') + 1]) || ENV['PORT'] || 3000
29
+ @port = ((ARGV.index('-p') && ARGV[ARGV.index('-p') + 1]) || ENV['PORT'] || 3000).to_i
30
30
  @bind = (ARGV.index('-ip') && ARGV[ARGV.index('-ip') + 1]) || ENV['IP'] || "0.0.0.0"
31
31
  @ssl = (ARGV.index('ssl') && true) || (@port == 443)
32
32
  @protocol = nil
@@ -75,13 +75,15 @@ module Iodine
75
75
  def on_open
76
76
  @protocol = Iodine.protocol
77
77
  @ssl = Iodine.ssl
78
+ @accept_proc = @protocol.method(:accept)
78
79
  end
79
80
  def call
80
81
  begin
81
82
  n_io = nil
82
83
  loop do
83
84
  n_io = @io.accept_nonblock
84
- @protocol.accept(n_io, @ssl)
85
+ # @protocol.accept(n_io, @ssl)
86
+ Iodine.run n_io, @ssl, &(@accept_proc)
85
87
  end
86
88
  rescue Errno::EWOULDBLOCK => e
87
89
 
@@ -175,6 +175,9 @@ module Iodine
175
175
  # Normally you won't need to override this method.
176
176
  def self.accept io, ssl
177
177
  ssl ? SSLConnector.new(io, self) : self.new(io)
178
+ rescue
179
+ io.close unless io.closed?
180
+ raise
178
181
  end
179
182
  # This methos updates the timeout "watch", signifying the IO was active.
180
183
  def touch
@@ -1,3 +1,3 @@
1
1
  module Iodine
2
- VERSION = "0.0.4"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iodine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Boaz Segev