package org.archive.wayback.archivalurl; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import junit.framework.TestCase; import org.archive.wayback.archivalurl.requestparser.DatelessReplayRequestParser; import org.archive.wayback.archivalurl.requestparser.PathDatePrefixQueryRequestParser; import org.archive.wayback.archivalurl.requestparser.PathDateRangeQueryRequestParser; import org.archive.wayback.archivalurl.requestparser.PathPrefixDatePrefixQueryRequestParser; import org.archive.wayback.archivalurl.requestparser.PathPrefixDateRangeQueryRequestParser; import org.archive.wayback.archivalurl.requestparser.ReplayRequestParser; import org.archive.wayback.core.WaybackRequest; import org.archive.wayback.exception.BadQueryException; import org.archive.wayback.exception.BetterRequestException; import org.archive.wayback.memento.MementoConstants; import org.archive.wayback.memento.TimeGateBadQueryException; import org.archive.wayback.memento.TimeMapRequestParser; import org.archive.wayback.webapp.AccessPoint; import org.easymock.EasyMock; import org.easymock.IAnswer; /** * Test case for {@link ArchivalUrlRequestParser}. * * This class tests entire {@code ArchivalUrlRequestParser}, including its sub-component * classes: {@link ReplayRequestParser}, {@link PathDatePrefixQueryRequestParser} * {@link PathDateRangeQueryRequestParser}, {@link PathPrefixDatePrefixQueryRequestParser}, * {@link PathPrefixDateRangeQueryRequestParser} and {@link DatelessReplayRequestParser}. * * @author Kenji Nagahashi * */ public class ArchivalUrlRequestParserTest extends TestCase { ArchivalUrlRequestParser cut; AccessPoint accessPoint; // must set before calling parse(). String acceptTimestampHeader = null; String acceptDatetimeHeader = null; final String EARLIEST_TIMESTAMP = "1996"; final String EXPECTED_START_TIMESTAMP = "19960101000000"; final String EXPECTED_END_TIMESTAMP = null; protected void setUp() throws Exception { super.setUp(); cut = new ArchivalUrlRequestParser(); // this affects what WaybackRequest.getStartTimestamp() returns. // here we leave lastestTimestamp null. cut.setEarliestTimestamp(EARLIEST_TIMESTAMP); // this needs to be called before use (but I don't see it called in // Spring config.) cut.init(); // refactoring note: RequestParser#parser takes AccessPoint as an argument. // it is bad because AccessPoint is not mock-able and it is a big class. // it'd be great if we can cut out an interface required for RequestParser // and use it in RequestParser instead. // (partial) list of AccessPoint methods used by RequestParser: // - translateRequestPathQuery(HttpServletRequest) (defined in RequestHandler) // - getMapParam(Map, String) (static) // - isEnableMemento() accessPoint = new AccessPoint(); } // lame query parameter parser just sufficient for testing. // FIXME: replace this with exiting well-tested library if there's one. private Map<String, String[]> parseParameters(String url) { int iq = url.indexOf("?"); if (iq < 0) return Collections.emptyMap(); Map<String, List<String>> map = new HashMap<String, List<String>>(); String query = url.substring(iq + 1); String[] params = query.split("&"); for (String kv : params) { int ieq = kv.indexOf("="); String k, v; if (ieq >= 0) { k = kv.substring(0, ieq); try { v = URLDecoder.decode(kv.substring(ieq + 1), "UTF-8"); } catch (UnsupportedEncodingException ex) { v = kv.substring(ieq + 1); } } else { k = kv; v = ""; } List<String> va = map.get(k); if (va == null) { map.put(k, va = new ArrayList<String>()); } va.add(v); } Map<String, String[]> parameterMap = new HashMap<String, String[]>(); for (Entry<String, List<String>> e : map.entrySet()) { List<String> va = e.getValue(); parameterMap.put(e.getKey(), va.toArray(new String[va.size()])); } return parameterMap; } protected HttpServletRequest getRequestMock(String requestURI, String query) { HttpServletRequest mock = EasyMock.createNiceMock(HttpServletRequest.class); // DatelessReplayRequestParser checks out Accept-Datetime HTTP header. If we // want to test it, we need to setup return value for getHeader() method. // RequestMapper accesses HttpServletequest.getAttribute(RequestMapper.REQUEST_CONTEXT_PREFIX) // which can be null. so we leave it null. // prefix must end with "/" (see RequestMapper#handleRequest(HttpServletRequest, HttpServletResponse) EasyMock.expect(mock.getAttribute(EasyMock.eq("webapp-request-context-path-prefix"))).andStubReturn("/web/"); EasyMock.expect(mock.getRequestURI()).andStubReturn(requestURI); EasyMock.expect(mock.getQueryString()).andStubReturn(query); EasyMock.expect(mock.getHeader(MementoConstants.ACCEPT_DATETIME)).andStubReturn(acceptDatetimeHeader); EasyMock.expect(mock.getHeader("Accept-Timestamp")).andStubReturn(acceptTimestampHeader); // used by OpenSearchRequestParser, TimeMapRequestParser final Map<String, String[]> parameterMap = parseParameters(requestURI); EasyMock.expect(mock.getParameterMap()).andStubReturn(parameterMap); EasyMock.expect(mock.getParameter(EasyMock.<String>notNull())) .andStubAnswer(new IAnswer<String>() { @Override public String answer() throws Throwable { String name = (String)EasyMock.getCurrentArguments()[0]; String[] va = parameterMap.get(name); return va != null ? va[0] : null; } }); return mock; } protected WaybackRequest parse(String url) throws BadQueryException, BetterRequestException { // note: url is set to HttpServletRequest's requestURI property. it should NOT contain // query part. RequestParser will receive value translated by RequestMapper.getRequestContextPath() // (i.e. "/web/" part removed.) HttpServletRequest req = getRequestMock(url, null); EasyMock.replay(req); return cut.parse(req, accessPoint); } public void testReplayRequest() throws Exception { WaybackRequest wbr = parse("/web/20100101000000/http://www.yahoo.com/"); assertNotNull(wbr); assertTrue(wbr.isReplayRequest()); assertEquals("20100101000000", wbr.getReplayTimestamp()); assertEquals("http://www.yahoo.com/", wbr.getRequestUrl()); } /** * timestamp without "*", path ending with "*". * <p>this is interpreted as replay request for the URL including trailing "*". * That sounds inconsistent with other cases. (BTW, resultant time-redirect URL * has no trailing "*" - there's a special handling happening somewhere.) * Should this be interpreted as URL-query for the specific date?</p> * @throws Exception */ public void testDatePathPrefix() throws Exception { WaybackRequest wbr = parse("/web/20100101000000/http://www.yahoo.com/*"); assertNotNull(wbr); assertTrue(wbr.isReplayRequest()); assertEquals("20100101000000", wbr.getReplayTimestamp()); // ReplayRequestParser does not strip trailing "*" off. assertEquals("http://www.yahoo.com/*", wbr.getRequestUrl()); } /** * test of {@link PathDatePreofixQueryRequestParser}. */ public void testDatePrefix() throws Exception { // less-than-14-digit timestamp with "*": narrowed time range, highlight // the latest within the range. WaybackRequest wbr1 = parse("/web/20100101*/http://www.yahoo.com/?p=2"); assertNotNull(wbr1); assertTrue(wbr1.isCaptureQueryRequest()); assertEquals("20100101000000", wbr1.getStartTimestamp()); assertEquals("20100101235959", wbr1.getEndTimestamp()); assertEquals("20100101235959", wbr1.getReplayTimestamp()); assertEquals("http://www.yahoo.com/?p=2", wbr1.getRequestUrl()); // just "*": entire time range, replay the latest. WaybackRequest wbr2 = parse("/web/*/http://www.yahoo.com/"); assertNotNull(wbr2); assertTrue(wbr2.isCaptureQueryRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr2.getStartTimestamp()); assertEquals(EXPECTED_END_TIMESTAMP, wbr2.getEndTimestamp()); assertEquals(null, wbr2.getReplayTimestamp()); // full 14-digit timestamp with "*": entire time range, highlight the // closest to the specified date. WaybackRequest wbr3 = parse("/web/20100101000000*/http://www.yahoo.com/"); assertNotNull(wbr3); assertTrue(wbr3.isCaptureQueryRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr3.getStartTimestamp()); assertEquals(EXPECTED_END_TIMESTAMP, wbr3.getEndTimestamp()); assertEquals("20100101000000", wbr3.getReplayTimestamp()); } /** * Another test of {@link PathDatePrefixQueryRequestParser}: * URL is recognized even when "{@code *}" is %-encoded. * <p>this is a desired behavior to be implemented (assertion is disabled). * see issue <a href="https://webarchive.jira.com/browse/WWM-110">WWM-110</a></p> * @throws Exception */ public void testDatePrefixEncoded() throws Exception { WaybackRequest wbr1 = parse("/web/20100101%2A/http://www.yahoo.com/?p=%2A"); assertNotNull(wbr1); assertTrue(wbr1.isCaptureQueryRequest()); assertEquals("20100101000000", wbr1.getStartTimestamp()); assertEquals("20100101235959", wbr1.getEndTimestamp()); assertEquals("20100101235959", wbr1.getReplayTimestamp()); assertEquals("http://www.yahoo.com/?p=%2A", wbr1.getRequestUrl()); WaybackRequest wbr2 = parse("/web/%2A/http://www.yahoo.com/"); assertNotNull(wbr2); assertTrue(wbr2.isCaptureQueryRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr2.getStartTimestamp()); assertEquals(EXPECTED_END_TIMESTAMP, wbr2.getEndTimestamp()); assertEquals(null, wbr2.getReplayTimestamp()); } /** * test for {@link PathDateRangeQueryRequestParser}. * <p>date range and specific path. * date range becomes start and end timestamps. but it doesn't * set replayTimestamp (it should, for consistency?) */ public void testPathDateRange() throws Exception { // range with full-length timestamps WaybackRequest wbr1 = parse("/web/20100101000000-20100630235959*/http://www.yahoo.com/"); assertNotNull(wbr1); assertTrue(wbr1.isCaptureQueryRequest()); assertEquals("20100101000000", wbr1.getStartTimestamp()); assertEquals("20100630235959", wbr1.getEndTimestamp()); // assertEquals("20100630235959", wbr1.getReplayTimestamp()); assertEquals(null, wbr1.getReplayTimestamp()); assertEquals("http://www.yahoo.com/", wbr1.getRequestUrl()); WaybackRequest wbr2 = parse("/web/2010-2014*/http://www.yahoo.com/?p=2"); assertNotNull(wbr2); assertTrue(wbr1.isCaptureQueryRequest()); assertEquals("20100101000000", wbr2.getStartTimestamp()); assertEquals("20141231235959", wbr2.getEndTimestamp()); // assertEquals("20141231235959", wbr2.getReplayTimestamp()); assertEquals(null, wbr2.getReplayTimestamp()); assertEquals("http://www.yahoo.com/?p=2", wbr2.getRequestUrl()); // Date range without "*" results in 404. We could make it work. WaybackRequest wbr3 = parse("/web/2010-2014/http://www.yahoo.com/"); assertNull(wbr3); } /** * test for {@link PathDateRangeQueryRequestParser}, %-encoded version. * @throws Exception */ public void testPathDateRangeEncoded() throws Exception { WaybackRequest wbr1 = parse("/web/20100101000000-20100630235959%2A/http://www.yahoo.com/"); assertNotNull(wbr1); assertTrue(wbr1.isCaptureQueryRequest()); assertEquals("20100101000000", wbr1.getStartTimestamp()); assertEquals("20100630235959", wbr1.getEndTimestamp()); // assertEquals("20100630235959", wbr1.getReplayTimestamp()); assertEquals(null, wbr1.getReplayTimestamp()); assertEquals("http://www.yahoo.com/", wbr1.getRequestUrl()); } /** * test of {@link PathPrefixDatePrefixQueryRequestParser}. * <p>this is a URL query with (optional) single timestamp date range. * timestamp, if non-empty, becomes start and end. * </p> */ public void testPathPrefixDatePrefix() throws Exception { WaybackRequest wbr1 = parse("/web/2010*/http://www.yahoo.com/*"); assertNotNull(wbr1); assertTrue(wbr1.isUrlQueryRequest()); assertEquals("20100101000000", wbr1.getStartTimestamp()); assertEquals("20101231235959", wbr1.getEndTimestamp()); // does not set replayTimestamp, but it is not a required behavior. assertEquals("http://www.yahoo.com/", wbr1.getRequestUrl()); WaybackRequest wbr2 = parse("/web/*/http://www.yahoo.com/*"); assertNotNull(wbr2); assertTrue(wbr2.isUrlQueryRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr2.getStartTimestamp()); assertEquals(null, wbr2.getEndTimestamp()); // does not set replayTimestamp, but it is not a required behavior. assertEquals("http://www.yahoo.com/", wbr2.getRequestUrl()); // timestamp is up to 13 digits. 14-digit timestamp results in null (-> 404). // TODO: there'd be a nicer way. WaybackRequest wbr3 = parse("/web/20130101000000*/http://www.yahoo.com/*"); assertNull(wbr3); } /** * test of {@link PathPrefixDatePrefixQueryRequestParser}. * <p>%-encoded timestamp.</p> * @throws Exception */ public void testPathPrefixDatePrefixEncoded() throws Exception { { WaybackRequest wbr = parse("/web/2010%2A/http://www.yahoo.com/*"); assertNotNull(wbr); assertTrue(wbr.isUrlQueryRequest()); assertEquals("20100101000000", wbr.getStartTimestamp()); assertEquals("20101231235959", wbr.getEndTimestamp()); assertEquals("http://www.yahoo.com/", wbr.getRequestUrl()); } // negative case - %2A doesn't make it path-prefix. { WaybackRequest wbr = parse("/web/2010%2A/http://www.yahoo.com/%2A"); assertNotNull(wbr); assertTrue(wbr.isCaptureQueryRequest()); assertEquals("20100101000000", wbr.getStartTimestamp()); assertEquals("20101231235959", wbr.getEndTimestamp()); assertEquals("http://www.yahoo.com/%2A", wbr.getRequestUrl()); } } /** * test of {@link PathPrefixDateRangeQueryRequestParser}. * <p>explicit timestamp range and trailing "*" in URL. * this is a URL-query request, timestamp range becomes * start and end timestamp.</p> * <p>timerange without "*" is not recognized. it could be.</p> */ public void testPathPrefixDateRange() throws Exception { { WaybackRequest wbr1 = parse("/web/20100101-20100531*/http://www.yahoo.com/*"); assertNotNull(wbr1); assertTrue(wbr1.isUrlQueryRequest()); assertEquals("20100101000000", wbr1.getStartTimestamp()); assertEquals("20100531235959", wbr1.getEndTimestamp()); assertEquals("http://www.yahoo.com/", wbr1.getRequestUrl()); } // TODO: date range without "*" } /** * test of {@link PathPrefixDateRangeQueryRequestParser}, * %-encoded version. * @throws Exception */ public void testPathPrefixdateRangeEncoded() throws Exception { { WaybackRequest wbr = parse("/web/20100101%2D20100531%2A/http://www.yahoo.com/*"); assertNotNull(wbr); assertTrue(wbr.isUrlQueryRequest()); assertEquals("20100101000000", wbr.getStartTimestamp()); assertEquals("20100531235959", wbr.getEndTimestamp()); assertEquals("http://www.yahoo.com/", wbr.getRequestUrl()); } { // URL part shall not be URL-decoded WaybackRequest wbr = parse("/web/20100101%2D20100531%2A/http%3a//www.yahoo.com/%2A"); assertNotNull(wbr); assertTrue(wbr.isCaptureQueryRequest()); assertEquals("20100101000000", wbr.getStartTimestamp()); assertEquals("20100531235959", wbr.getEndTimestamp()); // WaybackRequet#setRequestUrl() prepends "http://" if urlStr does // not begin with http:// assertEquals("http://http%3a//www.yahoo.com/%2A", wbr.getRequestUrl()); } } protected void checkPathDateless(WaybackRequest wbr, String requestUrl) { assertNotNull(wbr); assertTrue(wbr.isReplayRequest()); assertTrue(wbr.isBestLatestReplayRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr.getStartTimestamp()); assertEquals(EXPECTED_END_TIMESTAMP, wbr.getEndTimestamp()); assertEquals(requestUrl, wbr.getRequestUrl()); assertNotNull(wbr.getReplayDate()); assertNotNull(wbr.getAnchorDate()); } /** * test of {@link DatelessReplayRequestParser}. * <p>It also reads Replay/AchorDate from Accept-Date/Accept-Timestamp * HTTP headers (Accept-Date is part of Memento protocol). This test is * included here, even though it has some Memento-related code, because * core part of processing is for Archival-URL.</p> * <p>One notable difference from with-timestamp request is that * {@link WaybackRequest#isBestLatestReplayRequest} is set to true, which used * in several places for unclear purpose. This flag is not set in other * RequestParser's, even if request is asking for the best latest capture. * Probably flag's semantics is slightly different from what its name suggests.</p> * <p>As this pattern of requests come from URL that escaped Archival-URL * rewriting process, it runs extra check on it. Test includes a few negative cases * for non-URL paths.</p> * @throws Exception */ public void testPathDateless() throws Exception { { WaybackRequest wbr = parse("/web/http://www.yahoo.com/"); checkPathDateless(wbr, "http://www.yahoo.com/"); } { WaybackRequest wbr = parse("/web/https://www.yahoo.com/"); checkPathDateless(wbr, "https://www.yahoo.com/"); } { WaybackRequest wbr = parse("/web/http://www.yahoo.com:8080/"); checkPathDateless(wbr, "http://www.yahoo.com:8080/"); } // some client canonicalizes "//" in path into "/". // (why this isn't done for other patterns of requests?) { WaybackRequest wbr = parse("/web/http:/www.yahoo.com/"); checkPathDateless(wbr, "http://www.yahoo.com/"); } // doesn't repair "https:/" { WaybackRequest wbr = parse("/web/https:/www.yahoo.com/"); //checkPathDateless(wbr, "https://www.yahoo.com/"); assertNull(wbr); } // doesn't repair "ftp:/" either. { WaybackRequest wbr = parse("/web/ftp:/www.yahoo.com/afile"); assertNull(wbr); } // scheme-relative - results in NullPointerException FIXME { try { WaybackRequest wbr = parse("/web///www.yahoo.com/"); assertNull(wbr); } catch (NullPointerException ex) { // current behavior - FIXME. } } // regular case. { WaybackRequest wbr = parse("/web/www.yahoo.com/"); checkPathDateless(wbr, "http://www.yahoo.com/"); } // scheme-less URL with user info is rejected // TODO: why is this rejected? { try { @SuppressWarnings("unused") WaybackRequest wbr = parse("/web/user@www.yahoo.com/"); fail("BadQueryException was not thrown"); } catch (BadQueryException ex) { // expected; } } // but it's accepted with scheme. // TODO: should this be rejected as well? { WaybackRequest wbr = parse("/web/http://user@www.yahoo.com/"); checkPathDateless(wbr, "http://user@www.yahoo.com/"); } // just make sure path and query parts in requestUrl are preserved. { WaybackRequest wbr = parse("/web/www.yahoo.com/apis?v=2"); checkPathDateless(wbr, "http://www.yahoo.com/apis?v=2"); } // doesn't look like an URL. { WaybackRequest wbr = parse("/web/images/foo.gif"); assertNull(wbr); } { WaybackRequest wbr = parse("/web/handler.php?url=http://www.yahoo.com/"); assertNull(wbr); } // TODO: shouldn't this be parsed as dateless URL-Query? { WaybackRequest wbr = parse("/web/http://www.yahoo.com/*"); checkPathDateless(wbr, "http://www.yahoo.com/*"); } // ditto { WaybackRequest wbr = parse("/web/www.yahoo.com/*"); checkPathDateless(wbr, "http://www.yahoo.com/*"); } } public void testPathDatelessWithDateHeader() throws Exception { final String dateHeader = "Thu, 24 Apr 2014 21:15:51 UTC+00:00"; final Date date = (new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss z", Locale.ENGLISH)).parse(dateHeader); { acceptDatetimeHeader = dateHeader; WaybackRequest wbr = parse("/web/http://www.yahoo.com/"); assertNotNull(wbr); assertTrue(wbr.isReplayRequest()); assertTrue(wbr.isMementoTimegate()); assertFalse(wbr.isBestLatestReplayRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr.getStartTimestamp()); assertEquals(EXPECTED_END_TIMESTAMP, wbr.getEndTimestamp()); assertEquals(date, wbr.getReplayDate()); assertEquals(date, wbr.getAnchorDate()); } // invalid Accept-Datetime header { acceptDatetimeHeader = "invalid date"; try { @SuppressWarnings("unused") WaybackRequest wbr = parse("/web/http://www.yahoo.com/"); fail("did not throw exception"); } catch (TimeGateBadQueryException ex) { // expected } } // alternative Accept-Timestamp header. as long as it is valid, // invalid value in Accept-Datetime header doesn't cause exception. { acceptDatetimeHeader = "invalid date"; acceptTimestampHeader = "20140424211551"; WaybackRequest wbr = parse("/web/http://www.yahoo.com/"); assertNotNull(wbr); assertTrue(wbr.isReplayRequest()); assertFalse(wbr.isBestLatestReplayRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr.getStartTimestamp()); assertEquals(EXPECTED_END_TIMESTAMP, wbr.getEndTimestamp()); assertEquals(date, wbr.getReplayDate()); assertEquals(date, wbr.getAnchorDate()); } // invalid value in Accept-Timestamp header is silently ignored, // unless Accept-Datetime also has an invalid value. { acceptDatetimeHeader = null; acceptTimestampHeader = "*INVALID*"; WaybackRequest wbr = parse("/web/http://www.yahoo.com/"); assertNotNull(wbr); assertTrue(wbr.isReplayRequest()); assertTrue(wbr.isBestLatestReplayRequest()); assertEquals(EXPECTED_START_TIMESTAMP, wbr.getStartTimestamp()); assertEquals(EXPECTED_END_TIMESTAMP, wbr.getEndTimestamp()); } } /** * some pathological cases. * @throws Exception */ public void testPathological() throws Exception { { WaybackRequest wbr = parse("/web/20100101*30/http://www.yahoo.com/?p=*"); assertNull(wbr); } { WaybackRequest wbr = parse("/web/*20100101*/http://www.yahoo.com/"); assertNull(wbr); } { WaybackRequest wbr = parse("/web/20100101*im_/http://www.yahoo.com/a.png"); assertNull(wbr); } // TODO: should we accept this? { WaybackRequest wbr = parse("/web//20100101*/http://www.yahoo.com/"); assertNull(wbr); } } /** * tests for {@link TimeMapRequestParser} * @throws Exception */ public void testTimeMapRequest() throws Exception { { WaybackRequest wbr = parse("/web/timemap/link/http://www.yahoo.com/"); assertNotNull(wbr); assertTrue(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); assertEquals("format", "link", wbr.getMementoTimemapFormat()); assertEquals("requestUrl", "http://www.yahoo.com/", wbr.getRequestUrl()); } { WaybackRequest wbr = parse("/web/timemap/link/www.yahoo.com"); assertNotNull(wbr); assertTrue(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); assertEquals("format", "link", wbr.getMementoTimemapFormat()); // WaybackRequest.setRequestUrl() adds missing "http://". Similarly // http:/www.yahoo.com will be fixed to "http://www.yahoo.com". assertEquals("requestUrl", "http://www.yahoo.com", wbr.getRequestUrl()); } { String url = "http://www.yahoo.com"; String urlp = URLEncoder.encode(url, "UTF-8"); WaybackRequest wbr = parse("/web/timemap/link?url=" + urlp); assertNotNull(wbr); assertTrue(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); // FIXME: this is current behavior. shouldn't this be "link"? assertEquals("format", "link?url=" + urlp, wbr.getMementoTimemapFormat()); assertEquals("requestUrl", url, wbr.getRequestUrl()); } { String url = "http://www.yahoo.com/"; String urlp = URLEncoder.encode(url, "UTF-8"); WaybackRequest wbr = parse("/web/timemap/?url=" + urlp); assertNotNull(wbr); assertTrue(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); // FIXME: again, this is current behavior. value should be "", which shall be // interpreted as default value. assertEquals("format", "?url=" + urlp, wbr.getMementoTimemapFormat()); assertEquals("requestUrl", url, wbr.getRequestUrl()); } { WaybackRequest wbr = parse("/web/timemap?url=" + URLEncoder.encode("http://www.yahoo.com/", "UTF-8")); assertNotNull(wbr); // FIXME: This is current behavior. As format is null, isMementoTimemapRequest() returns false, // renders calendar view. This looks inconsistent with /web/timemap/?url=... pattern above. assertFalse(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); assertEquals("format", null, wbr.getMementoTimemapFormat()); assertEquals("requestUrl", "http://www.yahoo.com/", wbr.getRequestUrl()); } { String url = "http://www.yahoo.com"; String urlp = URLEncoder.encode(url, "UTF-8"); WaybackRequest wbr = parse("/web/timemap/link/?url=" + urlp); assertNotNull(wbr); assertTrue(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); assertEquals("format", "link", wbr.getMementoTimemapFormat()); // FIXME: this is current behavior. requestUrl gets bad value, url // parameter gets ignored. most likely results in empty results. // Note WaybackRequest.setRequestURI() prepends "http://". assertEquals("requestUrl", "http://?url=" + urlp, wbr.getRequestUrl()); //assertEquals("requestUrl", url, wbr.getRequestUrl()); } { WaybackRequest wbr = parse("/web/timemap?url=" + URLEncoder.encode("http://www.yahoo.com/", "UTF-8") + "&output=link"); assertNotNull(wbr); assertTrue(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); assertEquals("format", "link", wbr.getMementoTimemapFormat()); assertEquals("requestUrl", "http://www.yahoo.com/", wbr.getRequestUrl()); } { String url = "http://www.yahoo.com"; String urlp = URLEncoder.encode(url, "UTF-8"); WaybackRequest wbr = parse("/web/timemap/?url=" + urlp + "&output=link"); assertNotNull(wbr); assertTrue(wbr.isMementoTimemapRequest()); assertTrue(wbr.isCaptureQueryRequest()); // FIXME: this is current behavior. output parameter gets ignored, format gets // unexpected value. url parameter works. assertEquals("format", "?url=" + urlp + "&output=link", wbr.getMementoTimemapFormat()); //assertEquals("format", "link", wbr.getMementoTimemapFormat()); assertEquals("requestUrl", url, wbr.getRequestUrl()); } { WaybackRequest wbr = parse("/web/timemap"); assertNull(wbr); } } }