assertEqual( _pathologic_url_to_protocol_relative('http://example.com/foo/bar'), '//example.com/foo/bar', t('Protocol-relative URL creation with http:// URL') ); $this->assertEqual( _pathologic_url_to_protocol_relative('https://example.org/baz'), '//example.org/baz', t('Protocol-relative URL creation with https:// URL') ); // Build some paths to check against $test_paths =[ 'foo' => [ 'path' => 'foo', 'opts' => [] ], 'foo/bar' => [ 'path' => 'foo/bar', 'opts' => [] ], 'foo/bar?baz' => [ 'path' => 'foo/bar', 'opts' => ['query' => ['baz' => NULL]] ], 'foo/bar?baz=qux' => [ 'path' => 'foo/bar', 'opts' => ['query' => ['baz' => 'qux']] ], 'foo/bar#baz' => [ 'path' => 'foo/bar', 'opts' => ['fragment' => 'baz'], ], 'foo/bar?baz=qux&quux=quuux#quuuux' => [ 'path' => 'foo/bar', 'opts' => [ 'query' => ['baz' => 'qux', 'quux' => 'quuux'], 'fragment' => 'quuuux', ], ], 'foo%20bar?baz=qux%26quux' => [ 'path' => 'foo bar', 'opts' => [ 'query' => ['baz' => 'qux&quux'], ], ], '/' => [ 'path' => '', 'opts' => [], ], ]; foreach (['full', 'proto-rel', 'path'] as $protocol_style) { $format_id = _pathologic_build_format(['settings_source' => 'local', 'local_settings' => ['protocol_style' => $protocol_style]]); $paths = []; foreach ($test_paths as $path => $args) { $args['opts']['absolute'] = $protocol_style !== 'path'; $paths[$path] = _pathologic_content_url($args['path'], $args['opts']); if ($protocol_style === 'proto-rel') { $paths[$path] = _pathologic_url_to_protocol_relative($paths[$path]); } } $t10ns = [ '@clean' => empty($script_path) ? t('Yes') : t('No'), '@ps' => $protocol_style, ]; $this->assertEqual( check_markup('', $format_id), '', t('Simple paths. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('', $format_id), '', t('D7 and earlier-style non-clean URLs. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('', $format_id), '', t('D8-style non-clean URLs. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('
', $format_id), '', t('Paths with query string. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('', $format_id), '', t('Path with fragment. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('', $format_id), '', t('Fragment-only href. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); // @see https://drupal.org/node/2208223 $this->assertEqual( check_markup('', $format_id), '', t('Hash-only href. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('', $format_id), '', t('Path with query string and fragment. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('', $format_id), '', t('Path with URL encoded parts. Clean URLs: @clean; protocol style: @ps.', $t10ns) ); $this->assertEqual( check_markup('', $format_id), '', t('Path with just slash. Clean URLs: @clean; protocol style: @ps', $t10ns) ); } global $base_path; $this->assertEqual( check_markup('bar', $format_id), 'bar', t('Paths beginning with $base_path (like WYSIWYG editors like to make)') ); global $base_url; $this->assertEqual( check_markup('bar', $format_id), 'bar', t('Paths beginning with $base_url') ); // @see http://drupal.org/node/1617944 $this->assertEqual( check_markup('bar', $format_id), 'bar', t('Off-site schemeless URLs (//example.com/foo) ignored') ); // Test internal: and all base paths $format_id = _pathologic_build_format([ 'settings_source' => 'local', 'local_settings' => [ 'local_paths' => "http://example.com/qux\nhttp://example.org\n/bananas", 'protocol_style' => 'full', ], ]); // @see https://drupal.org/node/2030789 $this->assertEqual( check_markup('bar', $format_id), 'bar', t('On-site schemeless URLs processed') ); $this->assertEqual( check_markup('', $format_id), '', t('Path Filter compatibility (internal:)') ); $this->assertEqual( check_markup('look', $format_id), 'look', t('Path Filter compatibility (files:)') ); $this->assertEqual( check_markup('', $format_id), '', t('"All base paths for this site" functionality') ); $this->assertEqual( check_markup('bar', $format_id), 'bar', t('URLs with likely protocols are ignored') ); // Test hook_pathologic_alter() implementation. $this->assertEqual( check_markup('', $format_id), '', t('hook_pathologic_alter(): Alter $url_params') ); $this->assertEqual( check_markup('', $format_id), '', t('hook_pathologic_alter(): Passthrough with use_original option') ); // Test paths to existing files when clean URLs are disabled. // @see http://drupal.org/node/1672430 $script_path = ''; $filtered_tag = check_markup('', $format_id); $this->assertTrue( strpos($filtered_tag, 'q=') === FALSE, t('Paths to files don\'t have ?q= when clean URLs are off') ); $format_id = _pathologic_build_format([ 'settings_source' => 'global', 'local_settings' => [ 'protocol_style' => 'rel', ], ]); $this->config('pathologic.settings') ->set('protocol_style', 'proto-rel') ->set('local_paths', 'http://example.com/') ->save(); $this->assertEqual( check_markup('', $format_id), '', t('Use global settings when so configured on the format') ); // Test really broken URLs. // @see https://www.drupal.org/node/2602312 $original = 'foo'; $message = t('Fails sensibly when \Drupal\Core\Url::fromUri() throws exception'); try { $filtered = check_markup($original, $format_id); $this->assertEqual( $original, $filtered, $message ); } catch (\Exception $e) { $this->fail($message); } } } /** * Wrapper around url() which does HTML entity decoding and encoding. * * Since Pathologic works with paths in content, it needs to decode paths which * have been HTML-encoded, and re-encode them when done. This is a wrapper * around url() which does the same thing so that we can expect the results * from it and from Pathologic to still match in our tests. * * @see url() * @see http://drupal.org/node/1672932 * @see http://www.w3.org/TR/xhtml1/guidelines.html#C_12 */ function _pathologic_content_url($path, $options) { // If we should pretend this is a path to a file, make url() behave like clean // URLs are enabled. // @see _pathologic_replace() // @see http://drupal.org/node/1672430 if (!empty($options['is_file'])) { $options['script_path'] = ''; } if (parse_url($path, PHP_URL_SCHEME) === NULL) { if ($path == '') { return SafeMarkup::checkPlain(Url::fromRoute('', [], $options)->toString()); } $path = 'base://' . $path; } return SafeMarkup::checkPlain(Url::fromUri(htmlspecialchars_decode($path), $options)->toString()); } /** * Build a text format with Pathologic configured a certain way. * * @param $settings * An array of settings for the Pathologic instance on the format. * @return * A format machine name (consisting of random characters) for the format. */ function _pathologic_build_format($settings) { $format_id = user_password(); $format = entity_create('filter_format', [ 'format' => $format_id, 'name' => $format_id, ]); $format->setFilterConfig('filter_pathologic', [ 'status' => 1, 'settings' => $settings, ]); $format->save(); return $format_id; }