rflow-components-http 1.1.0 → 1.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +2 -0
- data/.ruby-version +1 -1
- data/.yardopts +1 -0
- data/Gemfile +1 -1
- data/README.md +1 -2
- data/Rakefile +2 -6
- data/lib/rflow/components/http/extensions.rb +107 -0
- data/lib/rflow/components/http/server.rb +47 -4
- data/lib/rflow/components/http/version.rb +2 -1
- data/lib/rflow/components/http.rb +5 -0
- data/rflow-components-http.gemspec +2 -1
- metadata +24 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 97f9bcce41e96a58c58513b6edb0ea9d02c1f5d4
|
4
|
+
data.tar.gz: 161ef0f6852b256d9270a641e541e56bc1e60bfe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 98a0c1e856216c7332bab76d5f45c05ca07dded321ef20b60e5a3a54b771895c3ab9690a38f35d44bc54282547bcc3ce3bc38480015c2f485111d9c88e1880e9
|
7
|
+
data.tar.gz: 1b35d706f8d764a859c4877641e90dd62dca32c639f6416e528709ca10bb00ad92acf734b1e1397b6027f5b4197004b8976f7dee754ae0a88f35c89cdeefdda4
|
data/.gitignore
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.1
|
1
|
+
ruby-2.3.1
|
data/.yardopts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--output ./doc --main README.md --files schema/*.avsc lib/**/*.rb - README.md LICENSE
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -48,8 +48,7 @@ run across:
|
|
48
48
|
https://github.com/eventmachine/evma_httpserver/blob/master/ext/http.h#L78
|
49
49
|
|
50
50
|
* No support for HTTP chunked transfer encoding, mostly because it
|
51
|
-
does not
|
52
|
-
|
51
|
+
does not send a Content-Length HTTP header.
|
53
52
|
|
54
53
|
## Client
|
55
54
|
|
data/Rakefile
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'bundler'
|
2
2
|
require 'rspec/core/rake_task'
|
3
|
-
require '
|
3
|
+
require 'yard'
|
4
4
|
Bundler::GemHelper.install_tasks
|
5
5
|
|
6
6
|
RSpec::Core::RakeTask.new(:spec) do |t|
|
@@ -8,8 +8,4 @@ RSpec::Core::RakeTask.new(:spec) do |t|
|
|
8
8
|
t.rspec_opts = '--tty --color'
|
9
9
|
end
|
10
10
|
|
11
|
-
Rake::
|
12
|
-
rd.main = "README.md"
|
13
|
-
rd.rdoc_files.include("README.md", "lib/**/*.rb")
|
14
|
-
rd.rdoc_dir = File.join('doc', 'html')
|
15
|
-
end
|
11
|
+
YARD::Rake::YardocTask.new
|
@@ -1,7 +1,110 @@
|
|
1
1
|
class RFlow
|
2
|
+
# @!parse
|
3
|
+
# # Fake classes in this tree to document the actual message types.
|
4
|
+
# class Message
|
5
|
+
# # Fake classes in this tree to document the actual message types.
|
6
|
+
# class Data
|
7
|
+
# # HTTP messages.
|
8
|
+
# module HTTP
|
9
|
+
# # RFlow message representing an HTTP request.
|
10
|
+
# class Request
|
11
|
+
# # @!attribute client_ip
|
12
|
+
# # The IP the request originated from.
|
13
|
+
# # @return [String]
|
14
|
+
#
|
15
|
+
# # @!attribute client_port
|
16
|
+
# # The port the request originated from.
|
17
|
+
# # @return [Integer]
|
18
|
+
#
|
19
|
+
# # @!attribute server_ip
|
20
|
+
# # The IP the request went to.
|
21
|
+
# # @return [String]
|
22
|
+
#
|
23
|
+
# # @!attribute server_port
|
24
|
+
# # The port the request went to.
|
25
|
+
# # @return [Integer]
|
26
|
+
#
|
27
|
+
# # @!attribute method
|
28
|
+
# # The HTTP method (POST, GET, etc.).
|
29
|
+
# # @return [String]
|
30
|
+
#
|
31
|
+
# # @!attribute uri
|
32
|
+
# # The URI the request was for.
|
33
|
+
# # @return [String]
|
34
|
+
#
|
35
|
+
# # @!attribute query_string
|
36
|
+
# # The query string attached to the URI.
|
37
|
+
# # @return [String]
|
38
|
+
#
|
39
|
+
# # @!attribute protocol
|
40
|
+
# # The HTTP protocol being used for the request.
|
41
|
+
# # @return [String]
|
42
|
+
#
|
43
|
+
# # @!attribute headers
|
44
|
+
# # The HTTP request headers.
|
45
|
+
# # @return [Hash]
|
46
|
+
#
|
47
|
+
# # @!attribute content
|
48
|
+
# # The HTTP body content.
|
49
|
+
# # @return [String]
|
50
|
+
#
|
51
|
+
# # Just here to force Yard to create documentation.
|
52
|
+
# # @!visibility private
|
53
|
+
# def initialize; end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# # RFlow message representing an HTTP response.
|
57
|
+
# class Response
|
58
|
+
# # @!attribute client_ip
|
59
|
+
# # The IP the response is going to.
|
60
|
+
# # @return [String]
|
61
|
+
#
|
62
|
+
# # @!attribute client_port
|
63
|
+
# # The port the response is going to.
|
64
|
+
# # @return [Integer]
|
65
|
+
#
|
66
|
+
# # @!attribute server_ip
|
67
|
+
# # The IP the response is coming from.
|
68
|
+
# # @return [String]
|
69
|
+
#
|
70
|
+
# # @!attribute server_port
|
71
|
+
# # The port the response is coming from.
|
72
|
+
# # @return [Integer]
|
73
|
+
#
|
74
|
+
# # @!attribute protocol
|
75
|
+
# # The HTTP protocol being used for the response.
|
76
|
+
# # @return [String]
|
77
|
+
#
|
78
|
+
# # @!attribute status_code
|
79
|
+
# # The HTTP response code.
|
80
|
+
# # @return [Integer]
|
81
|
+
#
|
82
|
+
# # @!attribute status_reason_phrase
|
83
|
+
# # The server-supplied reason phrase (+OK+, +Moved Temporarily+, etc.) for the {status_code}.
|
84
|
+
# # @return [String]
|
85
|
+
#
|
86
|
+
# # @!attribute headers
|
87
|
+
# # The HTTP response headers.
|
88
|
+
# # @return [Hash]
|
89
|
+
#
|
90
|
+
# # @!attribute content
|
91
|
+
# # The HTTP response body content.
|
92
|
+
# # @return [String]
|
93
|
+
#
|
94
|
+
# # Just here to force Yard to create documentation.
|
95
|
+
# # @!visibility private
|
96
|
+
# def initialize; end
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
# end
|
100
|
+
# end
|
101
|
+
|
102
|
+
# Code for RFlow components.
|
2
103
|
module Components
|
3
104
|
module HTTP
|
105
|
+
# @!visibility private
|
4
106
|
module Extensions
|
107
|
+
# @!visibility private
|
5
108
|
module IPConnectionExtension
|
6
109
|
# Default accessors
|
7
110
|
# TODO: validate the stuffs
|
@@ -16,7 +119,9 @@ class RFlow
|
|
16
119
|
end
|
17
120
|
|
18
121
|
# Need to be careful when extending to not clobber data already in data_object
|
122
|
+
# @!visibility private
|
19
123
|
module HTTPRequestExtension
|
124
|
+
# @!visibility private
|
20
125
|
def self.extended(base_data)
|
21
126
|
base_data.data_object ||= {'uri' => '/', 'method' => 'GET', 'protocol' => 'HTTP/1.0', 'headers' => {}, 'content' => ''}
|
22
127
|
end
|
@@ -33,7 +138,9 @@ class RFlow
|
|
33
138
|
end
|
34
139
|
|
35
140
|
# Need to be careful when extending to not clobber data already in data_object
|
141
|
+
# @!visibility private
|
36
142
|
module HTTPResponseExtension
|
143
|
+
# @!visibility private
|
37
144
|
def self.extended(base_data)
|
38
145
|
base_data.data_object ||= {'protocol' => 'HTTP/1.0', 'status_code' => 200, 'status_reason_phrase' => 'OK', 'headers' => {}, 'content' => ''}
|
39
146
|
end
|
@@ -5,14 +5,42 @@ require 'rflow'
|
|
5
5
|
class RFlow
|
6
6
|
module Components
|
7
7
|
module HTTP
|
8
|
+
# Implements a HTTP server based on +eventmachine_httpserver+. Accepts incoming HTTP
|
9
|
+
# connections, marshals the HTTP request into an RFlow message, annotates the message
|
10
|
+
# with a bit of provenance (see below) and then sends the message out its {request_port}.
|
11
|
+
# When a HTTP response message is received on {response_port}, checks the provenance to see
|
12
|
+
# if it matches an underlying TCP/HTTP connection and, if so, creates an actual HTTP
|
13
|
+
# response from the incoming message and sends it to the client.
|
14
|
+
#
|
15
|
+
# The HTTP request message sent from the HTTP server component utilizes the
|
16
|
+
# +RFlow::Message+ provenance feature to annotate a request message with a bit of metadata
|
17
|
+
# that allows subsequent response messages to be matched to their underlying TCP/HTTP
|
18
|
+
# connections. This means that any component that processes HTTP request messages to
|
19
|
+
# generate response messages must copy the provenance from the request message to the
|
20
|
+
# response message.
|
8
21
|
class Server < RFlow::Component
|
22
|
+
# @!attribute [r] response_port
|
23
|
+
# Expects +RFlow::Message+s of type {RFlow::Message::Data::HTTP::Response}
|
24
|
+
# representing responses being sent back corresponding to previously received
|
25
|
+
# requests. Each response should have +provenance+ copied from the request it's
|
26
|
+
# responding to.
|
27
|
+
# @return [RFlow::Component::InputPort]
|
9
28
|
input_port :response_port
|
29
|
+
|
30
|
+
# @!attribute [r] request_port
|
31
|
+
# Produces +RFlow::Message+s of type {RFlow::Message::Data::HTTP::Request}
|
32
|
+
# representing requests that have arrived on the socket managed by the component.
|
33
|
+
# Each features +provenance+ that must be copied to any response message.
|
34
|
+
# @return [RFlow::Component::OutputPort]
|
10
35
|
output_port :request_port
|
11
36
|
|
37
|
+
# @!visibility private
|
12
38
|
attr_accessor :port, :listen, :server_signature, :connections, :closed_connections,
|
13
39
|
:proxy_real_client_ip_header, :proxy_real_client_port_header,
|
14
40
|
:proxy_real_server_ip_header, :proxy_real_server_port_header
|
15
41
|
|
42
|
+
# RFlow-called method at startup.
|
43
|
+
# @return [void]
|
16
44
|
def configure!(config)
|
17
45
|
@listen = config['listen'] ? config['listen'] : '127.0.0.1'
|
18
46
|
@port = config['port'] ? config['port'].to_i : 8000
|
@@ -24,6 +52,8 @@ class RFlow
|
|
24
52
|
@closed_connections = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
|
25
53
|
end
|
26
54
|
|
55
|
+
# RFlow-called method at startup.
|
56
|
+
# @return [void]
|
27
57
|
def run!
|
28
58
|
@server_signature = EM.start_server(@listen, @port, Connection) do |conn|
|
29
59
|
conn.server = self
|
@@ -32,10 +62,13 @@ class RFlow
|
|
32
62
|
end
|
33
63
|
end
|
34
64
|
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
# context attribute that we stored
|
65
|
+
# RFlow-called method upon message arrival.
|
66
|
+
#
|
67
|
+
# Filters for messages that pertain to this component and have active connections
|
68
|
+
# by inspecting the provenance, specifically the context attribute that we stored
|
69
|
+
# originally.
|
70
|
+
#
|
71
|
+
# @return [void]
|
39
72
|
def process_message(input_port, input_port_key, connection, message)
|
40
73
|
return unless message.data_type_name == 'RFlow::Message::Data::HTTP::Response'
|
41
74
|
my_events = message.provenance.find_all {|processing_event| processing_event.component_instance_uuid == uuid}
|
@@ -55,19 +88,23 @@ class RFlow
|
|
55
88
|
end
|
56
89
|
end
|
57
90
|
|
91
|
+
# @!visibility private
|
58
92
|
class ClosedConnection
|
59
93
|
attr_accessor :client_details
|
94
|
+
# @!visibility private
|
60
95
|
def initialize(client_details)
|
61
96
|
@client_details = client_details
|
62
97
|
end
|
63
98
|
end
|
64
99
|
|
100
|
+
# @!visibility private
|
65
101
|
class Connection < EventMachine::Connection
|
66
102
|
include EventMachine::HttpServer
|
67
103
|
|
68
104
|
attr_accessor :server
|
69
105
|
attr_reader :client_ip, :client_port, :server_ip, :server_port
|
70
106
|
|
107
|
+
# @!visibility private
|
71
108
|
def post_init
|
72
109
|
@client_port, @client_ip = Socket.unpack_sockaddr_in(get_peername) rescue ["?", "?.?.?.?"]
|
73
110
|
@server_port, @server_ip = Socket.unpack_sockaddr_in(get_sockname) rescue ["?", "?.?.?.?"]
|
@@ -75,6 +112,7 @@ class RFlow
|
|
75
112
|
no_environment_strings
|
76
113
|
end
|
77
114
|
|
115
|
+
# @!visibility private
|
78
116
|
def client_details
|
79
117
|
if @real_client_ip
|
80
118
|
"#{client_ip}:#{client_port} (proxied from #{@real_client_ip}:#{@real_client_port})"
|
@@ -83,6 +121,7 @@ class RFlow
|
|
83
121
|
end
|
84
122
|
end
|
85
123
|
|
124
|
+
# @!visibility private
|
86
125
|
def server_details
|
87
126
|
if @real_server_ip
|
88
127
|
"#{server_ip}:#{server_port} (proxied as #{@real_server_ip}:#{@real_server_port})"
|
@@ -91,11 +130,13 @@ class RFlow
|
|
91
130
|
end
|
92
131
|
end
|
93
132
|
|
133
|
+
# @!visibility private
|
94
134
|
def receive_data(data)
|
95
135
|
RFlow.logger.debug { "#{server.name}: Received #{data.bytesize} bytes of data from #{client_details} to #{server_details}" }
|
96
136
|
super
|
97
137
|
end
|
98
138
|
|
139
|
+
# @!visibility private
|
99
140
|
def process_http_request
|
100
141
|
RFlow.logger.debug { "#{server.name}: Received HTTP request from #{client_details} to #{server_details} for #{@http_request_uri}" }
|
101
142
|
|
@@ -135,6 +176,7 @@ class RFlow
|
|
135
176
|
RFlow.logger.error "#{server.name}: Error processing HTTP request from #{client_details} to #{server_details} for #{@http_request_uri}: #{e.class.name}: #{e.message}, because: #{e.backtrace.inspect}"
|
136
177
|
end
|
137
178
|
|
179
|
+
# @!visibility private
|
138
180
|
def send_http_response(response_message = nil)
|
139
181
|
resp = EventMachine::DelegatedHttpResponse.new(self).tap do |r|
|
140
182
|
# Default values
|
@@ -160,6 +202,7 @@ class RFlow
|
|
160
202
|
|
161
203
|
# Called when a connection is torn down for whatever reason.
|
162
204
|
# Remove this connection from the server's list
|
205
|
+
# @!visibility private
|
163
206
|
def unbind(reason = nil)
|
164
207
|
RFlow.logger.debug { "#{server.name}: Disconnected from HTTP client #{client_details}#{reason.nil? ? '' : " due to '#{reason}'"}" }
|
165
208
|
server.closed_connections.write(signature.to_s, ClosedConnection.new(client_details))
|
@@ -1,12 +1,17 @@
|
|
1
1
|
require 'rflow/components/http/extensions'
|
2
2
|
require 'rflow/components/http/server'
|
3
3
|
|
4
|
+
# RFlow classes.
|
4
5
|
class RFlow
|
6
|
+
# RFlow component classes.
|
5
7
|
module Components
|
8
|
+
# HTTP RFlow component classes.
|
6
9
|
module HTTP
|
7
10
|
# Load the schemas
|
11
|
+
# @!visibility private
|
8
12
|
SCHEMA_DIRECTORY = ::File.expand_path(::File.join(::File.dirname(__FILE__), '..', '..', '..', 'schema'))
|
9
13
|
|
14
|
+
# @!visibility private
|
10
15
|
SCHEMA_FILES = {
|
11
16
|
'http_response.avsc' => 'RFlow::Message::Data::HTTP::Response',
|
12
17
|
'http_request.avsc' => 'RFlow::Message::Data::HTTP::Request',
|
@@ -22,9 +22,10 @@ Gem::Specification.new do |s|
|
|
22
22
|
s.require_paths = ["lib"]
|
23
23
|
|
24
24
|
s.add_dependency 'rflow', '~> 1.0'
|
25
|
-
s.add_dependency 'eventmachine_httpserver_update', '~> 0.2.1'
|
25
|
+
s.add_dependency 'eventmachine_httpserver_update', '~> 0.2', '>= 0.2.1'
|
26
26
|
|
27
27
|
s.add_development_dependency 'rspec', '~> 3.0'
|
28
28
|
s.add_development_dependency 'rspec-collection_matchers', '~> 1.0'
|
29
29
|
s.add_development_dependency 'rake', '>= 10.3'
|
30
|
+
s.add_development_dependency 'yard', '~> 0.9'
|
30
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rflow-components-http
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael L. Artz
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-10-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rflow
|
@@ -29,6 +29,9 @@ dependencies:
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.2'
|
34
|
+
- - ">="
|
32
35
|
- !ruby/object:Gem::Version
|
33
36
|
version: 0.2.1
|
34
37
|
type: :runtime
|
@@ -36,6 +39,9 @@ dependencies:
|
|
36
39
|
version_requirements: !ruby/object:Gem::Requirement
|
37
40
|
requirements:
|
38
41
|
- - "~>"
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0.2'
|
44
|
+
- - ">="
|
39
45
|
- !ruby/object:Gem::Version
|
40
46
|
version: 0.2.1
|
41
47
|
- !ruby/object:Gem::Dependency
|
@@ -80,6 +86,20 @@ dependencies:
|
|
80
86
|
- - ">="
|
81
87
|
- !ruby/object:Gem::Version
|
82
88
|
version: '10.3'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: yard
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0.9'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0.9'
|
83
103
|
description: HTTP client and server components for the RFlow FBP framework. Also
|
84
104
|
includes the necessary HTTP::Request and HTTP::Response message types
|
85
105
|
email:
|
@@ -93,6 +113,7 @@ files:
|
|
93
113
|
- ".ruby-gemset"
|
94
114
|
- ".ruby-version"
|
95
115
|
- ".travis.yml"
|
116
|
+
- ".yardopts"
|
96
117
|
- Gemfile
|
97
118
|
- LICENSE
|
98
119
|
- README.md
|
@@ -129,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
150
|
version: '0'
|
130
151
|
requirements: []
|
131
152
|
rubyforge_project: rflow-components-http
|
132
|
-
rubygems_version: 2.
|
153
|
+
rubygems_version: 2.5.1
|
133
154
|
signing_key:
|
134
155
|
specification_version: 4
|
135
156
|
summary: HTTP client and server components for the RFlow FBP framework
|