fluentd 1.20.0-aarch64-mingw-ucrt
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/.rubocop.yml +116 -0
- data/ADOPTERS.md +5 -0
- data/AGENTS.md +46 -0
- data/AUTHORS +2 -0
- data/CHANGELOG.md +3324 -0
- data/CONTRIBUTING.md +45 -0
- data/GOVERNANCE.md +55 -0
- data/GithubWorkflow.md +78 -0
- data/LICENSE +202 -0
- data/MAINTAINERS.md +19 -0
- data/README.md +73 -0
- data/Rakefile +89 -0
- data/SECURITY.md +47 -0
- data/bin/fluent-binlog-reader +7 -0
- data/bin/fluent-ca-generate +6 -0
- data/bin/fluent-cap-ctl +7 -0
- data/bin/fluent-cat +5 -0
- data/bin/fluent-ctl +7 -0
- data/bin/fluent-debug +5 -0
- data/bin/fluent-gem +9 -0
- data/bin/fluent-plugin-config-format +5 -0
- data/bin/fluent-plugin-generate +5 -0
- data/bin/fluentd +15 -0
- data/code-of-conduct.md +3 -0
- data/docs/SECURITY_AUDIT.pdf +0 -0
- data/example/copy_roundrobin.conf +39 -0
- data/example/counter.conf +18 -0
- data/example/filter_stdout.conf +22 -0
- data/example/in_forward.conf +14 -0
- data/example/in_forward_client.conf +37 -0
- data/example/in_forward_shared_key.conf +15 -0
- data/example/in_forward_tls.conf +14 -0
- data/example/in_forward_users.conf +24 -0
- data/example/in_forward_workers.conf +21 -0
- data/example/in_http.conf +16 -0
- data/example/in_out_forward.conf +17 -0
- data/example/in_sample_blocks.conf +17 -0
- data/example/in_sample_with_compression.conf +23 -0
- data/example/in_syslog.conf +15 -0
- data/example/in_tail.conf +14 -0
- data/example/in_tcp.conf +13 -0
- data/example/in_udp.conf +13 -0
- data/example/logevents.conf +25 -0
- data/example/multi_filters.conf +61 -0
- data/example/out_copy.conf +20 -0
- data/example/out_exec_filter.conf +42 -0
- data/example/out_file.conf +13 -0
- data/example/out_forward.conf +35 -0
- data/example/out_forward_buf_file.conf +23 -0
- data/example/out_forward_client.conf +109 -0
- data/example/out_forward_heartbeat_none.conf +16 -0
- data/example/out_forward_sd.conf +17 -0
- data/example/out_forward_shared_key.conf +36 -0
- data/example/out_forward_tls.conf +18 -0
- data/example/out_forward_users.conf +65 -0
- data/example/out_null.conf +36 -0
- data/example/sd.yaml +8 -0
- data/example/secondary_file.conf +42 -0
- data/example/suppress_config_dump.conf +7 -0
- data/example/v0_12_filter.conf +78 -0
- data/example/v1_literal_example.conf +36 -0
- data/example/worker_section.conf +36 -0
- data/fluent.conf +139 -0
- data/lib/fluent/agent.rb +168 -0
- data/lib/fluent/capability.rb +87 -0
- data/lib/fluent/clock.rb +66 -0
- data/lib/fluent/command/binlog_reader.rb +244 -0
- data/lib/fluent/command/bundler_injection.rb +45 -0
- data/lib/fluent/command/ca_generate.rb +184 -0
- data/lib/fluent/command/cap_ctl.rb +174 -0
- data/lib/fluent/command/cat.rb +365 -0
- data/lib/fluent/command/ctl.rb +180 -0
- data/lib/fluent/command/debug.rb +103 -0
- data/lib/fluent/command/fluentd.rb +385 -0
- data/lib/fluent/command/plugin_config_formatter.rb +308 -0
- data/lib/fluent/command/plugin_generator.rb +365 -0
- data/lib/fluent/compat/call_super_mixin.rb +76 -0
- data/lib/fluent/compat/detach_process_mixin.rb +33 -0
- data/lib/fluent/compat/exec_util.rb +144 -0
- data/lib/fluent/compat/file_util.rb +54 -0
- data/lib/fluent/compat/filter.rb +68 -0
- data/lib/fluent/compat/formatter.rb +117 -0
- data/lib/fluent/compat/formatter_utils.rb +85 -0
- data/lib/fluent/compat/handle_tag_and_time_mixin.rb +62 -0
- data/lib/fluent/compat/handle_tag_name_mixin.rb +53 -0
- data/lib/fluent/compat/input.rb +49 -0
- data/lib/fluent/compat/output.rb +721 -0
- data/lib/fluent/compat/output_chain.rb +60 -0
- data/lib/fluent/compat/parser.rb +310 -0
- data/lib/fluent/compat/parser_utils.rb +40 -0
- data/lib/fluent/compat/propagate_default.rb +62 -0
- data/lib/fluent/compat/record_filter_mixin.rb +34 -0
- data/lib/fluent/compat/set_tag_key_mixin.rb +50 -0
- data/lib/fluent/compat/set_time_key_mixin.rb +69 -0
- data/lib/fluent/compat/socket_util.rb +165 -0
- data/lib/fluent/compat/string_util.rb +34 -0
- data/lib/fluent/compat/structured_format_mixin.rb +26 -0
- data/lib/fluent/compat/type_converter.rb +90 -0
- data/lib/fluent/config/basic_parser.rb +122 -0
- data/lib/fluent/config/configure_proxy.rb +424 -0
- data/lib/fluent/config/dsl.rb +152 -0
- data/lib/fluent/config/element.rb +265 -0
- data/lib/fluent/config/error.rb +44 -0
- data/lib/fluent/config/literal_parser.rb +305 -0
- data/lib/fluent/config/parser.rb +119 -0
- data/lib/fluent/config/section.rb +272 -0
- data/lib/fluent/config/types.rb +257 -0
- data/lib/fluent/config/v1_parser.rb +200 -0
- data/lib/fluent/config/yaml_parser/fluent_value.rb +47 -0
- data/lib/fluent/config/yaml_parser/loader.rb +124 -0
- data/lib/fluent/config/yaml_parser/parser.rb +179 -0
- data/lib/fluent/config/yaml_parser/section_builder.rb +107 -0
- data/lib/fluent/config/yaml_parser.rb +56 -0
- data/lib/fluent/config.rb +89 -0
- data/lib/fluent/configurable.rb +202 -0
- data/lib/fluent/counter/base_socket.rb +44 -0
- data/lib/fluent/counter/client.rb +297 -0
- data/lib/fluent/counter/error.rb +86 -0
- data/lib/fluent/counter/mutex_hash.rb +163 -0
- data/lib/fluent/counter/server.rb +273 -0
- data/lib/fluent/counter/store.rb +205 -0
- data/lib/fluent/counter/validator.rb +145 -0
- data/lib/fluent/counter.rb +23 -0
- data/lib/fluent/daemon.rb +14 -0
- data/lib/fluent/daemonizer.rb +88 -0
- data/lib/fluent/engine.rb +269 -0
- data/lib/fluent/env.rb +45 -0
- data/lib/fluent/error.rb +37 -0
- data/lib/fluent/event.rb +369 -0
- data/lib/fluent/event_router.rb +315 -0
- data/lib/fluent/ext_monitor_require.rb +28 -0
- data/lib/fluent/file_wrapper.rb +137 -0
- data/lib/fluent/filter.rb +21 -0
- data/lib/fluent/fluent_log_event_router.rb +139 -0
- data/lib/fluent/formatter.rb +23 -0
- data/lib/fluent/input.rb +21 -0
- data/lib/fluent/label.rb +46 -0
- data/lib/fluent/load.rb +33 -0
- data/lib/fluent/log/console_adapter.rb +66 -0
- data/lib/fluent/log.rb +775 -0
- data/lib/fluent/match.rb +187 -0
- data/lib/fluent/mixin.rb +31 -0
- data/lib/fluent/msgpack_factory.rb +111 -0
- data/lib/fluent/oj_options.rb +61 -0
- data/lib/fluent/output.rb +29 -0
- data/lib/fluent/output_chain.rb +23 -0
- data/lib/fluent/parser.rb +23 -0
- data/lib/fluent/plugin/bare_output.rb +88 -0
- data/lib/fluent/plugin/base.rb +219 -0
- data/lib/fluent/plugin/buf_file.rb +256 -0
- data/lib/fluent/plugin/buf_file_single.rb +272 -0
- data/lib/fluent/plugin/buf_memory.rb +34 -0
- data/lib/fluent/plugin/buffer/chunk.rb +313 -0
- data/lib/fluent/plugin/buffer/file_chunk.rb +432 -0
- data/lib/fluent/plugin/buffer/file_single_chunk.rb +325 -0
- data/lib/fluent/plugin/buffer/memory_chunk.rb +91 -0
- data/lib/fluent/plugin/buffer.rb +1063 -0
- data/lib/fluent/plugin/compressable.rb +87 -0
- data/lib/fluent/plugin/exec_util.rb +22 -0
- data/lib/fluent/plugin/extractor.rb +132 -0
- data/lib/fluent/plugin/file_util.rb +22 -0
- data/lib/fluent/plugin/filter.rb +119 -0
- data/lib/fluent/plugin/filter_grep.rb +189 -0
- data/lib/fluent/plugin/filter_parser.rb +124 -0
- data/lib/fluent/plugin/filter_record_transformer.rb +325 -0
- data/lib/fluent/plugin/filter_stdout.rb +53 -0
- data/lib/fluent/plugin/formatter.rb +75 -0
- data/lib/fluent/plugin/formatter_csv.rb +92 -0
- data/lib/fluent/plugin/formatter_hash.rb +35 -0
- data/lib/fluent/plugin/formatter_json.rb +62 -0
- data/lib/fluent/plugin/formatter_ltsv.rb +44 -0
- data/lib/fluent/plugin/formatter_msgpack.rb +33 -0
- data/lib/fluent/plugin/formatter_out_file.rb +55 -0
- data/lib/fluent/plugin/formatter_single_value.rb +36 -0
- data/lib/fluent/plugin/formatter_stdout.rb +76 -0
- data/lib/fluent/plugin/formatter_tsv.rb +40 -0
- data/lib/fluent/plugin/in_debug_agent.rb +71 -0
- data/lib/fluent/plugin/in_dummy.rb +18 -0
- data/lib/fluent/plugin/in_exec.rb +124 -0
- data/lib/fluent/plugin/in_forward.rb +489 -0
- data/lib/fluent/plugin/in_gc_stat.rb +72 -0
- data/lib/fluent/plugin/in_http.rb +737 -0
- data/lib/fluent/plugin/in_monitor_agent.rb +406 -0
- data/lib/fluent/plugin/in_object_space.rb +93 -0
- data/lib/fluent/plugin/in_sample.rb +148 -0
- data/lib/fluent/plugin/in_syslog.rb +346 -0
- data/lib/fluent/plugin/in_tail/compatibility.rb +111 -0
- data/lib/fluent/plugin/in_tail/dir_watcher.rb +713 -0
- data/lib/fluent/plugin/in_tail/group_watch.rb +204 -0
- data/lib/fluent/plugin/in_tail/io_handler.rb +391 -0
- data/lib/fluent/plugin/in_tail/line_feeder.rb +230 -0
- data/lib/fluent/plugin/in_tail/position_file.rb +269 -0
- data/lib/fluent/plugin/in_tail/stat_watcher.rb +52 -0
- data/lib/fluent/plugin/in_tail/tail_watcher.rb +276 -0
- data/lib/fluent/plugin/in_tail/worker_pool.rb +298 -0
- data/lib/fluent/plugin/in_tail.rb +917 -0
- data/lib/fluent/plugin/in_tcp.rb +230 -0
- data/lib/fluent/plugin/in_udp.rb +101 -0
- data/lib/fluent/plugin/in_unix.rb +197 -0
- data/lib/fluent/plugin/input.rb +71 -0
- data/lib/fluent/plugin/metrics.rb +119 -0
- data/lib/fluent/plugin/metrics_local.rb +96 -0
- data/lib/fluent/plugin/multi_output.rb +179 -0
- data/lib/fluent/plugin/out_buffer.rb +40 -0
- data/lib/fluent/plugin/out_copy.rb +120 -0
- data/lib/fluent/plugin/out_exec.rb +105 -0
- data/lib/fluent/plugin/out_exec_filter.rb +319 -0
- data/lib/fluent/plugin/out_file.rb +371 -0
- data/lib/fluent/plugin/out_forward/ack_handler.rb +176 -0
- data/lib/fluent/plugin/out_forward/connection_manager.rb +131 -0
- data/lib/fluent/plugin/out_forward/error.rb +28 -0
- data/lib/fluent/plugin/out_forward/failure_detector.rb +84 -0
- data/lib/fluent/plugin/out_forward/handshake_protocol.rb +125 -0
- data/lib/fluent/plugin/out_forward/load_balancer.rb +114 -0
- data/lib/fluent/plugin/out_forward/socket_cache.rb +177 -0
- data/lib/fluent/plugin/out_forward.rb +865 -0
- data/lib/fluent/plugin/out_http.rb +419 -0
- data/lib/fluent/plugin/out_null.rb +74 -0
- data/lib/fluent/plugin/out_relabel.rb +32 -0
- data/lib/fluent/plugin/out_roundrobin.rb +84 -0
- data/lib/fluent/plugin/out_secondary_file.rb +148 -0
- data/lib/fluent/plugin/out_stdout.rb +81 -0
- data/lib/fluent/plugin/out_stream.rb +130 -0
- data/lib/fluent/plugin/output.rb +1688 -0
- data/lib/fluent/plugin/owned_by_mixin.rb +41 -0
- data/lib/fluent/plugin/parser.rb +274 -0
- data/lib/fluent/plugin/parser_apache.rb +28 -0
- data/lib/fluent/plugin/parser_apache2.rb +88 -0
- data/lib/fluent/plugin/parser_apache_error.rb +26 -0
- data/lib/fluent/plugin/parser_csv.rb +124 -0
- data/lib/fluent/plugin/parser_json.rb +118 -0
- data/lib/fluent/plugin/parser_ltsv.rb +49 -0
- data/lib/fluent/plugin/parser_msgpack.rb +72 -0
- data/lib/fluent/plugin/parser_multiline.rb +152 -0
- data/lib/fluent/plugin/parser_nginx.rb +28 -0
- data/lib/fluent/plugin/parser_none.rb +36 -0
- data/lib/fluent/plugin/parser_regexp.rb +68 -0
- data/lib/fluent/plugin/parser_syslog.rb +543 -0
- data/lib/fluent/plugin/parser_tsv.rb +47 -0
- data/lib/fluent/plugin/sd_file.rb +157 -0
- data/lib/fluent/plugin/sd_srv.rb +135 -0
- data/lib/fluent/plugin/sd_static.rb +58 -0
- data/lib/fluent/plugin/service_discovery.rb +65 -0
- data/lib/fluent/plugin/socket_util.rb +22 -0
- data/lib/fluent/plugin/storage.rb +84 -0
- data/lib/fluent/plugin/storage_local.rb +166 -0
- data/lib/fluent/plugin/string_util.rb +22 -0
- data/lib/fluent/plugin.rb +206 -0
- data/lib/fluent/plugin_helper/cert_option.rb +199 -0
- data/lib/fluent/plugin_helper/child_process.rb +369 -0
- data/lib/fluent/plugin_helper/compat_parameters.rb +343 -0
- data/lib/fluent/plugin_helper/counter.rb +51 -0
- data/lib/fluent/plugin_helper/event_emitter.rb +112 -0
- data/lib/fluent/plugin_helper/event_loop.rb +170 -0
- data/lib/fluent/plugin_helper/extract.rb +104 -0
- data/lib/fluent/plugin_helper/formatter.rb +147 -0
- data/lib/fluent/plugin_helper/http_server/app.rb +81 -0
- data/lib/fluent/plugin_helper/http_server/methods.rb +35 -0
- data/lib/fluent/plugin_helper/http_server/request.rb +53 -0
- data/lib/fluent/plugin_helper/http_server/router.rb +54 -0
- data/lib/fluent/plugin_helper/http_server/server.rb +116 -0
- data/lib/fluent/plugin_helper/http_server/ssl_context_builder.rb +41 -0
- data/lib/fluent/plugin_helper/http_server.rb +129 -0
- data/lib/fluent/plugin_helper/inject.rb +154 -0
- data/lib/fluent/plugin_helper/metrics.rb +136 -0
- data/lib/fluent/plugin_helper/parser.rb +147 -0
- data/lib/fluent/plugin_helper/record_accessor.rb +207 -0
- data/lib/fluent/plugin_helper/retry_state.rb +219 -0
- data/lib/fluent/plugin_helper/server.rb +840 -0
- data/lib/fluent/plugin_helper/service_discovery/manager.rb +146 -0
- data/lib/fluent/plugin_helper/service_discovery/round_robin_balancer.rb +43 -0
- data/lib/fluent/plugin_helper/service_discovery.rb +125 -0
- data/lib/fluent/plugin_helper/socket.rb +288 -0
- data/lib/fluent/plugin_helper/socket_option.rb +98 -0
- data/lib/fluent/plugin_helper/storage.rb +349 -0
- data/lib/fluent/plugin_helper/thread.rb +180 -0
- data/lib/fluent/plugin_helper/timer.rb +92 -0
- data/lib/fluent/plugin_helper.rb +75 -0
- data/lib/fluent/plugin_id.rb +93 -0
- data/lib/fluent/process.rb +22 -0
- data/lib/fluent/registry.rb +117 -0
- data/lib/fluent/root_agent.rb +468 -0
- data/lib/fluent/rpc.rb +95 -0
- data/lib/fluent/source_only_buffer_agent.rb +102 -0
- data/lib/fluent/static_config_analysis.rb +195 -0
- data/lib/fluent/supervisor.rb +1347 -0
- data/lib/fluent/system_config.rb +213 -0
- data/lib/fluent/test/base.rb +83 -0
- data/lib/fluent/test/driver/base.rb +231 -0
- data/lib/fluent/test/driver/base_owned.rb +83 -0
- data/lib/fluent/test/driver/base_owner.rb +135 -0
- data/lib/fluent/test/driver/event_feeder.rb +98 -0
- data/lib/fluent/test/driver/filter.rb +61 -0
- data/lib/fluent/test/driver/formatter.rb +30 -0
- data/lib/fluent/test/driver/input.rb +31 -0
- data/lib/fluent/test/driver/multi_output.rb +53 -0
- data/lib/fluent/test/driver/output.rb +102 -0
- data/lib/fluent/test/driver/parser.rb +30 -0
- data/lib/fluent/test/driver/storage.rb +30 -0
- data/lib/fluent/test/driver/test_event_router.rb +45 -0
- data/lib/fluent/test/filter_test.rb +77 -0
- data/lib/fluent/test/formatter_test.rb +65 -0
- data/lib/fluent/test/helpers.rb +138 -0
- data/lib/fluent/test/input_test.rb +174 -0
- data/lib/fluent/test/log.rb +79 -0
- data/lib/fluent/test/output_test.rb +156 -0
- data/lib/fluent/test/parser_test.rb +70 -0
- data/lib/fluent/test/startup_shutdown.rb +44 -0
- data/lib/fluent/test.rb +61 -0
- data/lib/fluent/time.rb +513 -0
- data/lib/fluent/timezone.rb +171 -0
- data/lib/fluent/tls.rb +105 -0
- data/lib/fluent/unique_id.rb +39 -0
- data/lib/fluent/variable_store.rb +40 -0
- data/lib/fluent/version.rb +21 -0
- data/lib/fluent/win32api.rb +38 -0
- data/lib/fluent/winsvc.rb +130 -0
- data/templates/new_gem/.gitignore +8 -0
- data/templates/new_gem/Gemfile +3 -0
- data/templates/new_gem/README.md.erb +43 -0
- data/templates/new_gem/Rakefile +13 -0
- data/templates/new_gem/fluent-plugin.gemspec.erb +28 -0
- data/templates/new_gem/lib/fluent/plugin/filter.rb.erb +14 -0
- data/templates/new_gem/lib/fluent/plugin/formatter.rb.erb +14 -0
- data/templates/new_gem/lib/fluent/plugin/input.rb.erb +11 -0
- data/templates/new_gem/lib/fluent/plugin/output.rb.erb +11 -0
- data/templates/new_gem/lib/fluent/plugin/parser.rb.erb +15 -0
- data/templates/new_gem/lib/fluent/plugin/storage.rb.erb +40 -0
- data/templates/new_gem/test/helper.rb.erb +7 -0
- data/templates/new_gem/test/plugin/test_filter.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_formatter.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_input.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_output.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_parser.rb.erb +18 -0
- data/templates/new_gem/test/plugin/test_storage.rb.erb +18 -0
- data/templates/plugin_config_formatter/param.md-compact.erb +25 -0
- data/templates/plugin_config_formatter/param.md-table.erb +10 -0
- data/templates/plugin_config_formatter/param.md.erb +34 -0
- data/templates/plugin_config_formatter/section.md.erb +12 -0
- metadata +996 -0
|
@@ -0,0 +1,737 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Fluentd
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
#
|
|
16
|
+
|
|
17
|
+
require 'fluent/plugin/extractor'
|
|
18
|
+
require 'fluent/plugin/input'
|
|
19
|
+
require 'fluent/plugin/parser'
|
|
20
|
+
require 'fluent/event'
|
|
21
|
+
|
|
22
|
+
require 'http/parser'
|
|
23
|
+
require 'webrick/httputils'
|
|
24
|
+
require 'uri'
|
|
25
|
+
require 'socket'
|
|
26
|
+
require 'json'
|
|
27
|
+
require 'ipaddr'
|
|
28
|
+
require 'openssl'
|
|
29
|
+
|
|
30
|
+
module Fluent::Plugin
|
|
31
|
+
class InHttpParser < Parser
|
|
32
|
+
Fluent::Plugin.register_parser('in_http', self)
|
|
33
|
+
|
|
34
|
+
config_set_default :time_key, 'time'
|
|
35
|
+
|
|
36
|
+
def configure(conf)
|
|
37
|
+
super
|
|
38
|
+
|
|
39
|
+
# if no time parser related parameters, use in_http's time convert rule
|
|
40
|
+
@time_parser = if conf.has_key?('time_type') || conf.has_key?('time_format')
|
|
41
|
+
time_parser_create
|
|
42
|
+
else
|
|
43
|
+
nil
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def parse(text)
|
|
48
|
+
# this plugin is dummy implementation not to raise error
|
|
49
|
+
yield nil, nil
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def get_time_parser
|
|
53
|
+
@time_parser
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
class HttpInput < Input
|
|
58
|
+
Fluent::Plugin.register_input('http', self)
|
|
59
|
+
|
|
60
|
+
helpers :parser, :compat_parameters, :event_loop, :server
|
|
61
|
+
|
|
62
|
+
EMPTY_GIF_IMAGE = "GIF89a\u0001\u0000\u0001\u0000\x80\xFF\u0000\xFF\xFF\xFF\u0000\u0000\u0000,\u0000\u0000\u0000\u0000\u0001\u0000\u0001\u0000\u0000\u0002\u0002D\u0001\u0000;".force_encoding("UTF-8")
|
|
63
|
+
|
|
64
|
+
desc 'The port to listen to.'
|
|
65
|
+
config_param :port, :integer, default: 9880
|
|
66
|
+
desc 'The bind address to listen to.'
|
|
67
|
+
config_param :bind, :string, default: '0.0.0.0'
|
|
68
|
+
desc 'The size limit of the POSTed element. Default is 32MB.'
|
|
69
|
+
config_param :body_size_limit, :size, default: 32*1024*1024 # TODO default
|
|
70
|
+
desc 'The size limit of the decompressed element.'
|
|
71
|
+
config_param :decompression_size_limit, :size, default: 256*1024*1024 # TODO default
|
|
72
|
+
desc 'The timeout limit for keeping the connection alive.'
|
|
73
|
+
config_param :keepalive_timeout, :time, default: 10 # TODO default
|
|
74
|
+
config_param :backlog, :integer, default: nil
|
|
75
|
+
desc 'Add HTTP_ prefix headers to the record.'
|
|
76
|
+
config_param :add_http_headers, :bool, default: false
|
|
77
|
+
desc 'Add REMOTE_ADDR header to the record.'
|
|
78
|
+
config_param :add_remote_addr, :bool, default: false
|
|
79
|
+
config_param :blocking_timeout, :time, default: 0.5
|
|
80
|
+
desc 'Set a allow list of domains that can do CORS (Cross-Origin Resource Sharing)'
|
|
81
|
+
config_param :cors_allow_origins, :array, default: nil
|
|
82
|
+
desc 'Tells browsers whether to expose the response to frontend when the credentials mode is "include".'
|
|
83
|
+
config_param :cors_allow_credentials, :bool, default: false
|
|
84
|
+
desc 'Respond with empty gif image of 1x1 pixel.'
|
|
85
|
+
config_param :respond_with_empty_img, :bool, default: false
|
|
86
|
+
desc 'Respond status code with 204.'
|
|
87
|
+
config_param :use_204_response, :bool, default: false
|
|
88
|
+
desc 'Dump error log or not'
|
|
89
|
+
config_param :dump_error_log, :bool, default: true
|
|
90
|
+
desc 'Add QUERY_ prefix query params to record'
|
|
91
|
+
config_param :add_query_params, :bool, default: false
|
|
92
|
+
desc "Add prefix to incoming tag"
|
|
93
|
+
config_param :add_tag_prefix, :string, default: nil
|
|
94
|
+
|
|
95
|
+
config_section :auth, required: false, multi: false do
|
|
96
|
+
desc 'The method for HTTP authentication'
|
|
97
|
+
config_param :method, :enum, list: [:basic], default: :basic
|
|
98
|
+
desc 'The username for basic authentication'
|
|
99
|
+
config_param :username, :string
|
|
100
|
+
desc 'The password for basic authentication'
|
|
101
|
+
config_param :password, :string, secret: true
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
config_section :security, required: false, multi: false do
|
|
105
|
+
config_section :client, param_name: :clients, required: false, multi: true do
|
|
106
|
+
desc 'Address or network of the client, IPv4 or IPv6. e.g. 192.168.1.10, 192.168.0.0/16, fd00::/8'
|
|
107
|
+
config_param :network, :string
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
config_section :parse do
|
|
112
|
+
config_set_default :@type, 'in_http'
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
EVENT_RECORD_PARAMETER = '_event_record'
|
|
116
|
+
|
|
117
|
+
def initialize
|
|
118
|
+
super
|
|
119
|
+
|
|
120
|
+
@km = nil
|
|
121
|
+
@nodes = []
|
|
122
|
+
@format_name = nil
|
|
123
|
+
@parser_time_key = nil
|
|
124
|
+
|
|
125
|
+
# default parsers
|
|
126
|
+
@parser_msgpack = nil
|
|
127
|
+
@parser_json = nil
|
|
128
|
+
@default_time_parser = nil
|
|
129
|
+
@default_keep_time_key = nil
|
|
130
|
+
@float_time_parser = nil
|
|
131
|
+
|
|
132
|
+
# <parse> configured parser
|
|
133
|
+
@custom_parser = nil
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def configure(conf)
|
|
137
|
+
compat_parameters_convert(conf, :parser)
|
|
138
|
+
|
|
139
|
+
super
|
|
140
|
+
|
|
141
|
+
if @cors_allow_credentials
|
|
142
|
+
if @cors_allow_origins.nil? || @cors_allow_origins.include?('*')
|
|
143
|
+
raise Fluent::ConfigError, "Cannot enable cors_allow_credentials without specific origins"
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
raise Fluent::ConfigError, "'add_tag_prefix' parameter must not be empty" if @add_tag_prefix && @add_tag_prefix.empty?
|
|
148
|
+
|
|
149
|
+
configure_security if @security
|
|
150
|
+
|
|
151
|
+
m = if @parser_configs.first['@type'] == 'in_http'
|
|
152
|
+
@parser_msgpack = parser_create(usage: 'parser_in_http_msgpack', type: 'msgpack')
|
|
153
|
+
@parser_msgpack.time_key = nil
|
|
154
|
+
@parser_msgpack.estimate_current_event = false
|
|
155
|
+
@parser_json = parser_create(usage: 'parser_in_http_json', type: 'json')
|
|
156
|
+
@parser_json.time_key = nil
|
|
157
|
+
@parser_json.estimate_current_event = false
|
|
158
|
+
|
|
159
|
+
default_parser = parser_create(usage: '')
|
|
160
|
+
@format_name = 'default'
|
|
161
|
+
@parser_time_key = default_parser.time_key
|
|
162
|
+
@default_time_parser = default_parser.get_time_parser
|
|
163
|
+
@default_keep_time_key = default_parser.keep_time_key
|
|
164
|
+
method(:parse_params_default)
|
|
165
|
+
else
|
|
166
|
+
@custom_parser = parser_create
|
|
167
|
+
@format_name = @parser_configs.first['@type']
|
|
168
|
+
@parser_time_key = @custom_parser.time_key
|
|
169
|
+
method(:parse_params_with_parser)
|
|
170
|
+
end
|
|
171
|
+
self.singleton_class.module_eval do
|
|
172
|
+
define_method(:parse_params, m)
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
class KeepaliveManager < Coolio::TimerWatcher
|
|
177
|
+
def initialize(timeout)
|
|
178
|
+
super(1, true)
|
|
179
|
+
@cons = {}
|
|
180
|
+
@timeout = timeout.to_i
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def add(sock)
|
|
184
|
+
@cons[sock] = sock
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def delete(sock)
|
|
188
|
+
@cons.delete(sock)
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def on_timer
|
|
192
|
+
@cons.each_pair {|sock,val|
|
|
193
|
+
if sock.step_idle > @timeout
|
|
194
|
+
sock.close
|
|
195
|
+
end
|
|
196
|
+
}
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def multi_workers_ready?
|
|
201
|
+
true
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def start
|
|
205
|
+
@_event_loop_run_timeout = @blocking_timeout
|
|
206
|
+
|
|
207
|
+
super
|
|
208
|
+
|
|
209
|
+
log.debug "listening http", bind: @bind, port: @port
|
|
210
|
+
|
|
211
|
+
@km = KeepaliveManager.new(@keepalive_timeout)
|
|
212
|
+
event_loop_attach(@km)
|
|
213
|
+
|
|
214
|
+
server_create_connection(:in_http, @port, bind: @bind, backlog: @backlog, &method(:on_server_connect))
|
|
215
|
+
@float_time_parser = Fluent::NumericTimeParser.new(:float)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def close
|
|
219
|
+
server_wait_until_stop
|
|
220
|
+
super
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
RES_TEXT_HEADER = {'Content-Type' => 'text/plain'}.freeze
|
|
224
|
+
RESPONSE_200 = ["200 OK".freeze, RES_TEXT_HEADER, "".freeze].freeze
|
|
225
|
+
RESPONSE_204 = ["204 No Content".freeze, {}.freeze].freeze
|
|
226
|
+
RESPONSE_IMG = ["200 OK".freeze, {'Content-Type'=>'image/gif; charset=utf-8'}.freeze, EMPTY_GIF_IMAGE].freeze
|
|
227
|
+
RES_400_STATUS = "400 Bad Request".freeze
|
|
228
|
+
RES_500_STATUS = "500 Internal Server Error".freeze
|
|
229
|
+
|
|
230
|
+
def on_request(path_info, params)
|
|
231
|
+
begin
|
|
232
|
+
path = path_info[1..-1] # remove /
|
|
233
|
+
tag = path.split('/').join('.')
|
|
234
|
+
tag = "#{@add_tag_prefix}.#{tag}" if @add_tag_prefix
|
|
235
|
+
|
|
236
|
+
mes = Fluent::MultiEventStream.new
|
|
237
|
+
parse_params(params) do |record_time, record|
|
|
238
|
+
if record.nil?
|
|
239
|
+
log.debug { "incoming event is invalid: path=#{path_info} params=#{params.to_json}" }
|
|
240
|
+
next
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
add_params_to_record(record, params)
|
|
244
|
+
|
|
245
|
+
time = if param_time = params['time']
|
|
246
|
+
param_time = param_time.to_f
|
|
247
|
+
param_time.zero? ? Fluent::EventTime.now : @float_time_parser.parse(param_time)
|
|
248
|
+
else
|
|
249
|
+
record_time.nil? ? convert_time_field(record) : record_time
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
mes.add(time, record)
|
|
253
|
+
end
|
|
254
|
+
rescue => e
|
|
255
|
+
if @dump_error_log
|
|
256
|
+
log.error "failed to process request", error: e
|
|
257
|
+
end
|
|
258
|
+
return [RES_400_STATUS, RES_TEXT_HEADER, "400 Bad Request\n#{e}\n"]
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
# TODO server error
|
|
262
|
+
begin
|
|
263
|
+
router.emit_stream(tag, mes) unless mes.empty?
|
|
264
|
+
rescue => e
|
|
265
|
+
if @dump_error_log
|
|
266
|
+
log.error "failed to emit data", error: e
|
|
267
|
+
end
|
|
268
|
+
return [RES_500_STATUS, RES_TEXT_HEADER, "500 Internal Server Error\n#{e}\n"]
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
if @respond_with_empty_img
|
|
272
|
+
return RESPONSE_IMG
|
|
273
|
+
else
|
|
274
|
+
if @use_204_response
|
|
275
|
+
return RESPONSE_204
|
|
276
|
+
else
|
|
277
|
+
return RESPONSE_200
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
private
|
|
283
|
+
|
|
284
|
+
def configure_security
|
|
285
|
+
@nodes = @security.clients.map do |client|
|
|
286
|
+
begin
|
|
287
|
+
IPAddr.new(client.network)
|
|
288
|
+
rescue ArgumentError
|
|
289
|
+
raise Fluent::ConfigError, "network '#{client.network}' address format is invalid"
|
|
290
|
+
end
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
def allowed_client?(address)
|
|
295
|
+
return true if @nodes.empty?
|
|
296
|
+
@nodes.any? { |node| node.include?(address) rescue false }
|
|
297
|
+
end
|
|
298
|
+
|
|
299
|
+
def on_server_connect(conn)
|
|
300
|
+
unless allowed_client?(conn.remote_addr)
|
|
301
|
+
log.warn "client address does not match any allowed network", address: conn.remote_addr
|
|
302
|
+
conn.data {|_data| }
|
|
303
|
+
conn.close
|
|
304
|
+
return
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
handler = Handler.new(conn, @km, method(:on_request),
|
|
308
|
+
@body_size_limit, @decompression_size_limit, @format_name, log,
|
|
309
|
+
@cors_allow_origins, @cors_allow_credentials,
|
|
310
|
+
@add_query_params, @auth)
|
|
311
|
+
|
|
312
|
+
conn.on(:data) do |data|
|
|
313
|
+
handler.on_read(data)
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
conn.on(:write_complete) do |_|
|
|
317
|
+
handler.on_write_complete
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
conn.on(:close) do |_|
|
|
321
|
+
handler.on_close
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def parse_params_default(params)
|
|
326
|
+
if msgpack = params['msgpack']
|
|
327
|
+
@parser_msgpack.parse(msgpack) do |_time, record|
|
|
328
|
+
yield nil, record
|
|
329
|
+
end
|
|
330
|
+
elsif js = params['json']
|
|
331
|
+
@parser_json.parse(js) do |_time, record|
|
|
332
|
+
yield nil, record
|
|
333
|
+
end
|
|
334
|
+
elsif ndjson = params['ndjson']
|
|
335
|
+
ndjson.split(/\r?\n/).each do |js|
|
|
336
|
+
@parser_json.parse(js) do |_time, record|
|
|
337
|
+
yield nil, record
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
else
|
|
341
|
+
raise "'json', 'ndjson' or 'msgpack' parameter is required"
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
def parse_params_with_parser(params)
|
|
346
|
+
if content = params[EVENT_RECORD_PARAMETER]
|
|
347
|
+
@custom_parser.parse(content) do |time, record|
|
|
348
|
+
yield time, record
|
|
349
|
+
end
|
|
350
|
+
else
|
|
351
|
+
raise "'#{EVENT_RECORD_PARAMETER}' parameter is required"
|
|
352
|
+
end
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
def add_params_to_record(record, params)
|
|
356
|
+
if @add_http_headers
|
|
357
|
+
params.each_pair { |k, v|
|
|
358
|
+
if k.start_with?("HTTP_".freeze)
|
|
359
|
+
record[k] = v
|
|
360
|
+
end
|
|
361
|
+
}
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
if @add_query_params
|
|
365
|
+
params.each_pair { |k, v|
|
|
366
|
+
if k.start_with?("QUERY_".freeze)
|
|
367
|
+
record[k] = v
|
|
368
|
+
end
|
|
369
|
+
}
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
if @add_remote_addr
|
|
373
|
+
record['REMOTE_ADDR'] = params['REMOTE_ADDR']
|
|
374
|
+
end
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
def convert_time_field(record)
|
|
378
|
+
if t = @default_keep_time_key ? record[@parser_time_key] : record.delete(@parser_time_key)
|
|
379
|
+
if @default_time_parser
|
|
380
|
+
@default_time_parser.parse(t)
|
|
381
|
+
else
|
|
382
|
+
Fluent::EventTime.from_time(Time.at(t))
|
|
383
|
+
end
|
|
384
|
+
else
|
|
385
|
+
Fluent::EventTime.now
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
class Handler
|
|
390
|
+
attr_reader :content_type
|
|
391
|
+
|
|
392
|
+
def initialize(io, km, callback, body_size_limit, decompression_size_limit, format_name, log,
|
|
393
|
+
cors_allow_origins, cors_allow_credentials, add_query_params, auth = nil)
|
|
394
|
+
@io = io
|
|
395
|
+
@km = km
|
|
396
|
+
@callback = callback
|
|
397
|
+
@body_size_limit = body_size_limit
|
|
398
|
+
@decompression_size_limit = decompression_size_limit
|
|
399
|
+
@next_close = false
|
|
400
|
+
@format_name = format_name
|
|
401
|
+
@log = log
|
|
402
|
+
@cors_allow_origins = cors_allow_origins
|
|
403
|
+
@cors_allow_credentials = cors_allow_credentials
|
|
404
|
+
@idle = 0
|
|
405
|
+
@add_query_params = add_query_params
|
|
406
|
+
@auth = auth
|
|
407
|
+
@authorization = nil
|
|
408
|
+
@km.add(self)
|
|
409
|
+
|
|
410
|
+
@remote_port, @remote_addr = io.remote_port, io.remote_addr
|
|
411
|
+
@parser = Http::Parser.new(self)
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
def step_idle
|
|
415
|
+
@idle += 1
|
|
416
|
+
end
|
|
417
|
+
|
|
418
|
+
def on_close
|
|
419
|
+
@km.delete(self)
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def on_read(data)
|
|
423
|
+
@idle = 0
|
|
424
|
+
@parser << data
|
|
425
|
+
rescue
|
|
426
|
+
@log.warn "unexpected error", error: $!.to_s
|
|
427
|
+
@log.warn_backtrace
|
|
428
|
+
@io.close
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
def on_message_begin
|
|
432
|
+
@body = ''
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def on_headers_complete(headers)
|
|
436
|
+
expect = nil
|
|
437
|
+
size = nil
|
|
438
|
+
|
|
439
|
+
if @parser.http_version == [1, 1]
|
|
440
|
+
@keep_alive = true
|
|
441
|
+
else
|
|
442
|
+
@keep_alive = false
|
|
443
|
+
end
|
|
444
|
+
@env = {}
|
|
445
|
+
@content_type = ""
|
|
446
|
+
@content_encoding = ""
|
|
447
|
+
@authorization = nil
|
|
448
|
+
headers.each_pair {|k,v|
|
|
449
|
+
@env["HTTP_#{k.tr('-','_').upcase}"] = v
|
|
450
|
+
case k
|
|
451
|
+
when /\AExpect\z/i
|
|
452
|
+
expect = v
|
|
453
|
+
when /\AContent-Length\Z/i
|
|
454
|
+
size = v.to_i
|
|
455
|
+
when /\AContent-Type\Z/i
|
|
456
|
+
@content_type = v
|
|
457
|
+
when /\AContent-Encoding\Z/i
|
|
458
|
+
@content_encoding = v
|
|
459
|
+
when /\AConnection\Z/i
|
|
460
|
+
if /close/i.match?(v)
|
|
461
|
+
@keep_alive = false
|
|
462
|
+
elsif /Keep-alive/i.match?(v)
|
|
463
|
+
@keep_alive = true
|
|
464
|
+
end
|
|
465
|
+
when /\AOrigin\Z/i
|
|
466
|
+
@origin = v
|
|
467
|
+
when /\AX-Forwarded-For\Z/i
|
|
468
|
+
# For multiple X-Forwarded-For headers. Use first header value.
|
|
469
|
+
v = v.first if v.is_a?(Array)
|
|
470
|
+
@remote_addr = v.split(",").first
|
|
471
|
+
when /\AAccess-Control-Request-Method\Z/i
|
|
472
|
+
@access_control_request_method = v
|
|
473
|
+
when /\AAccess-Control-Request-Headers\Z/i
|
|
474
|
+
@access_control_request_headers = v
|
|
475
|
+
when /\AAuthorization\Z/i
|
|
476
|
+
@authorization = v.is_a?(Array) ? v.first : v
|
|
477
|
+
end
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if @auth
|
|
481
|
+
# Never let the credential reach a record built by add_http_headers.
|
|
482
|
+
@env.delete("HTTP_AUTHORIZATION")
|
|
483
|
+
|
|
484
|
+
unless preflight_request? || authenticate
|
|
485
|
+
@log.warn "authentication failed", address: @remote_addr
|
|
486
|
+
send_response_and_close(RES_401_STATUS, {'WWW-Authenticate' => AUTH_CHALLENGE}, "")
|
|
487
|
+
return
|
|
488
|
+
end
|
|
489
|
+
end
|
|
490
|
+
|
|
491
|
+
if expect
|
|
492
|
+
if expect == '100-continue'.freeze
|
|
493
|
+
if !size || size < @body_size_limit
|
|
494
|
+
send_response_nobody("100 Continue", {})
|
|
495
|
+
else
|
|
496
|
+
send_response_and_close("413 Request Entity Too Large", {}, "Too large")
|
|
497
|
+
end
|
|
498
|
+
else
|
|
499
|
+
send_response_and_close("417 Expectation Failed", {}, "")
|
|
500
|
+
end
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def on_body(chunk)
|
|
505
|
+
return if closing?
|
|
506
|
+
|
|
507
|
+
if @body.bytesize + chunk.bytesize > @body_size_limit
|
|
508
|
+
unless closing?
|
|
509
|
+
send_response_and_close("413 Request Entity Too Large", {}, "Too large")
|
|
510
|
+
end
|
|
511
|
+
return
|
|
512
|
+
end
|
|
513
|
+
@body << chunk
|
|
514
|
+
end
|
|
515
|
+
|
|
516
|
+
RES_200_STATUS = "200 OK".freeze
|
|
517
|
+
RES_401_STATUS = "401 Unauthorized".freeze
|
|
518
|
+
AUTH_CHALLENGE = 'Basic realm="fluentd"'.freeze
|
|
519
|
+
RES_403_STATUS = "403 Forbidden".freeze
|
|
520
|
+
|
|
521
|
+
# Azure App Service sends GET requests for health checking purpose.
|
|
522
|
+
# Respond with `200 OK` to accommodate it.
|
|
523
|
+
def handle_get_request
|
|
524
|
+
return send_response_and_close(RES_200_STATUS, {}, "")
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
# Web browsers can send an OPTIONS request before performing POST
|
|
528
|
+
# to check if cross-origin requests are supported.
|
|
529
|
+
def handle_options_request
|
|
530
|
+
# Is CORS enabled in the first place?
|
|
531
|
+
if @cors_allow_origins.nil?
|
|
532
|
+
return send_response_and_close(RES_403_STATUS, {}, "")
|
|
533
|
+
end
|
|
534
|
+
|
|
535
|
+
# in_http does not support HTTP methods except POST
|
|
536
|
+
if @access_control_request_method != 'POST'
|
|
537
|
+
return send_response_and_close(RES_403_STATUS, {}, "")
|
|
538
|
+
end
|
|
539
|
+
|
|
540
|
+
header = {
|
|
541
|
+
"Access-Control-Allow-Methods" => "POST",
|
|
542
|
+
"Access-Control-Allow-Headers" => @access_control_request_headers || "",
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
# Check the origin and send back a CORS response
|
|
546
|
+
if @cors_allow_origins.include?('*')
|
|
547
|
+
header["Access-Control-Allow-Origin"] = "*"
|
|
548
|
+
send_response_and_close(RES_200_STATUS, header, "")
|
|
549
|
+
elsif include_cors_allow_origin
|
|
550
|
+
header["Access-Control-Allow-Origin"] = @origin
|
|
551
|
+
if @cors_allow_credentials
|
|
552
|
+
header["Access-Control-Allow-Credentials"] = true
|
|
553
|
+
end
|
|
554
|
+
send_response_and_close(RES_200_STATUS, header, "")
|
|
555
|
+
else
|
|
556
|
+
send_response_and_close(RES_403_STATUS, {}, "")
|
|
557
|
+
end
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def on_message_complete
|
|
561
|
+
return if closing?
|
|
562
|
+
|
|
563
|
+
if @parser.http_method == 'GET'.freeze
|
|
564
|
+
return handle_get_request()
|
|
565
|
+
end
|
|
566
|
+
|
|
567
|
+
if @parser.http_method == 'OPTIONS'.freeze
|
|
568
|
+
return handle_options_request()
|
|
569
|
+
end
|
|
570
|
+
|
|
571
|
+
# CORS check
|
|
572
|
+
# ==========
|
|
573
|
+
# For every incoming request, we check if we have some CORS
|
|
574
|
+
# restrictions and allow listed origins through @cors_allow_origins.
|
|
575
|
+
# If origin is empty, it's likely a server-to-server request and considered safe.
|
|
576
|
+
unless @cors_allow_origins.nil?
|
|
577
|
+
unless @cors_allow_origins.include?('*') || include_cors_allow_origin || @origin.nil?
|
|
578
|
+
send_response_and_close(RES_403_STATUS, {'Connection' => 'close'}, "")
|
|
579
|
+
return
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
|
|
583
|
+
# Content Encoding
|
|
584
|
+
# =================
|
|
585
|
+
# Decode payload according to the "Content-Encoding" header.
|
|
586
|
+
# For now, we only support 'gzip' and 'deflate'.
|
|
587
|
+
begin
|
|
588
|
+
if @content_encoding == 'gzip'.freeze
|
|
589
|
+
@body = Extractor.decompress_gzip(@body, limit: @decompression_size_limit)
|
|
590
|
+
elsif @content_encoding == 'deflate'.freeze
|
|
591
|
+
@body = Extractor.decompress_deflate(@body, limit: @decompression_size_limit)
|
|
592
|
+
end
|
|
593
|
+
rescue
|
|
594
|
+
@log.warn 'fails to decode payload', error: $!.to_s
|
|
595
|
+
send_response_and_close(RES_400_STATUS, {}, "")
|
|
596
|
+
return
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
@env['REMOTE_ADDR'] = @remote_addr if @remote_addr
|
|
600
|
+
|
|
601
|
+
uri = URI.parse(@parser.request_url)
|
|
602
|
+
params = parse_query(uri.query)
|
|
603
|
+
|
|
604
|
+
if @format_name != 'default'
|
|
605
|
+
params[EVENT_RECORD_PARAMETER] = @body
|
|
606
|
+
elsif /^application\/x-www-form-urlencoded/.match?(@content_type)
|
|
607
|
+
params.update parse_query(@body)
|
|
608
|
+
elsif @content_type =~ /^multipart\/form-data; boundary=(.+)/
|
|
609
|
+
boundary = WEBrick::HTTPUtils.dequote($1)
|
|
610
|
+
params.update WEBrick::HTTPUtils.parse_form_data(@body, boundary)
|
|
611
|
+
elsif /^application\/json/.match?(@content_type)
|
|
612
|
+
params['json'] = @body
|
|
613
|
+
elsif /^application\/csp-report/.match?(@content_type)
|
|
614
|
+
params['json'] = @body
|
|
615
|
+
elsif /^application\/msgpack/.match?(@content_type)
|
|
616
|
+
params['msgpack'] = @body
|
|
617
|
+
elsif /^application\/x-ndjson/.match?(@content_type)
|
|
618
|
+
params['ndjson'] = @body
|
|
619
|
+
end
|
|
620
|
+
path_info = uri.path
|
|
621
|
+
|
|
622
|
+
if (@add_query_params)
|
|
623
|
+
|
|
624
|
+
query_params = parse_query(uri.query)
|
|
625
|
+
|
|
626
|
+
query_params.each_pair {|k,v|
|
|
627
|
+
params["QUERY_#{k.tr('-','_').upcase}"] = v
|
|
628
|
+
}
|
|
629
|
+
end
|
|
630
|
+
|
|
631
|
+
params.merge!(@env)
|
|
632
|
+
|
|
633
|
+
@env.clear
|
|
634
|
+
|
|
635
|
+
code, header, body = @callback.call(path_info, params)
|
|
636
|
+
body = body.to_s
|
|
637
|
+
header = header.dup if header.frozen?
|
|
638
|
+
|
|
639
|
+
unless @cors_allow_origins.nil?
|
|
640
|
+
if @cors_allow_origins.include?('*')
|
|
641
|
+
header['Access-Control-Allow-Origin'] = '*'
|
|
642
|
+
elsif include_cors_allow_origin
|
|
643
|
+
header['Access-Control-Allow-Origin'] = @origin
|
|
644
|
+
if @cors_allow_credentials
|
|
645
|
+
header["Access-Control-Allow-Credentials"] = true
|
|
646
|
+
end
|
|
647
|
+
end
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
if @keep_alive
|
|
651
|
+
header['Connection'] = 'Keep-Alive'.freeze
|
|
652
|
+
send_response(code, header, body)
|
|
653
|
+
else
|
|
654
|
+
send_response_and_close(code, header, body)
|
|
655
|
+
end
|
|
656
|
+
end
|
|
657
|
+
|
|
658
|
+
def close
|
|
659
|
+
@io.close
|
|
660
|
+
end
|
|
661
|
+
|
|
662
|
+
def on_write_complete
|
|
663
|
+
@io.close if @next_close
|
|
664
|
+
end
|
|
665
|
+
|
|
666
|
+
def send_response_and_close(code, header, body)
|
|
667
|
+
send_response(code, header, body)
|
|
668
|
+
@next_close = true
|
|
669
|
+
end
|
|
670
|
+
|
|
671
|
+
def closing?
|
|
672
|
+
@next_close
|
|
673
|
+
end
|
|
674
|
+
|
|
675
|
+
def send_response(code, header, body)
|
|
676
|
+
header['Content-Length'] ||= body.bytesize
|
|
677
|
+
header['Content-Type'] ||= 'text/plain'.freeze
|
|
678
|
+
|
|
679
|
+
data = %[HTTP/1.1 #{code}\r\n]
|
|
680
|
+
header.each_pair {|k,v|
|
|
681
|
+
data << "#{k}: #{v}\r\n"
|
|
682
|
+
}
|
|
683
|
+
data << "\r\n".freeze
|
|
684
|
+
@io.write(data)
|
|
685
|
+
|
|
686
|
+
@io.write(body)
|
|
687
|
+
end
|
|
688
|
+
|
|
689
|
+
def send_response_nobody(code, header)
|
|
690
|
+
data = %[HTTP/1.1 #{code}\r\n]
|
|
691
|
+
header.each_pair {|k,v|
|
|
692
|
+
data << "#{k}: #{v}\r\n"
|
|
693
|
+
}
|
|
694
|
+
data << "\r\n".freeze
|
|
695
|
+
@io.write(data)
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
def include_cors_allow_origin
|
|
699
|
+
if @origin.nil?
|
|
700
|
+
return false
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
if @cors_allow_origins.include?(@origin)
|
|
704
|
+
return true
|
|
705
|
+
end
|
|
706
|
+
filtered_cors_allow_origins = @cors_allow_origins.select {|origin| origin != ""}
|
|
707
|
+
r = filtered_cors_allow_origins.find do |origin|
|
|
708
|
+
(start_str, end_str) = origin.split("*", 2)
|
|
709
|
+
@origin.start_with?(start_str) && @origin.end_with?(end_str)
|
|
710
|
+
end
|
|
711
|
+
|
|
712
|
+
!r.nil?
|
|
713
|
+
end
|
|
714
|
+
|
|
715
|
+
def parse_query(query)
|
|
716
|
+
query.nil? ? {} : Hash[URI.decode_www_form(query, Encoding::ASCII_8BIT)]
|
|
717
|
+
end
|
|
718
|
+
|
|
719
|
+
# Browsers never attach Authorization to a CORS preflight.
|
|
720
|
+
def preflight_request?
|
|
721
|
+
@parser.http_method == 'OPTIONS'.freeze
|
|
722
|
+
end
|
|
723
|
+
|
|
724
|
+
def authenticate
|
|
725
|
+
scheme, credentials = @authorization.to_s.split(' ', 2)
|
|
726
|
+
return false unless scheme == 'Basic'.freeze
|
|
727
|
+
|
|
728
|
+
username, password = credentials.to_s.unpack1('m').to_s.split(':', 2)
|
|
729
|
+
username_matched = OpenSSL.secure_compare(username.to_s, @auth.username)
|
|
730
|
+
password_matched = OpenSSL.secure_compare(password.to_s, @auth.password)
|
|
731
|
+
username_matched && password_matched
|
|
732
|
+
rescue ArgumentError
|
|
733
|
+
false
|
|
734
|
+
end
|
|
735
|
+
end
|
|
736
|
+
end
|
|
737
|
+
end
|