From edeeb3d82dfccfd87b28d4e6c177209b8cc5516c Mon Sep 17 00:00:00 2001 From: Daniel Heath Date: Tue, 30 Apr 2019 11:25:41 +1000 Subject: [PATCH] Add spec for middleware --- lib/html-proofer/middleware.rb | 24 ++++-- ...ck_sri_true_log_level_error_type_file_.yml | 78 +++++++++++++++++++ spec/html-proofer/middleware_spec.rb | 33 ++++++++ 3 files changed, 130 insertions(+), 5 deletions(-) create mode 100644 spec/html-proofer/fixtures/vcr_cassettes/links/integrity_and_cors_pagination_rels_html_check_sri_true_log_level_error_type_file_.yml create mode 100644 spec/html-proofer/middleware_spec.rb diff --git a/lib/html-proofer/middleware.rb b/lib/html-proofer/middleware.rb index 7d979829..273d4b04 100644 --- a/lib/html-proofer/middleware.rb +++ b/lib/html-proofer/middleware.rb @@ -3,6 +3,16 @@ module HTMLProofer class Middleware + class InvalidHtmlError < StandardError + def initialize(failures) + @failures = failures + end + + def message + "HTML Validation errors (skip by adding ?SKIP_VALIDATION to URL): \n#{@failures.join("\n")}" + end + end + def self.options @options ||= { type: :file, @@ -43,12 +53,16 @@ def call(env) return result if env['REQUEST_METHOD'] != 'GET' return result if env['QUERY_STRING'] =~ /SKIP_VALIDATION/ return result if result.first != 200 - - # [@status, @headers, @response] body = [] result.last.each { |e| body << e } - html = body.join('').lstrip - if HTML_SIGNATURE.any? { |sig| html.downcase.starts_with? sig.downcase } + + body = body.join('') + begin + html = body.lstrip + rescue + return result # Invalid encoding; it's not gonna be html. + end + if HTML_SIGNATURE.any? { |sig| html.upcase.starts_with? sig } parsed = HTMLProofer::Runner.new( 'response', Middleware.options @@ -57,7 +71,7 @@ def call(env) ) if parsed[:failures].length > 0 - raise "HTML Validation errors (skip by adding ?SKIP_VALIDATION to URL): \n#{parsed[:failures].join("\n")}" + raise InvalidHtmlError.new(parsed[:failures]) end end result diff --git a/spec/html-proofer/fixtures/vcr_cassettes/links/integrity_and_cors_pagination_rels_html_check_sri_true_log_level_error_type_file_.yml b/spec/html-proofer/fixtures/vcr_cassettes/links/integrity_and_cors_pagination_rels_html_check_sri_true_log_level_error_type_file_.yml new file mode 100644 index 00000000..1e528042 --- /dev/null +++ b/spec/html-proofer/fixtures/vcr_cassettes/links/integrity_and_cors_pagination_rels_html_check_sri_true_log_level_error_type_file_.yml @@ -0,0 +1,78 @@ +--- +http_interactions: +- request: + method: head + uri: https://github.com + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; HTML Proofer/3.10.2; +https://github.com/gjtorikian/html-proofer) + Accept: + - application/xml,application/xhtml+xml,text/html;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Expect: + - '' + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 30 Apr 2019 01:12:11 GMT + Content-Type: + - text/html; charset=utf-8 + Server: + - GitHub.com + Status: + - 200 OK + Vary: + - X-PJAX + - Accept-Encoding + ETag: + - W/"ddb3d55638fd1d4c24ac9dd9bc28408b" + Cache-Control: + - max-age=0, private, must-revalidate + Set-Cookie: + - has_recent_activity=1; path=/; expires=Tue, 30 Apr 2019 02:12:11 -0000 + - _octo=GH1.1.327282718.1556586731; domain=.github.com; path=/; expires=Fri, + 30 Apr 2021 01:12:11 -0000 + - logged_in=no; domain=.github.com; path=/; expires=Sat, 30 Apr 2039 01:12:11 + -0000; secure; HttpOnly + - _gh_sess=Y21MUitHSCtkcnpJeUMzeFVsQndUdDhQMk9DSUNDME90TmhzTWFTcThZK2NOWDVDbENVdjFrS1Zmd21ncjFpTjhuT2tjWFMvbEVKUUlGK1R0S3R1ZlhmMkhvZy9BL1Q4MkUxaVpHVXRRQi85bDRjbkxJQmdzK3lWV2VQdk9yeFdmZHpCcjZMdUpWazVmQXZ2cU9zL1ZXM2pHQ2NNaXYwU1FDZkNTLzZnclF6WnJNdHhCV0FqVHdmVTJpUWlYL3REakRYQ3ZlSFp5bWZOVE85OTRuNDB4QT09LS1aQTZMaXNDM0ZORzc0R0czbkprMVpRPT0%3D--afb215b5aff4934992d0087b0c30ed41ad2b6c27; + path=/; secure; HttpOnly + X-Request-Id: + - c80accfb-85c8-4c94-81f7-d6c41c997baa + Strict-Transport-Security: + - max-age=31536000; includeSubdomains; preload + X-Frame-Options: + - deny + X-Content-Type-Options: + - nosniff + X-XSS-Protection: + - 1; mode=block + Referrer-Policy: + - origin-when-cross-origin, strict-origin-when-cross-origin + Expect-CT: + - max-age=2592000, report-uri="https://api.github.com/_private/browser/errors" + Content-Security-Policy: + - 'default-src ''none''; base-uri ''self''; block-all-mixed-content; connect-src + ''self'' uploads.github.com www.githubstatus.com collector.githubapp.com api.github.com + www.google-analytics.com github-cloud.s3.amazonaws.com github-production-repository-file-5c1aeb.s3.amazonaws.com + github-production-upload-manifest-file-7fdce7.s3.amazonaws.com github-production-user-asset-6210df.s3.amazonaws.com + wss://live.github.com; font-src github.githubassets.com; form-action ''self'' + github.com gist.github.com; frame-ancestors ''none''; frame-src render.githubusercontent.com; + img-src ''self'' data: github.githubassets.com identicons.github.com collector.githubapp.com + github-cloud.s3.amazonaws.com *.githubusercontent.com customer-stories-feed.github.com; + manifest-src ''self''; media-src ''none''; script-src github.githubassets.com; + style-src ''unsafe-inline'' github.githubassets.com' + X-GitHub-Request-Id: + - A7A4:22D8:27ED84:3DA226:5CC7A0EB + body: + encoding: UTF-8 + string: '' + http_version: '1.1' + adapter_metadata: + effective_url: https://github.com/ + recorded_at: Tue, 30 Apr 2019 01:12:11 GMT +recorded_with: VCR 2.9.3 diff --git a/spec/html-proofer/middleware_spec.rb b/spec/html-proofer/middleware_spec.rb new file mode 100644 index 00000000..69a1b340 --- /dev/null +++ b/spec/html-proofer/middleware_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe 'Middleware test' do + let(:request) { {'REQUEST_METHOD' => 'GET'} } + let(:response) { File.open(response_fixture) } + let(:app) { Proc.new { |*args| [200, {}, response] } } + let(:middleware) { HTMLProofer::Middleware.new(app) } + subject { middleware.call(request) } + + context 'with invalid HTML' do + let(:response_fixture) { File.join(FIXTURES_DIR, 'html', 'missing_closing_quotes.html') } + it 'raises an error' do + expect { + subject + }.to raise_error(HTMLProofer::Middleware::InvalidHtmlError) + end + end + + context 'with valid HTML' do + let(:response_fixture) { File.join(FIXTURES_DIR, 'html', 'html5_tags.html') } + it 'does not raise an error' do + subject + end + end + + context 'with non-HTML content' do + let(:response_fixture) { File.join(FIXTURES_DIR, 'images', 'gpl.png') } + it 'does not raise an error' do + subject + end + end + +end