#------------------------------------------------------------------- # WebGUI is Copyright 2001-2009 Plain Black Corporation. #------------------------------------------------------------------- # Please read the legal notices (docs/legal.txt) and the license # (docs/license.txt) that came with this distribution before using # this software. #------------------------------------------------------------------- # http://www.plainblack.com info@plainblack.com #------------------------------------------------------------------- use FindBin; use strict; use lib "$FindBin::Bin/../lib"; use WebGUI::Test; use WebGUI::PseudoRequest; use WebGUI::Session; use WebGUI::Asset; my @getRefererUrlTests = ( { input => undef, output => undef, comment => 'getRefererUrl returns undef unless there is a referrer', }, { input => 'http://www.domain.com/myUrl.html', output => 'myUrl.html', comment => 'getRefererUrl returns the url minus the gateway', }, { input => 'http://www.domain.com/myUrl.html?op=switchAdminOn', output => 'myUrl.html', comment => 'getRefererUrl returns the url minus the gateway', }, { input => 'https://www.site.com/myUrl.html', output => 'myUrl.html', comment => 'getRefererUrl handles SSL urls', }, { input => 'itunes://www.site.com/myUrl.html', output => undef, comment => 'getRefererUrl only handles HTTP protocols', }, { input => 'http://site/myUrl.html', output => 'myUrl.html', comment => 'getRefererUrl will also parse weird URLs', }, ); use Test::More; use Test::MockObject::Extends; plan tests => 87 + scalar(@getRefererUrlTests); my $session = WebGUI::Test->session; my $pseudoRequest = WebGUI::PseudoRequest->new(); $session->{_request} = $pseudoRequest; #disable caching my $preventProxyCache = $session->setting->get('preventProxyCache'); $session->setting->set('preventProxyCache', 0); ####################################### # # append # ####################################### my $url = 'http://localhost.localdomain/foo'; my $url2; $url2 = $session->url->append($url,'a=b'); is( $url2, $url.'?a=b', 'append first pair'); $url2 = $session->url->append($url2,'c=d'); is( $url2, $url.'?a=b;c=d', 'append second pair'); ####################################### # # gateway # ####################################### WebGUI::Test->originalConfig('gateway'); $session->config->set('gateway', '/'); is( $session->config->get('gateway'), '/', 'Set gateway for downstream tests'); $url2 = $session->url->gateway; is( $url2, '/', 'gateway: args'); $url2 = $session->url->gateway('/home'); is( $url2, '/home', 'gateway: with leading slash'); $url2 = $session->url->gateway('home'); is( $url2, '/home', 'gateway: without leading slash'); #Disable caching $session->setting->set(preventProxyCache => 1); is( 1, $session->setting->get('preventProxyCache'), 'gateway: disable proxy caching'); $url2 = $session->url->gateway('home'); like( $url2, qr{/home\?noCache=\d+:\d+$}, 'gateway: check proxy prevention setting'); $url2 = $session->url->gateway('home','',1); is( $url2, '/home', 'gateway: skipPreventProxyCache'); #Enable caching $session->setting->set(preventProxyCache => 0); $url = '/home'; $url2 = $session->url->gateway($url,'a=b'); is( $url2, '/home?a=b', 'append one pair via gateway'); #Restore original proxy cache setting so downstream tests work with no surprises $session->setting->set(preventProxyCache => $preventProxyCache ); ####################################### # # setSiteUrl and getSiteUrl # ####################################### ##Memorize the current setting and set up the default setting to start tests. my $setting_hostToUse = $session->setting->get('hostToUse'); $session->setting->set('hostToUse', 'HTTP_HOST'); my $sitename = $session->config->get('sitename')->[0]; WebGUI::Test->originalConfig('webServerPort'); $session->config->delete('webServerPort'); is( $session->url->getSiteURL, 'http://'.$sitename, 'getSiteURL from config as http_host'); $session->url->setSiteURL('http://webgui.org'); is( $session->url->getSiteURL, 'http://webgui.org', 'override config setting with setSiteURL'); ##Create a fake environment hash so we can muck with it. my %mockEnv = %ENV; my $env = $session->env; $env = Test::MockObject::Extends->new($env); $env->mock('get', sub { return $mockEnv{$_[1]} } ); $mockEnv{HTTPS} = "on"; $session->url->setSiteURL(undef); is( $session->url->getSiteURL, 'https://'.$sitename, 'getSiteURL from config as http_host with SSL'); $mockEnv{HTTPS} = ""; $mockEnv{HTTP_HOST} = "devsite.com"; $session->url->setSiteURL(undef); is( $session->url->getSiteURL, 'http://'.$sitename, 'getSiteURL where requested host is not a configured site'); WebGUI::Test->originalConfig('sitename'); $session->config->addToArray('sitename', 'devsite.com'); $session->url->setSiteURL(undef); is( $session->url->getSiteURL, 'http://devsite.com', 'getSiteURL where requested host is not the first configured site'); $session->setting->set('hostToUse', 'sitename'); $session->url->setSiteURL(undef); is( $session->url->getSiteURL, 'http://'.$sitename, 'getSiteURL where illegal host has been requested'); $session->config->set('webServerPort', 80); $session->url->setSiteURL(undef); is( $session->url->getSiteURL, 'http://'.$sitename.':80', 'getSiteURL with a port'); $session->config->set('webServerPort', 8880); $session->url->setSiteURL(undef); is( $session->url->getSiteURL, 'http://'.$sitename.':8880', 'getSiteURL with a non-standard port'); $session->url->setSiteURL('http://'.$sitename); is( $session->url->getSiteURL, 'http://'.$sitename, 'restore config setting'); $session->setting->set('hostToUse', $setting_hostToUse); ####################################### # # makeCompliant # ####################################### $url = 'level1 /level2/level3 '; $url2 = 'level1-/level2/level3'; is $session->url->makeCompliant($url), $url2, 'internal spaces encoded, trailing spaces removed'; is $session->url->makeCompliant('home/'), 'home', '... trailing slashes removed'; is $session->url->makeCompliant('home is where the heart is'), 'home-is-where-the-heart-is', '... makeCompliant translates spaces to dashes'; is $session->url->makeCompliant('/home'), 'home', '... removes initial slash'; is $session->url->makeCompliant('home -- here'), 'home-here', 'multiple dashes collapsed'; is $session->url->makeCompliant('home!@#$%^&*here'), 'home-here', 'non-word characters collapsed to single dash'; is $session->url->makeCompliant("home\x{2267}here"), 'home-here', 'non-word international characters removed'; is $session->url->makeCompliant("home\x{1EE9}here"), "home\x{1EE9}here", 'word international characters not removed'; my $character = "\x{00C0}"; utf8::upgrade($character); is( $session->url->makeCompliant($character), $character, 'utf8 allowed in URLs'); ####################################### # # getRequestedUrl # ####################################### my $originalRequest = $session->request; ##Save the original request object $session->{_request} = undef; is($session->url->getRequestedUrl, undef, 'getRequestedUrl returns undef unless it has a request object'); $session->{_request} = $originalRequest; $pseudoRequest->uri('empty'); is($session->request->uri, 'empty', 'Validate Mock Object operation'); $pseudoRequest->uri('full'); is($session->request->uri, 'full', 'Validate Mock Object operation #2'); $pseudoRequest->uri('/path1/file1'); is($session->url->getRequestedUrl, 'path1/file1', 'getRequestedUrl, fetch'); $pseudoRequest->uri('/path2/file2'); is($session->url->getRequestedUrl, 'path1/file1', 'getRequestedUrl, check cache of previous result'); $session->url->{_requestedUrl} = undef; ##Manually clear cached value $pseudoRequest->uri('/path2/file2?param1=one;param2=two'); is($session->url->getRequestedUrl, 'path2/file2', 'getRequestedUrl, does not return params'); $session->url->{_requestedUrl} = undef; my $utf8_url = "Viel Spa\x{00DF}"; $pseudoRequest->uri($utf8_url); use Encode; my $decoded_url = decode_utf8($utf8_url); is $session->url->getRequestedUrl(), $decoded_url, 'getRequestedUrl returns utf8 decoded data'; ####################################### # # page # ####################################### my $sessionAsset = $session->asset; $session->asset(undef); $session->url->{_requestedUrl} = undef; ##Manually clear cached value $pseudoRequest->uri('/path1/">file1'); is($session->url->page, '/path1/%22%3Efile1', 'page with no args returns getRequestedUrl through gateway, escaping the requested URL for safety'); is($session->url->page('op=viewHelpTOC;topic=Article'), '/path1/%22%3Efile1?op=viewHelpTOC;topic=Article', 'page: pairs are appended'); $url2 = 'http://'.$session->config->get('sitename')->[0].'/path1/%22%3Efile1'; is($session->url->page('',1), $url2, 'page: withFullUrl includes method and sitename'); $session->setting->set('preventProxyCache', 0); is($session->url->page('','',1), '/path1/%22%3Efile1', 'page: skipPreventProxyCache is a no-op with preventProxyCache off in settings'); $session->setting->set('preventProxyCache', 1); my $cacheableUrl = $session->url->page('','',1); is($cacheableUrl, '/path1/%22%3Efile1', 'page: skipPreventProxyCache does not change url'); like($session->url->page('','',0), qr(^/path1/%22%3Efile1\?noCache=\d{0,4}:\d+$), 'page: noCache added'); ##Restore original setting $session->setting->set('preventProxyCache', $preventProxyCache); my $defaultAsset = WebGUI::Asset->getDefault($session); $session->asset($defaultAsset); is($session->url->page, $session->url->gateway($defaultAsset->get('url')), 'page:session asset trumps requestedUrl'); $session->asset($sessionAsset); ####################################### # # getReferrerUrl # ####################################### $mockEnv{'HTTP_REFERER'} = 'test'; is($session->env->get('HTTP_REFERER'), 'test', 'testing overridden ENV'); foreach my $test (@getRefererUrlTests) { $mockEnv{HTTP_REFERER} = $test->{input}; is($session->url->getRefererUrl, $test->{output}, $test->{comment}); } ####################################### # # makeAbsolute # ####################################### is($session->url->makeAbsolute('page1', '/layer1/layer2/'), '/layer1/layer2/page1', 'makeAbsolute: use a different root'); is($session->url->makeAbsolute('page1', '/layer1/page2'), '/layer1/page1', 'makeAbsolute: use a second root that is one level shallower'); is($session->url->makeAbsolute('page1'), '/page1', 'makeAbsolute: default baseUrl from session->asset'); ####################################### # # extras # ####################################### my $extras = WebGUI::Test->originalConfig('extrasURL'); WebGUI::Test->originalConfig('cdn'); $session->config->delete('cdn'); is($session->url->extras, $extras.'/', 'extras method returns URL to extras with a trailing slash'); is($session->url->extras('foo.html'), join('/', $extras,'foo.html'), 'extras method appends to the extras url'); is($session->url->extras('/foo.html'), join('/', $extras,'foo.html'), 'extras method removes extra slashes'); is($session->url->extras('/dir1//foo.html'), join('/', $extras,'dir1/foo.html'), 'extras method removes extra slashes anywhere'); $extras = 'http://mydomain.com/'; $session->config->set('extrasURL', $extras); is($session->url->extras('/foo.html'), join('', $extras,'foo.html'), 'extras method removes extra slashes'); is($session->url->extras('/dir1//foo.html'), join('', $extras,'dir1/foo.html'), 'extras method removes extra slashes anywhere'); $extras = 'https://mydomain.com/'; $session->config->set('extrasURL', $extras); is($session->url->extras('/foo.html'), join('', $extras,'foo.html'), 'extras method removes extra slashes'); is($session->url->extras('/dir1//foo.html'), join('', $extras,'dir1/foo.html'), 'extras method removes extra slashes anywhere'); $extras = 'http://mydomain.com/'; $session->config->set('extrasURL', $extras); my $cdnCfg = { "enabled" => 1, "extrasCdn" => "http://extras.example.com/", "extrasSsl" => "https://ssl.example.com/", "extrasExclude" => ["^tiny"] }; $session->config->set('cdn', $cdnCfg); is($session->url->extras('/dir1/foo.html'), join('', $cdnCfg->{extrasCdn}, 'dir1/foo.html'), 'extras cleartext with CDN'); is($session->url->extras('tinymce'), join('', $extras, 'tinymce'), 'extras exclusion from CDN'); # Note: env is already mocked above. $mockEnv{HTTPS} = 'on'; is($session->url->extras('/dir1/foo.html'), join('', $cdnCfg->{extrasSsl}, 'dir1/foo.html'), 'extras using extrasSsl with HTTPS'); $mockEnv{HTTPS} = undef; $mockEnv{SSLPROXY} = 1; is($session->url->extras('/dir1/foo.html'), join('', $cdnCfg->{extrasSsl}, 'dir1/foo.html'), 'extras using extrasSsl with SSLPROXY'); delete $mockEnv{SSLPROXY}; ####################################### # # escape and unescape # Our goal in this test is just to show that the calls to the URI module work, # not to test the URI methods themselves # ####################################### my $escapeString = '10% is enough;'; my $escapedString = $session->url->escape($escapeString); my $unEscapedString = $session->url->unescape($escapeString); is($escapedString, '10%25%20is%20enough%3B', 'escape method'); is($unEscapedString, '10% is enough;', 'unescape method'); ####################################### # # urlize # part of urlize is calling makeCompliant, which is tested elsewhere. # these tests will just make sure that it was called correctly and # check other urlize behavior # ####################################### is($session->url->urlize('HOME/PATH1'), 'home/path1', 'urlize: urls are lower cased'); is $session->url->urlize('home/../out-of-bounds'), 'home/out-of-bounds', '... removes ../'; is $session->url->urlize('home/./here'), 'home/here', '... removes ./'; is $session->url->urlize('home/../../out-of-bounds'), 'home/out-of-bounds', '... removes multiple ../'; is $session->url->urlize('home/././here'), 'home/here', '... removes multiple ./'; ####################################### # # getBackToSiteURL # ####################################### $sessionAsset = $session->asset; $session->{_asset} = undef; $session->url->{_requestedUrl} = undef; ##Manually clear cached value $pseudoRequest->uri('/goBackToTheSite'); is($session->url->getBackToSiteURL, '/goBackToTheSite', 'getBackToSiteURL: when session asset is undefined, the method falls back to using page'); $session->asset($sessionAsset); is($session->url->getBackToSiteURL, $session->asset->getUrl, q!getBackToSiteURL: for most regular old assets, it takes you back to the assets container!); my $defaultAssetUrl = WebGUI::Asset->getDefault($session)->getUrl; $session->asset( WebGUI::Asset->getImportNode($session) ); is( $session->url->getBackToSiteURL, $defaultAssetUrl, q!getBackToSiteURL: importNode asset returns you to the default Asset! ); $session->asset( WebGUI::Asset->getMedia($session) ); is( $session->url->getBackToSiteURL, $defaultAssetUrl, q!getBackToSiteURL: Media Folder asset returns you to the default Asset! ); $session->asset( WebGUI::Asset->getRoot($session) ); is( $session->url->getBackToSiteURL, $defaultAssetUrl, q!getBackToSiteURL: Root returns you to the default Asset! ); TODO: { local $TODO = 'extra tests for getBackToSiteURL'; ok(0, 'test a child of the import node'); ok(0, 'test a child of the media folder'); } my $versionTag = WebGUI::VersionTag->getWorking($session); WebGUI::Test->addToCleanup($versionTag); my $statefulAsset = WebGUI::Asset->getRoot($session)->addChild({ className => 'WebGUI::Asset::Snippet' }); $versionTag->commit; $session->asset( $statefulAsset ); $statefulAsset->{_properties}{state} = 'published'; is( $session->url->getBackToSiteURL, WebGUI::Asset->getRoot($session)->getUrl, q!getBackToSiteURL: When asset state is published, it returns you to the Assets container! ); $statefulAsset->{_properties}{state} = 'trash'; is( $session->url->getBackToSiteURL, $defaultAssetUrl, q!getBackToSiteURL: When asset state is trash, it returns you to the default Asset! ); $statefulAsset->{_properties}{state} = 'clipboard'; is( $session->url->getBackToSiteURL, $defaultAssetUrl, q!getBackToSiteURL: When asset state is clipboard, it returns you to the default Asset! ); ####################################### # # forceSecureConnection # ####################################### WebGUI::Test->originalConfig('sslEnabled'); ##Test all the false cases, first $session->config->set('sslEnabled', 0); $mockEnv{HTTPS} = 'not on'; $mockEnv{SSLPROXY} = 0; ok( ! $session->url->forceSecureConnection(), 'sslEnabled must be 1 to force SSL'); $session->config->set('sslEnabled', 1); $mockEnv{HTTPS} = 'on'; $mockEnv{SSLPROXY} = 0; ok( ! $session->url->forceSecureConnection(), 'HTTPS must not be "on" to force SSL'); $session->config->set('sslEnabled', 1); $mockEnv{HTTPS} = 'not on'; $mockEnv{SSLPROXY} = 1; ok( ! $session->url->forceSecureConnection(), 'SSLPROXY must not be true to force SSL'); ok( ! $session->url->forceSecureConnection('/test/url'), 'all conditions must be met, even if a URL is directly passed in'); ##Validate the HTTP object state before we start $session->http->setStatus('200', 'OK'); is($session->http->getStatus, 200, 'http status is okay, 200'); is($session->http->getRedirectLocation, undef, 'redirect location is empty'); $mockEnv{HTTPS} = 'not on'; $mockEnv{SSLPROXY} = 0; my $secureUrl = $session->url->getSiteURL . '/foo/bar/baz/buz'; $secureUrl =~ s/http:/https:/; ok($session->url->forceSecureConnection('/foo/bar/baz/buz'), 'forced secure connection'); is($session->http->getStatus, 302, 'http status set to redirect, 302'); is($session->http->getRedirectLocation, $secureUrl, 'redirect location set to proper passed in URL with SSL and sitename added'); $session->http->setStatus('200', 'OK'); $session->http->setRedirectLocation(undef); $secureUrl = $session->url->getSiteURL . $session->url->page(); $secureUrl =~ s/http:/https:/; ok($session->url->forceSecureConnection(), 'forced secure connection with no url param'); ok($session->http->isRedirect, '... and redirect status code was set'); is($session->http->getRedirectLocation, $secureUrl, '... and redirect status code was set');