rflow-components-http 1.1.0 → 1.1.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/.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
|