sensu-em 2.0.0-java
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 +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +12 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +33 -0
- data/GNU +281 -0
- data/Gemfile +2 -0
- data/LICENSE +60 -0
- data/README.md +109 -0
- data/Rakefile +20 -0
- data/docs/DocumentationGuidesIndex.md +27 -0
- data/docs/GettingStarted.md +521 -0
- data/docs/old/ChangeLog +211 -0
- data/docs/old/DEFERRABLES +246 -0
- data/docs/old/EPOLL +141 -0
- data/docs/old/INSTALL +13 -0
- data/docs/old/KEYBOARD +42 -0
- data/docs/old/LEGAL +25 -0
- data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
- data/docs/old/PURE_RUBY +75 -0
- data/docs/old/RELEASE_NOTES +94 -0
- data/docs/old/SMTP +4 -0
- data/docs/old/SPAWNED_PROCESSES +148 -0
- data/docs/old/TODO +8 -0
- data/eventmachine.gemspec +38 -0
- data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
- data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
- data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
- data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
- data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
- data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
- data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
- data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
- data/examples/old/ex_channel.rb +43 -0
- data/examples/old/ex_queue.rb +2 -0
- data/examples/old/ex_tick_loop_array.rb +15 -0
- data/examples/old/ex_tick_loop_counter.rb +32 -0
- data/examples/old/helper.rb +2 -0
- data/ext/binder.cpp +124 -0
- data/ext/binder.h +46 -0
- data/ext/cmain.cpp +887 -0
- data/ext/ed.cpp +1988 -0
- data/ext/ed.h +422 -0
- data/ext/em.cpp +2352 -0
- data/ext/em.h +253 -0
- data/ext/eventmachine.h +128 -0
- data/ext/extconf.rb +179 -0
- data/ext/fastfilereader/extconf.rb +103 -0
- data/ext/fastfilereader/mapper.cpp +214 -0
- data/ext/fastfilereader/mapper.h +59 -0
- data/ext/fastfilereader/rubymain.cpp +127 -0
- data/ext/kb.cpp +79 -0
- data/ext/page.cpp +107 -0
- data/ext/page.h +51 -0
- data/ext/pipe.cpp +347 -0
- data/ext/project.h +161 -0
- data/ext/rubymain.cpp +1318 -0
- data/ext/ssl.cpp +468 -0
- data/ext/ssl.h +94 -0
- data/java/.classpath +6 -0
- data/java/.gitignore +1 -0
- data/java/.project +17 -0
- data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
- data/java/src/com/rubyeventmachine/EmReactor.java +529 -0
- data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
- data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
- data/java/src/com/rubyeventmachine/EventCode.java +26 -0
- data/java/src/com/rubyeventmachine/EventableChannel.java +130 -0
- data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +180 -0
- data/java/src/com/rubyeventmachine/EventableSocketChannel.java +405 -0
- data/java/src/com/rubyeventmachine/SslBox.java +310 -0
- data/lib/em/buftok.rb +110 -0
- data/lib/em/callback.rb +58 -0
- data/lib/em/channel.rb +64 -0
- data/lib/em/completion.rb +304 -0
- data/lib/em/connection.rb +712 -0
- data/lib/em/deferrable/pool.rb +2 -0
- data/lib/em/deferrable.rb +210 -0
- data/lib/em/file_watch.rb +73 -0
- data/lib/em/future.rb +61 -0
- data/lib/em/iterator.rb +231 -0
- data/lib/em/messages.rb +66 -0
- data/lib/em/pool.rb +151 -0
- data/lib/em/process_watch.rb +45 -0
- data/lib/em/processes.rb +123 -0
- data/lib/em/protocols/header_and_content.rb +138 -0
- data/lib/em/protocols/httpclient.rb +279 -0
- data/lib/em/protocols/httpclient2.rb +600 -0
- data/lib/em/protocols/line_and_text.rb +125 -0
- data/lib/em/protocols/line_protocol.rb +29 -0
- data/lib/em/protocols/linetext2.rb +161 -0
- data/lib/em/protocols/memcache.rb +331 -0
- data/lib/em/protocols/object_protocol.rb +46 -0
- data/lib/em/protocols/postgres3.rb +246 -0
- data/lib/em/protocols/saslauth.rb +175 -0
- data/lib/em/protocols/smtpclient.rb +365 -0
- data/lib/em/protocols/smtpserver.rb +643 -0
- data/lib/em/protocols/socks4.rb +66 -0
- data/lib/em/protocols/stomp.rb +205 -0
- data/lib/em/protocols/tcptest.rb +54 -0
- data/lib/em/protocols.rb +37 -0
- data/lib/em/pure_ruby.rb +1017 -0
- data/lib/em/queue.rb +71 -0
- data/lib/em/resolver.rb +209 -0
- data/lib/em/spawnable.rb +84 -0
- data/lib/em/streamer.rb +118 -0
- data/lib/em/threaded_resource.rb +90 -0
- data/lib/em/tick_loop.rb +85 -0
- data/lib/em/timers.rb +61 -0
- data/lib/em/version.rb +3 -0
- data/lib/eventmachine.rb +1553 -0
- data/lib/jeventmachine.rb +321 -0
- data/lib/rubyeventmachine.jar +0 -0
- data/rakelib/cpp.rake_example +77 -0
- data/rakelib/package.rake +98 -0
- data/rakelib/test.rake +8 -0
- data/tests/client.crt +31 -0
- data/tests/client.key +51 -0
- data/tests/em_test_helper.rb +64 -0
- data/tests/server.crt +36 -0
- data/tests/server.key +51 -0
- data/tests/test_attach.rb +150 -0
- data/tests/test_basic.rb +294 -0
- data/tests/test_channel.rb +62 -0
- data/tests/test_completion.rb +177 -0
- data/tests/test_connection_count.rb +53 -0
- data/tests/test_defer.rb +18 -0
- data/tests/test_deferrable.rb +35 -0
- data/tests/test_epoll.rb +145 -0
- data/tests/test_error_handler.rb +38 -0
- data/tests/test_exc.rb +28 -0
- data/tests/test_file_watch.rb +65 -0
- data/tests/test_futures.rb +170 -0
- data/tests/test_get_sock_opt.rb +37 -0
- data/tests/test_handler_check.rb +35 -0
- data/tests/test_hc.rb +155 -0
- data/tests/test_httpclient.rb +190 -0
- data/tests/test_httpclient2.rb +133 -0
- data/tests/test_idle_connection.rb +25 -0
- data/tests/test_inactivity_timeout.rb +54 -0
- data/tests/test_iterator.rb +97 -0
- data/tests/test_kb.rb +34 -0
- data/tests/test_line_protocol.rb +33 -0
- data/tests/test_ltp.rb +138 -0
- data/tests/test_ltp2.rb +288 -0
- data/tests/test_next_tick.rb +104 -0
- data/tests/test_object_protocol.rb +36 -0
- data/tests/test_pause.rb +102 -0
- data/tests/test_pending_connect_timeout.rb +52 -0
- data/tests/test_pool.rb +194 -0
- data/tests/test_process_watch.rb +48 -0
- data/tests/test_processes.rb +128 -0
- data/tests/test_proxy_connection.rb +180 -0
- data/tests/test_pure.rb +88 -0
- data/tests/test_queue.rb +50 -0
- data/tests/test_resolver.rb +55 -0
- data/tests/test_running.rb +14 -0
- data/tests/test_sasl.rb +47 -0
- data/tests/test_send_file.rb +217 -0
- data/tests/test_servers.rb +33 -0
- data/tests/test_set_sock_opt.rb +37 -0
- data/tests/test_shutdown_hooks.rb +23 -0
- data/tests/test_smtpclient.rb +55 -0
- data/tests/test_smtpserver.rb +57 -0
- data/tests/test_spawn.rb +293 -0
- data/tests/test_ssl_args.rb +78 -0
- data/tests/test_ssl_echo_data.rb +60 -0
- data/tests/test_ssl_methods.rb +56 -0
- data/tests/test_ssl_verify.rb +82 -0
- data/tests/test_stomp.rb +37 -0
- data/tests/test_system.rb +42 -0
- data/tests/test_threaded_resource.rb +53 -0
- data/tests/test_tick_loop.rb +59 -0
- data/tests/test_timers.rb +123 -0
- data/tests/test_ud.rb +8 -0
- data/tests/test_unbind_reason.rb +48 -0
- metadata +297 -0
data/lib/em/pool.rb
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
module EventMachine
|
|
2
|
+
# = EventMachine::Pool
|
|
3
|
+
#
|
|
4
|
+
# A simple async resource pool based on a resource and work queue. Resources
|
|
5
|
+
# are enqueued and work waits for resources to become available.
|
|
6
|
+
#
|
|
7
|
+
# Example:
|
|
8
|
+
#
|
|
9
|
+
# EM.run do
|
|
10
|
+
# pool = EM::Pool.new
|
|
11
|
+
# spawn = lambda { pool.add EM::HttpRequest.new('http://example.org') }
|
|
12
|
+
# 10.times { spawn[] }
|
|
13
|
+
# done, scheduled = 0, 0
|
|
14
|
+
#
|
|
15
|
+
# check = lambda do
|
|
16
|
+
# done += 1
|
|
17
|
+
# if done >= scheduled
|
|
18
|
+
# EM.stop
|
|
19
|
+
# end
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
22
|
+
# pool.on_error { |conn| spawn[] }
|
|
23
|
+
#
|
|
24
|
+
# 100.times do
|
|
25
|
+
# pool.perform do |conn|
|
|
26
|
+
# req = conn.get :path => '/', :keepalive => true
|
|
27
|
+
#
|
|
28
|
+
# req.callback do
|
|
29
|
+
# p [:success, conn.object_id, i, req.response.size]
|
|
30
|
+
# check[]
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# req.errback { check[] }
|
|
34
|
+
#
|
|
35
|
+
# req
|
|
36
|
+
# end
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# Resources are expected to be controlled by an object responding to a
|
|
41
|
+
# deferrable/completion style API with callback and errback blocks.
|
|
42
|
+
#
|
|
43
|
+
class Pool
|
|
44
|
+
|
|
45
|
+
def initialize
|
|
46
|
+
@resources = EM::Queue.new
|
|
47
|
+
@removed = []
|
|
48
|
+
@contents = []
|
|
49
|
+
@on_error = nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def add resource
|
|
53
|
+
@contents << resource
|
|
54
|
+
requeue resource
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def remove resource
|
|
58
|
+
@contents.delete resource
|
|
59
|
+
@removed << resource
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Returns a list for introspection purposes only. You should *NEVER* call
|
|
63
|
+
# modification or work oriented methods on objects in this list. A good
|
|
64
|
+
# example use case is periodic statistics collection against a set of
|
|
65
|
+
# connection resources.
|
|
66
|
+
#
|
|
67
|
+
# For example:
|
|
68
|
+
# pool.contents.inject(0) { |sum, connection| connection.num_bytes }
|
|
69
|
+
def contents
|
|
70
|
+
@contents.dup
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# Define a default catch-all for when the deferrables returned by work
|
|
74
|
+
# blocks enter a failed state. By default all that happens is that the
|
|
75
|
+
# resource is returned to the pool. If on_error is defined, this block is
|
|
76
|
+
# responsible for re-adding the resource to the pool if it is still usable.
|
|
77
|
+
# In other words, it is generally assumed that on_error blocks explicitly
|
|
78
|
+
# handle the rest of the lifetime of the resource.
|
|
79
|
+
def on_error *a, &b
|
|
80
|
+
@on_error = EM::Callback(*a, &b)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# Perform a given #call-able object or block. The callable object will be
|
|
84
|
+
# called with a resource from the pool as soon as one is available, and is
|
|
85
|
+
# expected to return a deferrable.
|
|
86
|
+
#
|
|
87
|
+
# The deferrable will have callback and errback added such that when the
|
|
88
|
+
# deferrable enters a finished state, the object is returned to the pool.
|
|
89
|
+
#
|
|
90
|
+
# If on_error is defined, then objects are not automatically returned to the
|
|
91
|
+
# pool.
|
|
92
|
+
def perform(*a, &b)
|
|
93
|
+
work = EM::Callback(*a, &b)
|
|
94
|
+
|
|
95
|
+
@resources.pop do |resource|
|
|
96
|
+
if removed? resource
|
|
97
|
+
@removed.delete resource
|
|
98
|
+
reschedule work
|
|
99
|
+
else
|
|
100
|
+
process work, resource
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
alias reschedule perform
|
|
105
|
+
|
|
106
|
+
# A peek at the number of enqueued jobs waiting for resources
|
|
107
|
+
def num_waiting
|
|
108
|
+
@resources.num_waiting
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Removed will show resources in a partial pruned state. Resources in the
|
|
112
|
+
# removed list may not appear in the contents list if they are currently in
|
|
113
|
+
# use.
|
|
114
|
+
def removed? resource
|
|
115
|
+
@removed.include? resource
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
protected
|
|
119
|
+
def requeue resource
|
|
120
|
+
@resources.push resource
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def failure resource
|
|
124
|
+
if @on_error
|
|
125
|
+
@contents.delete resource
|
|
126
|
+
@on_error.call resource
|
|
127
|
+
# Prevent users from calling a leak.
|
|
128
|
+
@removed.delete resource
|
|
129
|
+
else
|
|
130
|
+
requeue resource
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def completion deferrable, resource
|
|
135
|
+
deferrable.callback { requeue resource }
|
|
136
|
+
deferrable.errback { failure resource }
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def process work, resource
|
|
140
|
+
deferrable = work.call resource
|
|
141
|
+
if deferrable.kind_of?(EM::Deferrable)
|
|
142
|
+
completion deferrable, resource
|
|
143
|
+
else
|
|
144
|
+
raise ArgumentError, "deferrable expected from work"
|
|
145
|
+
end
|
|
146
|
+
rescue Exception
|
|
147
|
+
failure resource
|
|
148
|
+
raise
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
module EventMachine
|
|
2
|
+
|
|
3
|
+
# This is subclassed from EventMachine::Connection for use with the process monitoring API. Read the
|
|
4
|
+
# documentation on the instance methods of this class, and for a full explanation see EventMachine.watch_process.
|
|
5
|
+
class ProcessWatch < Connection
|
|
6
|
+
# @private
|
|
7
|
+
Cfork = 'fork'.freeze
|
|
8
|
+
# @private
|
|
9
|
+
Cexit = 'exit'.freeze
|
|
10
|
+
|
|
11
|
+
# @private
|
|
12
|
+
def receive_data(data)
|
|
13
|
+
case data
|
|
14
|
+
when Cfork
|
|
15
|
+
process_forked
|
|
16
|
+
when Cexit
|
|
17
|
+
process_exited
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Returns the pid that EventMachine::watch_process was originally called with.
|
|
22
|
+
def pid
|
|
23
|
+
@pid
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Should be redefined with the user's custom callback that will be fired when the prcess is forked.
|
|
27
|
+
#
|
|
28
|
+
# There is currently not an easy way to get the pid of the forked child.
|
|
29
|
+
def process_forked
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Should be redefined with the user's custom callback that will be fired when the process exits.
|
|
33
|
+
#
|
|
34
|
+
# stop_watching is called automatically after this callback
|
|
35
|
+
def process_exited
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Discontinue monitoring of the process.
|
|
39
|
+
# This will be called automatically when a process dies. User code may call it as well.
|
|
40
|
+
def stop_watching
|
|
41
|
+
EventMachine::unwatch_pid(@signature)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
data/lib/em/processes.rb
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
|
5
|
+
# Date:: 13 Dec 07
|
|
6
|
+
#
|
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
|
8
|
+
# usage examples.
|
|
9
|
+
#
|
|
10
|
+
#----------------------------------------------------------------------------
|
|
11
|
+
#
|
|
12
|
+
# Copyright (C) 2006-08 by Francis Cianfrocca. All Rights Reserved.
|
|
13
|
+
# Gmail: blackhedd
|
|
14
|
+
#
|
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
|
19
|
+
#
|
|
20
|
+
# See the file COPYING for complete licensing information.
|
|
21
|
+
#
|
|
22
|
+
#---------------------------------------------------------------------------
|
|
23
|
+
#
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
module EventMachine
|
|
28
|
+
|
|
29
|
+
# EM::DeferrableChildProcess is a sugaring of a common use-case
|
|
30
|
+
# involving EM::popen.
|
|
31
|
+
# Call the #open method on EM::DeferrableChildProcess, passing
|
|
32
|
+
# a command-string. #open immediately returns an EM::Deferrable
|
|
33
|
+
# object. It also schedules the forking of a child process, which
|
|
34
|
+
# will execute the command passed to #open.
|
|
35
|
+
# When the forked child terminates, the Deferrable will be signalled
|
|
36
|
+
# and execute its callbacks, passing the data that the child process
|
|
37
|
+
# wrote to stdout.
|
|
38
|
+
#
|
|
39
|
+
class DeferrableChildProcess < EventMachine::Connection
|
|
40
|
+
include EventMachine::Deferrable
|
|
41
|
+
|
|
42
|
+
# @private
|
|
43
|
+
def initialize
|
|
44
|
+
super
|
|
45
|
+
@data = []
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Sugars a common use-case involving forked child processes.
|
|
49
|
+
# #open takes a String argument containing an shell command
|
|
50
|
+
# string (including arguments if desired). #open immediately
|
|
51
|
+
# returns an EventMachine::Deferrable object, without blocking.
|
|
52
|
+
#
|
|
53
|
+
# It also invokes EventMachine#popen to run the passed-in
|
|
54
|
+
# command in a forked child process.
|
|
55
|
+
#
|
|
56
|
+
# When the forked child terminates, the Deferrable that
|
|
57
|
+
# #open calls its callbacks, passing the data returned
|
|
58
|
+
# from the child process.
|
|
59
|
+
#
|
|
60
|
+
def self.open cmd
|
|
61
|
+
EventMachine.popen( cmd, DeferrableChildProcess )
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# @private
|
|
65
|
+
def receive_data data
|
|
66
|
+
@data << data
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# @private
|
|
70
|
+
def unbind
|
|
71
|
+
succeed( @data.join )
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @private
|
|
76
|
+
class SystemCmd < EventMachine::Connection
|
|
77
|
+
def initialize cb
|
|
78
|
+
@cb = cb
|
|
79
|
+
@output = []
|
|
80
|
+
end
|
|
81
|
+
def receive_data data
|
|
82
|
+
@output << data
|
|
83
|
+
end
|
|
84
|
+
def unbind
|
|
85
|
+
@cb.call @output.join(''), get_status if @cb
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# EM::system is a simple wrapper for EM::popen. It is similar to Kernel::system, but requires a
|
|
90
|
+
# single string argument for the command and performs no shell expansion.
|
|
91
|
+
#
|
|
92
|
+
# The block or proc passed to EM::system is called with two arguments: the output generated by the command,
|
|
93
|
+
# and a Process::Status that contains information about the command's execution.
|
|
94
|
+
#
|
|
95
|
+
# EM.run{
|
|
96
|
+
# EM.system('ls'){ |output,status| puts output if status.exitstatus == 0 }
|
|
97
|
+
# }
|
|
98
|
+
#
|
|
99
|
+
# You can also supply an additional proc to send some data to the process:
|
|
100
|
+
#
|
|
101
|
+
# EM.run{
|
|
102
|
+
# EM.system('sh', proc{ |process|
|
|
103
|
+
# process.send_data("echo hello\n")
|
|
104
|
+
# process.send_data("exit\n")
|
|
105
|
+
# }, proc{ |out,status|
|
|
106
|
+
# puts(out)
|
|
107
|
+
# })
|
|
108
|
+
# }
|
|
109
|
+
#
|
|
110
|
+
# Like EventMachine.popen, EventMachine.system currently does not work on windows.
|
|
111
|
+
# It returns the pid of the spawned process.
|
|
112
|
+
def EventMachine::system cmd, *args, &cb
|
|
113
|
+
cb ||= args.pop if args.last.is_a? Proc
|
|
114
|
+
init = args.pop if args.last.is_a? Proc
|
|
115
|
+
|
|
116
|
+
# merge remaining arguments into the command
|
|
117
|
+
cmd = [cmd, *args] if args.any?
|
|
118
|
+
|
|
119
|
+
EM.get_subprocess_pid(EM.popen(cmd, SystemCmd, cb) do |c|
|
|
120
|
+
init[c] if init
|
|
121
|
+
end.signature)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
#--
|
|
2
|
+
#
|
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
|
5
|
+
# Date:: 15 Nov 2006
|
|
6
|
+
#
|
|
7
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
|
8
|
+
# usage examples.
|
|
9
|
+
#
|
|
10
|
+
#----------------------------------------------------------------------------
|
|
11
|
+
#
|
|
12
|
+
# Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
|
13
|
+
# Gmail: blackhedd
|
|
14
|
+
#
|
|
15
|
+
# This program is free software; you can redistribute it and/or modify
|
|
16
|
+
# it under the terms of either: 1) the GNU General Public License
|
|
17
|
+
# as published by the Free Software Foundation; either version 2 of the
|
|
18
|
+
# License, or (at your option) any later version; or 2) Ruby's License.
|
|
19
|
+
#
|
|
20
|
+
# See the file COPYING for complete licensing information.
|
|
21
|
+
#
|
|
22
|
+
#---------------------------------------------------------------------------
|
|
23
|
+
#
|
|
24
|
+
#
|
|
25
|
+
|
|
26
|
+
module EventMachine
|
|
27
|
+
module Protocols
|
|
28
|
+
|
|
29
|
+
# === Usage
|
|
30
|
+
#
|
|
31
|
+
# class RequestHandler < EM::P::HeaderAndContentProtocol
|
|
32
|
+
# def receive_request headers, content
|
|
33
|
+
# p [:request, headers, content]
|
|
34
|
+
# end
|
|
35
|
+
# end
|
|
36
|
+
#
|
|
37
|
+
# EM.run{
|
|
38
|
+
# EM.start_server 'localhost', 80, RequestHandler
|
|
39
|
+
# }
|
|
40
|
+
#
|
|
41
|
+
#--
|
|
42
|
+
# Originally, this subclassed LineAndTextProtocol, which in
|
|
43
|
+
# turn relies on BufferedTokenizer, which doesn't gracefully
|
|
44
|
+
# handle the transitions between lines and binary text.
|
|
45
|
+
# Changed 13Sep08 by FCianfrocca.
|
|
46
|
+
class HeaderAndContentProtocol < Connection
|
|
47
|
+
include LineText2
|
|
48
|
+
|
|
49
|
+
ContentLengthPattern = /Content-length:\s*(\d+)/i
|
|
50
|
+
|
|
51
|
+
def initialize *args
|
|
52
|
+
super
|
|
53
|
+
init_for_request
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def receive_line line
|
|
57
|
+
case @hc_mode
|
|
58
|
+
when :discard_blanks
|
|
59
|
+
unless line == ""
|
|
60
|
+
@hc_mode = :headers
|
|
61
|
+
receive_line line
|
|
62
|
+
end
|
|
63
|
+
when :headers
|
|
64
|
+
if line == ""
|
|
65
|
+
raise "unrecognized state" unless @hc_headers.length > 0
|
|
66
|
+
if respond_to?(:receive_headers)
|
|
67
|
+
receive_headers @hc_headers
|
|
68
|
+
end
|
|
69
|
+
# @hc_content_length will be nil, not 0, if there was no content-length header.
|
|
70
|
+
if @hc_content_length.to_i > 0
|
|
71
|
+
set_binary_mode @hc_content_length
|
|
72
|
+
else
|
|
73
|
+
dispatch_request
|
|
74
|
+
end
|
|
75
|
+
else
|
|
76
|
+
@hc_headers << line
|
|
77
|
+
if ContentLengthPattern =~ line
|
|
78
|
+
# There are some attacks that rely on sending multiple content-length
|
|
79
|
+
# headers. This is a crude protection, but needs to become tunable.
|
|
80
|
+
raise "extraneous content-length header" if @hc_content_length
|
|
81
|
+
@hc_content_length = $1.to_i
|
|
82
|
+
end
|
|
83
|
+
if @hc_headers.length == 1 and respond_to?(:receive_first_header_line)
|
|
84
|
+
receive_first_header_line line
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
else
|
|
88
|
+
raise "internal error, unsupported mode"
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def receive_binary_data text
|
|
93
|
+
@hc_content = text
|
|
94
|
+
dispatch_request
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def dispatch_request
|
|
98
|
+
if respond_to?(:receive_request)
|
|
99
|
+
receive_request @hc_headers, @hc_content
|
|
100
|
+
end
|
|
101
|
+
init_for_request
|
|
102
|
+
end
|
|
103
|
+
private :dispatch_request
|
|
104
|
+
|
|
105
|
+
def init_for_request
|
|
106
|
+
@hc_mode = :discard_blanks
|
|
107
|
+
@hc_headers = []
|
|
108
|
+
# originally was @hc_headers ||= []; @hc_headers.clear to get a performance
|
|
109
|
+
# boost, but it's counterproductive because a subclassed handler will have to
|
|
110
|
+
# call dup to use the header array we pass in receive_headers.
|
|
111
|
+
|
|
112
|
+
@hc_content_length = nil
|
|
113
|
+
@hc_content = ""
|
|
114
|
+
end
|
|
115
|
+
private :init_for_request
|
|
116
|
+
|
|
117
|
+
# Basically a convenience method. We might create a subclass that does this
|
|
118
|
+
# automatically. But it's such a performance killer.
|
|
119
|
+
def headers_2_hash hdrs
|
|
120
|
+
self.class.headers_2_hash hdrs
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
class << self
|
|
124
|
+
def headers_2_hash hdrs
|
|
125
|
+
hash = {}
|
|
126
|
+
hdrs.each {|h|
|
|
127
|
+
if /\A([^\s:]+)\s*:\s*/ =~ h
|
|
128
|
+
tail = $'.dup
|
|
129
|
+
hash[ $1.downcase.gsub(/-/,"_").intern ] = tail
|
|
130
|
+
end
|
|
131
|
+
}
|
|
132
|
+
hash
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|