# encoding: utf-8 require "spec_helper" require "logstash/patterns/core" describe "SYSLOGLINE" do let(:value) { "Mar 16 00:01:25 evita postfix/smtpd[1713]: connect from camomile.cloud9.net[168.100.1.3]" } let(:grok) { grok_match(subject, value) } it "a pattern pass the grok expression" do expect(grok).to pass end it "matches a simple message" do expect(subject).to match(value) end it "generates the program field" do expect(grok_match(subject, value)).to include("program" => "postfix/smtpd") end end describe "HTTP DATE parsing" do context "HTTPDATE", "when having a German month" do let(:value) { '[04/Mai/2015:13:17:15 +0200]'} it "generates the month field" do expect(grok_match(subject, value)).to pass end end context "HTTPDATE", "when having a English month" do let(:value) { '[04/March/2015:13:17:15 +0200]'} it "generates the month field" do expect(grok_match(subject, value)).to pass end end context "HTTPDATE", "when having a wrong months" do let(:value) { '[04/Map/2015:13:17:15 +0200]'} it "generates the month field" do expect(grok_match(subject, value)).not_to pass end end end describe "TOMCATLOG" do let(:value) { '2014-01-09 20:03:28,269 -0800 | ERROR | com.example.service.ExampleService - something compeletely unexpected happened...'} it "generates the logmessage field" do expect(grok_match(subject, value)).to include("logmessage" => "something compeletely unexpected happened...") end end describe 'LOGLEVEL' do it 'matches info label' do expect(grok_match(subject, 'INFO')).to pass expect(grok_match(subject, 'info')).to pass end it 'matches information label' do expect(grok_match(subject, 'information')).to pass expect(grok_match(subject, 'Information')).to pass expect(grok_match(subject, 'INFORMATION')).to pass end end describe "IPORHOST" do let(:pattern) { "IPORHOST" } context "matching an IP" do let(:value) { '127.0.0.1' } it "should match the IP value" do expect(grok_match(pattern, value)).to pass end end context "matching a HOST" do let(:value) { 'example.org' } it "should match the IP value" do expect(grok_match(pattern, value)).to pass end end end describe "UNIXPATH" do let(:pattern) { 'UNIXPATH' } let(:value) { '/foo/bar' } it "should match the path" do expect(grok_match(pattern, value, true)).to pass end context "when using comma separators and other regexp" do let(:pattern) { '((a=(?%{UNIXPATH})?|b=(?%{UNIXPATH})?)(,\s)?)+' } let(:grok) do grok = LogStash::Filters::Grok.new("match" => ["message", pattern]) grok.register grok end let(:value) { 'a=/some/path, b=/some/other/path' } it "was expected to extract both but never really did" do # or maybe on JRuby 1.7 event = build_event(value) grok.filter(event) expect( event.to_hash['a'] ).to eql '/some/path,' expect( event.to_hash['b'] ).to be nil end end context 'relative path' do let(:path_matcher) do # non-exact matcher grok = LogStash::Filters::Grok.new("match" => ["message", '%{UNIXPATH:path}']) grok.register lambda { |msg| event = build_event(msg); grok.filter(event); event } end it "should not match (only partially)" do expect(grok_match(pattern, 'a/./b/c', true)).to_not pass event = path_matcher.('a/./b/c') expect( event.to_hash['path'] ).to eql '/./b/c' expect(grok_match(pattern, ',/.', true)).to_not pass event = path_matcher.(',/.') expect( event.to_hash['path'] ).to eql '/.' expect(grok_match(pattern, '+/.../', true)).to_not pass event = path_matcher.('+/.../') expect( event.to_hash['path'] ).to eql '/.../' expect(grok_match(pattern, '~/b/', true)).to_not pass event = path_matcher.('~/b/') expect( event.to_hash['path'] ).to eql '/b/' expect(grok_match(pattern, './b//', true)).to_not pass expect(grok_match(pattern, 'a//b', true)).to_not pass end it "should not match paths starting with ." do expect(grok_match(pattern, '../0', true)).to_not pass expect(grok_match(pattern, './~', true)).to_not pass expect(grok_match(pattern, '.../-', true)).to_not pass expect(grok_match(pattern, './', true)).to_not pass expect(grok_match(pattern, './,', true)).to_not pass expect(grok_match(pattern, '../', true)).to_not pass expect(grok_match(pattern, '.a/', true)).to_not pass expect(grok_match(pattern, '.~/', true)).to_not pass end it "should not match expression wout separator" do expect(grok_match(pattern, '.')).to_not pass expect(grok_match(pattern, '..')).to_not pass expect(grok_match(pattern, '...')).to_not pass expect(grok_match(pattern, '.,')).to_not pass expect(grok_match(pattern, '.-')).to_not pass end end context "dotted path" do it "should match path containing ." do expect(grok_match(pattern, '/some/./path/', true)).to pass expect(grok_match(pattern, '/some/../path', true)).to pass expect(grok_match(pattern, '/../.', true)).to pass expect(grok_match(pattern, '/.', true)).to pass expect(grok_match(pattern, '/..', true)).to pass expect(grok_match(pattern, '/...', true)).to pass end end context "separators" do it "should match root" do expect(grok_match(pattern, '/', true)).to pass end it "should match" do expect(grok_match(pattern, '//', true)).to pass expect(grok_match(pattern, '//00', true)).to pass expect(grok_match(pattern, '///a', true)).to pass expect(grok_match(pattern, '/a//', true)).to pass expect(grok_match(pattern, '///a//b/c///', true)).to pass end it "should not match windows separator" do expect(grok_match(pattern, "\\a", true)).to_not pass expect(grok_match(pattern, '/0\\', true)).to_not pass expect(grok_match(pattern, "/a\\b", true)).to_not pass end end context "long path" do let(:grok) do grok = LogStash::Filters::Grok.new("match" => ["message", '%{UNIXPATH:path} '], 'timeout_millis' => 1500) grok.register grok end let(:value) { '/opt/abcdef/1/.22/3:3+3/foo@BAR/X-Y+Z/~Sample_l_SUBc b' } it "should match the path" do event = build_event(value) grok.filter(event) expect( event.to_hash['path'] ).to eql '/opt/abcdef/1/.22/3:3+3/foo@BAR/X-Y+Z/~Sample_l_SUBc' end it "should not match with invalid chars (or cause DoS)" do event = build_event(value.sub('SUB', '&^_')) grok.filter(event) # used to call a looong looop (DoS) despite the timeout guard expect( event.to_hash['tags'] ).to include '_grokparsefailure' end end it "matches paths with non-ascii characters" do event = build_event path = '/opt/Čierný_Peter/.中' build_grok('UNIXPATH:path').filter event expect( event.get('path') ).to eql path end end describe "WINPATH" do let(:pattern) { 'WINPATH' } let(:value) { 'C:\\foo\\bar' } it "should match the path" do expect(grok_match(pattern, value, true)).to pass end it "should match root path" do expect(grok_match(pattern, 'C:\\', true)).to pass expect(grok_match(pattern, 'C:\\\\', true)).to pass expect(grok_match(pattern, 'a:\\', true)).to pass expect(grok_match(pattern, 'x:\\\\', true)).to pass end it "should match paths with spaces" do expect(grok_match(pattern, 'C:\\Documents and Settings\\Public', true)).to pass expect(grok_match(pattern, 'C:\\\\Users\\\\Public\\\\.Mozilla Firefox', true)).to pass end it "should not match unix-style paths" do expect(grok_match(pattern, '/foo', true)).to_not pass expect(grok_match(pattern, '//C/path', true)).to_not pass expect(grok_match(pattern, '/', true)).to_not pass expect(grok_match(pattern, '/foo/bar', true)).to_not pass expect(grok_match(pattern, '/..', true)).to_not pass expect(grok_match(pattern, 'C://', true)).to_not pass end it "matches paths with non-ascii characters" do expect(grok_match(pattern, 'C:\\Čierný Peter\\.中.exe', true)).to pass end context 'relative paths' do it "should not match" do expect(grok_match(pattern, 'a\\bar', true)).to_not pass expect(grok_match(pattern, 'foo\\bar', true)).to_not pass expect(grok_match(pattern, 'C\\A\\B', true)).to_not pass expect(grok_match(pattern, 'C\\\\0', true)).to_not pass expect(grok_match(pattern, '.\\0', true)).to_not pass expect(grok_match(pattern, '..\\', true)).to_not pass expect(grok_match(pattern, '...\\-', true)).to_not pass expect(grok_match(pattern, '.\\', true)).to_not pass expect(grok_match(pattern, '.\\,', true)).to_not pass expect(grok_match(pattern, '..\\', true)).to_not pass expect(grok_match(pattern, '.a\\', true)).to_not pass end it "should not match expression wout separator" do expect(grok_match(pattern, '.')).to_not pass expect(grok_match(pattern, '..')).to_not pass expect(grok_match(pattern, '...')).to_not pass expect(grok_match(pattern, 'C:')).to_not pass expect(grok_match(pattern, 'C')).to_not pass end end end describe "URIPROTO" do let(:pattern) { 'URIPROTO' } context "http is a valid URIPROTO" do let(:value) { 'http' } it "should match" do expect(grok_match(pattern,value)).to pass end end context "android-app is a valid URIPROTO" do let(:value) { 'android-app' } it "should match" do expect(grok_match(pattern,value)).to pass end end end describe "URIPATH" do let(:pattern) { 'URIPATH' } context "when matching valid URIs" do context "and the URI is simple" do let(:value) { '/foo' } it "should match the path" do expect(grok_match(pattern,value)).to pass end end context "and the URI has a trailing slash" do let(:value) { '/foo/' } it "should match the path" do expect(grok_match(pattern,value)).to pass end end context "and the URI has multiple levels" do let(:value) { '/foo/bar' } it "should match the path" do expect(grok_match(pattern,value)).to pass end end context "and the URI has fancy characters" do let(:value) { '/aA1$.+!*\'(){},~:;=@#%&|-' } it "should match the path" do expect(grok_match(pattern,value)).to pass end end end context "when matching invalid URIs" do context "and the URI has no leading slash" do let(:value) { 'foo' } it "should not match the path" do expect(grok_match(pattern,value)).not_to pass end end context "and the URI has invalid characters" do let(:value) { '/`' } xit "should not match the path" do expect(grok_match(pattern,value)).not_to pass end end end end describe "IPV4" do let(:pattern) { 'IPV4' } let(:value) { "127.0.0.1" } it "should match the path" do expect(grok_match(pattern,value)).to pass end context "when parsing a local IP" do let(:value) { "10.0.0.1" } it "should match the path" do expect(grok_match(pattern,value)).to pass end end context "when parsing a wrong IP" do let(:value) { "192.300.300.300" } it "should match the path" do expect(grok_match(pattern,value)).not_to pass end end end describe "URN" do let(:pattern) { "URN" } # Valid URNs # http://tools.ietf.org/html/rfc2141#section-2 let(:simple) { "urn:example:foo" } let(:unreserved) { "urn:example:" + [*'A'..'Z', *'a'..'z', *'0'..'9', "()+,-.::=@;$_!*'"].join() } let(:reserved) { "urn:example:/#?" } let(:escaped_upper) { "urn:example:%25foo%2Fbar%3F%23" } let(:escaped_lower) { "urn:example:%25foo%2fbar%3f%23" } let(:only_escaped) { "urn:example:%00" } let(:long_nid) { "urn:example-example-example-example-:foo" } # Invalid URNs let(:bad_prefix) { "URN:example:foo" } let(:empty_nid) { "urn::foo" } let(:leading_hyphen) { "urn:-example:foo" } let(:bad_nid) { "urn:example.com:foo" } let(:percent_nid) { "urn:example%41com:foo" } let(:too_long_nid) { "urn:example-example-example-example-x:foo" } let(:empty_nss) { "urn:example:" } let(:naked_percent) { "urn:example:%" } let(:short_percent) { "urn:example:%a" } let(:nonhex_percent) { "urn:example:%ax" } context "when testing a valid URN" do it "should match a simple URN" do expect(grok_match(pattern, simple)).to pass end it "should match a complex URN" do expect(grok_match(pattern, unreserved)).to pass end it "should allow reserved characters" do expect(grok_match(pattern, reserved)).to pass end it "should allow percent-escapes" do expect(grok_match(pattern, escaped_upper)).to pass expect(grok_match(pattern, escaped_lower)).to pass expect(grok_match(pattern, only_escaped)).to pass end it "should match a URN with a 32-character NID" do expect(grok_match(pattern, long_nid)).to pass end end context "when testing an invalid URN" do it "should reject capitalized 'URN'" do expect(grok_match(pattern, bad_prefix)).not_to pass end it "should reject an empty NID" do expect(grok_match(pattern, empty_nid)).not_to pass end it "should reject an NID with a leading hyphen" do expect(grok_match(pattern, leading_hyphen)).not_to pass end it "should reject an NID with a special character" do expect(grok_match(pattern, bad_nid)).not_to pass end it "should reject an NID with a percent sign" do expect(grok_match(pattern, percent_nid)).not_to pass end it "should reject an NID longer than 32 characters" do expect(grok_match(pattern, too_long_nid)).not_to pass end it "should reject a URN with an empty NSS" do expect(grok_match(pattern, empty_nss)).not_to pass end it "should reject non-escape percent signs" do expect(grok_match(pattern, naked_percent)).not_to pass expect(grok_match(pattern, short_percent)).not_to pass expect(grok_match(pattern, nonhex_percent)).not_to pass end end end