From: <rb...@us...> - 2013-12-07 20:33:29
|
Revision: 8820 http://sourceforge.net/p/htmlunit/code/8820 Author: rbri Date: 2013-12-07 20:33:26 +0000 (Sat, 07 Dec 2013) Log Message: ----------- next try to fix our cache Issue 1352 Modified Paths: -------------- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/Cache.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/CacheTest.java Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/Cache.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/Cache.java 2013-12-06 18:43:32 UTC (rev 8819) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/Cache.java 2013-12-07 20:33:26 UTC (rev 8820) @@ -55,11 +55,13 @@ */ private static class Entry implements Comparable<Entry>, Serializable { private final String key_; - private final Object value_; + private WebResponse response_; + private Object value_; private long lastAccess_; - Entry(final String key, final Object value) { + Entry(final String key, final WebResponse response, final Object value) { key_ = key; + response_ = response; value_ = value; lastAccess_ = System.currentTimeMillis(); } @@ -97,7 +99,7 @@ public void cacheIfPossible(final WebRequest request, final WebResponse response, final Object toCache) { if (isCacheable(request, response)) { final String url = response.getWebRequest().getUrl().toString(); - final Entry entry = new Entry(url, toCache); + final Entry entry = new Entry(url, response, toCache); entries_.put(entry.key_, entry); deleteOverflow(); } @@ -115,7 +117,7 @@ * @param styleSheet the parsed version of <tt>css</tt> */ public void cache(final String css, final CSSStyleSheet styleSheet) { - final Entry entry = new Entry(css, styleSheet); + final Entry entry = new Entry(css, null, styleSheet); entries_.put(entry.key_, entry); deleteOverflow(); } @@ -202,6 +204,27 @@ } /** + * Returns the cached resonse corresponding to the specified request. If there is + * no corresponding cached object, this method returns <tt>null</tt>. + * + * @param request the request whose corresponding response is sought + * @return the cached response corresponding to the specified request if any + */ + public WebResponse getCachedResponse(final WebRequest request) { + if (HttpMethod.GET != request.getHttpMethod()) { + return null; + } + final Entry cachedEntry = entries_.get(request.getUrl().toString()); + if (cachedEntry == null) { + return null; + } + synchronized (entries_) { + cachedEntry.touch(); + } + return cachedEntry.response_; + } + + /** * Returns the cached object corresponding to the specified request. If there is * no corresponding cached object, this method returns <tt>null</tt>. * Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java 2013-12-06 18:43:32 UTC (rev 8819) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/WebClient.java 2013-12-07 20:33:26 UTC (rev 8820) @@ -1271,10 +1271,10 @@ addDefaultHeaders(webRequest); // Retrieve the response, either from the cache or from the server. - final Object fromCache = getCache().getCachedObject(webRequest); + final WebResponse fromCache = getCache().getCachedResponse(webRequest); final WebResponse webResponse; - if (fromCache != null && fromCache instanceof WebResponse) { - webResponse = new WebResponseFromCache((WebResponse) fromCache, webRequest); + if (fromCache != null) { + webResponse = new WebResponseFromCache(fromCache, webRequest); } else { try { @@ -1283,7 +1283,7 @@ catch (final NoHttpResponseException e) { return new WebResponse(responseDataNoHttpResponse_, webRequest, 0); } - getCache().cacheIfPossible(webRequest, webResponse, webResponse); + getCache().cacheIfPossible(webRequest, webResponse, null); } // Continue according to the HTTP status code. Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java 2013-12-06 18:43:32 UTC (rev 8819) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/html/HtmlPage.java 2013-12-07 20:33:26 UTC (rev 8820) @@ -1094,12 +1094,18 @@ request.setAdditionalHeader("Referer", referringRequest.getUrl().toString()); request.setAdditionalHeader("Accept", client.getBrowserVersion().getScriptAcceptHeader()); + // our cache is a bit strange; + // loadWebResponse check the cache for the web response + // AND also fixes the request url for the following cache lookups + final WebResponse response = client.loadWebResponse(request); + + // now we can look into the cache with the fixed request for + // a cached script final Object cachedScript = cache.getCachedObject(request); if (cachedScript instanceof Script) { return (Script) cachedScript; } - final WebResponse response = client.loadWebResponse(request); client.printContentIfNecessary(response); client.throwFailingHttpStatusCodeExceptionIfNecessary(response); @@ -1148,6 +1154,7 @@ final JavaScriptEngine javaScriptEngine = client.getJavaScriptEngine(); final Script script = javaScriptEngine.compile(this, scriptCode, url.toExternalForm(), 1); if (script != null) { + // cache the script cache.cacheIfPossible(request, response, script); } Modified: trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java =================================================================== --- trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java 2013-12-06 18:43:32 UTC (rev 8819) +++ trunk/htmlunit/src/main/java/com/gargoylesoftware/htmlunit/javascript/host/css/CSSStyleSheet.java 2013-12-07 20:33:26 UTC (rev 8820) @@ -305,14 +305,20 @@ request.setAdditionalHeader("Referer", referer); } - uri = request.getUrl().toExternalForm(); + // our cache is a bit strange; + // loadWebResponse check the cache for the web response + // AND also fixes the request url for the following cache lookups + final WebResponse response = client.loadWebResponse(request); + + // now we can look into the cache with the fixed request for + // a cached script final Cache cache = client.getCache(); final Object fromCache = cache.getCachedObject(request); if (fromCache != null && fromCache instanceof org.w3c.dom.css.CSSStyleSheet) { + uri = request.getUrl().toExternalForm(); sheet = new CSSStyleSheet(element, (org.w3c.dom.css.CSSStyleSheet) fromCache, uri); } else { - final WebResponse response = client.loadWebResponse(request); uri = response.getWebRequest().getUrl().toExternalForm(); client.printContentIfNecessary(response); client.throwFailingHttpStatusCodeExceptionIfNecessary(response); @@ -321,6 +327,7 @@ source.setByteStream(response.getContentAsStream()); source.setEncoding(response.getContentCharset()); sheet = new CSSStyleSheet(element, source, uri); + // cache the style sheet cache.cacheIfPossible(request, response, sheet.getWrappedSheet()); response.cleanUp(); } Modified: trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/CacheTest.java =================================================================== --- trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/CacheTest.java 2013-12-06 18:43:32 UTC (rev 8819) +++ trunk/htmlunit/src/test/java/com/gargoylesoftware/htmlunit/CacheTest.java 2013-12-07 20:33:26 UTC (rev 8820) @@ -31,9 +31,7 @@ import org.junit.runner.RunWith; import com.gargoylesoftware.htmlunit.BrowserRunner.Alerts; -import com.gargoylesoftware.htmlunit.BrowserRunner.Browser; import com.gargoylesoftware.htmlunit.BrowserRunner.Browsers; -import com.gargoylesoftware.htmlunit.BrowserRunner.NotYetImplemented; import com.gargoylesoftware.htmlunit.html.HtmlPage; import com.gargoylesoftware.htmlunit.util.NameValuePair; @@ -140,8 +138,7 @@ *@throws Exception if the test fails */ @Test - @NotYetImplemented(Browser.FF) - public void usageUrlEncoded() throws Exception { + public void jsUrlEncoded() throws Exception { final String content = "<html>\n" + "<head>\n" + " <title>page 1</title>\n" @@ -198,6 +195,76 @@ *@throws Exception if the test fails */ @Test + public void cssUrlEncoded() throws Exception { + final String content = "<html>\n" + + "<head>\n" + + " <title>page 1</title>\n" + + " <link href='foo1.css' type='text/css' rel='stylesheet'>\n" + + " <link href='foo2.js?foo[1]=bar/baz' type='text/css' rel='stylesheet'>\n" + + "</head>\n" + + "<body>\n" + + " <a href='page2.html'>to page 2</a>\n" + + " <script>\n" + + " var sheets = document.styleSheets;\n" + + " alert(sheets.length);\n" + + " var rules = sheets[0].cssRules || sheets[0].rules;\n" + + " alert(rules.length);\n" + + " rules = sheets[1].cssRules || sheets[1].rules;\n" + + " alert(rules.length);\n" + + " </script>\n" + " </body>\n" + + "</body>\n" + + "</html>"; + + final String content2 = "<html>\n2" + + "<head>\n" + + " <title>page 2</title>\n" + + " <link href='foo2.js?foo[1]=bar/baz' type='text/css' rel='stylesheet'>\n" + + "</head>\n" + + "<body>\n" + + " <a href='page1.html'>to page 1</a>\n" + + " <script>\n" + + " var sheets = document.styleSheets;\n" + + " alert(sheets.length);\n" + + " var rules = sheets[0].cssRules || sheets[0].rules;\n" + + " alert(rules.length);\n" + + " </script>\n" + " </body>\n" + + "</body>\n" + + "</html>"; + + final URL urlPage1 = new URL(URL_FIRST, "page1.html"); + getMockWebConnection().setResponse(urlPage1, content); + final URL urlPage2 = new URL(URL_FIRST, "page2.html"); + getMockWebConnection().setResponse(urlPage2, content2); + + final List<NameValuePair> headers = new ArrayList<NameValuePair>(); + headers.add(new NameValuePair("Last-Modified", "Sun, 15 Jul 2007 20:46:27 GMT")); + getMockWebConnection().setResponse(new URL(URL_FIRST, "foo1.js"), "", + 200, "ok", "text/css", headers); + getMockWebConnection().setDefaultResponse("", 200, "ok", "text/css", headers); + + final WebClient webClient = getWebClientWithMockWebConnection(); + + final List<String> collectedAlerts = new ArrayList<String>(); + webClient.setAlertHandler(new CollectingAlertHandler(collectedAlerts)); + + final HtmlPage page1 = webClient.getPage(urlPage1); + final String[] expectedAlerts = {"2", "0", "0"}; + assertEquals(expectedAlerts, collectedAlerts); + assertEquals(3, getMockWebConnection().getRequestCount()); + + collectedAlerts.clear(); + page1.getAnchors().get(0).click(); + + assertEquals(new String[] {"1", "0"}, collectedAlerts); + assertEquals(4, getMockWebConnection().getRequestCount()); + assertEquals("no request for scripts should have been performed", + urlPage2, getMockWebConnection().getLastWebRequest().getUrl()); + } + + /** + *@throws Exception if the test fails + */ + @Test public void maxSizeMaintained() throws Exception { final String html = "<html><head><title>page 1</title>\n" + "<script src='foo1.js' type='text/javascript'/>\n" |