plezi 0.7.7 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +3 -3
- data/lib/plezi.rb +35 -36
- data/lib/plezi/common/cache.rb +94 -0
- data/lib/plezi/{base → common}/dsl.rb +87 -68
- data/lib/plezi/{base → common}/logging.rb +15 -15
- data/lib/plezi/eventmachine/connection.rb +192 -0
- data/lib/plezi/eventmachine/em.rb +95 -0
- data/lib/plezi/eventmachine/io.rb +265 -0
- data/lib/plezi/eventmachine/protocol.rb +54 -0
- data/lib/plezi/eventmachine/queue.rb +51 -0
- data/lib/plezi/eventmachine/ssl_connection.rb +138 -0
- data/lib/plezi/eventmachine/timers.rb +117 -0
- data/lib/plezi/eventmachine/workers.rb +35 -0
- data/lib/plezi/handlers/http_host.rb +4 -4
- data/lib/plezi/handlers/magic_helpers.rb +1 -21
- data/lib/plezi/handlers/route.rb +3 -3
- data/lib/plezi/server/{helpers/http.rb → http.rb} +1 -57
- data/lib/plezi/server/{protocols/http_protocol.rb → http_protocol.rb} +18 -35
- data/lib/plezi/server/{protocols/http_request.rb → http_request.rb} +1 -1
- data/lib/plezi/server/{protocols/http_response.rb → http_response.rb} +45 -22
- data/lib/plezi/server/{helpers/mime_types.rb → mime_types.rb} +0 -0
- data/lib/plezi/server/{protocols/websocket.rb → websocket.rb} +34 -37
- data/lib/plezi/server/{protocols/ws_response.rb → ws_response.rb} +37 -19
- data/lib/plezi/version.rb +1 -1
- data/plezi.gemspec +3 -3
- data/resources/config.ru +9 -11
- metadata +27 -30
- data/lib/plezi/base/cache.rb +0 -89
- data/lib/plezi/base/connections.rb +0 -33
- data/lib/plezi/base/engine.rb +0 -77
- data/lib/plezi/base/events.rb +0 -93
- data/lib/plezi/base/io_reactor.rb +0 -62
- data/lib/plezi/base/rack_app.rb +0 -89
- data/lib/plezi/base/services.rb +0 -57
- data/lib/plezi/base/timers.rb +0 -71
- data/lib/plezi/server/README.md +0 -33
- data/lib/plezi/server/services/basic_service.rb +0 -224
- data/lib/plezi/server/services/no_service.rb +0 -196
- data/lib/plezi/server/services/ssl_service.rb +0 -193
@@ -1,196 +0,0 @@
|
|
1
|
-
module Plezi
|
2
|
-
|
3
|
-
# this class is a basic TCP socket service.
|
4
|
-
#
|
5
|
-
# a protocol should be assigned, or the service will fall back to an echo service.
|
6
|
-
#
|
7
|
-
# a protocol should answer to: on_connect(service), on_message(service, data), on_disconnect(service) and on_exception(service, exception)
|
8
|
-
#
|
9
|
-
# the on_message method should return any data that wasn't used (to be sent again as part of the next `on_message` call, once more data is received).
|
10
|
-
#
|
11
|
-
# if the protocol is a class, these methods should be instance methods.
|
12
|
-
# a protocol class should support the initialize(service, parameters={}) method as well.
|
13
|
-
#
|
14
|
-
# to-do: fix logging
|
15
|
-
class NoService
|
16
|
-
|
17
|
-
# create a listener (io) - will create a TCPServer socket
|
18
|
-
#
|
19
|
-
# listeners are 'server sockets' that answer to `accept` by creating a new connection socket (io).
|
20
|
-
def self.create_service port, parameters
|
21
|
-
self
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.accept
|
25
|
-
false
|
26
|
-
end
|
27
|
-
|
28
|
-
# instance methods
|
29
|
-
|
30
|
-
attr_reader :socket, :locker, :closed, :parameters, :out_que, :active_time
|
31
|
-
attr_accessor :protocol, :handler, :timeout
|
32
|
-
|
33
|
-
# creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.
|
34
|
-
def initialize socket, parameters = {}
|
35
|
-
@handler = parameters[:handler]
|
36
|
-
@socket = nil
|
37
|
-
# socket.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, "\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #== [10 sec 0 usec].pack '1_2'
|
38
|
-
@out_que = []
|
39
|
-
@locker = Mutex.new
|
40
|
-
@parameters = parameters
|
41
|
-
@protocol = parameters[:protocol]
|
42
|
-
@protocol = protocol.new self, parameters if protocol.is_a?(Class)
|
43
|
-
@protocol.on_connect self if @protocol && @protocol.methods.include?(:on_connect)
|
44
|
-
touch
|
45
|
-
@timeout ||= 5
|
46
|
-
# Plezi.callback self, :on_message
|
47
|
-
end
|
48
|
-
|
49
|
-
# # sets a connection timeout
|
50
|
-
# def set_timeout timeout = 8
|
51
|
-
# @timeout = timeout
|
52
|
-
# end
|
53
|
-
|
54
|
-
# checks if a connection timed out
|
55
|
-
def timedout?
|
56
|
-
Time.now - @active_time > @timeout
|
57
|
-
end
|
58
|
-
|
59
|
-
# resets the timer for the connection timeout
|
60
|
-
def touch
|
61
|
-
@active_time = Time.now
|
62
|
-
end
|
63
|
-
|
64
|
-
# returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).
|
65
|
-
def io
|
66
|
-
touch
|
67
|
-
@socket
|
68
|
-
end
|
69
|
-
|
70
|
-
# sends data immidiately - forcing the data to be sent, flushing any pending messages in the que
|
71
|
-
def send data = nil
|
72
|
-
touch
|
73
|
-
end
|
74
|
-
|
75
|
-
# sends data immidiately, interrupting any pending que and ignoring thread safety.
|
76
|
-
def send_unsafe_interrupt data = nil
|
77
|
-
touch
|
78
|
-
_send data rescue disconnect
|
79
|
-
end
|
80
|
-
|
81
|
-
# sends data without waiting - data might be sent in a different order then intended.
|
82
|
-
def send_nonblock data
|
83
|
-
touch
|
84
|
-
locker.synchronize {@out_que << data}
|
85
|
-
Plezi.callback(self, :send)
|
86
|
-
end
|
87
|
-
|
88
|
-
# adds data to the out buffer - but doesn't send the data until a send event is called.
|
89
|
-
def << data
|
90
|
-
touch
|
91
|
-
locker.synchronize {@out_que << data}
|
92
|
-
end
|
93
|
-
|
94
|
-
# makes sure any data in the que is send and calls `flush` on the socket, to make sure the buffer is sent.
|
95
|
-
def flush
|
96
|
-
end
|
97
|
-
|
98
|
-
# event based interface for messages.
|
99
|
-
|
100
|
-
# notice: since it is all async evet base - multipart messages might be garbled up...?
|
101
|
-
# todo: protect from garbeling.
|
102
|
-
def on_message
|
103
|
-
# return false if locker.locked?
|
104
|
-
return false if locker.locked?
|
105
|
-
return disconnect if (_disconnected? rescue true)
|
106
|
-
locker.synchronize do
|
107
|
-
begin
|
108
|
-
touch
|
109
|
-
if protocol
|
110
|
-
protocol.on_message self
|
111
|
-
end
|
112
|
-
rescue Exception => e
|
113
|
-
Plezi.error e
|
114
|
-
return disconnect
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
|
-
# called once a socket is disconnected or needs to be disconnected.
|
120
|
-
def on_disconnect
|
121
|
-
Plezi.callback Plezi, :remove_connection, self
|
122
|
-
|
123
|
-
close
|
124
|
-
end
|
125
|
-
|
126
|
-
# status markers
|
127
|
-
|
128
|
-
# closes the connection
|
129
|
-
def close
|
130
|
-
end
|
131
|
-
# returns true if the service is disconnected
|
132
|
-
def disconnected?
|
133
|
-
false
|
134
|
-
end
|
135
|
-
# disconects the service.
|
136
|
-
def disconnect
|
137
|
-
on_disconnect
|
138
|
-
end
|
139
|
-
# returns true if the socket has content to be read.
|
140
|
-
def has_incoming_data?
|
141
|
-
false
|
142
|
-
end
|
143
|
-
|
144
|
-
|
145
|
-
# identification markers
|
146
|
-
|
147
|
-
#returns the service type - set to normal
|
148
|
-
def service_type
|
149
|
-
'no-service'
|
150
|
-
end
|
151
|
-
#returns true if the service is encrypted using the OpenSSL library.
|
152
|
-
def ssl?
|
153
|
-
false
|
154
|
-
end
|
155
|
-
|
156
|
-
#################
|
157
|
-
# overide the followind methods for any child class.
|
158
|
-
|
159
|
-
# this is a public method and it should be used by child classes to implement each
|
160
|
-
# read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.
|
161
|
-
def read size = 1048576
|
162
|
-
''
|
163
|
-
end
|
164
|
-
|
165
|
-
protected
|
166
|
-
|
167
|
-
# this is a protected method, it should be used by child classes to implement each
|
168
|
-
# send action.
|
169
|
-
def _send data
|
170
|
-
''
|
171
|
-
end
|
172
|
-
# this is a protected method, it should be used by child classes to implement each
|
173
|
-
# close action. doesn't accept any arguments.
|
174
|
-
def _close
|
175
|
-
end
|
176
|
-
# this is a protected method, it should be used by child classes to tell if the socket
|
177
|
-
# was closed (returns true/false).
|
178
|
-
def _disconnected?
|
179
|
-
false # if mode is read only, it's the same as closed.
|
180
|
-
end
|
181
|
-
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
|
186
|
-
######
|
187
|
-
## example requests
|
188
|
-
|
189
|
-
# GET / HTTP/1.1
|
190
|
-
# Host: localhost:2000
|
191
|
-
# Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
|
192
|
-
# Cookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w
|
193
|
-
# User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
|
194
|
-
# Accept-Language: en-us
|
195
|
-
# Accept-Encoding: gzip, deflate
|
196
|
-
# Connection: keep-alive
|
@@ -1,193 +0,0 @@
|
|
1
|
-
module Plezi
|
2
|
-
|
3
|
-
# test connections with: openssl s_client -connect localhost:3000
|
4
|
-
|
5
|
-
# this class is a basic TCP socket service with SSL.
|
6
|
-
#
|
7
|
-
# a protocol should be assigned, or the service will fall back to an echo service.
|
8
|
-
#
|
9
|
-
# to-do: fix self certificate issue (fails).
|
10
|
-
class SSLService < BasicService
|
11
|
-
|
12
|
-
# instance methods
|
13
|
-
|
14
|
-
attr_reader :ssl_socket
|
15
|
-
|
16
|
-
# creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.
|
17
|
-
def initialize soc, parameters = {}
|
18
|
-
context = OpenSSL::SSL::SSLContext.new
|
19
|
-
context.set_params verify_mode: OpenSSL::SSL::VERIFY_NONE# OpenSSL::SSL::VERIFY_PEER #OpenSSL::SSL::VERIFY_NONE
|
20
|
-
# context.options DoNotReverseLookup: true
|
21
|
-
if parameters[:ssl_cert] && parameters[:ssl_key]
|
22
|
-
context.cert = parameters[:ssl_cert]
|
23
|
-
context.key = parameters[:ssl_key]
|
24
|
-
else
|
25
|
-
context.cert, context.key = self.class.self_cert
|
26
|
-
end
|
27
|
-
context.cert_store = OpenSSL::X509::Store.new
|
28
|
-
context.cert_store.set_default_paths
|
29
|
-
@ssl_socket = OpenSSL::SSL::SSLSocket.new(soc, context)
|
30
|
-
@ssl_socket.sync_close = true
|
31
|
-
@socket = soc
|
32
|
-
@ssl_socket.accept
|
33
|
-
super
|
34
|
-
end
|
35
|
-
# identification markers
|
36
|
-
|
37
|
-
#returns the service type - set to normal
|
38
|
-
def service_type
|
39
|
-
'encrypted'
|
40
|
-
end
|
41
|
-
#returns true if the service is encrypted using the OpenSSL library.
|
42
|
-
def ssl?
|
43
|
-
true
|
44
|
-
end
|
45
|
-
|
46
|
-
# returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).
|
47
|
-
def io
|
48
|
-
touch
|
49
|
-
@ssl_socket
|
50
|
-
end
|
51
|
-
|
52
|
-
# reads from the connection
|
53
|
-
def read size = 1048576
|
54
|
-
data = ''
|
55
|
-
begin
|
56
|
-
loop { data << ssl_socket.read_nonblock( size) }
|
57
|
-
rescue Exception => e
|
58
|
-
|
59
|
-
end
|
60
|
-
touch unless data.empty?
|
61
|
-
data
|
62
|
-
end
|
63
|
-
|
64
|
-
protected
|
65
|
-
|
66
|
-
#sends data over the connection
|
67
|
-
def _send data
|
68
|
-
ssl_socket.write data
|
69
|
-
end
|
70
|
-
|
71
|
-
#closes the connection
|
72
|
-
def _close
|
73
|
-
ssl_socket.flush rescue true
|
74
|
-
ssl_socket.close
|
75
|
-
end
|
76
|
-
|
77
|
-
# checks if the connection is closed
|
78
|
-
def _disconnected?
|
79
|
-
ssl_socket.closed? || ssl_socket.io.closed? rescue true # || ssl_socket.io.stat.mode == 0140222 <= if mode is read only, it's the same as closed.
|
80
|
-
end
|
81
|
-
|
82
|
-
|
83
|
-
# SSL certificate
|
84
|
-
|
85
|
-
# returns the current self-signed certificate - or creates a new one, if there is no current certificate.
|
86
|
-
def self.self_cert bits=2048, cn=nil, comment='a self signed certificate for when we only need encryption and no more.'
|
87
|
-
@@self_cert ||= create_cert
|
88
|
-
return *@@self_cert
|
89
|
-
end
|
90
|
-
#creates a self-signed certificate
|
91
|
-
def self.create_cert bits=2048, cn=nil, comment='a self signed certificate for when we only need encryption and no more.'
|
92
|
-
unless cn
|
93
|
-
host_name = Socket::gethostbyname(Socket::gethostname)[0].split('.')
|
94
|
-
cn = ''
|
95
|
-
host_name.each {|n| cn << "/DC=#{n}"}
|
96
|
-
cn << "/CN=#{host_name.join('.')}"
|
97
|
-
end
|
98
|
-
# cn ||= "CN=#{Socket::gethostbyname(Socket::gethostname)[0] rescue Socket::gethostname}"
|
99
|
-
|
100
|
-
rsa = OpenSSL::PKey::RSA.new(bits)
|
101
|
-
cert = OpenSSL::X509::Certificate.new
|
102
|
-
cert.version = 2
|
103
|
-
cert.serial = 1
|
104
|
-
name = OpenSSL::X509::Name.parse(cn)
|
105
|
-
cert.subject = name
|
106
|
-
cert.issuer = name
|
107
|
-
cert.not_before = Time.now
|
108
|
-
cert.not_after = Time.now + (365*24*60*60)
|
109
|
-
cert.public_key = rsa.public_key
|
110
|
-
|
111
|
-
ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
|
112
|
-
ef.issuer_certificate = cert
|
113
|
-
cert.extensions = [
|
114
|
-
ef.create_extension("basicConstraints","CA:FALSE"),
|
115
|
-
ef.create_extension("keyUsage", "keyEncipherment"),
|
116
|
-
ef.create_extension("subjectKeyIdentifier", "hash"),
|
117
|
-
ef.create_extension("extendedKeyUsage", "serverAuth"),
|
118
|
-
ef.create_extension("nsComment", comment),
|
119
|
-
]
|
120
|
-
aki = ef.create_extension("authorityKeyIdentifier",
|
121
|
-
"keyid:always,issuer:always")
|
122
|
-
cert.add_extension(aki)
|
123
|
-
cert.sign(rsa, OpenSSL::Digest::SHA1.new)
|
124
|
-
|
125
|
-
return cert, rsa
|
126
|
-
end
|
127
|
-
|
128
|
-
# def self.cert_test
|
129
|
-
# #Creating a CA
|
130
|
-
# root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key
|
131
|
-
# root_ca = OpenSSL::X509::Certificate.new
|
132
|
-
# root_ca.version = 2 # cf. RFC 5280 - to make it a "v3" certificate
|
133
|
-
# root_ca.serial = 1
|
134
|
-
# root_ca.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby CA"
|
135
|
-
# root_ca.issuer = root_ca.subject # root CA's are "self-signed"
|
136
|
-
# root_ca.public_key = root_key.public_key
|
137
|
-
# root_ca.not_before = Time.now
|
138
|
-
# root_ca.not_after = root_ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity
|
139
|
-
# ef = OpenSSL::X509::ExtensionFactory.new
|
140
|
-
# ef.subject_certificate = root_ca
|
141
|
-
# ef.issuer_certificate = root_ca
|
142
|
-
# root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
|
143
|
-
# root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
|
144
|
-
# root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
|
145
|
-
# root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
|
146
|
-
# root_ca.sign(root_key, OpenSSL::Digest::SHA256.new)
|
147
|
-
# #Creating an End-Point Certificate
|
148
|
-
# key = OpenSSL::PKey::RSA.new 2048
|
149
|
-
# cert = OpenSSL::X509::Certificate.new
|
150
|
-
# cert.version = 2
|
151
|
-
# cert.serial = 2
|
152
|
-
# cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby certificate"
|
153
|
-
# cert.issuer = root_ca.subject # root CA is the issuer
|
154
|
-
# cert.public_key = key.public_key
|
155
|
-
# cert.not_before = Time.now
|
156
|
-
# cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 # 1 years validity
|
157
|
-
# ef = OpenSSL::X509::ExtensionFactory.new
|
158
|
-
# ef.subject_certificate = cert
|
159
|
-
# ef.issuer_certificate = root_ca
|
160
|
-
# cert.add_extension extension_factory.create_extension('keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')
|
161
|
-
# cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
|
162
|
-
# cert.sign(root_key, OpenSSL::Digest::SHA256.new)
|
163
|
-
|
164
|
-
# # #Creating a Certificate
|
165
|
-
# # name = OpenSSL::X509::Name.parse 'CN=localhost/DC=localhost'
|
166
|
-
# # cert = OpenSSL::X509::Certificate.new
|
167
|
-
# # cert.version = 2
|
168
|
-
# # cert.serial = 0
|
169
|
-
# # cert.not_before = Time.now
|
170
|
-
# # cert.not_after = Time.now + 3600
|
171
|
-
# # key = OpenSSL::PKey::RSA.new 2048
|
172
|
-
# # cert.public_key = key.public_key
|
173
|
-
# # cert.subject = name
|
174
|
-
|
175
|
-
# # # Certificate Extensions
|
176
|
-
# # cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:FALSE', true)
|
177
|
-
# # cert.add_extension extension_factory.create_extension('keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')
|
178
|
-
# # cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')
|
179
|
-
|
180
|
-
# # # Signing a Certificate
|
181
|
-
# # cert.issuer = name
|
182
|
-
# # cert.sign key, OpenSSL::Digest::SHA1.new
|
183
|
-
|
184
|
-
# #server
|
185
|
-
# context = OpenSSL::SSL::SSLContext.new
|
186
|
-
# context.cert = cert
|
187
|
-
# context.key = key
|
188
|
-
# tcp_server = TCPServer.new 8080
|
189
|
-
# ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context
|
190
|
-
# ssl_socket = ssl_server.accept
|
191
|
-
# end
|
192
|
-
end
|
193
|
-
end
|