diff --git a/VERSION.txt b/VERSION.txt index 64373dc8c17..5b686062831 100644 --- a/VERSION.txt +++ b/VERSION.txt @@ -1,4 +1,17 @@ -jetty-7.6.0-SNAPSHOT +jetty-8.1.0-SNAPSHOT + +jetty-8.1.0.RC0 - 30 November 2011 + + 352565 cookie httponly flag ignored + + 353285 ServletSecurity annotation ignored + + 357163 jetty 8 ought to proxy jetty8 javadocs + + 357209 JSP tag listeners not called + + 360051 SocketConnectionTest.testServerClosedConnection is excluded. + + 361135 Allow session cookies to NEVER be marked as secure, even on HTTPS + requests. + + 362249 update shell scripts to jetty8 + + 363878 Add ecj compiler to jetty-8 for jsp + + 364283 can't parse the servlet multipart-config for the web.xml + + 364430 Support web.xml enabled state for servlets jetty-7.6.0.RC0 - 29 November 2011 + Refactored NIO layer for better half close handling @@ -30,6 +43,22 @@ jetty-7.6.0.RC0 - 29 November 2011 + 364657 Support HTTP only cookies from standard API + JETTY-1442 add _hostHeader setter for ProxyRule +jetty-8.0.4.v20111024 - 24 October 2011 + + 358263 JDBCSessionIdManager add setDatasource(DataSource) method + + 358649 Replace existing StdErrLog system properties for DEBUG/IGNORED with + LEVEL instead. + + 360836 Accept parameters with bad UTF-8. Use replacement character + + 360912 CrossOriginFilter does not send Access-Control-Allow-Origin on + responses. 355103 Make allowCredentials default to true in + CrossOriginFilter. + + 360938 Connections closed after a while. + + 361135 secure cookies for sessions + + 361319 Log initialization does not catch correct exceptions on all jvms + + 361325 359292 Allow KeyStore to be set + + 361456 release timer task on connection failed + + 361655 ExecutorThreadPool.isLowOnThreads() returns wrong value. + + JETTY-1444 start threadpool before selector manager + jetty-7.5.4.v20111024 - 24 October 2011 + 358263 JDBCSessionIdManager add setDatasource(DataSource) method + 358649 Replace existing StdErrLog system properties for DEBUG/IGNORED with @@ -45,12 +74,12 @@ jetty-7.5.4.v20111024 - 24 October 2011 + 361655 ExecutorThreadPool.isLowOnThreads() returns wrong value. + JETTY-1444 start threadpool before selector manager -jetty-7.5.3.v20111011 - 11 October 2011 +jetty-8.0.3.v20111011 - 11 October 2011 + 348978 migrate jetty-http-spi + 358649 StdErrLog system properties for package/class logging LEVEL. -jetty-7.5.2.v20111006 - 06 October 2011 - + 336443 check nonce count is increasing +jetty-8.0.2.v20111006 - 06 October 2011 + + 336443 add missing comma in DigestAuthenticator string + 342161 ScannerTest fails intermittently on Mac OS X + 346419 testing HttpClient FDs + 353267 Request._parameters initialization bug @@ -58,8 +87,10 @@ jetty-7.5.2.v20111006 - 06 October 2011 + 353627 Basic Auth checks that Basic method has been send + 356144 Allow SelectorManager thread priority to be set + 356274 Start SSL socket factory in call to open() + + 357163 jetty 8 ought to proxy jetty8 javadocs + 357178 websockets draft 14 support + 357188 Send content buffer directly + + 357209 JSP tag listeners not called + 357216 Logging via Log4J does not expand braces in format strings + 357240 more half close refinements + 357338 remove debug @@ -99,6 +130,73 @@ jetty-7.5.2.v20111006 - 06 October 2011 + JETTY-1434 Add a jsp that exercises jstl. + JETTY-1439 space in directory installation path causes classloader problem +jetty-7.5.3.v20111011 - 11 October 2011 + + 348978 migrate jetty-http-spi + + 358649 StdErrLog system properties for package/class logging LEVEL. + +jetty-7.5.2.v20111006 - 06 October 2011 + + 336443 check nonce count is increasing + + 342161 ScannerTest fails intermittently on Mac OS X + + 346419 testing HttpClient FDs + + 353267 Request._parameters initialization bug + + 353509 jetty-client unit tests are running too long + + 353627 Basic Auth checks that Basic method has been send + + 356144 Allow SelectorManager thread priority to be set + + 356274 Start SSL socket factory in call to open() + + 357178 websockets draft 14 support + + 357188 Send content buffer directly + + 357209 JSP tag listeners not called + + 357216 Logging via Log4J does not expand braces in format strings + + 357240 more half close refinements + + 357338 remove debug + + 357672 resolve issue with serializing pojos with mongodb session manager, + thanks to john simone for the discovery and fix + + 357959 Include javadoc in distribution + + 358027 NullPointerException in ResourceHandler with jetty-stylesheet.css + + 358035 idle time only active if > 0 + + 358147 Add catch for UnknownHostException to fix leaky file descriptor in + client + + 358164 Dispatch from servlet to handler + + 358263 add method for osgi users to register a driver as Class.forName does + not work for them + + 358649 StdErrLog system properties for package/class logging LEVEL. + + 358674 Still allows sslv3 for now + + 358687 Updated jsp does not scan for system tlds Fixed pattern. + + 358784 JSP broken on Java 1.5 + + 358925 bit more javadoc on usage + + 358959 File descriptor leak with UnresolvedAddressException + + 359309 adjust previous test for servletPath to include pathInfo + + 359673 updated websocket version handling + + 359675 Principal != String, fix for issue in property file login manager + + 360051 SocketConnectionTest.testServerClosedConnection is excluded. + + 360066 jsps referenced in web.xml elements do not compile + + JETTY-1130 Access Sessions from HashSessionIdManager + + JETTY-1277 Fixed sendRedirect encoding of relative locations + + JETTY-1322 idle sweeper checks for closed endp + + JETTY-1377 extra logging for busy selector + + JETTY-1378 new sys property for the latest jsp-impl to force the use of the + JDTCompiler when running in OSGi. + + JETTY-1414 applied to PropertyUserStore + + JETTY-1415 Start/Stop Server and Client only once in test, code format + + JETTY-1420 Set Host header for new request in RedirectListener + + JETTY-1421 Implement RedirectListener.onException,onConnectionFailed + + JETTY-1423 force connection to be closed returned + + JETTY-1430 local JNDI contexts don't carry environment + + JETTY-1434 Add a jsp that exercises jstl. + + JETTY-1439 space in directory installation path causes classloader problem + +jetty-8.0.1.v20110908 - 08 September 2011 + + 350634 Added Resource.newResource(File) + + 356190 fix monodb tests for changed test api + + 356428 removed timed waits from test + + 356693 reduce visibility to webapp of websocket implementations + + 356695 jetty server jars are provided for websockets + + 356726 Instead of the sessionDestroyed called sessionCreated after + invalidate session + + 356751 Add null protection to ServletContextHandler.doStop + + 356823 correctly decode close codes. Send not utf-8 close code. + + 357058 Acceptor thread blocking + jetty-7.5.1.v20110908 - 08 September 2011 + 350634 Added Resource.newResource(File) + 356190 fix monodb tests for changed test api @@ -111,6 +209,12 @@ jetty-7.5.1.v20110908 - 08 September 2011 + 356823 correctly decode close codes. Send not utf-8 close code. + 357058 Acceptor thread blocking +jetty-8.0.0.v20110901 - 01 September 2011 + + 352565 cookie httponly flag ignored + + 353073 better warnings + + 353285 ServletSecurity annotation ignored + + 356421 Upgraded websocket to draft 13 support + jetty-7.5.0.v20110901 - 01 September 2011 + 356421 Upgraded websocket to draft 13 support + 353073 better warnings @@ -145,6 +249,19 @@ jetty-7.5.0.RC1 - 19 August 2011 + JETTY-1414 HashLoginService doesn't refresh realm if specified config filename is not an absolute platform specific value +jetty-8.0.0.RC0 - 16 August 2011 + + Merge from jetty-7.4.3 + + Enable annotations by default + + 352565 cookie httponly flag ignored + + 353285 ServletSecurity annotation ignored + +jetty-8.0.0.M3 - 27 May 2011 + + 324505 Implement API login + + 335500 request.getParts() throws a NullPointerException + + 343472 isUserInRole does not prevent subsequent login call. + + 346180 jsp-2.2 support + + Updated to jetty-7.4.2.v20110526 + jetty-7.5.0.RC0 - 15 August 2011 + 298502 Handle 200 Connect responses with no content-length + 347484 / - > ${/} in some paths in grant codebases @@ -327,6 +444,26 @@ jetty-7.4.0.RC0 + Ensure generated fragment names are unique + Added extra session removal test +jetty-8.0.0.M2 - 16 November 2010 + + 320073 Reconsile configuration mechanism + + 321068 JSF2 fails to initialize + + 324493 Registration init parameter handling null check, setInitParameters + additive + + 324505 Request.login method must throw ServletException if it cant login + + 324872 allow disabling listener restriction from using *Registration + interfaces + + 327416 Change meaning of @HandlesTypes in line with latest interpretation by + JSR315 + + 327489 Change meaning of @MultipartConfig to match servlet spec 3.0 + maintenance release 3.0a + + 328008 Handle update to Servlet Spec 3 Section 8.2.3.h.ii + + 330188 Reject web-fragment.xml with same as another already loaded + one + + 330208 Support new wording on servlet-mapping and filter-mapping merging + from servlet3.0a + + 330292 request.getParts() returns only one part when the name is the same + + Update to jetty-7.2.1.v20101111 + jetty-7.3.1.v20110307 - 07 March 2011 + 316382 Support a more strict SSL option with certificates + 333481 Handle UCS-4 codepoints in decode and encode @@ -352,9 +489,7 @@ jetty-7.3.1.v20110307 - 07 March 2011 + 338068 Leaking ConstraintMappings on redeploy + 338092 ProxyServlet leaks memory + 338607 Removed managed attributes when context is stopped - + 338880 Fixed failing buffer range checks - + 338920 Handle non existent real path directories - + 338961 AJP packet size + + 338819 Externally control Deployment Manager application lifecycle + JETTY-1304 Allow quoted boundaries in Multipart filter + JETTY-1317 More elegent handling of bad URIs in requests + JETTY-1331 Allow alternate XML configuration processors (eg spring) @@ -540,7 +675,6 @@ jetty-7.2.0.RC0 - 01 October 2010 + JETTY-1245 Do not use direct buffers with NIO SSL + JETTY-1249 Apply max idle time to all connectors + JETTY-1250 Parallel start of HandlerCollection - + JETTY-1252 Handle more multipart transfer encodings + JETTY-1256 annotation and jta jars from Orbit + JETTY-1259 NullPointerException in JDBCSessionIdManager when invalidating session @@ -568,6 +702,15 @@ jetty-7.1.6.v20100715 + JETTY-1249 Apply max idle time to all connectors + JETTY-1251 Replace then close selector for JVM bugs +jetty-8.0.0.M1 - 12 July 2010 + + 306350 Ensure jars excluded by ordering are not scanned for annotations + + JETTY-1224 Change jetty-8 merge rules for fragment descriptors and + annotations + + Ensure in web.xml overrides relative in + fragments + + Ensure empty implies exclusion of all fragments + + Ensure servlet-api jar class inheritance hierarchy is scanned + jetty-7.1.5.v20100705 + Update ecj to 3.6 Helios release drop + 288194 Add blacklist/whitelist to ProxyServlet and ProxyHandler @@ -731,6 +874,9 @@ jetty-7.1.0.RC0 - 27 April 2010 + Fix jetty-plus.xml reference to addLifeCycle + JETTY-1200 SSL NIO Endpoint wraps non NIO buffers + JETTY-1202 Use platform default algorithm for SecureRandom + + Merged 7.0.2.v20100331 + + Add NPE protection to ContainerInitializerConfiguration + + Temporarily remove jetty-osgi module to clarify jsp version compatibility + JETTY-1212 handle long content lengths + JETTY-1214 avoid ISE when scavenging invalid session + JETTY-903 Stop both caches @@ -877,9 +1023,18 @@ jetty-7.0.2.RC0 + Added IPAccessHandler + Updated Servlet3Continuation to final 3.0.20100224 + 305997 Coalesce buffers in ChannelEndPoint.flush() - + 306028 Enable TCP_NODELAY by default in client connectors + + 306028 Enable TCP_NODELAY by default in client connectors <<<<<<< HEAD + +jetty-8.0.0.M0 - 28 February 2010 + + Updated servlet 3.0 spec 20100224 + + Merged 7.0.1.v20091116 + + Updated to cometd 1.0.1 jetty-7.0.1.v20091125 - 25 November 2009 + + ======= + +jetty-7.0.1.v20091125 - 25 November 2009 + + >>>>>>> origin/master + 274251 DefaultServlet supports exact match mode. + 288401 HttpExchange.cancel() Method Unimplemented + 289027 deobfuscate HttpClient SSL passwords diff --git a/example-async-rest/async-rest-jar/pom.xml b/example-async-rest/async-rest-jar/pom.xml new file mode 100644 index 00000000000..de9e6e8e334 --- /dev/null +++ b/example-async-rest/async-rest-jar/pom.xml @@ -0,0 +1,24 @@ + + + org.eclipse.jetty + example-async-rest + 8.1.0-SNAPSHOT + + 4.0.0 + org.eclipse.jetty.example-async-rest + example-async-rest-jar + jar + Example Async Rest :: Jar + + + org.eclipse.jetty + jetty-client + ${project.version} + + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + provided + + + diff --git a/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java new file mode 100644 index 00000000000..c71f80067a1 --- /dev/null +++ b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AbstractRestServlet.java @@ -0,0 +1,116 @@ +//======================================================================== +//Copyright 2004-2008 Mort Bay Consulting Pty. Ltd. +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package org.eclipse.jetty.example.asyncrest; + +import java.io.IOException; +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.net.URLEncoder; +import java.util.Map; +import java.util.Queue; + +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * Abstract Servlet implementation class AsyncRESTServlet. + * Enquires ebay REST service for auctions by key word. + * May be configured with init parameters:
+ *
appid
The eBay application ID to use
+ *
+ * Each request examines the following request parameters:
+ *
items
The keyword to search for
+ *
+ */ +public class AbstractRestServlet extends HttpServlet +{ + protected final static String __DEFAULT_APPID = "Webtide81-adf4-4f0a-ad58-d91e41bbe85"; + protected final static String STYLE = + ""; + + protected final static String ITEMS_PARAM = "items"; + protected final static String APPID_PARAM = "appid"; + + protected String _appid; + + public void init(ServletConfig servletConfig) throws ServletException + { + if (servletConfig.getInitParameter(APPID_PARAM) == null) + _appid = __DEFAULT_APPID; + else + _appid = servletConfig.getInitParameter(APPID_PARAM); + } + + protected String restURL(String item) + { + try + { + return ("http://open.api.ebay.com/shopping?MaxEntries=3&appid=" + _appid + + "&version=573&siteid=0&callname=FindItems&responseencoding=JSON&QueryKeywords=" + + URLEncoder.encode(item,"UTF-8")); + } + catch(Exception e) + { + throw new RuntimeException(e); + } + } + + protected String generateThumbs(Queue> results) + { + StringBuilder thumbs = new StringBuilder(); + for (Map m : results) + { + if (!m.containsKey("GalleryURL")) + continue; + + thumbs.append(""); + thumbs.append(""); + thumbs.append(" "); + } + return thumbs.toString(); + } + + protected String ms(long nano) + { + BigDecimal dec = new BigDecimal(nano); + return dec.divide(new BigDecimal(1000000L)).setScale(1,RoundingMode.UP).toString(); + } + + protected int width(long nano) + { + int w=(int)((nano+999999L)/5000000L); + if (w==0) + w=2; + return w; + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + doGet(request, response); + } + +} diff --git a/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java new file mode 100644 index 00000000000..2380a08daaf --- /dev/null +++ b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/AsyncRestServlet.java @@ -0,0 +1,207 @@ +//======================================================================== +//Copyright 2004-2008 Mort Bay Consulting Pty. Ltd. +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package org.eclipse.jetty.example.asyncrest; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Map; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.servlet.AsyncContext; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.client.ContentExchange; +import org.eclipse.jetty.client.HttpClient; +import org.eclipse.jetty.util.ajax.JSON; + +/** + * Servlet implementation class AsyncRESTServlet. + * Enquires ebay REST service for auctions by key word. + * May be configured with init parameters:
+ *
appid
The eBay application ID to use
+ *
+ * Each request examines the following request parameters:
+ *
items
The keyword to search for
+ *
+ */ +public class AsyncRestServlet extends AbstractRestServlet +{ + final static String RESULTS_ATTR = "org.eclipse.jetty.demo.client"; + final static String DURATION_ATTR = "org.eclipse.jetty.demo.duration"; + final static String START_ATTR = "org.eclispe.jetty.demo.start"; + + HttpClient _client; + + public void init(ServletConfig servletConfig) throws ServletException + { + super.init(servletConfig); + + _client = new HttpClient(); + _client.setConnectorType(HttpClient.CONNECTOR_SELECT_CHANNEL); + + try + { + _client.start(); + } + catch (Exception e) + { + throw new ServletException(e); + } + } + + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + Long start=System.nanoTime(); + + // Do we have results yet? + Queue> results = (Queue>) request.getAttribute(RESULTS_ATTR); + + // If no results, this must be the first dispatch, so send the REST request(s) + if (results==null) + { + // define results data structures + final Queue> resultsQueue = new ConcurrentLinkedQueue>(); + request.setAttribute(RESULTS_ATTR, results=resultsQueue); + + // suspend the request + // This is done before scheduling async handling to avoid race of + // dispatch before startAsync! + final AsyncContext async = request.startAsync(); + async.setTimeout(30000); + + // extract keywords to search for + String[] keywords=request.getParameter(ITEMS_PARAM).split(","); + final AtomicInteger outstanding=new AtomicInteger(keywords.length); + + // Send request each keyword + for (final String item:keywords) + { + _client.send( + new AsyncRestRequest(item) + { + void onAuctionFound(Map auction) + { + resultsQueue.add(auction); + } + void onComplete() + { + if (outstanding.decrementAndGet()<=0) + async.dispatch(); + } + }); + } + + // save timing info and return + request.setAttribute(START_ATTR, start); + request.setAttribute(DURATION_ATTR, new Long(System.nanoTime() - start)); + + return; + } + + // We have results! + + // Generate the response + String thumbs = generateThumbs(results); + + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.println(""); + out.println(STYLE); + out.println(""); + + long initial = (Long) request.getAttribute(DURATION_ATTR); + long start0 = (Long) request.getAttribute(START_ATTR); + + long now = System.nanoTime(); + long total=now-start0; + long generate=now-start; + long thread=initial+generate; + + out.print("Asynchronous: "+request.getParameter(ITEMS_PARAM)+"
"); + out.print("Total Time: "+ms(total)+"ms
"); + + out.print("Thread held (red): "+ms(thread)+"ms (" + ms(initial) + " initial + " + ms(generate) + " generate )
"); + out.print("Async wait (green): "+ms(total-thread)+"ms
"); + + out.println(""+ + ""+ + ""); + + out.println("
"); + out.println(thumbs); + out.println("
"); + out.println(""); + out.close(); + } + + private abstract class AsyncRestRequest extends ContentExchange + { + AsyncRestRequest(final String item) + { + // send the exchange + setMethod("GET"); + setURL(restURL(item)); + } + + abstract void onAuctionFound(Map details); + abstract void onComplete(); + + protected void onResponseComplete() throws IOException + { + // extract auctions from the results + Map query = (Map) JSON.parse(this.getResponseContent()); + Object[] auctions = (Object[]) query.get("Item"); + if (auctions != null) + { + for (Object o : auctions) + onAuctionFound((Map)o); + } + + onComplete(); + } + + /* ------------------------------------------------------------ */ + protected void onConnectionFailed(Throwable ex) + { + getServletContext().log("onConnectionFailed: ",ex); + onComplete(); + } + + /* ------------------------------------------------------------ */ + protected void onException(Throwable ex) + { + getServletContext().log("onConnectionFailed: ",ex); + onComplete(); + } + + /* ------------------------------------------------------------ */ + protected void onExpire() + { + getServletContext().log("onConnectionFailed: expired"); + onComplete(); + } + } + + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + doGet(request, response); + } + +} diff --git a/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java new file mode 100644 index 00000000000..07e8158943c --- /dev/null +++ b/example-async-rest/async-rest-jar/src/main/java/org/eclipse/jetty/example/asyncrest/SerialRestServlet.java @@ -0,0 +1,102 @@ +//======================================================================== +//Copyright 2004-2008 Mort Bay Consulting Pty. Ltd. +//------------------------------------------------------------------------ +//Licensed under the Apache License, Version 2.0 (the "License"); +//you may not use this file except in compliance with the License. +//You may obtain a copy of the License at +//http://www.apache.org/licenses/LICENSE-2.0 +//Unless required by applicable law or agreed to in writing, software +//distributed under the License is distributed on an "AS IS" BASIS, +//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +//See the License for the specific language governing permissions and +//limitations under the License. +//======================================================================== + +package org.eclipse.jetty.example.asyncrest; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.LinkedList; +import java.util.Map; +import java.util.Queue; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.eclipse.jetty.util.ajax.JSON; + +/** + * Servlet implementation class SerialRestServlet + */ +public class SerialRestServlet extends AbstractRestServlet +{ + protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + long start = System.nanoTime(); + + + String[] keywords=request.getParameter(ITEMS_PARAM).split(","); + Queue> results = new LinkedList>(); + + // make all requests serially + for (String itemName : keywords) + { + URL url = new URL(restURL(itemName)); + + HttpURLConnection connection = (HttpURLConnection)url.openConnection(); + connection.setRequestMethod("GET"); + + Map query = (Map)JSON.parse(new BufferedReader(new InputStreamReader(connection.getInputStream()))); + Object[] auctions = (Object[]) query.get("Item"); + if (auctions != null) + { + for (Object o : auctions) + results.add((Map) o); + } + } + + + // Generate the response + String thumbs=generateThumbs(results); + + response.setContentType("text/html"); + PrintWriter out = response.getWriter(); + out.println(""); + out.println(STYLE); + out.println(""); + + long now = System.nanoTime(); + long total=now-start; + + out.print("Blocking: "+request.getParameter(ITEMS_PARAM)+"
"); + out.print("Total Time: "+ms(total)+"ms
"); + out.print("Thread held (red): "+ms(total)+"ms
"); + + out.println(""); + + out.println("
"); + out.println(thumbs); + out.println("
"); + out.println(""); + out.close(); + + + + } + + /** + * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse + * response) + */ + protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException + { + doGet(request, response); + } + +} diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest.html b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest.html new file mode 100644 index 00000000000..f92f7f661d4 --- /dev/null +++ b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest.html @@ -0,0 +1,38 @@ + + + + + +

Blocking vs Asynchronous REST

+

+This demo calls the EBay WS API both synchronously and asynchronously, +to obtain items matching each of the keywords passed on the query +string. The time the request thread is head is displayed for both. +

+ + + + + + + + + + + + + +
+ + + +
+ + + +
+ + diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/green.png b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/green.png new file mode 100644 index 00000000000..d0fb8420c5d Binary files /dev/null and b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/green.png differ diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/red.png b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/red.png new file mode 100644 index 00000000000..f2a79a07fbc Binary files /dev/null and b/example-async-rest/async-rest-jar/src/main/resources/META-INF/resources/asyncrest/red.png differ diff --git a/example-async-rest/async-rest-jar/src/main/resources/META-INF/web-fragment.xml b/example-async-rest/async-rest-jar/src/main/resources/META-INF/web-fragment.xml new file mode 100644 index 00000000000..9876d9983bf --- /dev/null +++ b/example-async-rest/async-rest-jar/src/main/resources/META-INF/web-fragment.xml @@ -0,0 +1,22 @@ + + + SerialRestServlet + SerialRestServlet + org.eclipse.jetty.example.asyncrest.SerialRestServlet + + + SerialRestServlet + /testSerial + + + + AsyncRestServlet + AsyncRestServlet + org.eclipse.jetty.example.asyncrest.AsyncRestServlet + true + + + AsyncRestServlet + /testAsync + + \ No newline at end of file diff --git a/example-async-rest/async-rest-webapp/pom.xml b/example-async-rest/async-rest-webapp/pom.xml new file mode 100644 index 00000000000..92a80085cec --- /dev/null +++ b/example-async-rest/async-rest-webapp/pom.xml @@ -0,0 +1,33 @@ + + + org.eclipse.jetty + example-async-rest + 8.1.0-SNAPSHOT + + 4.0.0 + org.eclipse.jetty.example-async-rest + example-async-rest-webapp + war + Example Async Rest :: Webapp + + async-rest + + + + org.eclipse.jetty.example-async-rest + example-async-rest-jar + ${project.version} + + + org.eclipse.jetty + jetty-webapp + ${project.version} + test + + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + provided + + + diff --git a/example-async-rest/async-rest-webapp/src/main/webapp/META-INF/MANIFEST.MF b/example-async-rest/async-rest-webapp/src/main/webapp/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..5e9495128c0 --- /dev/null +++ b/example-async-rest/async-rest-webapp/src/main/webapp/META-INF/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: + diff --git a/example-async-rest/async-rest-webapp/src/main/webapp/WEB-INF/web.xml b/example-async-rest/async-rest-webapp/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..8916bdb6afa --- /dev/null +++ b/example-async-rest/async-rest-webapp/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,9 @@ + + + + Async REST Webservice Example + + diff --git a/example-async-rest/async-rest-webapp/src/main/webapp/index.html b/example-async-rest/async-rest-webapp/src/main/webapp/index.html new file mode 100644 index 00000000000..f92f7f661d4 --- /dev/null +++ b/example-async-rest/async-rest-webapp/src/main/webapp/index.html @@ -0,0 +1,38 @@ + + + + + +

Blocking vs Asynchronous REST

+

+This demo calls the EBay WS API both synchronously and asynchronously, +to obtain items matching each of the keywords passed on the query +string. The time the request thread is head is displayed for both. +

+ + + + + + + + + + + + + +
+ + + +
+ + + +
+ + diff --git a/example-async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java b/example-async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java new file mode 100644 index 00000000000..c3b5e751753 --- /dev/null +++ b/example-async-rest/async-rest-webapp/src/test/java/org/eclipse/jetty/example/asyncrest/DemoServer.java @@ -0,0 +1,30 @@ +package org.eclipse.jetty.example.asyncrest; + +import org.eclipse.jetty.server.Connector; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.nio.SelectChannelConnector; +import org.eclipse.jetty.webapp.WebAppContext; + +public class DemoServer +{ + public static void main(String[] args) + throws Exception + { + String jetty_home = System.getProperty("jetty.home","."); + + Server server = new Server(); + + Connector connector=new SelectChannelConnector(); + connector.setPort(Integer.getInteger("jetty.port",8080).intValue()); + server.setConnectors(new Connector[]{connector}); + + WebAppContext webapp = new WebAppContext(); + webapp.setContextPath("/"); + webapp.setWar(jetty_home+"/target/example-async-rest-webapp-8.0.0.M0-SNAPSHOT"); + + server.setHandler(webapp); + + server.start(); + server.join(); + } +} diff --git a/example-async-rest/pom.xml b/example-async-rest/pom.xml new file mode 100644 index 00000000000..4e9fabfbc24 --- /dev/null +++ b/example-async-rest/pom.xml @@ -0,0 +1,16 @@ + + + org.eclipse.jetty + jetty-project + 8.1.0-SNAPSHOT + + 4.0.0 + org.eclipse.jetty + example-async-rest + pom + Example Async Rest + + async-rest-jar + async-rest-webapp + + diff --git a/example-jetty-embedded/pom.xml b/example-jetty-embedded/pom.xml index 3eb95b0ea27..1e87f41f8c6 100644 --- a/example-jetty-embedded/pom.xml +++ b/example-jetty-embedded/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 example-jetty-embedded diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java index 899c682bc08..3f133c5d44e 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/LikeJettyXml.java @@ -135,7 +135,7 @@ public class LikeJettyXml webapp_provider.setDefaultsDescriptor(jetty_home + "/etc/webdefault.xml"); webapp_provider.setContextXmlDir(jetty_home + "/contexts"); deployer.addAppProvider(webapp_provider); - + HashLoginService login = new HashLoginService(); login.setName("Test Realm"); login.setConfig(jetty_home + "/etc/realm.properties"); diff --git a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java index 919b4f40a80..079ed2f154a 100644 --- a/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java +++ b/example-jetty-embedded/src/main/java/org/eclipse/jetty/embedded/ManyContexts.java @@ -69,5 +69,4 @@ public class ManyContexts System.err.println(server.dump()); server.join(); } - } diff --git a/jetty-aggregate/jetty-all-server/pom.xml b/jetty-aggregate/jetty-all-server/pom.xml index 072ff23321e..9add0c35961 100644 --- a/jetty-aggregate/jetty-all-server/pom.xml +++ b/jetty-aggregate/jetty-all-server/pom.xml @@ -2,9 +2,10 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 + org.eclipse.jetty.aggregate jetty-all-server Jetty :: Aggregate :: All Server @@ -135,9 +136,9 @@ provided - javax.servlet - servlet-api - compile + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + ${servlet.spec.version} org.eclipse.jetty diff --git a/jetty-aggregate/jetty-all/pom.xml b/jetty-aggregate/jetty-all/pom.xml index 3a6eee3ac51..c2be5589583 100644 --- a/jetty-aggregate/jetty-all/pom.xml +++ b/jetty-aggregate/jetty-all/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-all @@ -103,12 +103,8 @@ provided - org.mortbay.jetty - servlet-api - - - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} @@ -119,8 +115,8 @@ provided - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} compile @@ -136,8 +132,8 @@ provided - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} org.apache.geronimo.specs @@ -205,6 +201,11 @@ ${project.version} provided + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + compile + org.eclipse.jetty jetty-nested diff --git a/jetty-aggregate/jetty-client/pom.xml b/jetty-aggregate/jetty-client/pom.xml index e30ee5b160a..5dacc662cb3 100644 --- a/jetty-aggregate/jetty-client/pom.xml +++ b/jetty-aggregate/jetty-client/pom.xml @@ -2,9 +2,10 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 + org.eclipse.jetty.aggregate jetty-client Jetty :: Aggregate :: HTTP Client diff --git a/jetty-aggregate/jetty-plus/pom.xml b/jetty-aggregate/jetty-plus/pom.xml index ff9bf1f74c9..2aa7e809ecc 100644 --- a/jetty-aggregate/jetty-plus/pom.xml +++ b/jetty-aggregate/jetty-plus/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-plus @@ -85,8 +85,8 @@ provided - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} org.apache.geronimo.specs @@ -103,9 +103,10 @@ - javax.servlet - servlet-api - compile + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + ${servlet.spec.version} + compile org.apache.geronimo.specs diff --git a/jetty-aggregate/jetty-server/pom.xml b/jetty-aggregate/jetty-server/pom.xml index 8d3cdddcb2f..6fd8fe28204 100644 --- a/jetty-aggregate/jetty-server/pom.xml +++ b/jetty-aggregate/jetty-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-server @@ -85,21 +85,20 @@ provided - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + org.eclipse.jetty jetty-websocket ${project.version} provided - - javax.servlet - servlet-api - compile - diff --git a/jetty-aggregate/jetty-servlet/pom.xml b/jetty-aggregate/jetty-servlet/pom.xml index 2e4f9bd47ee..71de4606341 100644 --- a/jetty-aggregate/jetty-servlet/pom.xml +++ b/jetty-aggregate/jetty-servlet/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-servlet @@ -85,16 +85,15 @@ provided - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} - - javax.servlet - servlet-api - compile - + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + org.eclipse.jetty jetty-websocket diff --git a/jetty-aggregate/jetty-webapp/pom.xml b/jetty-aggregate/jetty-webapp/pom.xml index 47090b07d8f..5b3c9c5372e 100644 --- a/jetty-aggregate/jetty-webapp/pom.xml +++ b/jetty-aggregate/jetty-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.aggregate jetty-aggregate-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-webapp @@ -85,15 +85,15 @@ provided - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} - - javax.servlet - servlet-api - compile - + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + compile + diff --git a/jetty-aggregate/pom.xml b/jetty-aggregate/pom.xml index 41d2d360551..dc3954e38d5 100644 --- a/jetty-aggregate/pom.xml +++ b/jetty-aggregate/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT org.eclipse.jetty.aggregate jetty-aggregate-project diff --git a/jetty-ajp/pom.xml b/jetty-ajp/pom.xml index c02155bea81..31523119e34 100644 --- a/jetty-ajp/pom.xml +++ b/jetty-ajp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-ajp diff --git a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java index 37ff45fac6c..3632b291844 100644 --- a/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java +++ b/jetty-ajp/src/main/java/org/eclipse/jetty/ajp/Ajp13SocketConnector.java @@ -36,10 +36,10 @@ public class Ajp13SocketConnector extends SocketConnector static boolean __allowShutdown = false; public Ajp13SocketConnector() { - super.setRequestHeaderSize(Ajp13Packet.MAX_PACKET_SIZE); - super.setResponseHeaderSize(Ajp13Packet.MAX_PACKET_SIZE); - super.setRequestBufferSize(Ajp13Packet.MAX_PACKET_SIZE); - super.setResponseBufferSize(Ajp13Packet.MAX_PACKET_SIZE); + super.setRequestHeaderSize(Ajp13Packet.MAX_DATA_SIZE); + super.setResponseHeaderSize(Ajp13Packet.MAX_DATA_SIZE); + super.setRequestBufferSize(Ajp13Packet.MAX_DATA_SIZE); + super.setResponseBufferSize(Ajp13Packet.MAX_DATA_SIZE); // IN AJP protocol the socket stay open, so // by default the time out is set to 0 seconds super.setMaxIdleTime(0); diff --git a/jetty-annotations/pom.xml b/jetty-annotations/pom.xml index a4b6c219f44..84a2a00bf2c 100644 --- a/jetty-annotations/pom.xml +++ b/jetty-annotations/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-annotations @@ -13,6 +13,23 @@ + + org.apache.maven.plugins + maven-assembly-plugin + + + package + + single + + + + config + + + + + org.apache.felix maven-bundle-plugin @@ -25,7 +42,7 @@ - javax.servlet.*;version="[2.5,3.0)",* + javax.servlet.*;version="3.0",* diff --git a/jetty-annotations/src/main/config/etc/jetty-annotations.xml b/jetty-annotations/src/main/config/etc/jetty-annotations.xml new file mode 100644 index 00000000000..7aa719d7ca6 --- /dev/null +++ b/jetty-annotations/src/main/config/etc/jetty-annotations.xml @@ -0,0 +1,23 @@ + + + + + + + + + + org.eclipse.jetty.webapp.configuration + + + org.eclipse.jetty.webapp.WebInfConfiguration + org.eclipse.jetty.webapp.WebXmlConfiguration + org.eclipse.jetty.webapp.MetaInfConfiguration + org.eclipse.jetty.webapp.FragmentConfiguration + org.eclipse.jetty.annotations.AnnotationConfiguration + org.eclipse.jetty.webapp.JettyWebXmlConfiguration + + + + + diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java index bb04460c503..dc5bea6cb7e 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationConfiguration.java @@ -13,8 +13,32 @@ package org.eclipse.jetty.annotations; +import java.net.URI; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.ServiceLoader; +import java.util.Set; + +import javax.servlet.ServletContainerInitializer; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.annotation.HandlesTypes; + + +import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; +import org.eclipse.jetty.plus.annotation.ContainerInitializer; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.Configuration; import org.eclipse.jetty.webapp.AbstractConfiguration; +import org.eclipse.jetty.webapp.Descriptor; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.FragmentDescriptor; +import org.eclipse.jetty.webapp.MetaDataComplete; import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.WebDescriptor; /** * Configuration for Annotations @@ -23,15 +47,401 @@ import org.eclipse.jetty.webapp.WebAppContext; */ public class AnnotationConfiguration extends AbstractConfiguration { + private static final Logger LOG = Log.getLogger(AnnotationConfiguration.class); + public static final String CLASS_INHERITANCE_MAP = "org.eclipse.jetty.classInheritanceMap"; + public static final String CONTAINER_INITIALIZERS = "org.eclipse.jetty.containerInitializers"; + + + public void preConfigure(final WebAppContext context) throws Exception + { + } + @Override public void configure(WebAppContext context) throws Exception - { + { + boolean metadataComplete = context.getMetaData().isMetaDataComplete(); context.addDecorator(new AnnotationDecorator(context)); + + + //Even if metadata is complete, we still need to scan for ServletContainerInitializers - if there are any + AnnotationParser parser = null; + if (!metadataComplete) + { + //If metadata isn't complete, if this is a servlet 3 webapp or isConfigDiscovered is true, we need to search for annotations + if (context.getServletContext().getEffectiveMajorVersion() >= 3 || context.isConfigurationDiscovered()) + { + parser = createAnnotationParser(); + parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", new WebServletAnnotationHandler(context)); + parser.registerAnnotationHandler("javax.servlet.annotation.WebFilter", new WebFilterAnnotationHandler(context)); + parser.registerAnnotationHandler("javax.servlet.annotation.WebListener", new WebListenerAnnotationHandler(context)); + } + } + else + if (LOG.isDebugEnabled()) LOG.debug("Metadata-complete==true, not processing discoverable servlet annotations for context "+context); + + + + //Regardless of metadata, if there are any ServletContainerInitializers with @HandlesTypes, then we need to scan all the + //classes so we can call their onStartup() methods correctly + List nonExcludedInitializers = getNonExcludedInitializers(context); + parser = registerServletContainerInitializerAnnotationHandlers(context, parser, nonExcludedInitializers); + + if (parser != null) + { + if (LOG.isDebugEnabled()) LOG.debug("Scanning all classses for annotations: webxmlVersion="+context.getServletContext().getEffectiveMajorVersion()+" configurationDiscovered="+context.isConfigurationDiscovered()); + parseContainerPath(context, parser); + //email from Rajiv Mordani jsrs 315 7 April 2010 + // If there is a then the ordering should be + // WEB-INF/classes the order of the declared elements + others. + // In case there is no others then it is + // WEB-INF/classes + order of the elements. + parseWebInfClasses(context, parser); + parseWebInfLib (context, parser); + } } - + + + + /** + * @return a new AnnotationParser. This method can be overridden to use a different impleemntation of + * the AnnotationParser. Note that this is considered internal API. + */ + protected AnnotationParser createAnnotationParser() + { + return new AnnotationParser(); + } + @Override public void cloneConfigure(WebAppContext template, WebAppContext context) throws Exception { context.addDecorator(new AnnotationDecorator(context)); } + + + + + public AnnotationParser registerServletContainerInitializerAnnotationHandlers (WebAppContext context, AnnotationParser parser, List scis) + throws Exception + { + + //TODO verify my interpretation of the spec. That is, that metadata-complete has nothing + //to do with finding the ServletContainerInitializers, classes designated to be of interest to them, + //or even calling them on startup. + + //Get all ServletContainerInitializers, and check them for HandlesTypes annotations. + //For each class in the HandlesTypes value, if it IS an annotation, register a handler + //that will record the classes that have that annotation. + //If it is NOT an annotation, then we will interrogate the type hierarchy discovered during + //parsing later on to find the applicable classes. + + if (scis == null || scis.isEmpty()) + return parser; // nothing to do + + ServletContainerInitializerListener listener = new ServletContainerInitializerListener(); + listener.setWebAppContext(context); + context.addEventListener(listener); + + //may need to add a listener + + ArrayList initializers = new ArrayList(); + context.setAttribute(CONTAINER_INITIALIZERS, initializers); + + for (ServletContainerInitializer service : scis) + { + HandlesTypes annotation = service.getClass().getAnnotation(HandlesTypes.class); + ContainerInitializer initializer = new ContainerInitializer(); + initializer.setTarget(service); + initializers.add(initializer); + if (annotation != null) + { + //There is a HandlesTypes annotation on the on the ServletContainerInitializer + Class[] classes = annotation.value(); + if (classes != null) + { + initializer.setInterestedTypes(classes); + + //We need to create a parser if we haven't already + if (parser == null) + parser = createAnnotationParser(); + + //If we haven't already done so, we need to register a handler that will + //process the whole class hierarchy + if (context.getAttribute(CLASS_INHERITANCE_MAP) == null) + { + ClassInheritanceHandler classHandler = new ClassInheritanceHandler(); + context.setAttribute(CLASS_INHERITANCE_MAP, classHandler.getMap()); + parser.registerClassHandler(classHandler); + } + + for (Class c: classes) + { + //The value of one of the HandlesTypes classes is actually an Annotation itself so + //register a handler for it + if (c.isAnnotation()) + { + if (LOG.isDebugEnabled()) LOG.debug("Registering annotation handler for "+c.getName()); + + parser.registerAnnotationHandler(c.getName(), new ContainerInitializerAnnotationHandler(initializer, c)); + } + } + } + else + if (LOG.isDebugEnabled()) LOG.debug("No classes in HandlesTypes on initializer "+service.getClass()); + } + else + if (LOG.isDebugEnabled()) LOG.debug("No annotation on initializer "+service.getClass()); + } + + //return the parser in case we lazily created it + return parser; + } + + + + + + + /** + * Check to see if the ServletContainerIntializer loaded via the ServiceLoader came + * from a jar that is excluded by the fragment ordering. See ServletSpec 3.0 p.85. + * @param orderedJars + * @param service + * @return + */ + public boolean isFromExcludedJar (WebAppContext context, ServletContainerInitializer service) + throws Exception + { + List orderedJars = context.getMetaData().getOrderedWebInfJars(); + + //If no ordering, nothing is excluded + if (context.getMetaData().getOrdering() == null) + return false; + + //there is an ordering, but there are no jars resulting from the ordering, everything excluded + if (orderedJars.isEmpty()) + return true; + + String loadingJarName = Thread.currentThread().getContextClassLoader().getResource(service.getClass().getName().replace('.','/')+".class").toString(); + + int i = loadingJarName.indexOf(".jar"); + if (i < 0) + return false; //not from a jar therefore not from WEB-INF so not excludable + + loadingJarName = loadingJarName.substring(0,i+4); + loadingJarName = (loadingJarName.startsWith("jar:")?loadingJarName.substring(4):loadingJarName); + URI loadingJarURI = Resource.newResource(loadingJarName).getURI(); + boolean found = false; + Iterator itor = orderedJars.iterator(); + while (!found && itor.hasNext()) + { + Resource r = itor.next(); + found = r.getURI().equals(loadingJarURI); + } + + return !found; + } + + + + public List getNonExcludedInitializers (WebAppContext context) + throws Exception + { + List nonExcludedInitializers = new ArrayList(); + + //We use the ServiceLoader mechanism to find the ServletContainerInitializer classes to inspect + ServiceLoader loadedInitializers = ServiceLoader.load(ServletContainerInitializer.class, context.getClassLoader()); + + if (loadedInitializers != null) + { + for (ServletContainerInitializer service : loadedInitializers) + { + if (!isFromExcludedJar(context, service)) + nonExcludedInitializers.add(service); + } + } + return nonExcludedInitializers; + } + + + + + public void parseContainerPath (final WebAppContext context, final AnnotationParser parser) + throws Exception + { + //if no pattern for the container path is defined, then by default scan NOTHING + LOG.debug("Scanning container jars"); + + //clear any previously discovered annotations + clearAnnotationList(parser.getAnnotationHandlers()); + + //Convert from Resource to URI + ArrayList containerUris = new ArrayList(); + for (Resource r : context.getMetaData().getOrderedContainerJars()) + { + URI uri = r.getURI(); + containerUris.add(uri); + } + + parser.parse (containerUris.toArray(new URI[containerUris.size()]), + new ClassNameResolver () + { + public boolean isExcluded (String name) + { + if (context.isSystemClass(name)) return false; + if (context.isServerClass(name)) return true; + return false; + } + + public boolean shouldOverride (String name) + { + //looking at system classpath + if (context.isParentLoaderPriority()) + return true; + return false; + } + }); + + //gather together all annotations discovered + List annotations = new ArrayList(); + gatherAnnotations(annotations, parser.getAnnotationHandlers()); + + context.getMetaData().addDiscoveredAnnotations(annotations); + } + + + public void parseWebInfLib (final WebAppContext context, final AnnotationParser parser) + throws Exception + { + List frags = context.getMetaData().getFragments(); + + //email from Rajiv Mordani jsrs 315 7 April 2010 + //jars that do not have a web-fragment.xml are still considered fragments + //they have to participate in the ordering + ArrayList webInfUris = new ArrayList(); + + List jars = context.getMetaData().getOrderedWebInfJars(); + + //No ordering just use the jars in any order + if (jars == null || jars.isEmpty()) + jars = context.getMetaData().getWebInfJars(); + + for (Resource r : jars) + { + //clear any previously discovered annotations from handlers + clearAnnotationList(parser.getAnnotationHandlers()); + + + URI uri = r.getURI(); + FragmentDescriptor f = getFragmentFromJar(r, frags); + + //if a jar has no web-fragment.xml we scan it (because it is not exluded by the ordering) + //or if it has a fragment we scan it if it is not metadata complete + if (f == null || !isMetaDataComplete(f)) + { + parser.parse(uri, + new ClassNameResolver() + { + public boolean isExcluded (String name) + { + if (context.isSystemClass(name)) return true; + if (context.isServerClass(name)) return false; + return false; + } + + public boolean shouldOverride (String name) + { + //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? + if (context.isParentLoaderPriority()) + return false; + return true; + } + }); + List annotations = new ArrayList(); + gatherAnnotations(annotations, parser.getAnnotationHandlers()); + context.getMetaData().addDiscoveredAnnotations(r, annotations); + } + } + } + + public void parseWebInfClasses (final WebAppContext context, final AnnotationParser parser) + throws Exception + { + LOG.debug("Scanning classes in WEB-INF/classes"); + if (context.getWebInf() != null) + { + Resource classesDir = context.getWebInf().addPath("classes/"); + if (classesDir.exists()) + { + clearAnnotationList(parser.getAnnotationHandlers()); + parser.parse(classesDir, + new ClassNameResolver() + { + public boolean isExcluded (String name) + { + if (context.isSystemClass(name)) return true; + if (context.isServerClass(name)) return false; + return false; + } + + public boolean shouldOverride (String name) + { + //looking at webapp classpath, found already-parsed class of same name - did it come from system or duplicate in webapp? + if (context.isParentLoaderPriority()) + return false; + return true; + } + }); + + //TODO - where to set the annotations discovered from WEB-INF/classes? + List annotations = new ArrayList(); + gatherAnnotations(annotations, parser.getAnnotationHandlers()); + context.getMetaData().addDiscoveredAnnotations (annotations); + } + } + } + + + + public FragmentDescriptor getFragmentFromJar (Resource jar, List frags) + throws Exception + { + //check if the jar has a web-fragment.xml + FragmentDescriptor d = null; + for (FragmentDescriptor frag: frags) + { + Resource fragResource = frag.getResource(); //eg jar:file:///a/b/c/foo.jar!/META-INF/web-fragment.xml + if (Resource.isContainedIn(fragResource,jar)) + { + d = frag; + break; + } + } + return d; + } + + public boolean isMetaDataComplete (WebDescriptor d) + { + return (d!=null && d.getMetaDataComplete() == MetaDataComplete.True); + } + + protected void clearAnnotationList (List handlers) + { + if (handlers == null) + return; + + for (DiscoverableAnnotationHandler h:handlers) + { + if (h instanceof AbstractDiscoverableAnnotationHandler) + ((AbstractDiscoverableAnnotationHandler)h).resetList(); + } + } + + protected void gatherAnnotations (List annotations, List handlers) + { + for (DiscoverableAnnotationHandler h:handlers) + { + if (h instanceof AbstractDiscoverableAnnotationHandler) + annotations.addAll(((AbstractDiscoverableAnnotationHandler)h).getAnnotationList()); + } + } } diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java index 25b7546d5f8..0b0df258ef7 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationDecorator.java @@ -45,6 +45,8 @@ public class AnnotationDecorator implements Decorator _introspector.registerHandler(new PostConstructAnnotationHandler(context)); _introspector.registerHandler(new PreDestroyAnnotationHandler(context)); _introspector.registerHandler(new DeclareRolesAnnotationHandler(context)); + _introspector.registerHandler(new MultiPartConfigAnnotationHandler(context)); + _introspector.registerHandler(new ServletSecurityAnnotationHandler(context)); } /* ------------------------------------------------------------ */ diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java index 84a8c00954a..1709acd3831 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/AnnotationParser.java @@ -639,10 +639,11 @@ public class AnnotationParser parse(uris, resolver); } - private void scanClass (InputStream is) + protected void scanClass (InputStream is) throws IOException { ClassReader reader = new ClassReader(is); reader.accept(new MyClassVisitor(), ClassReader.SKIP_CODE|ClassReader.SKIP_DEBUG|ClassReader.SKIP_FRAMES); } } + diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java new file mode 100644 index 00000000000..6b38163c8e7 --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ContainerInitializerAnnotationHandler.java @@ -0,0 +1,67 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + + +package org.eclipse.jetty.annotations; + +import java.util.List; + +import javax.servlet.annotation.HandlesTypes; + +import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; +import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.eclipse.jetty.plus.annotation.ContainerInitializer; +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.log.Log; + +/** + * ContainerInitializerAnnotationHandler + * + * Discovers classes that contain the specified annotation, either at class or + * method level. The specified annotation is derived from an @HandlesTypes on + * a ServletContainerInitializer class. + */ +public class ContainerInitializerAnnotationHandler implements DiscoverableAnnotationHandler +{ + ContainerInitializer _initializer; + Class _annotation; + + public ContainerInitializerAnnotationHandler (ContainerInitializer initializer, Class annotation) + { + _initializer = initializer; + _annotation = annotation; + } + + /** + * Handle finding a class that is annotated with the annotation we were constructed with. + * @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List) + */ + public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotationName, + List values) + { + _initializer.addAnnotatedTypeName(className); + } + + public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, + List values) + { + _initializer.addAnnotatedTypeName(className); + } + + public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + List values) + { + _initializer.addAnnotatedTypeName(className); + } + +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java new file mode 100644 index 00000000000..7a02031352a --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/MultiPartConfigAnnotationHandler.java @@ -0,0 +1,90 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.Servlet; +import javax.servlet.annotation.MultipartConfig; + +import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.webapp.Descriptor; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; + +/** + * MultiPartConfigAnnotationHandler + * + * + */ +public class MultiPartConfigAnnotationHandler extends AbstractIntrospectableAnnotationHandler +{ + protected WebAppContext _context; + + public MultiPartConfigAnnotationHandler(WebAppContext context) + { + //TODO verify that MultipartConfig is not inheritable + super(false); + _context = context; + } + /** + * @see org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler#doHandle(java.lang.Class) + */ + public void doHandle(Class clazz) + { + if (!Servlet.class.isAssignableFrom(clazz)) + return; + + MultipartConfig multi = (MultipartConfig) clazz.getAnnotation(MultipartConfig.class); + if (multi == null) + return; + + MetaData metaData = _context.getMetaData(); + + //TODO: The MultipartConfigElement needs to be set on the ServletHolder's Registration. + //How to identify the correct Servlet? If the Servlet has no WebServlet annotation on it, does it mean that this MultipartConfig + //annotation applies to all declared instances in web.xml/programmatically? + //Assuming TRUE for now. + + ServletHolder holder = getServletHolderForClass(clazz); + if (holder != null) + { + Descriptor d = metaData.getOriginDescriptor(holder.getName()+".servlet.multipart-config"); + //if a descriptor has already set the value for multipart config, do not + //let the annotation override it + if (d == null) + { + metaData.setOrigin(holder.getName()+".servlet.multipart-config"); + holder.getRegistration().setMultipartConfig(new MultipartConfigElement(multi)); + } + } + } + + private ServletHolder getServletHolderForClass (Class clazz) + { + ServletHolder holder = null; + ServletHolder[] holders = _context.getServletHandler().getServlets(); + if (holders != null) + { + for (ServletHolder h : holders) + { + if (h.getClassName().equals(clazz.getName())) + { + holder = h; + } + } + } + return holder; + } +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializerListener.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializerListener.java new file mode 100644 index 00000000000..e3cac47aaa3 --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletContainerInitializerListener.java @@ -0,0 +1,140 @@ +package org.eclipse.jetty.annotations; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.eclipse.jetty.annotations.AnnotationConfiguration; +import org.eclipse.jetty.plus.annotation.ContainerInitializer; +import org.eclipse.jetty.util.MultiMap; +import org.eclipse.jetty.webapp.WebAppContext; + +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +/** + * ServletContainerInitializerListener + * + * + */ +public class ServletContainerInitializerListener implements ServletContextListener +{ + WebAppContext _context = null; + + + public void setWebAppContext (WebAppContext context) + { + _context = context; + } + + /** + * @see javax.servlet.ServletContextListener#contextInitialized(javax.servlet.ServletContextEvent) + */ + public void contextInitialized(ServletContextEvent sce) + { + List initializers = (List)_context.getAttribute(AnnotationConfiguration.CONTAINER_INITIALIZERS); + MultiMap classMap = (MultiMap)_context.getAttribute(AnnotationConfiguration.CLASS_INHERITANCE_MAP); + + if (initializers != null) + { + for (ContainerInitializer i : initializers) + { + //We have already found the classes that directly have an annotation that was in the HandlesTypes + //annotation of the ServletContainerInitializer. For each of those classes, walk the inheritance + //hierarchy to find classes that extend or implement them. + if (i.getAnnotatedTypeNames() != null) + { + Set annotatedClassNames = new HashSet(i.getAnnotatedTypeNames()); + for (String name : annotatedClassNames) + { + //add the class with the annotation + i.addApplicableTypeName(name); + //add the classes that inherit the annotation + if (classMap != null) + { + List implementsOrExtends = (List)classMap.getValues(name); + if (implementsOrExtends != null && !implementsOrExtends.isEmpty()) + addInheritedTypes(classMap, i, implementsOrExtends); + } + } + } + + + //Now we need to look at the HandlesTypes classes that were not annotations. We need to + //find all classes that extend or implement them. + if (i.getInterestedTypes() != null) + { + for (Class c : i.getInterestedTypes()) + { + if (!c.isAnnotation()) + { + //add the classes that implement or extend the class. + //TODO but not including the class itself? + if (classMap != null) + { + List implementsOrExtends = (List)classMap.getValues(c.getName()); + if (implementsOrExtends != null && !implementsOrExtends.isEmpty()) + addInheritedTypes(classMap, i, implementsOrExtends); + } + } + } + } + + //instantiate ServletContainerInitializers, call doStart + try + { + i.callStartup(_context); + } + catch (Exception e) + { + //OK, how do I throw an exception such that it really stops the startup sequence? + e.printStackTrace(); + } + } + + //TODO Email from Jan Luehe 18 August: after all ServletContainerInitializers have been + //called, need to check to see if there are any ServletRegistrations remaining + //that are "preliminary" and fail the deployment if so. + } + + } + + + void addInheritedTypes (MultiMap classMap, ContainerInitializer initializer, List applicableTypes) + { + for (String s : applicableTypes) + { + //add the name of the class that extends or implements + initializer.addApplicableTypeName(s); + + //walk the hierarchy and find all types that extend or implement it + List implementsOrExtends = (List)classMap.getValues(s); + if (implementsOrExtends != null && !implementsOrExtends.isEmpty()) + addInheritedTypes (classMap, initializer, implementsOrExtends); + } + } + + + /** + * @see javax.servlet.ServletContextListener#contextDestroyed(javax.servlet.ServletContextEvent) + */ + public void contextDestroyed(ServletContextEvent sce) + { + // TODO Auto-generated method stub + + } + +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java new file mode 100644 index 00000000000..a439f0df9bc --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/ServletSecurityAnnotationHandler.java @@ -0,0 +1,293 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.annotation.HttpConstraint; +import javax.servlet.annotation.HttpMethodConstraint; +import javax.servlet.annotation.ServletSecurity; +import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; +import javax.servlet.annotation.ServletSecurity.TransportGuarantee; + +import org.eclipse.jetty.annotations.AnnotationIntrospector.AbstractIntrospectableAnnotationHandler; +import org.eclipse.jetty.security.ConstraintAware; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.util.LazyList; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.webapp.WebAppContext; + +/** + * ServletSecurityAnnotationHandler + * + * Inspect a class to see if it has an @ServletSecurity annotation on it, + * setting up the s. + * + * A servlet can be defined in: + *
    + *
  • web.xml + *
  • web-fragment.xml + *
  • @WebServlet annotation discovered + *
  • ServletContext.createServlet + *
+ * + * The ServletSecurity annotation for a servlet should only be processed + * iff metadata-complete == false. + */ +public class ServletSecurityAnnotationHandler extends AbstractIntrospectableAnnotationHandler +{ + private static final Logger LOG = Log.getLogger(ServletSecurityAnnotationHandler.class); + + private WebAppContext _context; + + public ServletSecurityAnnotationHandler(WebAppContext wac) + { + super(false); + _context = wac; + } + + /** + * @see org.eclipse.jetty.annotations.AnnotationIntrospector.IntrospectableAnnotationHandler#handle(java.lang.Class) + */ + public void doHandle(Class clazz) + { + if (!(_context.getSecurityHandler() instanceof ConstraintAware)) + { + LOG.warn("SecurityHandler not ConstraintAware, skipping security annotation processing"); + return; + } + + ServletSecurity servletSecurity = (ServletSecurity)clazz.getAnnotation(ServletSecurity.class); + if (servletSecurity == null) + return; + + //If there are already constraints defined (ie from web.xml or programmatically(?)) that match any + //of the url patterns defined for this servlet, then skip the security annotation. + + List servletMappings = getServletMappings(clazz.getCanonicalName()); + List constraintMappings = ((ConstraintAware)_context.getSecurityHandler()).getConstraintMappings(); + + if (constraintsExist(servletMappings, constraintMappings)) + { + LOG.warn("Constraints already defined for "+clazz.getName()+", skipping ServletSecurity annotation"); + return; + } + + //Make a fresh list + constraintMappings = new ArrayList(); + + //Get the values that form the constraints that will apply unless there are HttpMethodConstraints to augment them + HttpConstraint defaults = servletSecurity.value(); + + //Make a Constraint for the and specified by the HttpConstraint + Constraint defaultConstraint = makeConstraint (clazz, + defaults.rolesAllowed(), + defaults.value(), + defaults.transportGuarantee()); + + constraintMappings.addAll(makeMethodMappings(clazz, + defaultConstraint, + servletMappings, + servletSecurity.httpMethodConstraints())); + + //set up the security constraints produced by the annotation + ConstraintAware securityHandler = (ConstraintAware)_context.getSecurityHandler(); + + for (ConstraintMapping m:constraintMappings) + securityHandler.addConstraintMapping(m); + } + + + + /** + * Make a jetty Constraint object, which represents the and + * elements, based on the security annotation. + * @param servlet + * @param rolesAllowed + * @param permitOrDeny + * @param transport + * @return + */ + protected Constraint makeConstraint (Class servlet, String[] rolesAllowed, EmptyRoleSemantic permitOrDeny, TransportGuarantee transport) + { + Constraint constraint = new Constraint(); + if (rolesAllowed == null || rolesAllowed.length==0) + { + if (permitOrDeny.equals(EmptyRoleSemantic.DENY)) + { + //Equivalent to with no roles + constraint.setName(servlet.getName()+"-Deny"); + constraint.setAuthenticate(true); + } + else + { + //Equivalent to no + constraint.setAuthenticate(false); + constraint.setName(servlet.getName()+"-Permit"); + } + } + else + { + //Equivalent to with list of s + constraint.setAuthenticate(true); + constraint.setRoles(rolesAllowed); + constraint.setName(servlet.getName()+"-RolesAllowed"); + } + + //Equivalent to //CONFIDENTIAL + constraint.setDataConstraint((transport.equals(TransportGuarantee.CONFIDENTIAL)?Constraint.DC_CONFIDENTIAL:Constraint.DC_NONE)); + return constraint; + } + + + /** + * Make a ConstraintMapping which captures the or elements for a particular url pattern, + * and relates it to a Constraint object ( and ). + * @param constraint + * @param url + * @param method + * @param omissions + * @return + */ + protected ConstraintMapping makeConstraintMapping (Constraint constraint, String url, String method, String[] omissions) + { + ConstraintMapping mapping = new ConstraintMapping(); + mapping.setConstraint(constraint); + mapping.setPathSpec(url); + if (method != null) + mapping.setMethod(method); + if (omissions != null) + mapping.setMethodOmissions(omissions); + return mapping; + } + + /** + * Make the Jetty Constraints and ConstraintMapping objects that correspond to the HttpMethodConstraint + * annotations for each url pattern for the servlet. + * @param servlet + * @param defaultConstraint + * @param servletMappings + * @param annotations + * @return + */ + protected List makeMethodMappings (Class servlet, Constraint defaultConstraint, List servletMappings, HttpMethodConstraint[] annotations) + { + List mappings = new ArrayList(); + + //for each url-pattern existing for the servlet make a ConstraintMapping for the HttpConstraint, and ConstraintMappings for + //each HttpMethodConstraint + for (ServletMapping sm : servletMappings) + { + for (String url : sm.getPathSpecs()) + { + //Make a ConstraintMapping that matches the defaultConstraint + ConstraintMapping defaultMapping = makeConstraintMapping(defaultConstraint, url, null, null); + + //If there are HttpMethodConstraint annotations, make a Constraint and a ConstraintMapping for it + if (annotations != null && annotations.length>0) + { + List omissions = new ArrayList(); + + //for each HttpMethodConstraint annotation, make a new Constraint and ConstraintMappings for this url + for (int i=0; i < annotations.length;i++) + { + //Make a Constraint that captures the and elements + Constraint methodConstraint = makeConstraint(servlet, + annotations[i].rolesAllowed(), + annotations[i].emptyRoleSemantic(), + annotations[i].transportGuarantee()); + + //Make ConstraintMapping that captures the elements + ConstraintMapping methodConstraintMapping = makeConstraintMapping (methodConstraint, + url,annotations[i].value(), + null); + mappings.add(methodConstraintMapping); + omissions.add(annotations[i].value()); + } + defaultMapping.setMethodOmissions(omissions.toArray(new String[0])); + } + + //add the constraint mapping containing the http-method-omissions, if there are any + mappings.add(defaultMapping); + } + } + return mappings; + } + + + + /** + * Get the ServletMappings for the servlet's class. + * @param className + * @return + */ + protected List getServletMappings(String className) + { + List results = new ArrayList(); + ServletMapping[] mappings = _context.getServletHandler().getServletMappings(); + for (ServletMapping mapping : mappings) + { + //Check the name of the servlet that this mapping applies to, and then find the ServletHolder for it to find it's class + ServletHolder holder = _context.getServletHandler().getServlet(mapping.getServletName()); + if (holder.getClassName().equals(className)) + results.add(mapping); + } + return results; + } + + + + /** + * Check if there are already elements defined that match the url-patterns for + * the servlet. + * @param servletMappings + * @return + */ + protected boolean constraintsExist (List servletMappings, List constraintMappings) + { + boolean exists = false; + + //Check to see if the path spec on each constraint mapping matches a pathSpec in the servlet mappings. + //If it does, then we should ignore the security annotations. + for (ServletMapping mapping : servletMappings) + { + //Get its url mappings + String[] pathSpecs = mapping.getPathSpecs(); + if (pathSpecs == null) + continue; + + //Check through the constraints to see if there are any whose pathSpecs (url mappings) + //match the servlet. If so, then we already have constraints defined for this servlet, + //and we will not be processing the annotation (ie web.xml or programmatic override). + for (int i=0; constraintMappings != null && i < constraintMappings.size() && !exists; i++) + { + for (int j=0; j < pathSpecs.length; j++) + { + if (pathSpecs[j].equals(constraintMappings.get(i).getPathSpec())) + { + exists = true; + break; + } + } + } + } + return exists; + } + +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java index d1ad40bbf4d..5b394efeb67 100644 --- a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/Util.java @@ -56,7 +56,8 @@ public class Util javax.servlet.ServletRequestListener.class.isAssignableFrom(c) || javax.servlet.ServletRequestAttributeListener.class.isAssignableFrom(c) || javax.servlet.http.HttpSessionListener.class.isAssignableFrom(c) || - javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c)) + javax.servlet.http.HttpSessionAttributeListener.class.isAssignableFrom(c) || + javax.servlet.AsyncListener.class.isAssignableFrom(c)) isServlet=true; diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java new file mode 100644 index 00000000000..e41d9724ccc --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotation.java @@ -0,0 +1,212 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.util.ArrayList; +import java.util.EnumSet; + +import javax.servlet.DispatcherType; +import javax.servlet.Filter; +import javax.servlet.annotation.WebFilter; +import javax.servlet.annotation.WebInitParam; + +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.FilterMapping; +import org.eclipse.jetty.servlet.Holder; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.Origin; + +/** + * WebFilterAnnotation + * + * + */ +public class WebFilterAnnotation extends DiscoveredAnnotation +{ + private static final Logger LOG = Log.getLogger(WebFilterAnnotation.class); + + /** + * @param context + * @param className + */ + public WebFilterAnnotation(WebAppContext context, String className) + { + super(context, className); + } + + /** + * @see org.eclipse.jetty.annotations.ClassAnnotation#apply() + */ + public void apply() + { + // TODO verify against rules for annotation v descriptor + + Class clazz = getTargetClass(); + if (clazz == null) + { + LOG.warn(_className+" cannot be loaded"); + return; + } + + + //Servlet Spec 8.1.2 + if (!Filter.class.isAssignableFrom(clazz)) + { + LOG.warn(clazz.getName()+" is not assignable from javax.servlet.Filter"); + return; + } + MetaData metaData = _context.getMetaData(); + + WebFilter filterAnnotation = (WebFilter)clazz.getAnnotation(WebFilter.class); + + if (filterAnnotation.value().length > 0 && filterAnnotation.urlPatterns().length > 0) + { + LOG.warn(clazz.getName()+" defines both @WebFilter.value and @WebFilter.urlPatterns"); + return; + } + + String name = (filterAnnotation.filterName().equals("")?clazz.getName():filterAnnotation.filterName()); + String[] urlPatterns = filterAnnotation.value(); + if (urlPatterns.length == 0) + urlPatterns = filterAnnotation.urlPatterns(); + + FilterHolder holder = _context.getServletHandler().getFilter(name); + if (holder == null) + { + //Filter with this name does not already exist, so add it + holder = _context.getServletHandler().newFilterHolder(Holder.Source.ANNOTATION); + holder.setName(name); + + holder.setHeldClass(clazz); + metaData.setOrigin(name+".filter.filter-class"); + + holder.setDisplayName(filterAnnotation.displayName()); + metaData.setOrigin(name+".filter.display-name"); + + for (WebInitParam ip: filterAnnotation.initParams()) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(name+".filter.init-param."+ip.name()); + } + + FilterMapping mapping = new FilterMapping(); + mapping.setFilterName(holder.getName()); + + if (urlPatterns.length > 0) + { + ArrayList paths = new ArrayList(); + for (String s:urlPatterns) + { + paths.add(Util.normalizePattern(s)); + } + mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()])); + } + + if (filterAnnotation.servletNames().length > 0) + { + ArrayList names = new ArrayList(); + for (String s : filterAnnotation.servletNames()) + { + names.add(s); + } + mapping.setServletNames((String[])names.toArray(new String[names.size()])); + } + + EnumSet dispatcherSet = EnumSet.noneOf(DispatcherType.class); + for (DispatcherType d : filterAnnotation.dispatcherTypes()) + { + dispatcherSet.add(d); + } + mapping.setDispatcherTypes(dispatcherSet); + metaData.setOrigin(name+".filter.mappings"); + + holder.setAsyncSupported(filterAnnotation.asyncSupported()); + metaData.setOrigin(name+".filter.async-supported"); + + _context.getServletHandler().addFilter(holder); + _context.getServletHandler().addFilterMapping(mapping); + } + else + { + //A Filter definition for the same name already exists from web.xml + //ServletSpec 3.0 p81 if the Filter is already defined and has mappings, + //they override the annotation. If it already has DispatcherType set, that + //also overrides the annotation. Init-params are additive, but web.xml overrides + //init-params of the same name. + for (WebInitParam ip: filterAnnotation.initParams()) + { + //if (holder.getInitParameter(ip.name()) == null) + if (metaData.getOrigin(name+".filter.init-param."+ip.name())==Origin.NotSet) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(name+".filter.init-param."+ip.name()); + } + } + + FilterMapping[] mappings = _context.getServletHandler().getFilterMappings(); + boolean mappingExists = false; + if (mappings != null) + { + for (FilterMapping m:mappings) + { + if (m.getFilterName().equals(name)) + { + mappingExists = true; + break; + } + } + } + //if a descriptor didn't specify at least one mapping, use the mappings from the annotation and the DispatcherTypes + //from the annotation + if (!mappingExists) + { + FilterMapping mapping = new FilterMapping(); + mapping.setFilterName(holder.getName()); + + if (urlPatterns.length > 0) + { + ArrayList paths = new ArrayList(); + for (String s:urlPatterns) + { + paths.add(Util.normalizePattern(s)); + } + mapping.setPathSpecs((String[])paths.toArray(new String[paths.size()])); + } + if (filterAnnotation.servletNames().length > 0) + { + ArrayList names = new ArrayList(); + for (String s : filterAnnotation.servletNames()) + { + names.add(s); + } + mapping.setServletNames((String[])names.toArray(new String[names.size()])); + } + + EnumSet dispatcherSet = EnumSet.noneOf(DispatcherType.class); + for (DispatcherType d : filterAnnotation.dispatcherTypes()) + { + dispatcherSet.add(d); + } + mapping.setDispatcherTypes(dispatcherSet); + _context.getServletHandler().addFilterMapping(mapping); + metaData.setOrigin(name+".filter.mappings"); + } + } + } + +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java new file mode 100644 index 00000000000..e20cbae8d69 --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebFilterAnnotationHandler.java @@ -0,0 +1,58 @@ +// ======================================================================== +// Copyright (c) 2009-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.util.List; + +import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; +import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.WebAppContext; + +/** + * WebFilterAnnotationHandler + * + * + */ +public class WebFilterAnnotationHandler extends AbstractDiscoverableAnnotationHandler +{ + private static final Logger LOG = Log.getLogger(WebFilterAnnotationHandler.class); + + public WebFilterAnnotationHandler (WebAppContext context) + { + super(context); + } + + public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, + List values) + { + WebFilterAnnotation wfAnnotation = new WebFilterAnnotation(_context, className); + addAnnotation(wfAnnotation); + } + + public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, + List values) + { + LOG.warn ("@WebFilter not applicable for fields: "+className+"."+fieldName); + } + + public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + List values) + { + LOG.warn ("@WebFilter not applicable for methods: "+className+"."+methodName+" "+signature); + } + +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java new file mode 100644 index 00000000000..42463093bfa --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotation.java @@ -0,0 +1,85 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import javax.servlet.ServletContextAttributeListener; +import javax.servlet.ServletContextListener; +import javax.servlet.ServletRequestAttributeListener; +import javax.servlet.ServletRequestListener; +import javax.servlet.http.HttpSessionAttributeListener; +import javax.servlet.http.HttpSessionListener; + +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.Origin; + +/** + * WebListenerAnnotation + * + * + */ +public class WebListenerAnnotation extends DiscoveredAnnotation +{ + private static final Logger LOG = Log.getLogger(WebListenerAnnotation.class); + + /** + * @param context + * @param className + */ + public WebListenerAnnotation(WebAppContext context, String className) + { + super(context, className); + } + + /** + * @see org.eclipse.jetty.annotations.ClassAnnotation#apply() + */ + public void apply() + { + // TODO check algorithm against ordering rules for descriptors v annotations + + Class clazz = getTargetClass(); + + if (clazz == null) + { + LOG.warn(_className+" cannot be loaded"); + return; + } + + try + { + if (ServletContextListener.class.isAssignableFrom(clazz) || + ServletContextAttributeListener.class.isAssignableFrom(clazz) || + ServletRequestListener.class.isAssignableFrom(clazz) || + ServletRequestAttributeListener.class.isAssignableFrom(clazz) || + HttpSessionListener.class.isAssignableFrom(clazz) || + HttpSessionAttributeListener.class.isAssignableFrom(clazz)) + { + java.util.EventListener listener = (java.util.EventListener)clazz.newInstance(); + MetaData metaData = _context.getMetaData(); + if (metaData.getOrigin(clazz.getName()+".listener") == Origin.NotSet) + _context.addEventListener(listener); + } + else + LOG.warn(clazz.getName()+" does not implement one of the servlet listener interfaces"); + } + catch (Exception e) + { + LOG.warn(e); + } + } +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java new file mode 100644 index 00000000000..970ee9c7212 --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebListenerAnnotationHandler.java @@ -0,0 +1,53 @@ +// ======================================================================== +// Copyright (c) 2009-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.annotations; + +import java.util.List; + +import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.webapp.WebAppContext; + +public class WebListenerAnnotationHandler extends AbstractDiscoverableAnnotationHandler +{ + private static final Logger LOG = Log.getLogger(WebListenerAnnotationHandler.class); + + public WebListenerAnnotationHandler (WebAppContext context) + { + super(context); + } + + /** + * @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List) + */ + public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotation, + List values) + { + WebListenerAnnotation wlAnnotation = new WebListenerAnnotation(_context, className); + addAnnotation(wlAnnotation); + } + + public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, + List values) + { + LOG.warn ("@WebListener is not applicable to fields: "+className+"."+fieldName); + } + + public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + List values) + { + LOG.warn ("@WebListener is not applicable to methods: "+className+"."+methodName+" "+signature); + } + +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java new file mode 100644 index 00000000000..66861553f01 --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotation.java @@ -0,0 +1,171 @@ +// ======================================================================== +// Copyright (c) 2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.util.ArrayList; + +import javax.servlet.annotation.WebInitParam; +import javax.servlet.annotation.WebServlet; +import javax.servlet.http.HttpServlet; + +import org.eclipse.jetty.servlet.Holder; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.util.LazyList; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.MetaData; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.Origin; + +/** + * WebServletAnnotation + * + * + */ +public class WebServletAnnotation extends DiscoveredAnnotation +{ + private static final Logger LOG = Log.getLogger(WebServletAnnotation.class); + + public WebServletAnnotation (WebAppContext context, String className) + { + super(context, className); + } + + /** + * @see org.eclipse.jetty.annotations.ClassAnnotation#apply() + */ + public void apply() + { + //TODO check this algorithm with new rules for applying descriptors and annotations in order + Class clazz = getTargetClass(); + + if (clazz == null) + { + LOG.warn(_className+" cannot be loaded"); + return; + } + + //Servlet Spec 8.1.1 + if (!HttpServlet.class.isAssignableFrom(clazz)) + { + LOG.warn(clazz.getName()+" is not assignable from javax.servlet.http.HttpServlet"); + return; + } + + WebServlet annotation = (WebServlet)clazz.getAnnotation(WebServlet.class); + + if (annotation.urlPatterns().length > 0 && annotation.value().length > 0) + { + LOG.warn(clazz.getName()+ " defines both @WebServlet.value and @WebServlet.urlPatterns"); + return; + } + + String[] urlPatterns = annotation.value(); + if (urlPatterns.length == 0) + urlPatterns = annotation.urlPatterns(); + + if (urlPatterns.length == 0) + { + LOG.warn(clazz.getName()+ " defines neither @WebServlet.value nor @WebServlet.urlPatterns"); + return; + } + + //canonicalize the patterns + ArrayList urlPatternList = new ArrayList(); + for (String p : urlPatterns) + urlPatternList.add(Util.normalizePattern(p)); + + String servletName = (annotation.name().equals("")?clazz.getName():annotation.name()); + + MetaData metaData = _context.getMetaData(); + + //Find out if a of this type already exists with this name + ServletHolder[] holders = _context.getServletHandler().getServlets(); + boolean isNew = true; + ServletHolder holder = null; + if (holders != null) + { + for (ServletHolder h : holders) + { + if (h.getClassName().equals(clazz.getName()) && h.getName().equals(servletName)) + { + holder = h; + isNew = false; + break; + } + } + } + + if (isNew) + { + //No servlet of this name has already been defined, either by a descriptor + //or another annotation (which would be impossible). + holder = _context.getServletHandler().newServletHolder(Holder.Source.ANNOTATION); + holder.setHeldClass(clazz); + metaData.setOrigin(servletName+".servlet.servlet-class"); + + holder.setName(servletName); + holder.setDisplayName(annotation.displayName()); + metaData.setOrigin(servletName+".servlet.display-name"); + + holder.setInitOrder(annotation.loadOnStartup()); + metaData.setOrigin(servletName+".servlet.load-on-startup"); + + holder.setAsyncSupported(annotation.asyncSupported()); + metaData.setOrigin(servletName+".servlet.async-supported"); + + for (WebInitParam ip:annotation.initParams()) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(servletName+".servlet.init-param."+ip.name()); + } + + _context.getServletHandler().addServlet(holder); + ServletMapping mapping = new ServletMapping(); + mapping.setServletName(holder.getName()); + mapping.setPathSpecs( LazyList.toStringArray(urlPatternList)); + _context.getServletHandler().addServletMapping(mapping); + metaData.setOrigin(servletName+".servlet.mappings"); + } + else + { + //check if the existing servlet has each init-param from the annotation + //if not, add it + for (WebInitParam ip:annotation.initParams()) + { + //if (holder.getInitParameter(ip.name()) == null) + if (metaData.getOrigin(servletName+".servlet.init-param"+ip.name())==Origin.NotSet) + { + holder.setInitParameter(ip.name(), ip.value()); + metaData.setOrigin(servletName+".servlet.init-param."+ip.name()); + } + } + + //check the url-patterns, if there annotation has a new one, add it + ServletMapping[] mappings = _context.getServletHandler().getServletMappings(); + + //ServletSpec 3.0 p81 If a servlet already has url mappings from a + //descriptor the annotation is ignored + if (mappings == null && metaData.getOriginDescriptor(servletName+".servlet.mappings") != null) + { + ServletMapping mapping = new ServletMapping(); + mapping.setServletName(servletName); + mapping.setPathSpecs(LazyList.toStringArray(urlPatternList)); + _context.getServletHandler().addServletMapping(mapping); + } + } + } +} diff --git a/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java new file mode 100644 index 00000000000..89b82a33b0d --- /dev/null +++ b/jetty-annotations/src/main/java/org/eclipse/jetty/annotations/WebServletAnnotationHandler.java @@ -0,0 +1,68 @@ +// ======================================================================== +// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.util.List; + +import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; +import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.eclipse.jetty.util.log.Log; +import org.eclipse.jetty.util.log.Logger; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.WebAppContext; + +/** + * WebServletAnnotationHandler + * + * Process a WebServlet annotation on a class. + * + */ +public class WebServletAnnotationHandler extends AbstractDiscoverableAnnotationHandler +{ + private static final Logger LOG = Log.getLogger(WebServletAnnotationHandler.class); + + public WebServletAnnotationHandler (WebAppContext context) + { + super(context); + } + + + /** + * Handle discovering a WebServlet annotation. + * + * + * @see org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler#handleClass(java.lang.String, int, int, java.lang.String, java.lang.String, java.lang.String[], java.lang.String, java.util.List) + */ + public void handleClass(String className, int version, int access, String signature, String superName, String[] interfaces, String annotationName, + List values) + { + if (!"javax.servlet.annotation.WebServlet".equals(annotationName)) + return; + + WebServletAnnotation annotation = new WebServletAnnotation (_context, className); + addAnnotation(annotation); + } + + public void handleField(String className, String fieldName, int access, String fieldType, String signature, Object value, String annotation, + List values) + { + LOG.warn ("@WebServlet annotation not supported for fields"); + } + + public void handleMethod(String className, String methodName, int access, String params, String signature, String[] exceptions, String annotation, + List values) + { + LOG.warn ("@WebServlet annotation not supported for methods"); + } +} diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java index 4c85ee713ca..a0652322002 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/FilterC.java @@ -18,16 +18,20 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import javax.annotation.Resource; import javax.annotation.security.RunAs; +import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.annotation.WebFilter; +import javax.servlet.annotation.WebInitParam; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +@WebFilter(filterName="CFilter", dispatcherTypes={DispatcherType.REQUEST}, urlPatterns = {"/*"}, initParams={@WebInitParam(name="a", value="99")}, asyncSupported=false) @RunAs("admin") public class FilterC implements Filter { diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java index d839c47c715..29b041a4953 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ListenerC.java @@ -14,7 +14,9 @@ package org.eclipse.jetty.annotations; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; +import javax.servlet.annotation.WebListener; +@WebListener public class ListenerC implements ServletContextListener { diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java index 87cad8bc608..781a4e0715e 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/ServletC.java @@ -20,6 +20,12 @@ import javax.annotation.Resource; import javax.annotation.security.DeclareRoles; import javax.annotation.security.RunAs; import javax.servlet.ServletException; +import javax.servlet.annotation.HttpConstraint; +import javax.servlet.annotation.HttpMethodConstraint; +import javax.servlet.annotation.MultipartConfig; +import javax.servlet.annotation.ServletSecurity; +import javax.servlet.annotation.WebInitParam; +import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -27,7 +33,10 @@ import javax.servlet.http.HttpServletResponse; @DeclareRoles({"alice"}) +@WebServlet(urlPatterns = { "/foo/*", "/bah/*" }, name="CServlet", initParams={@WebInitParam(name="x", value="y")}, loadOnStartup=2, asyncSupported=false) +@MultipartConfig(fileSizeThreshold=1000, maxFileSize=2000, maxRequestSize=3000) @RunAs("admin") +@ServletSecurity(value=@HttpConstraint(rolesAllowed={"fred", "bill", "dorothy"}), httpMethodConstraints={@HttpMethodConstraint(value="GET", rolesAllowed={"bob", "carol", "ted"})}) public class ServletC extends HttpServlet { @Resource (mappedName="foo", type=Double.class) diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java new file mode 100644 index 00000000000..e9bf229a03e --- /dev/null +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationConfiguration.java @@ -0,0 +1,53 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.annotations; + +import java.io.File; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import junit.framework.TestCase; + +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.FragmentDescriptor; +import org.eclipse.jetty.webapp.WebAppContext; + +/** + * TestAnnotationConfiguration + * + * + */ +public class TestAnnotationConfiguration extends TestCase +{ + public void testGetFragmentFromJar () + throws Exception + { + String dir = System.getProperty("basedir", "."); + File file = new File(dir); + file=new File(file.getCanonicalPath()); + URL url=file.toURL(); + + Resource jar1 = Resource.newResource(url+"file.jar"); + + AnnotationConfiguration config = new AnnotationConfiguration(); + WebAppContext wac = new WebAppContext(); + + List frags = new ArrayList(); + frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file.jar!/fooa.props"))); + frags.add(new FragmentDescriptor(Resource.newResource("jar:"+url+"file2.jar!/foob.props"))); + + assertNotNull(config.getFragmentFromJar(jar1, frags)); + } +} diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java index e7f482de01f..7cfc0aafe44 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestAnnotationInheritance.java @@ -13,20 +13,23 @@ package org.eclipse.jetty.annotations; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; - import java.util.ArrayList; import java.util.List; - +import java.util.Map; import javax.naming.Context; import javax.naming.InitialContext; import org.eclipse.jetty.annotations.AnnotationParser.DiscoverableAnnotationHandler; import org.eclipse.jetty.annotations.AnnotationParser.Value; +import org.eclipse.jetty.util.MultiMap; import org.junit.After; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + /** * */ @@ -186,4 +189,40 @@ public class TestAnnotationInheritance }); assertEquals (1, handler.annotatedClassNames.size()); } + + @Test + public void testTypeInheritanceHandling() throws Exception + { + AnnotationParser parser = new AnnotationParser(); + ClassInheritanceHandler handler = new ClassInheritanceHandler(); + parser.registerClassHandler(handler); + + class Foo implements InterfaceD + { + } + + classNames.clear(); + classNames.add(ClassA.class.getName()); + classNames.add(ClassB.class.getName()); + classNames.add(InterfaceD.class.getName()); + classNames.add(Foo.class.getName()); + + parser.parse(classNames, null); + + MultiMap map = handler.getMap(); + assertNotNull(map); + assertFalse(map.isEmpty()); + assertEquals(2, map.size()); + Map stringArrayMap = map.toStringArrayMap(); + assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.ClassA")); + assertTrue (stringArrayMap.keySet().contains("org.eclipse.jetty.annotations.InterfaceD")); + String[] classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.ClassA"); + assertEquals(1, classes.length); + assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]); + + classes = (String[])stringArrayMap.get("org.eclipse.jetty.annotations.InterfaceD"); + assertEquals(2, classes.length); + assertEquals ("org.eclipse.jetty.annotations.ClassB", classes[0]); + assertEquals(Foo.class.getName(), classes[1]); + } } diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java new file mode 100644 index 00000000000..af8d9eed237 --- /dev/null +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestSecurityAnnotationConversions.java @@ -0,0 +1,328 @@ +// ======================================================================== +// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.annotations; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.annotation.ServletSecurity; +import javax.servlet.annotation.HttpConstraint; +import javax.servlet.annotation.HttpMethodConstraint; +import javax.servlet.annotation.ServletSecurity.TransportGuarantee; +import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic; +import javax.servlet.http.HttpServlet; + +import org.eclipse.jetty.security.ConstraintAware; +import org.eclipse.jetty.security.ConstraintMapping; +import org.eclipse.jetty.servlet.Holder; +import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; +import org.eclipse.jetty.util.LazyList; +import org.eclipse.jetty.util.security.Constraint; +import org.eclipse.jetty.webapp.WebAppContext; + +import junit.framework.TestCase; + +public class TestSecurityAnnotationConversions extends TestCase +{ + @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.DENY)) + public static class DenyServlet extends HttpServlet + {} + + @ServletSecurity + public static class PermitServlet extends HttpServlet + {} + + @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"})) + public static class RolesServlet extends HttpServlet + {} + + @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}), + httpMethodConstraints={@HttpMethodConstraint(value="GET")}) + public static class Method1Servlet extends HttpServlet + {} + + @ServletSecurity(value=@HttpConstraint(value=EmptyRoleSemantic.PERMIT, transportGuarantee=TransportGuarantee.CONFIDENTIAL, rolesAllowed={"tom", "dick", "harry"}), + httpMethodConstraints={@HttpMethodConstraint(value="GET", transportGuarantee=TransportGuarantee.CONFIDENTIAL)}) + public static class Method2Servlet extends HttpServlet + {} + + + public void setUp() + { + } + + public void testDenyAllOnClass () + throws Exception + { + + WebAppContext wac = makeWebAppContext(DenyServlet.class.getCanonicalName(), "denyServlet", new String[]{"/foo/*", "*.foo"}); + + //Assume we found 1 servlet with a @HttpConstraint with value=EmptyRoleSemantic.DENY security annotation + ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); + AnnotationIntrospector introspector = new AnnotationIntrospector(); + introspector.registerHandler(annotationHandler); + + //set up the expected outcomes: + //1 ConstraintMapping per ServletMapping pathSpec + Constraint expectedConstraint = new Constraint(); + expectedConstraint.setAuthenticate(true); + expectedConstraint.setDataConstraint(Constraint.DC_NONE); + + ConstraintMapping[] expectedMappings = new ConstraintMapping[2]; + + expectedMappings[0] = new ConstraintMapping(); + expectedMappings[0].setConstraint(expectedConstraint); + expectedMappings[0].setPathSpec("/foo/*"); + + expectedMappings[1] = new ConstraintMapping(); + expectedMappings[1].setConstraint(expectedConstraint); + expectedMappings[1].setPathSpec("*.foo"); + + introspector.introspect(DenyServlet.class); + + compareResults(expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + } + + + public void testPermitAll() + throws Exception + { + //Assume we found 1 servlet with a @ServletSecurity security annotation + WebAppContext wac = makeWebAppContext(PermitServlet.class.getCanonicalName(), "permitServlet", new String[]{"/foo/*", "*.foo"}); + + ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); + AnnotationIntrospector introspector = new AnnotationIntrospector(); + introspector.registerHandler(annotationHandler); + + + //set up the expected outcomes: + //1 ConstraintMapping per ServletMapping pathSpec + Constraint expectedConstraint = new Constraint(); + expectedConstraint.setAuthenticate(false); + expectedConstraint.setDataConstraint(Constraint.DC_NONE); + + ConstraintMapping[] expectedMappings = new ConstraintMapping[2]; + expectedMappings[0] = new ConstraintMapping(); + expectedMappings[0].setConstraint(expectedConstraint); + expectedMappings[0].setPathSpec("/foo/*"); + + expectedMappings[1] = new ConstraintMapping(); + expectedMappings[1].setConstraint(expectedConstraint); + expectedMappings[1].setPathSpec("*.foo"); + + introspector.introspect(PermitServlet.class); + + compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + } + + public void testRolesAllowedWithTransportGuarantee () + throws Exception + { + //Assume we found 1 servlet with annotation with roles defined and + //and a TransportGuarantee + + WebAppContext wac = makeWebAppContext(RolesServlet.class.getCanonicalName(), "rolesServlet", new String[]{"/foo/*", "*.foo"}); + + ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); + AnnotationIntrospector introspector = new AnnotationIntrospector(); + introspector.registerHandler(annotationHandler); + + //set up the expected outcomes:compareResults + //1 ConstraintMapping per ServletMapping + Constraint expectedConstraint = new Constraint(); + expectedConstraint.setAuthenticate(true); + expectedConstraint.setRoles(new String[]{"tom", "dick", "harry"}); + expectedConstraint.setDataConstraint(Constraint.DC_CONFIDENTIAL); + + ConstraintMapping[] expectedMappings = new ConstraintMapping[2]; + expectedMappings[0] = new ConstraintMapping(); + expectedMappings[0].setConstraint(expectedConstraint); + expectedMappings[0].setPathSpec("/foo/*"); + + expectedMappings[1] = new ConstraintMapping(); + expectedMappings[1].setConstraint(expectedConstraint); + expectedMappings[1].setPathSpec("*.foo"); + + introspector.introspect(RolesServlet.class); + compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + } + + + public void testMethodAnnotation () + throws Exception + { + //ServletSecurity annotation with HttpConstraint of TransportGuarantee.CONFIDENTIAL, and a list of rolesAllowed, and + //a HttpMethodConstraint for GET method that permits all and has TransportGuarantee.NONE (ie is default) + + WebAppContext wac = makeWebAppContext(Method1Servlet.class.getCanonicalName(), "method1Servlet", new String[]{"/foo/*", "*.foo"}); + + //set up the expected outcomes: - a Constraint for the RolesAllowed on the class + //with userdata constraint of DC_CONFIDENTIAL + //and mappings for each of the pathSpecs + Constraint expectedConstraint1 = new Constraint(); + expectedConstraint1.setAuthenticate(true); + expectedConstraint1.setRoles(new String[]{"tom", "dick", "harry"}); + expectedConstraint1.setDataConstraint(Constraint.DC_CONFIDENTIAL); + + //a Constraint for the PermitAll on the doGet method with a userdata + //constraint of DC_CONFIDENTIAL inherited from the class + Constraint expectedConstraint2 = new Constraint(); + expectedConstraint2.setDataConstraint(Constraint.DC_NONE); + + ConstraintMapping[] expectedMappings = new ConstraintMapping[4]; + expectedMappings[0] = new ConstraintMapping(); + expectedMappings[0].setConstraint(expectedConstraint1); + expectedMappings[0].setPathSpec("/foo/*"); + expectedMappings[0].setMethodOmissions(new String[]{"GET"}); + expectedMappings[1] = new ConstraintMapping(); + expectedMappings[1].setConstraint(expectedConstraint1); + expectedMappings[1].setPathSpec("*.foo"); + expectedMappings[1].setMethodOmissions(new String[]{"GET"}); + + expectedMappings[2] = new ConstraintMapping(); + expectedMappings[2].setConstraint(expectedConstraint2); + expectedMappings[2].setPathSpec("/foo/*"); + expectedMappings[2].setMethod("GET"); + expectedMappings[3] = new ConstraintMapping(); + expectedMappings[3].setConstraint(expectedConstraint2); + expectedMappings[3].setPathSpec("*.foo"); + expectedMappings[3].setMethod("GET"); + + AnnotationIntrospector introspector = new AnnotationIntrospector(); + ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); + introspector.registerHandler(annotationHandler); + introspector.introspect(Method1Servlet.class); + compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + } + + public void testMethodAnnotation2 () + throws Exception + { + //A ServletSecurity annotation that has HttpConstraint of CONFIDENTIAL with defined roles, but a + //HttpMethodConstraint for GET that permits all, but also requires CONFIDENTIAL + WebAppContext wac = makeWebAppContext(Method2Servlet.class.getCanonicalName(), "method2Servlet", new String[]{"/foo/*", "*.foo"}); + + AnnotationIntrospector introspector = new AnnotationIntrospector(); + ServletSecurityAnnotationHandler annotationHandler = new ServletSecurityAnnotationHandler(wac); + introspector.registerHandler(annotationHandler); + + //set up the expected outcomes: - a Constraint for the RolesAllowed on the class + //with userdata constraint of DC_CONFIDENTIAL + //and mappings for each of the pathSpecs + Constraint expectedConstraint1 = new Constraint(); + expectedConstraint1.setAuthenticate(true); + expectedConstraint1.setRoles(new String[]{"tom", "dick", "harry"}); + expectedConstraint1.setDataConstraint(Constraint.DC_CONFIDENTIAL); + + //a Constraint for the Permit on the GET method with a userdata + //constraint of DC_CONFIDENTIAL + Constraint expectedConstraint2 = new Constraint(); + expectedConstraint2.setDataConstraint(Constraint.DC_CONFIDENTIAL); + + ConstraintMapping[] expectedMappings = new ConstraintMapping[4]; + expectedMappings[0] = new ConstraintMapping(); + expectedMappings[0].setConstraint(expectedConstraint1); + expectedMappings[0].setPathSpec("/foo/*"); + expectedMappings[0].setMethodOmissions(new String[]{"GET"}); + expectedMappings[1] = new ConstraintMapping(); + expectedMappings[1].setConstraint(expectedConstraint1); + expectedMappings[1].setPathSpec("*.foo"); + expectedMappings[1].setMethodOmissions(new String[]{"GET"}); + + expectedMappings[2] = new ConstraintMapping(); + expectedMappings[2].setConstraint(expectedConstraint2); + expectedMappings[2].setPathSpec("/foo/*"); + expectedMappings[2].setMethod("GET"); + expectedMappings[3] = new ConstraintMapping(); + expectedMappings[3].setConstraint(expectedConstraint2); + expectedMappings[3].setPathSpec("*.foo"); + expectedMappings[3].setMethod("GET"); + + introspector.introspect(Method2Servlet.class); + compareResults (expectedMappings, ((ConstraintAware)wac.getSecurityHandler()).getConstraintMappings()); + } + + private void compareResults (ConstraintMapping[] expectedMappings, List actualMappings) + { + assertNotNull(actualMappings); + assertEquals(expectedMappings.length, actualMappings.size()); + + for (int k=0; k < actualMappings.size(); k++) + { + ConstraintMapping am = actualMappings.get(k); + boolean matched = false; + + for (int i=0; i< expectedMappings.length && !matched; i++) + { + ConstraintMapping em = expectedMappings[i]; + if (em.getPathSpec().equals(am.getPathSpec())) + { + if ((em.getMethod()==null && am.getMethod() == null) || em.getMethod() != null && em.getMethod().equals(am.getMethod())) + { + matched = true; + + assertEquals(em.getConstraint().getAuthenticate(), am.getConstraint().getAuthenticate()); + assertEquals(em.getConstraint().getDataConstraint(), am.getConstraint().getDataConstraint()); + if (em.getMethodOmissions() == null) + { + assertNull(am.getMethodOmissions()); + } + else + { + assertTrue(Arrays.equals(am.getMethodOmissions(), em.getMethodOmissions())); + } + + if (em.getConstraint().getRoles() == null) + { + assertNull(am.getConstraint().getRoles()); + } + else + { + assertTrue(Arrays.equals(em.getConstraint().getRoles(), am.getConstraint().getRoles())); + } + } + } + } + + if (!matched) + fail("No expected ConstraintMapping matching method:"+am.getMethod()+" pathSpec: "+am.getPathSpec()); + } + } + + + private WebAppContext makeWebAppContext (String className, String servletName, String[] paths) + { + WebAppContext wac = new WebAppContext(); + + ServletHolder[] holders = new ServletHolder[1]; + holders[0] = new ServletHolder(); + holders[0].setClassName(className); + holders[0].setName(servletName); + holders[0].setServletHandler(wac.getServletHandler()); + wac.getServletHandler().setServlets(holders); + wac.setSecurityHandler(new ConstraintSecurityHandler()); + + ServletMapping[] servletMappings = new ServletMapping[1]; + servletMappings[0] = new ServletMapping(); + + servletMappings[0].setPathSpecs(paths); + servletMappings[0].setServletName(servletName); + wac.getServletHandler().setServletMappings(servletMappings); + return wac; + } +} diff --git a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java index ef875f96149..9dc25abda17 100644 --- a/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java +++ b/jetty-annotations/src/test/java/org/eclipse/jetty/annotations/TestServletAnnotations.java @@ -1,5 +1,5 @@ // ======================================================================== -//Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -13,12 +13,19 @@ package org.eclipse.jetty.annotations; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import org.eclipse.jetty.security.ConstraintSecurityHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.eclipse.jetty.servlet.ServletMapping; import org.eclipse.jetty.webapp.WebAppContext; import org.junit.Test; @@ -29,8 +36,50 @@ import org.junit.Test; */ public class TestServletAnnotations { - @Test + public void testServletAnnotation() throws Exception + { + List classes = new ArrayList(); + classes.add("org.eclipse.jetty.annotations.ServletC"); + AnnotationParser parser = new AnnotationParser(); + + WebAppContext wac = new WebAppContext(); + WebServletAnnotationHandler handler = new WebServletAnnotationHandler(wac); + parser.registerAnnotationHandler("javax.servlet.annotation.WebServlet", handler); + + parser.parse(classes, new ClassNameResolver () + { + public boolean isExcluded(String name) + { + return false; + } + + public boolean shouldOverride(String name) + { + return false; + } + }); + + assertEquals(1, handler.getAnnotationList().size()); + assertTrue(handler.getAnnotationList().get(0) instanceof WebServletAnnotation); + + handler.getAnnotationList().get(0).apply(); + + ServletHolder[] holders = wac.getServletHandler().getServlets(); + assertNotNull(holders); + assertEquals(1, holders.length); + assertEquals("CServlet", holders[0].getName()); + ServletMapping[] mappings = wac.getServletHandler().getServletMappings(); + assertNotNull(mappings); + assertEquals(1, mappings.length); + String[] paths = mappings[0].getPathSpecs(); + assertNotNull(paths); + assertEquals(2, paths.length); + assertEquals("y", holders[0].getInitParameter("x")); + assertEquals(2,holders[0].getInitOrder()); + assertFalse(holders[0].isAsyncSupported()); + } + public void testDeclareRoles () throws Exception { diff --git a/jetty-client/pom.xml b/jetty-client/pom.xml index 02a0320bdd9..a3fe86d0588 100644 --- a/jetty-client/pom.xml +++ b/jetty-client/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 diff --git a/jetty-continuation/pom.xml b/jetty-continuation/pom.xml index 6c4c47b893a..fd0303ea879 100644 --- a/jetty-continuation/pom.xml +++ b/jetty-continuation/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-continuation @@ -64,11 +64,11 @@
- org.mortbay.jetty - servlet-api - 3.0.20100224 - provided - + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + ${servlet.spec.version} + provided + org.mortbay.jetty jetty-util diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java index a6bc9286e7c..6a90a5ad3c9 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/ContinuationSupport.java @@ -36,7 +36,7 @@ public class ContinuationSupport static { boolean servlet3Support=false; - Constructors3cc=null; + Constructors3cc=null; try { boolean servlet3=ServletRequest.class.getMethod("startAsync")!=null; @@ -52,11 +52,11 @@ public class ContinuationSupport finally { __servlet3=servlet3Support; - __newServlet3Continuation=s3cc; + __newServlet3Continuation=(Constructor)s3cc; } boolean jetty6Support=false; - Constructorj6cc=null; + Constructorj6cc=null; try { Class jetty6ContinuationClass = ContinuationSupport.class.getClassLoader().loadClass("org.mortbay.util.ajax.Continuation"); @@ -73,7 +73,7 @@ public class ContinuationSupport finally { __jetty6=jetty6Support; - __newJetty6Continuation=j6cc; + __newJetty6Continuation=(Constructor)j6cc; } Class waiting=null; diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java index cede7e22af4..51cc48e68c2 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/FauxContinuation.java @@ -500,4 +500,4 @@ class FauxContinuation implements FilteredContinuation throw new IllegalStateException("!suspended"); } -} \ No newline at end of file +} diff --git a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java index e4bca0be202..9486b725ad8 100644 --- a/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java +++ b/jetty-continuation/src/main/java/org/eclipse/jetty/continuation/Servlet3Continuation.java @@ -59,6 +59,7 @@ public class Servlet3Continuation implements Continuation public void onTimeout(AsyncEvent event) throws IOException { _initial=false; + System.err.println("Doing dispatch on timed out continuation for "+_request.getAttribute("FOO")); event.getAsyncContext().dispatch(); } }); diff --git a/jetty-deploy/pom.xml b/jetty-deploy/pom.xml index 528e7ce46c0..ddc4f1c10e5 100644 --- a/jetty-deploy/pom.xml +++ b/jetty-deploy/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-deploy diff --git a/jetty-deploy/src/main/config/etc/jetty-deploy.xml b/jetty-deploy/src/main/config/etc/jetty-deploy.xml index dd25f7ff34c..1b3fd66dcd2 100644 --- a/jetty-deploy/src/main/config/etc/jetty-deploy.xml +++ b/jetty-deploy/src/main/config/etc/jetty-deploy.xml @@ -22,7 +22,7 @@ org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern - .*/.*jsp-api-[^/]*\.jar$|.*/.*jsp-[^/]*\.jar$|.*/.*taglibs[^/]*\.jar$ + .*/servlet-api-[^/]*\.jar$ diff --git a/jetty-distribution/pom.xml b/jetty-distribution/pom.xml index 173d546d426..23496645470 100644 --- a/jetty-distribution/pom.xml +++ b/jetty-distribution/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT jetty-distribution Jetty :: Distribution Assemblies @@ -12,18 +12,18 @@ http://download.eclipse.org/jetty/orbit target/distribution 3.6 - ${javax-activation-version}.0.v201005080500 - 1.0.0.v20100513-0750 - 2.1.0.v201004190952 + ${javax-activation-version}.0.v201105071233 + 1.1.0.v201105051105 + 2.2.0.v201105051105 ${javax-mail-version}.v201005082020 - 2.5.0.v200910301333 - 2.1.0.v201004190952 + 3.0.0.v201103241727 + 2.2.0.v201103241009 1.2.0.v201004190952 - 1.0.0.v201004190952 - 2.1.0.v201110031002 + 2.2.0.v201105051105 1.2.0.v201004190952 - 3.1.0.v200803061910 + 3.3.1.v201101071600 1.1.1.v201004190952 + 2.2.2.v201108011116 @@ -87,8 +87,9 @@ - + + @@ -123,12 +124,11 @@ - + - @@ -354,6 +354,11 @@ jetty-policy ${project.version} + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + ${servlet.spec.version} + org.eclipse.jetty jetty-servlets diff --git a/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh b/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh index 550390edce1..16371bea30e 100755 --- a/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh +++ b/jetty-distribution/src/main/resources/bin/jetty-cygwin.sh @@ -5,7 +5,7 @@ # To get the service to restart correctly on reboot, uncomment below (3 lines): # ======================== # chkconfig: 3 99 99 -# description: Jetty 7 webserver +# description: Jetty 8 webserver # processname: jetty # ======================== @@ -134,8 +134,8 @@ NO_START=0 ################################################## # See if there's a default configuration file ################################################## -if [ -f /etc/default/jetty7 ] ; then - . /etc/default/jetty7 +if [ -f /etc/default/jetty8 ] ; then + . /etc/default/jetty8 elif [ -f /etc/default/jetty ] ; then . /etc/default/jetty fi @@ -196,13 +196,13 @@ if [ "$JETTY_HOME" = "" ] ; then /home \ " JETTY_DIR_NAMES=" \ - jetty-7 \ - jetty7 \ - jetty-7.* \ + jetty-8 \ + jetty8 \ + jetty-8.* \ jetty \ - Jetty-7 \ - Jetty7 \ - Jetty-7.* \ + Jetty-8 \ + Jetty8 \ + Jetty-8.* \ Jetty \ " @@ -511,7 +511,7 @@ case "$ACTION" in echo -n "Starting Jetty: " if [ "$NO_START" = "1" ]; then - echo "Not starting jetty - NO_START=1 in /etc/default/jetty7"; + echo "Not starting jetty - NO_START=1 in /etc/default/jetty8"; exit 0; fi diff --git a/jetty-distribution/src/main/resources/bin/jetty.sh b/jetty-distribution/src/main/resources/bin/jetty.sh index 7f6b5494639..5442d2fe14c 100755 --- a/jetty-distribution/src/main/resources/bin/jetty.sh +++ b/jetty-distribution/src/main/resources/bin/jetty.sh @@ -5,7 +5,7 @@ # To get the service to restart correctly on reboot, uncomment below (3 lines): # ======================== # chkconfig: 3 99 99 -# description: Jetty 7 webserver +# description: Jetty 8 webserver # processname: jetty # ======================== @@ -136,7 +136,7 @@ shift ################################################## # Read any configuration files ################################################## -for CONFIG in /etc/default/jetty{,7} $HOME/.jettyrc; do +for CONFIG in /etc/default/jetty{,8} $HOME/.jettyrc; do if [ -f "$CONFIG" ] ; then readConfig "$CONFIG" fi @@ -192,13 +192,13 @@ if [ -z "$JETTY_HOME" ] ; then "/home" ) JETTY_DIR_NAMES=( - "jetty-7" - "jetty7" - "jetty-7.*" + "jetty-8" + "jetty8" + "jetty-8.*" "jetty" - "Jetty-7" - "Jetty7" - "Jetty-7.*" + "Jetty-8" + "Jetty8" + "Jetty-8.*" "Jetty" ) diff --git a/jetty-distribution/src/main/resources/start.ini b/jetty-distribution/src/main/resources/start.ini index 6dec0543b5a..36ddff67583 100644 --- a/jetty-distribution/src/main/resources/start.ini +++ b/jetty-distribution/src/main/resources/start.ini @@ -46,7 +46,7 @@ # for a full listing do # java -jar start.jar --list-options #----------------------------------------------------------- -OPTIONS=Server,jsp,jmx,resources,websocket,ext +OPTIONS=Server,jsp,jmx,resources,websocket,ext,plus,annotations #----------------------------------------------------------- @@ -57,6 +57,7 @@ OPTIONS=Server,jsp,jmx,resources,websocket,ext #----------------------------------------------------------- #etc/jetty-jmx.xml etc/jetty.xml +etc/jetty-annotations.xml # etc/jetty-ssl.xml # etc/jetty-requestlog.xml etc/jetty-deploy.xml diff --git a/jetty-http-spi/pom.xml b/jetty-http-spi/pom.xml index 856673b86eb..2842860f0c3 100644 --- a/jetty-http-spi/pom.xml +++ b/jetty-http-spi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-http-spi diff --git a/jetty-http/pom.xml b/jetty-http/pom.xml index 53d5c6e9641..eebb8c2e5d6 100644 --- a/jetty-http/pom.xml +++ b/jetty-http/pom.xml @@ -2,7 +2,7 @@ jetty-project org.eclipse.jetty - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 org.eclipse.jetty @@ -18,8 +18,9 @@ ${project.version} - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + ${servlet.spec.version} provided diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java index ed2989b7ff5..36d38a7dea9 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/HttpFields.java @@ -19,10 +19,12 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collections; +import java.util.Collection; import java.util.Date; import java.util.Enumeration; import java.util.GregorianCalendar; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -346,6 +348,22 @@ public class HttpFields } } + /* -------------------------------------------------------------- */ + /** + * Get Collection of header names. + */ + public Collection getFieldNamesCollection() + { + final List list = new ArrayList(_fields.size()); + + for (Field f : _fields) + { + if (f!=null) + list.add(BufferUtil.to8859_1_String(f._name)); + } + return list; + } + /* -------------------------------------------------------------- */ /** * Get enumeration of header _names. Returns an enumeration of strings representing the header @@ -378,7 +396,7 @@ public class HttpFields /** * Get a Field by index. * @return A Field value or null if the Field value has not been set - * for this revision of the fields. + * */ public Field getField(int i) { @@ -445,6 +463,30 @@ public class HttpFields return field==null?null:field._value; } + + /* -------------------------------------------------------------- */ + /** + * Get multi headers + * + * @return Enumeration of the values, or null if no such header. + * @param name the case-insensitive field name + */ + public Collection getValuesCollection(String name) + { + Field field = getField(name); + if (field==null) + return null; + + final List list = new ArrayList(); + + while(field!=null) + { + list.add(field.getValue()); + field=field._next; + } + return list; + } + /* -------------------------------------------------------------- */ /** * Get multi headers @@ -1372,5 +1414,4 @@ public class HttpFields return ("[" + getName() + "=" + _value + (_next == null ? "" : "->") + "]"); } } - } diff --git a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java index 18012e950f5..55550f723c3 100644 --- a/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java +++ b/jetty-http/src/test/java/org/eclipse/jetty/http/HttpGeneratorClientTest.java @@ -49,7 +49,7 @@ public class HttpGeneratorClientTest generator.completeHeader(fields,false); - generator.addContent(new ByteArrayBuffer(content).asMutableBuffer(),true); + generator.addContent(new ByteArrayBuffer(content),true); generator.flushBuffer(); generator.complete(); generator.flushBuffer(); @@ -74,7 +74,7 @@ public class HttpGeneratorClientTest String content = "The quick brown fox jumped over the lazy dog"; - generator.addContent(new ByteArrayBuffer(content).asMutableBuffer(),true); + generator.addContent(new ByteArrayBuffer(content),true); generator.completeHeader(fields,true); generator.flushBuffer(); @@ -103,7 +103,7 @@ public class HttpGeneratorClientTest generator.completeHeader(fields,false); - generator.addContent(new ByteArrayBuffer(content).asMutableBuffer(),false); + generator.addContent(new ByteArrayBuffer(content),false); generator.flushBuffer(); generator.complete(); generator.flushBuffer(); diff --git a/jetty-io/pom.xml b/jetty-io/pom.xml index 8a5f69852a6..43c64437ad4 100644 --- a/jetty-io/pom.xml +++ b/jetty-io/pom.xml @@ -2,7 +2,7 @@ jetty-project org.eclipse.jetty - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 org.eclipse.jetty diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java index 1b7ca44b6fe..ff50406e26a 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/AbstractBuffer.java @@ -500,43 +500,37 @@ public abstract class AbstractBuffer implements Buffer public void setGetIndex(int getIndex) { - /* bounds checking */ - if (__boundsChecking) - { - if (isImmutable()) - throw new IllegalStateException(__IMMUTABLE); - if (getIndex < 0) - throw new IllegalArgumentException("getIndex<0: " + getIndex + "<0"); - if (getIndex > putIndex()) - throw new IllegalArgumentException("getIndex>putIndex: " + getIndex + ">" + putIndex()); - } - + /* bounds checking + if (isImmutable()) + throw new IllegalStateException(__IMMUTABLE); + if (getIndex < 0) + throw new IllegalArgumentException("getIndex<0: " + getIndex + "<0"); + if (getIndex > putIndex()) + throw new IllegalArgumentException("getIndex>putIndex: " + getIndex + ">" + putIndex()); + */ _get = getIndex; _hash=0; } public void setMarkIndex(int index) { - + /* if (index>=0 && isImmutable()) throw new IllegalStateException(__IMMUTABLE); - + */ _mark = index; } public void setPutIndex(int putIndex) { - if (__boundsChecking) - { - /* bounds checking */ - if (isImmutable()) - throw new IllegalStateException(__IMMUTABLE); - if (putIndex > capacity()) + /* bounds checking + if (isImmutable()) + throw new IllegalStateException(__IMMUTABLE); + if (putIndex > capacity()) throw new IllegalArgumentException("putIndex>capacity: " + putIndex + ">" + capacity()); - if (getIndex() > putIndex) + if (getIndex() > putIndex) throw new IllegalArgumentException("getIndex>putIndex: " + getIndex() + ">" + putIndex); - } - + */ _put = putIndex; _hash=0; } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayBuffer.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayBuffer.java index 933dbf98b28..f66a52c0018 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayBuffer.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayBuffer.java @@ -352,8 +352,7 @@ public class ByteArrayBuffer extends AbstractBuffer throws IOException { out.write(_bytes,getIndex(),length()); - if (!isImmutable()) - clear(); + clear(); } /* ------------------------------------------------------------ */ diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java index a0e4f8e96df..029ed2f84ee 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/ByteArrayEndPoint.java @@ -246,8 +246,7 @@ public class ByteArrayEndPoint implements ConnectedEndPoint } } int len = _out.put(buffer); - if (!buffer.isImmutable()) - buffer.skip(len); + buffer.skip(len); return len; } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedIOException.java b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedIOException.java new file mode 100644 index 00000000000..34d67804f2d --- /dev/null +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/UncheckedIOException.java @@ -0,0 +1,43 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + + +package org.eclipse.jetty.io; + +/* ------------------------------------------------------------ */ +/** + * Subclass of {@link java.lang.RuntimeException} used to signal that there + * was an {@link java.io.IOException} thrown by underlying {@link UncheckedPrintWriter} + */ +public class UncheckedIOException extends RuntimeException +{ + public UncheckedIOException() + { + super(); + } + + public UncheckedIOException(String message) + { + super(message); + } + + public UncheckedIOException(Throwable cause) + { + super(cause); + } + + public UncheckedIOException(String message, Throwable cause) + { + super(message,cause); + } +} diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java index 0ebab0058d3..a92e2e83700 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/bio/StreamEndPoint.java @@ -157,8 +157,7 @@ public class StreamEndPoint implements EndPoint int length=buffer.length(); if (length>0) buffer.writeTo(_out); - if (!buffer.isImmutable()) - buffer.clear(); + buffer.clear(); return length; } diff --git a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java index fb3c09145a8..f4a0d527b97 100644 --- a/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java +++ b/jetty-io/src/main/java/org/eclipse/jetty/io/nio/ChannelEndPoint.java @@ -398,6 +398,12 @@ public class ChannelEndPoint implements EndPoint } finally { + // adjust buffer 0 and 1 + if (!header.isImmutable()) + header.setGetIndex(bbuf0.position()); + if (!buffer.isImmutable()) + buffer.setGetIndex(bbuf1.position()); + bbuf0.position(0); bbuf1.position(0); bbuf0.limit(bbuf0.capacity()); diff --git a/jetty-jaspi/pom.xml b/jetty-jaspi/pom.xml index f06938ce0f8..f64ce709727 100644 --- a/jetty-jaspi/pom.xml +++ b/jetty-jaspi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-jaspi diff --git a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java index 1793ec83f8d..0eb96bed747 100644 --- a/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java +++ b/jetty-jaspi/src/main/java/org/eclipse/jetty/security/jaspi/SimpleAuthConfig.java @@ -65,7 +65,7 @@ public class SimpleAuthConfig implements ServerAuthConfig return true; } - public void refresh() + public void refresh() { } } diff --git a/jetty-jmx/pom.xml b/jetty-jmx/pom.xml index 4b9a0dc2a9d..82c7d898236 100644 --- a/jetty-jmx/pom.xml +++ b/jetty-jmx/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-jmx diff --git a/jetty-jndi/pom.xml b/jetty-jndi/pom.xml index 5eaf6fef291..f78fa3bbd91 100644 --- a/jetty-jndi/pom.xml +++ b/jetty-jndi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-jndi diff --git a/jetty-monitor/pom.xml b/jetty-monitor/pom.xml index bfff477df54..99ab3621d9b 100644 --- a/jetty-monitor/pom.xml +++ b/jetty-monitor/pom.xml @@ -19,7 +19,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-monitor diff --git a/jetty-nested/pom.xml b/jetty-nested/pom.xml index 40da79b3cfe..fbc9ad575a3 100644 --- a/jetty-nested/pom.xml +++ b/jetty-nested/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT jetty-nested Jetty :: Nested diff --git a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java index 0d98785a526..a8bf06a6567 100644 --- a/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java +++ b/jetty-nested/src/main/java/org/eclipse/jetty/nested/NestedConnection.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.nested; import java.io.IOException; import java.util.Enumeration; +import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.ServletInputStream; import javax.servlet.http.HttpServletRequest; @@ -24,7 +25,6 @@ import org.eclipse.jetty.http.HttpFields; import org.eclipse.jetty.http.HttpURI; import org.eclipse.jetty.io.Connection; import org.eclipse.jetty.server.AbstractHttpConnection; -import org.eclipse.jetty.server.DispatcherType; public class NestedConnection extends AbstractHttpConnection diff --git a/jetty-nosql/pom.xml b/jetty-nosql/pom.xml index 75b77f019a9..ba4c50b5c7a 100644 --- a/jetty-nosql/pom.xml +++ b/jetty-nosql/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-nosql @@ -28,7 +28,7 @@ maven-bundle-plugin - javax.servlet.*;version="[2.5,3.0)",org.eclipse.jetty.server.session.jmx;version="[7.5,8)";resolution:=optional,,org.eclipse.jetty.*;version="[7.5,8)",* + javax.servlet.*;version="2.5.0",org.eclipse.jetty.server.session.jmx;version="8.0.0";resolution:=optional,,org.eclipse.jetty.*;version="8.0.0",* true diff --git a/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF index df5a595516a..c853162b973 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-boot-jsp/META-INF/MANIFEST.MF @@ -3,34 +3,20 @@ Bundle-ManifestVersion: 2 Bundle-Name: Jetty-OSGi-Jasper integration Fragment-Host: org.eclipse.jetty.osgi.boot Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.jsp -Bundle-Version: 7.4.1.qualifier +Bundle-Version: 8.0.0.qualifier Bundle-Vendor: Mort Bay Consulting -Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Import-Package: com.sun.el;resolution:=optional, - com.sun.el.lang;resolution:=optional, - com.sun.el.parser;resolution:=optional, - com.sun.el.util;resolution:=optional, - com.sun.org.apache.commons.logging;split=glassfish;version="[2.1,3)";resolution:=optional, - javax.el;version="1.0.0";resolution:=optional, - javax.servlet;version="2.5.0", - javax.servlet.jsp;version="2.1.0", - javax.servlet.jsp.el;version="2.1.0", +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Import-Package: com.sun.el;version="2.2.0";resolution:=optional, + javax.el;version="2.2.0";resolution:=optional, + javax.servlet.jsp;version="2.2.0", + javax.servlet.jsp.el;version="2.2.0", javax.servlet.jsp.jstl.core;version="1.2.0";resolution:=optional, javax.servlet.jsp.jstl.fmt;version="1.2.0";resolution:=optional, javax.servlet.jsp.jstl.sql;version="1.2.0";resolution:=optional, javax.servlet.jsp.jstl.tlv;version="1.2.0";resolution:=optional, - javax.servlet.jsp.resources;version="2.1.0", - javax.servlet.jsp.tagext;version="2.1.0", - javax.servlet.resources;version="2.5.0", - org.apache.jasper;version="2.0.0";resolution:=optional, - org.apache.jasper.compiler;version="2.0.0";resolution:=optional, - org.apache.jasper.compiler.tagplugin;version="2.0.0";resolution:=optional, - org.apache.jasper.runtime;version="2.0.0";resolution:=optional, - org.apache.jasper.security;version="2.0.0";resolution:=optional, - org.apache.jasper.servlet;version="2.0.0";resolution:=optional, - org.apache.jasper.tagplugins.jstl;version="2.0.0";resolution:=optional, - org.apache.jasper.util;version="2.0.0";resolution:=optional, - org.apache.jasper.xmlparser;version="2.0.0";resolution:=optional, + org.apache.jasper;version="2.1.0";resolution:=optional, + org.apache.jasper.compiler;version="2.1.0";resolution:=optional, + org.apache.jasper.xmlparser;version="2.1.0";resolution:=optional, org.apache.taglibs.standard;version="1.2.0";resolution:=optional, org.apache.taglibs.standard.extra.spath;version="1.2.0";resolution:=optional, org.apache.taglibs.standard.functions;version="1.2.0";resolution:=optional, @@ -54,4 +40,6 @@ Import-Package: com.sun.el;resolution:=optional, org.apache.taglibs.standard.tag.rt.xml;version="1.2.0";resolution:=optional, org.apache.taglibs.standard.tei;version="1.2.0";resolution:=optional, org.apache.taglibs.standard.tlv;version="1.2.0";resolution:=optional, - org.eclipse.jetty.jsp;version="[7.0,8.0)";resolution:=optional + org.glassfish.jsp.api;version="2.2.2";resolution:=optional +DynamicImport-Package: org.apache.jasper.*;version="2.1.0" + diff --git a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml index 76e530cde78..2c669d7db2b 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-jsp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT ../pom.xml 4.0.0 @@ -32,19 +32,41 @@ org.eclipse.osgi org.eclipse.osgi.services + org.mortbay.jetty jsp-2.1-glassfish + 2.1.v20100127 + + + + javax.el + el-api + 2.2 - org.mortbay.jetty - jsp-api-2.1-glassfish - - - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + + + + sun + http://download.java.net/maven/2/ + + + @@ -55,7 +77,7 @@ process-resources - + diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java index 89a5f9e3714..0e9df2e771f 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jasper/WebappRegistrationCustomizerImpl.java @@ -122,7 +122,6 @@ public class WebappRegistrationCustomizerImpl implements WebappRegistrationCusto */ public URL[] getJarsWithTlds(OSGiAppProvider provider, BundleFileLocatorHelper locatorHelper) throws Exception { - HashSet> classesToAddToTheTldBundles = new HashSet>(); //Look for the jstl bundle diff --git a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java index 6e34d4a5902..99a567cd70d 100644 --- a/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java +++ b/jetty-osgi/jetty-osgi-boot-jsp/src/main/java/org/eclipse/jetty/osgi/boot/jsp/FragmentActivator.java @@ -36,7 +36,7 @@ public class FragmentActivator implements BundleActivator * */ public void start(BundleContext context) throws Exception { - System.setProperty("org.apache.jasper.compiler.disablejsr199", Boolean.TRUE.toString()); + System.setProperty("org.apache.jasper.compiler.disablejsr199", Boolean.TRUE.toString()); WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new WebappRegistrationCustomizerImpl()); WebBundleDeployerHelper.JSP_REGISTRATION_HELPERS.add(new PluggableWebAppRegistrationCustomizerImpl()); } diff --git a/jetty-osgi/jetty-osgi-boot-logback/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-boot-logback/META-INF/MANIFEST.MF deleted file mode 100644 index 8587cac0b01..00000000000 --- a/jetty-osgi/jetty-osgi-boot-logback/META-INF/MANIFEST.MF +++ /dev/null @@ -1,20 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Jetty-OSGi-Logback integration -Fragment-Host: org.eclipse.jetty.osgi.boot -Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.logback;singleton:=true -Bundle-Version: 7.3.0.qualifier -Bundle-Vendor: Mort Bay Consulting -Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Import-Package: ch.qos.logback.classic, - ch.qos.logback.classic.joran, - ch.qos.logback.core, - ch.qos.logback.core.joran, - ch.qos.logback.core.joran.spi, - ch.qos.logback.core.spi, - ch.qos.logback.core.util, - ch.qos.logback.access.jetty.v7;resolution:=optional, - org.apache.commons.logging;resolution:=optional, - org.apache.log4j;resolution:=optional, - org.osgi.framework, - org.slf4j diff --git a/jetty-osgi/jetty-osgi-boot-logback/META-INF/readme.txt b/jetty-osgi/jetty-osgi-boot-logback/META-INF/readme.txt deleted file mode 100644 index 20960b4bd4e..00000000000 --- a/jetty-osgi/jetty-osgi-boot-logback/META-INF/readme.txt +++ /dev/null @@ -1,12 +0,0 @@ -This bundle is made to inject the logback dependencies along with the slf4j dependencies to support log4j and commons-logging. -It will read the configuration in the jettyhome/resources/logback-test.xml or jettyhome/resources/logback.xml folder. - - -It was tested with these bundles: -#this provides lg4j and commons-logging via slf4j -SLF4J = group("com.springsource.slf4j.api", "com.springsource.slf4j.org.apache.log4j", "com.springsource.slf4j.org.apache.commons.logging", - :under=>"org.slf4j", :version=>"1.5.6") - -#logback is not exporting enough packages for us to be able to configure logback classic programatically.. on the springsource version they are fine... -LOGBACK = group("com.springsource.ch.qos.logback.core", "com.springsource.ch.qos.logback.classic", - :under=>"ch.qos.logback", :version=>"0.9.15") \ No newline at end of file diff --git a/jetty-osgi/jetty-osgi-boot-logback/build.properties b/jetty-osgi/jetty-osgi-boot-logback/build.properties deleted file mode 100644 index 6d10c98886e..00000000000 --- a/jetty-osgi/jetty-osgi-boot-logback/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/main/java/ -output.. = target/classes/ -bin.includes = META-INF/,\ - . -src.includes = META-INF/ diff --git a/jetty-osgi/jetty-osgi-boot-logback/pom.xml b/jetty-osgi/jetty-osgi-boot-logback/pom.xml deleted file mode 100644 index 595e77a4b24..00000000000 --- a/jetty-osgi/jetty-osgi-boot-logback/pom.xml +++ /dev/null @@ -1,109 +0,0 @@ - - - org.eclipse.jetty.osgi - jetty-osgi-project - 7.6.0-SNAPSHOT - ../pom.xml - - 4.0.0 - org.eclipse.jetty.osgi - jetty-osgi-boot-logback - Jetty :: OSGi :: Boot Logback - Jetty OSGi Boot Logback bundle - - ${project.groupId}.boot.logback - - - - org.eclipse.jetty.osgi - jetty-osgi-boot - ${project.version} - provided - - - org.eclipse.osgi - org.eclipse.osgi - - - org.eclipse.jetty - jetty-webapp - - - org.eclipse.osgi - org.eclipse.osgi.services - - - org.slf4j - slf4j-api - - - org.slf4j - jcl-over-slf4j - - - org.slf4j - log4j-over-slf4j - - - ch.qos.logback - logback-core - - - ch.qos.logback - logback-classic - - - - - - - maven-antrun-plugin - - - process-resources - - - - - - - run - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - artifact-jar - - jar - - - - test-jar - - test-jar - - - - - - target/classes/META-INF/MANIFEST.MF - - - - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.osgi.boot.logback.* - - - - - - - diff --git a/jetty-osgi/jetty-osgi-boot-logback/src/main/java/org/eclipse/jetty/osgi/boot/logback/FragmentActivator.java b/jetty-osgi/jetty-osgi-boot-logback/src/main/java/org/eclipse/jetty/osgi/boot/logback/FragmentActivator.java deleted file mode 100644 index 919c10fada8..00000000000 --- a/jetty-osgi/jetty-osgi-boot-logback/src/main/java/org/eclipse/jetty/osgi/boot/logback/FragmentActivator.java +++ /dev/null @@ -1,86 +0,0 @@ -// ======================================================================== -// Copyright (c) 2009 Intalio, Inc. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.boot.logback; - -import java.io.File; -import java.util.Map; - -import org.eclipse.jetty.osgi.boot.internal.webapp.LibExtClassLoaderHelper; -import org.eclipse.jetty.osgi.boot.internal.webapp.OSGiWebappClassLoader; -import org.eclipse.jetty.osgi.boot.internal.webapp.LibExtClassLoaderHelper.IFilesInJettyHomeResourcesProcessor; -import org.eclipse.jetty.osgi.boot.logback.internal.LogbackInitializer; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - - -/** - * Pseudo fragment activator. - * Called by the main org.eclipse.jetty.osgi.boot bundle. - * Please note: this is not a real BundleActivator. Simply something called back by - * the host bundle. - * The fragment is in charge of placing a hook to configure logback - * when the files inside jettyhome/resources are parsed. - */ -public class FragmentActivator implements BundleActivator, IFilesInJettyHomeResourcesProcessor -{ - /** - * - */ - public void start(BundleContext context) throws Exception - { - LibExtClassLoaderHelper.registeredFilesInJettyHomeResourcesProcessors.add(this); - - //now let's make sure no log4j, no slf4j and no commons.logging - //get inserted as a library that is not an osgi library - OSGiWebappClassLoader.addClassThatIdentifiesAJarThatMustBeRejected("org.apache.commons.logging.Log"); - OSGiWebappClassLoader.addClassThatIdentifiesAJarThatMustBeRejected("org.apache.log4j.Logger"); - OSGiWebappClassLoader.addClassThatIdentifiesAJarThatMustBeRejected("org.slf4j.Logger"); - //OSGiWebappClassLoader.addClassThatIdentifiesAJarThatMustBeRejected(java.util.logging.Logger.class); - - } - - /** - * Called when this bundle is stopped so the Framework can perform the - * bundle-specific activities necessary to stop the bundle. In general, this - * method should undo the work that the BundleActivator.start - * method started. There should be no active threads that were started by - * this bundle when this bundle returns. A stopped bundle must not call any - * Framework objects. - * - *

- * This method must complete and return to its caller in a timely manner. - * - * @param context The execution context of the bundle being stopped. - * @throws Exception If this method throws an exception, the - * bundle is still marked as stopped, and the Framework will remove - * the bundle's listeners, unregister all services registered by the - * bundle, and release all services used by the bundle. - */ - public void stop(BundleContext context) throws Exception - { - LibExtClassLoaderHelper.registeredFilesInJettyHomeResourcesProcessors.remove(this); - } - - public void processFilesInResourcesFolder(File jettyHome, Map files) - { - try - { - LogbackInitializer.processFilesInResourcesFolder(jettyHome, files); - } - catch (Throwable t) - { - t.printStackTrace(); - } - } - -} diff --git a/jetty-osgi/jetty-osgi-boot-logback/src/main/java/org/eclipse/jetty/osgi/boot/logback/internal/LogbackInitializer.java b/jetty-osgi/jetty-osgi-boot-logback/src/main/java/org/eclipse/jetty/osgi/boot/logback/internal/LogbackInitializer.java deleted file mode 100644 index 71134ab2c1b..00000000000 --- a/jetty-osgi/jetty-osgi-boot-logback/src/main/java/org/eclipse/jetty/osgi/boot/logback/internal/LogbackInitializer.java +++ /dev/null @@ -1,98 +0,0 @@ -// ======================================================================== -// Copyright (c) 2009 Intalio, Inc. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// Contributors: -// Hugues Malphettes - initial API and implementation -// ======================================================================== -package org.eclipse.jetty.osgi.boot.logback.internal; - -import java.io.File; -import java.util.Map; - -import org.slf4j.LoggerFactory; - -import ch.qos.logback.classic.LoggerContext; -import ch.qos.logback.classic.joran.JoranConfigurator; -import ch.qos.logback.core.joran.JoranConfiguratorBase; -import ch.qos.logback.core.joran.spi.JoranException; -import ch.qos.logback.core.util.StatusPrinter; - -/** - * Setup logback eventually located in the config file inside jettyhome/resources - * All logback related code is done in this separate class for better debug - * and isolation when it does not load. - */ -public class LogbackInitializer { - - /** - * @return true when we are currently being run by the pde in development mode. - */ - private static boolean isPDEDevelopment() - { - String eclipseCommands = System.getProperty("eclipse.commands"); - // detect if we are being run from the pde: ie during development. - return eclipseCommands != null && eclipseCommands.indexOf("-dev") != -1 - && (eclipseCommands.indexOf("-dev\n") != -1 - || eclipseCommands.indexOf("-dev\r") != -1 - || eclipseCommands.indexOf("-dev ") != -1); - } - - - /** - * Follow the configuration for logback. - * unless the system propery was set in which case it - * was assume it was already setup. - */ - public static void processFilesInResourcesFolder(File jettyHome, Map files) - { - String logbackConf = System.getProperty("logback.configurationFile"); - if (logbackConf != null) - { - File confFile = new File(logbackConf); - if (confFile.exists()) - { - //assume logback was configured by this one? - return; - } - } - - File logConf = isPDEDevelopment() ? files.get("logback-dev.xml") : null; - if (logConf == null) - { - logConf = files.get("logback-test.xml"); - } - if (logConf == null) - { - logConf = files.get("logback.xml"); - } - if (logConf == null) - { - return; - } - // assume SLF4J is bound to logback in the current environment - LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory(); - - try - { - JoranConfiguratorBase configurator = new JoranConfigurator(); - configurator.setContext(lc); - lc.reset(); - configurator.doConfigure(logConf.getAbsoluteFile().getAbsolutePath()); - } - catch (JoranException je) - { - je.printStackTrace(); - } - StatusPrinter.printIfErrorsOccured(lc); - - } - -} diff --git a/jetty-osgi/jetty-osgi-boot-warurl/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-boot-warurl/META-INF/MANIFEST.MF index 28a7a1456e8..d51822383cb 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-boot-warurl/META-INF/MANIFEST.MF @@ -2,10 +2,10 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Support for rfc66 war url scheme Bundle-SymbolicName: org.eclipse.jetty.osgi.boot.warurl;singleton:=true -Bundle-Version: 7.3.0.qualifier +Bundle-Version: 8.0.0.qualifier Bundle-Activator: org.eclipse.jetty.osgi.boot.warurl.WarUrlActivator Bundle-Vendor: Mort Bay Consulting -Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Import-Package: org.eclipse.jetty.util, org.osgi.framework, org.osgi.service.url diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml index a0463cc5643..4b305bb0442 100644 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml +++ b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT ../pom.xml 4.0.0 @@ -33,7 +33,7 @@ process-resources - + diff --git a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho b/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho deleted file mode 100644 index b30ae7a4641..00000000000 --- a/jetty-osgi/jetty-osgi-boot-warurl/pom.xml.tycho +++ /dev/null @@ -1,14 +0,0 @@ - - - 4.0.0 - - jetty-osgi - 7.0.1-SNAPSHOT - org.eclipse.jetty.osgi - - org.eclipse.jetty.osgi - org.eclipse.jetty.osgi.boot.warurl - 7.0.1.qualifier - eclipse-plugin - diff --git a/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF index e7dfce0738a..dd7d7e3523b 100644 --- a/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-boot/META-INF/MANIFEST.MF @@ -1,32 +1,34 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Jetty OSGi bootstrap -Bundle-SymbolicName: org.eclipse.jetty.osgi.boot;singleton:=true +Bundle-SymbolicName: org.eclipse.jetty.osgi.boot Bundle-Vendor: Mort Bay Consulting -Bundle-Version: 7.4.3.qualifier +Bundle-Version: 8.0.0.qualifier Bundle-Activator: org.eclipse.jetty.osgi.boot.JettyBootstrapActivator Import-Package: javax.mail;version="1.4.0";resolution:=optional, javax.mail.event;version="1.4.0";resolution:=optional, javax.mail.internet;version="1.4.0";resolution:=optional, javax.mail.search;version="1.4.0";resolution:=optional, javax.mail.util;version="1.4.0";resolution:=optional, - javax.servlet;version="2.5.0", - javax.servlet.http;version="2.5.0", + javax.servlet;version="3.0", + javax.servlet.http;version="3.0", javax.transaction;version="1.1.0";resolution:=optional, javax.transaction.xa;version="1.1.0";resolution:=optional, - org.eclipse.jetty.deploy;version="7.4.0", - org.eclipse.jetty.deploy.providers;version="7.4.0", - org.eclipse.jetty.http;version="7.4.0", - org.eclipse.jetty.nested;version="7.4.0";resolution:=optional, - org.eclipse.jetty.server;version="7.4.0", - org.eclipse.jetty.server.handler;version="7.4.0", - org.eclipse.jetty.servlet;version="7.4.0", - org.eclipse.jetty.util;version="7.4.0", - org.eclipse.jetty.util.component;version="7.4.0", - org.eclipse.jetty.util.log;version="7.4.0", - org.eclipse.jetty.util.resource;version="7.4.0", - org.eclipse.jetty.webapp;version="7.4.1.v20110513", - org.eclipse.jetty.xml;version="7.4.0", + org.eclipse.jetty.nested;version="8.0.0";resolution:=optional, + org.eclipse.jetty.annotations;version="8.0.0";resolution:=optional, + org.eclipse.jetty.deploy;version="8.0.0", + org.eclipse.jetty.deploy.providers;version="8.0.0", + org.eclipse.jetty.http;version="8.0.0", + org.eclipse.jetty.nested;version="8.0.0";resolution:=optional, + org.eclipse.jetty.server;version="8.0.0", + org.eclipse.jetty.server.handler;version="8.0.0", + org.eclipse.jetty.servlet;version="8.0.0", + org.eclipse.jetty.util;version="8.0.0", + org.eclipse.jetty.util.component;version="8.0.0", + org.eclipse.jetty.util.log;version="8.0.0", + org.eclipse.jetty.util.resource;version="8.0.0", + org.eclipse.jetty.webapp;version="8.0.0", + org.eclipse.jetty.xml;version="8.0.0", org.osgi.framework, org.osgi.service.cm;version="1.2.0", org.osgi.service.packageadmin, @@ -38,9 +40,10 @@ Import-Package: javax.mail;version="1.4.0";resolution:=optional, org.slf4j.spi;resolution:=optional, org.xml.sax, org.xml.sax.helpers -Bundle-RequiredExecutionEnvironment: J2SE-1.5 +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Bundle-Classpath: . -Export-Package: org.eclipse.jetty.osgi.boot;version="7.4.0", - org.eclipse.jetty.osgi.nested;version="7.4.0", - org.eclipse.jetty.osgi.boot.utils;version="7.4.0" -DynamicImport-Package: org.eclipse.jetty.*;version="[7.3,8)" +Export-Package: org.eclipse.jetty.osgi.boot;version="8.0.0", + org.eclipse.jetty.osgi.nested;version="8.0.0", + org.eclipse.jetty.osgi.boot.utils;version="8.0.0", + org.eclipse.jetty.osgi.annotations;version="8.0.0" +DynamicImport-Package: org.eclipse.jetty.*;version="[8.0,9)" diff --git a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml index 49bf343dc69..7ee94270903 100644 --- a/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml +++ b/jetty-osgi/jetty-osgi-boot/jettyhome/etc/jetty-osgi-default.xml @@ -123,7 +123,6 @@ - diff --git a/jetty-osgi/jetty-osgi-boot/pom.xml b/jetty-osgi/jetty-osgi-boot/pom.xml index 87a7087125d..878c70cd4ee 100644 --- a/jetty-osgi/jetty-osgi-boot/pom.xml +++ b/jetty-osgi/jetty-osgi-boot/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT ../pom.xml 4.0.0 @@ -14,6 +14,10 @@ ${project.groupId}.boot + + org.eclipse.jetty + jetty-annotations + org.eclipse.jetty jetty-webapp @@ -117,6 +121,8 @@ javax.servlet.http;version="2.5.0", javax.transaction;version="1.1.0";resolution:=optional, javax.transaction.xa;version="1.1.0";resolution:=optional, + org.eclipse.jetty.nested;version="8.0.0";resolution:=optional, + org.eclipse.jetty.annotations;version="8.0.0";resolution:=optional, org.osgi.framework, org.osgi.service.cm;version="1.2.0", org.osgi.service.packageadmin, @@ -128,12 +134,11 @@ org.slf4j.helpers;resolution:=optional, org.xml.sax, org.xml.sax.helpers, - org.eclipse.jetty.nested;resolution:=optional, * - org.eclipse.jetty.*;version="[7.3,8)" + org.eclipse.jetty.*;version="[8.0.0,9.0.0)" - J2SE-1.5 + JavaSE-1.6 diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java new file mode 100644 index 00000000000..7706b859f58 --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationConfiguration.java @@ -0,0 +1,197 @@ +// ======================================================================== +// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.osgi.annotations; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jetty.annotations.ClassNameResolver; +import org.eclipse.jetty.osgi.boot.OSGiWebappConstants; +import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker; +import org.eclipse.jetty.util.resource.Resource; +import org.eclipse.jetty.webapp.DiscoveredAnnotation; +import org.eclipse.jetty.webapp.WebAppContext; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; + +/** + * Extend the AnnotationConfiguration to support OSGi: + * Look for annotations inside WEB-INF/lib and also in the fragments and required bundles. + * Discover them using a scanner adapted to OSGi instead of the jarscanner. + */ +public class AnnotationConfiguration extends org.eclipse.jetty.annotations.AnnotationConfiguration +{ + + /** + * This parser scans the bundles using the OSGi APIs instead of assuming a jar. + */ + @Override + protected org.eclipse.jetty.annotations.AnnotationParser createAnnotationParser() + { + return new AnnotationParser(); + } + + /** + * Here is the order in which jars and osgi artifacts are scanned for discoverable annotations. + *

    + *
  1. The container jars are scanned.
  2. + *
  3. The WEB-INF/classes are scanned
  4. + *
  5. The osgi fragment to the web bundle are parsed.
  6. + *
  7. The WEB-INF/lib are scanned
  8. + *
  9. The required bundles are parsed
  10. + *
+ */ + @Override + public void parseWebInfLib (WebAppContext context, org.eclipse.jetty.annotations.AnnotationParser parser) + throws Exception + { + AnnotationParser oparser = (AnnotationParser)parser; + + Bundle webbundle = (Bundle) context.getAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE); + Bundle[] fragAndRequiredBundles = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(webbundle); + if (fragAndRequiredBundles != null) + { + //index: + for (Bundle bundle : fragAndRequiredBundles) + { + Resource bundleRes = oparser.indexBundle(bundle); + if (!context.getMetaData().getWebInfJars().contains(bundleRes)) + { + context.getMetaData().addWebInfJar(bundleRes); + } + } + + //scan the fragments + for (Bundle fragmentBundle : fragAndRequiredBundles) + { + if (fragmentBundle.getHeaders().get(Constants.FRAGMENT_HOST) != null) + { + //a fragment indeed: + parseFragmentBundle(context,oparser,webbundle,fragmentBundle); + } + } + } + //scan ourselves + parseWebBundle(context,oparser,webbundle); + + //scan the WEB-INF/lib + super.parseWebInfLib(context,parser); + if (fragAndRequiredBundles != null) + { + //scan the required bundles + for (Bundle requiredBundle : fragAndRequiredBundles) + { + if (requiredBundle.getHeaders().get(Constants.FRAGMENT_HOST) == null) + { + //a bundle indeed: + parseRequiredBundle(context,oparser,webbundle,requiredBundle); + } + } + } + } + + /** + * Scan a fragment bundle for servlet annotations + * @param context The webapp context + * @param parser The parser + * @param webbundle The current webbundle + * @param fragmentBundle The OSGi fragment bundle to scan + * @throws Exception + */ + protected void parseFragmentBundle(WebAppContext context, AnnotationParser parser, + Bundle webbundle, Bundle fragmentBundle) throws Exception + { + parseBundle(context,parser,webbundle,fragmentBundle); + } + + /** + * Scan a bundle required by the webbundle for servlet annotations + * @param context The webapp context + * @param parser The parser + * @param webbundle The current webbundle + * @param fragmentBundle The OSGi required bundle to scan + * @throws Exception + */ + protected void parseWebBundle(WebAppContext context, AnnotationParser parser, Bundle webbundle) + throws Exception + { + parseBundle(context,parser,webbundle,webbundle); + } + + /** + * Scan a bundle required by the webbundle for servlet annotations + * @param context The webapp context + * @param parser The parser + * @param webbundle The current webbundle + * @param fragmentBundle The OSGi required bundle to scan + * @throws Exception + */ + protected void parseRequiredBundle(WebAppContext context, AnnotationParser parser, + Bundle webbundle, Bundle requiredBundle) throws Exception + { + parseBundle(context,parser,webbundle,requiredBundle); + } + + protected void parseBundle(WebAppContext context, AnnotationParser parser, + Bundle webbundle, Bundle bundle) throws Exception + { + Resource bundleRes = parser.getResource(bundle); + parser.parse(bundle,createClassNameResolver(context)); + List annotations = new ArrayList(); + gatherAnnotations(annotations, parser.getAnnotationHandlers()); + if (webbundle == bundle) + { + //just like the super with its question about annotations in WEB-INF/classes: + //"TODO - where to set the annotations discovered from WEB-INF/classes?" + context.getMetaData().addDiscoveredAnnotations(annotations); + } + else + { + context.getMetaData().addDiscoveredAnnotations(bundleRes, annotations); + } + } + + /** + * Returns the same classname resolver than for the webInfjar scanner + * @param context + * @return + */ + protected ClassNameResolver createClassNameResolver(final WebAppContext context) + { + return createClassNameResolver(context,true,false,false,false); + } + + protected ClassNameResolver createClassNameResolver(final WebAppContext context, + final boolean excludeSysClass, final boolean excludeServerClass, final boolean excludeEverythingElse, + final boolean overrideIsParenLoaderIsPriority) + { + return new ClassNameResolver () + { + public boolean isExcluded (String name) + { + if (context.isSystemClass(name)) return excludeSysClass; + if (context.isServerClass(name)) return excludeServerClass; + return excludeEverythingElse; + } + + public boolean shouldOverride (String name) + { + //looking at system classpath + if (context.isParentLoaderPriority()) + return overrideIsParenLoaderIsPriority; + return !overrideIsParenLoaderIsPriority; + } + }; + } + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java new file mode 100644 index 00000000000..fa7732f791f --- /dev/null +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/annotations/AnnotationParser.java @@ -0,0 +1,192 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.osgi.annotations; + +import java.io.File; +import java.net.URI; +import java.net.URL; +import java.util.Comparator; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; + +import org.eclipse.jetty.annotations.ClassNameResolver; +import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper; +import org.eclipse.jetty.util.resource.Resource; +import org.osgi.framework.Bundle; +import org.osgi.framework.Constants; + +/** + * + */ +public class AnnotationParser extends org.eclipse.jetty.annotations.AnnotationParser +{ + private Set _alreadyParsed = new HashSet(); + + private Map _uriToBundle = new HashMap(); + private Map _resourceToBundle = new HashMap(); + private Map _bundleToUri = new HashMap(); + + /** + * Keep track of a jetty URI Resource and its associated OSGi bundle. + * @param uri + * @param bundle + * @throws Exception + */ + protected Resource indexBundle(Bundle bundle) throws Exception + { + File bundleFile = BundleFileLocatorHelper.DEFAULT.getBundleInstallLocation(bundle); + Resource resource = Resource.newResource(bundleFile.toURI()); + URI uri = resource.getURI(); + _uriToBundle.put(uri,bundle); + _bundleToUri.put(bundle,uri); + _resourceToBundle.put(bundle,resource); + return resource; + } + protected URI getURI(Bundle bundle) + { + return _bundleToUri.get(bundle); + } + protected Resource getResource(Bundle bundle) + { + return _resourceToBundle.get(bundle); + } + /** + * + */ + @Override + public void parse (URI[] uris, ClassNameResolver resolver) + throws Exception + { + for (URI uri : uris) + { + Bundle associatedBundle = _uriToBundle.get(uri); + if (associatedBundle == null) + { + if (!_alreadyParsed.add(uri)) + { + continue; + } + //a jar in WEB-INF/lib or the WEB-INF/classes + //use the behavior of the super class for a standard jar. + super.parse(new URI[] {uri},resolver); + } + else + { + parse(associatedBundle,resolver); + } + } + } + + protected void parse(Bundle bundle, ClassNameResolver resolver) + throws Exception + { + URI uri = _bundleToUri.get(bundle); + if (!_alreadyParsed.add(uri)) + { + return; + } + + String bundleClasspath = (String)bundle.getHeaders().get(Constants.BUNDLE_CLASSPATH); + if (bundleClasspath == null) + { + bundleClasspath = "."; + } + //order the paths first by the number of tokens in the path second alphabetically. + TreeSet paths = new TreeSet( + new Comparator() + { + public int compare(String o1, String o2) + { + int paths1 = new StringTokenizer(o1,"/",false).countTokens(); + int paths2 = new StringTokenizer(o2,"/",false).countTokens(); + if (paths1 == paths2) + { + return o1.compareTo(o2); + } + return paths2 - paths1; + } + }); + boolean hasDotPath = false; + StringTokenizer tokenizer = new StringTokenizer(bundleClasspath, ",;", false); + while (tokenizer.hasMoreTokens()) + { + String token = tokenizer.nextToken().trim(); + if (!token.startsWith("/")) + { + token = "/" + token; + } + if (token.equals("/.")) + { + hasDotPath = true; + } + else if (!token.endsWith(".jar") && !token.endsWith("/")) + { + paths.add(token+"/"); + } + else + { + paths.add(token); + } + } + //support the development environment: maybe the classes are inside bin or target/classes + //this is certainly not useful in production. + //however it makes our life so much easier during development. + if (bundle.getEntry("/.classpath") != null) + { + if (bundle.getEntry("/bin/") != null) + { + paths.add("/bin/"); + } + else if (bundle.getEntry("/target/classes/") != null) + { + paths.add("/target/classes/"); + } + } + Enumeration classes = bundle.findEntries("/","*.class",true); + if (classes == null) + { + return; + } + while (classes.hasMoreElements()) + { + URL classUrl = (URL) classes.nextElement(); + String path = classUrl.getPath(); + //remove the longest path possible: + String name = null; + for (String prefixPath : paths) + { + if (path.startsWith(prefixPath)) + { + name = path.substring(prefixPath.length()); + break; + } + } + if (name == null && hasDotPath) + { + //remove the starting '/' + name = path.substring(1); + } + //transform into a classname to pass to the resolver + String shortName = name.replace('/', '.').substring(0,name.length()-6); + if ((resolver == null)|| (!resolver.isExcluded(shortName) && (!isParsed(shortName) || resolver.shouldOverride(shortName)))) + scanClass(classUrl.openStream()); + } + } + +} diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java index fe3fa1ad792..1bc559d4d14 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/OSGiAppProvider.java @@ -69,7 +69,6 @@ public class OSGiAppProvider extends ScanningAppProvider implements AppProvider private String _defaultsDescriptor; private String _tldBundles; private String[] _configurationClasses; - private boolean _autoInstallOSGiBundles = true; //Keep track of the bundles that were installed and that are waiting for the diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java index 27068cb1167..4b7876b52ed 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleDeployerHelper.java @@ -499,6 +499,13 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper //can pick it up. wah.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundle); + if (wah instanceof WebAppContext) + { + if (_wrapper.getOSGiAppProvider().getConfigurationClasses() != null) + { + ((WebAppContext)wah).setConfigurationClasses(_wrapper.getOSGiAppProvider().getConfigurationClasses()); + } + } Bundle[] fragments = PackageAdminServiceTracker.INSTANCE.getFragmentsAndRequiredBundles(contributor); if (fragments != null && fragments.length != 0) @@ -812,3 +819,4 @@ public class WebBundleDeployerHelper implements IWebBundleDeployerHelper } + diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java index 3cfea34c932..0ac8a09f888 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/internal/webapp/WebBundleTrackerCustomizer.java @@ -152,7 +152,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer { String warFolderRelativePath = (String)dic.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH); if (warFolderRelativePath != null) { - String contextPath = getWebContextPath(bundle, dic, false);//(String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); + String contextPath = (String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); if (contextPath == null || !contextPath.startsWith("/")) { LOG.warn("The manifest header '" + OSGiWebappConstants.JETTY_WAR_FOLDER_PATH + @@ -215,7 +215,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer { // pointing to files and folders inside WEB-INF. We should // filter-out // META-INF too - String rfc66ContextPath = getWebContextPath(bundle,dic,rfc66Webxml==null); + String rfc66ContextPath = getWebContextPath(bundle,dic); try { JettyBootstrapActivator.registerWebapplication(bundle,".",rfc66ContextPath); @@ -230,14 +230,11 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer { } } - private String getWebContextPath(Bundle bundle, Dictionary dic, boolean webinfWebxmlExists) + private String getWebContextPath(Bundle bundle, Dictionary dic) { String rfc66ContextPath = (String)dic.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH); if (rfc66ContextPath == null) { - if (!webinfWebxmlExists) { - return null; - } // extract from the last token of the bundle's location: // (really ? // could consider processing the symbolic name as an alternative @@ -250,7 +247,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer { int lastDot = rfc66ContextPath.lastIndexOf('.'); if (lastDot != -1) { - rfc66ContextPath = rfc66ContextPath.substring(0,lastDot); + rfc66ContextPath = rfc66ContextPath.substring(0,lastDot); } } if (!rfc66ContextPath.startsWith("/")) @@ -259,7 +256,7 @@ public class WebBundleTrackerCustomizer implements BundleTrackerCustomizer { } return rfc66ContextPath; } - + private void unregister(Bundle bundle) { // nothing to do: when the bundle is stopped, each one of its service diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java index 73b127cd637..33344060fa1 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/DefaultFileLocatorHelper.java @@ -72,7 +72,7 @@ public class DefaultFileLocatorHelper implements BundleFileLocatorHelper { // some osgi frameworks do use the file protocole directly in some // situations. Do use the FileResource to transform the URL into a File: URL#toURI is broken - return new FileResource(url).getFile().getParentFile().getParentFile(); + return new FileResource(url).getFile().getParentFile().getParentFile(); } else if (url.getProtocol().equals("bundleentry")) { diff --git a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java index b7c17bbf55d..9a8b6de5d83 100644 --- a/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java +++ b/jetty-osgi/jetty-osgi-boot/src/main/java/org/eclipse/jetty/osgi/boot/utils/internal/PackageAdminServiceTracker.java @@ -314,3 +314,4 @@ public class PackageAdminServiceTracker implements ServiceListener } } + diff --git a/jetty-osgi/jetty-osgi-equinoxtools/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-equinoxtools/META-INF/MANIFEST.MF deleted file mode 100644 index 9097d5b9116..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/META-INF/MANIFEST.MF +++ /dev/null @@ -1,22 +0,0 @@ -Manifest-Version: 1.0 -Bundle-ManifestVersion: 2 -Bundle-Name: Console -Bundle-SymbolicName: org.eclipse.jetty.osgi.equinoxtools -Bundle-Description: Example application: equinox console accesssible on the web -Bundle-Version: 7.4.2.qualifier -Bundle-Activator: org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator -Import-Package: javax.servlet;version="2.5.0", - javax.servlet.http;version="2.5.0", - org.eclipse.jetty.continuation;version="7.4.0", - org.eclipse.jetty.io;version="7.4.0", - org.eclipse.jetty.util;version="7.4.0", - org.eclipse.jetty.util.log;version="7.4.0", - org.eclipse.jetty.websocket;version="7.4.0", - org.eclipse.osgi.framework.console;version="1.1.0", - org.osgi.framework;version="1.3.0", - org.osgi.service.http;version="1.2.0", - org.osgi.util.tracker;version="1.3.0" -Export-Package: org.eclipse.jetty.osgi.equinoxtools;x-internal:=true;version="7.4.2", - org.eclipse.jetty.osgi.equinoxtools.console;x-internal:=true;version="7.4.2" -Bundle-RequiredExecutionEnvironment: J2SE-1.5 - diff --git a/jetty-osgi/jetty-osgi-equinoxtools/build.properties b/jetty-osgi/jetty-osgi-equinoxtools/build.properties deleted file mode 100644 index 05786b032b1..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/build.properties +++ /dev/null @@ -1,5 +0,0 @@ -source.. = src/ -output.. = bin/ -bin.includes = META-INF/,\ - equinoxconsole/,\ - . diff --git a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/index.html b/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/index.html deleted file mode 100644 index 4deba32c282..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/index.html +++ /dev/null @@ -1,85 +0,0 @@ - - Async Equinox Console - - - -
-
-
- Username:  -
- -
- - diff --git a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/ws/index.html b/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/ws/index.html deleted file mode 100644 index 4d5acc96d7d..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/equinoxconsole/ws/index.html +++ /dev/null @@ -1,109 +0,0 @@ - - Equinox Console (WebSocket) - - - -
-
-
- Username:  -
- -
- - -

-This is a demonstration of the Jetty websocket server. -

- - - - diff --git a/jetty-osgi/jetty-osgi-equinoxtools/pom.xml b/jetty-osgi/jetty-osgi-equinoxtools/pom.xml deleted file mode 100644 index fbb16968697..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/pom.xml +++ /dev/null @@ -1,105 +0,0 @@ - - - org.eclipse.jetty.osgi - jetty-osgi-project - 7.6.0-SNAPSHOT - ../pom.xml - - 4.0.0 - jetty-osgi-equinoxtools - Jetty :: OSGi :: Example Equinox Tools - Jetty OSGi Example Equinox Tools - - v20110513 - 7.4.1.v20110513 - 3.6.0.v20100517 - 3.2.100.v20100503 - ${project.groupId}.equinoxtools - - - - org.eclipse.jetty - jetty-webapp - ${project.version} - - - org.eclipse.jetty - jetty-continuation - ${project.version} - - - org.eclipse.jetty - jetty-websocket - ${project.version} - - - org.eclipse.jetty - jetty-servlet - - - org.eclipse.osgi - org.eclipse.osgi - ${osgi-version} - - - org.eclipse.osgi - org.eclipse.osgi.services - ${osgi-services-version} - - - - - - - maven-antrun-plugin - - - process-resources - - - - - - - - - - run - - - - - - org.apache.maven.plugins - maven-jar-plugin - - - artifact-jar - - jar - - - - test-jar - - test-jar - - - - - - target/classes/META-INF/MANIFEST.MF - - - - - org.codehaus.mojo - findbugs-maven-plugin - - org.eclipse.jetty.osgi.equinoxtools.* - - - - - - diff --git a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/WebEquinoxToolsActivator.java b/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/WebEquinoxToolsActivator.java deleted file mode 100644 index 1477e0d602b..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/WebEquinoxToolsActivator.java +++ /dev/null @@ -1,127 +0,0 @@ -// ======================================================================== -// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.equinoxtools; - -import javax.servlet.ServletException; - -import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxChattingSupport; -import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxConsoleContinuationServlet; -import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxConsoleSyncServlet; -import org.eclipse.jetty.osgi.equinoxtools.console.EquinoxConsoleWebSocketServlet; -import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleSession; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.osgi.framework.console.ConsoleSession; -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; -import org.osgi.framework.ServiceReference; -import org.osgi.service.http.HttpService; -import org.osgi.service.http.NamespaceException; -import org.osgi.util.tracker.ServiceTracker; -import org.osgi.util.tracker.ServiceTrackerCustomizer; - -/** - * When started will register on the HttpService 3 servlets for 3 different styles of equinox consoles. - */ -public class WebEquinoxToolsActivator implements BundleActivator -{ - private static final Logger LOG = Log.getLogger(WebEquinoxToolsActivator.class); - - - private static BundleContext context; - public static BundleContext getContext() - { - return context; - } - - private HttpService _httpService; - private ServiceTracker _tracker; - private EquinoxChattingSupport _equinoxChattingSupport; - - - /* - * (non-Javadoc) - * - * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) - */ - public void start(BundleContext bundleContext) throws Exception - { - WebEquinoxToolsActivator.context = bundleContext; - - ServiceTrackerCustomizer httpServiceTrackerCustomizer = new ServiceTrackerCustomizer() - { - public void removedService(ServiceReference reference, Object service) - { - _httpService = null; - } - - public void modifiedService(ServiceReference reference, Object service) - { - _httpService = (HttpService)context.getService(reference); - } - - public Object addingService(ServiceReference reference) - { - _httpService = (HttpService)context.getService(reference); - try - { - //TODO; some effort to use the same console session on the 2 async console servlets? - - //websocket: -// WebConsoleSession wsSession = new WebConsoleSession(); -// WebEquinoxConsoleActivator.context.registerService(ConsoleSession.class.getName(), wsSession, null); -// EquinoxChattingSupport wsEquinoxChattingSupport = new EquinoxChattingSupport(wsSession); - _httpService.registerResources("/equinoxconsole/ws/index.html","/equinoxconsole/ws/index.html",null); - _httpService.registerServlet("/equinoxconsole/ws",new EquinoxConsoleWebSocketServlet(/*wsSession, wsEquinoxChattingSupport*/),null,null); - - //continuations: -// WebConsoleSession contSession = new WebConsoleSession(); -// WebEquinoxConsoleActivator.context.registerService(ConsoleSession.class.getName(), contSession, null); -// EquinoxChattingSupport contEquinoxChattingSupport = new EquinoxChattingSupport(contSession); - _httpService.registerResources("/equinoxconsole/index.html","/equinoxconsole/index.html",null); - _httpService.registerServlet("/equinoxconsole",new EquinoxConsoleContinuationServlet(/*contSession, contEquinoxChattingSupport*/),null,null); - - //legacy synchroneous; keep it in a separate console session. - WebConsoleSession syncSession = new WebConsoleSession(); - WebEquinoxToolsActivator.context.registerService(ConsoleSession.class.getName(), syncSession, null); - _httpService.registerServlet("/equinoxconsole/sync",new EquinoxConsoleSyncServlet(syncSession),null,null); - } - catch (ServletException e) - { - LOG.warn(e); - } - catch (NamespaceException e) - { - LOG.warn(e); - } - return _httpService; - } - }; - - _tracker = new ServiceTracker(context,HttpService.class.getName(),httpServiceTrackerCustomizer); - _tracker.open(); - } - - /* - * (non-Javadoc) - * - * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) - */ - public void stop(BundleContext bundleContext) throws Exception - { - _tracker.close(); - WebEquinoxToolsActivator.context = null; - } - - -} diff --git a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxChattingSupport.java b/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxChattingSupport.java deleted file mode 100644 index fbb9cfaa1ae..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxChattingSupport.java +++ /dev/null @@ -1,150 +0,0 @@ -// ======================================================================== -// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.equinoxtools.console; - -import java.util.LinkedList; -import java.util.Queue; - -import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener; - -/** - * Processing of the messages to be received and sent to the chat servlets. - * Made to be extended for filtering of the messages and commands. - */ -public class EquinoxChattingSupport -{ - - private WebConsoleSession _consoleSession; - - public EquinoxChattingSupport(WebConsoleSession consoleSession) - { - _consoleSession = consoleSession; - } - - /** - * Split the output into multiple lines. - * Format them for the json messages sent to the chat. - * Empties the console output from what is already displayed in the chat. - * @return The lines to add to the message queue of each client. - */ - protected Queue processConsoleOutput(boolean escape, OnFlushListener onflush) - { - Queue result = new LinkedList(); - String toDisplay = _consoleSession.getOutputAsWriter().getBuffer().toString(); - //the last listener to be called is in charge of clearing the console. - boolean clearConsole = _consoleSession.getOnFlushListeners().indexOf(onflush) == _consoleSession.getOnFlushListeners().size(); - if (clearConsole) - { - _consoleSession.clearOutput(); - } - boolean lastLineIsComplete = toDisplay.endsWith("\n") || toDisplay.endsWith("\r"); - String[] lines = toDisplay.split("\n"); - String lastLine = lastLineIsComplete ? null : lines[lines.length-1]; - if (clearConsole) - { - _consoleSession.getOutputAsWriter().append(lastLine); - } - for (int lnNb = 0; lnNb < (lastLineIsComplete ? lines.length : lines.length-1); lnNb++) - { - String line = lines[lnNb]; - while (line.trim().startsWith("null")) - {//hum.. - line = line.trim().substring("null".length()).trim(); - } - if (line.startsWith("osgi>")) - { - result.add("osgi>"); - result.add(escape ? jsonEscapeString(line.substring("osgi>".length())) : line.substring("osgi>".length())); - } - else - { - result.add(" "); - result.add(escape ? jsonEscapeString(line) : line); - } - } - return result; - } - - /** - * http://www.ietf.org/rfc/rfc4627.txt - * @param str - * @return The same string escaped according to the JSON RFC. - */ - public static String jsonEscapeString(String str) - { - StringBuilder sb = new StringBuilder(); - char[] asChars = str.toCharArray(); - for (char ch : asChars) - { - switch (ch) - { - //the reserved characters - case '"': - sb.append("\\\""); - break; - case '\\': - sb.append("\\\\"); - break; - case '\b': - sb.append("\\b"); - break; - case '\f': - sb.append("\\f"); - break; - case '\n': - sb.append("\\n"); - break; - case '\r': - sb.append("\\r"); - break; - case '\t': - sb.append("\\t"); - break; - case '/': - sb.append("\\/"); - break; - default: - //The non reserved characters - if (ch >= '\u0000' && ch <= '\u001F') - { - //escape as a unicode number when out of range. - String ss = Integer.toHexString(ch); - sb.append("\\u"); - for (int i = 0; i < 4 - ss.length(); i++) - { - //padding - sb.append('0'); - } - sb.append(ss.toUpperCase()); - } - else - { - sb.append(ch); - } - } - } - return sb.toString(); - } - - public void broadcast(OnFlushListener source) - { - for (OnFlushListener onflush : _consoleSession.getOnFlushListeners()) - { - if (onflush != source) - { - onflush.onFlush(); - } - } - } - -} diff --git a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleContinuationServlet.java b/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleContinuationServlet.java deleted file mode 100644 index 9cdf57cf844..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleContinuationServlet.java +++ /dev/null @@ -1,247 +0,0 @@ -// ======================================================================== -// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.equinoxtools.console; - -import java.io.IOException; -import java.io.PrintWriter; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.Map; -import java.util.Queue; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.continuation.Continuation; -import org.eclipse.jetty.continuation.ContinuationSupport; -import org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator; -import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener; -import org.eclipse.osgi.framework.console.ConsoleSession; - -/** - * Async servlet with jetty continuations to interact with the equinox console. - * Ported from jetty's example 'ChatServlet' - */ -public class EquinoxConsoleContinuationServlet extends HttpServlet implements OnFlushListener -{ - - private static final long serialVersionUID = 1L; - private Map _consoleUsers = new HashMap(); - private WebConsoleSession _consoleSession; - private EquinoxChattingSupport _support; - - /** - * @param consoleSession - */ - public EquinoxConsoleContinuationServlet() - { - - } - /** - * @param consoleSession - */ - public EquinoxConsoleContinuationServlet(WebConsoleSession consoleSession, EquinoxChattingSupport support) - { - _consoleSession = consoleSession; - _support = support; - } - @Override - public void init() throws ServletException - { - if (_consoleSession == null) - { - _consoleSession = new WebConsoleSession(); - WebEquinoxToolsActivator.getContext().registerService(ConsoleSession.class.getName(), _consoleSession, null); - } - if (_support == null) - { - _support = new EquinoxChattingSupport(_consoleSession); - } - _consoleSession.addOnFlushListener(this); - } - @Override - public void destroy() - { - _consoleSession.removeOnFlushListener(this); - } - - // Serve the HTML with embedded CSS and Javascript. - // This should be static content and should use real JS libraries. - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - if (request.getParameter("action")!=null) - doPost(request,response); - else - response.sendRedirect(request.getContextPath() + request.getServletPath() - + (request.getPathInfo() != null ? request.getPathInfo() : "") + "/index.html"); - } - - // Handle Ajax calls from browser - @Override - protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - // Ajax calls are form encoded - String action = request.getParameter("action"); - String message = request.getParameter("message"); - String username = request.getParameter("user"); - - if (action.equals("join")) - join(request,response,username); - else if (action.equals("poll")) - poll(request,response,username); - else if (action.equals("chat")) - chat(request,response,username,message); - } - - private synchronized void join(HttpServletRequest request,HttpServletResponse response,String username) - throws IOException - { - ConsoleUser member = new ConsoleUser(username); - _consoleUsers.put(username,member); - response.setContentType("text/json;charset=utf-8"); - PrintWriter out=response.getWriter(); - out.print("{action:\"join\"}"); - } - - private synchronized void poll(HttpServletRequest request,HttpServletResponse response,String username) - throws IOException - { - ConsoleUser member = _consoleUsers.get(username); - if (member==null) - { - response.sendError(503); - return; - } - - synchronized(member) - { - if (member.getMessageQueue().size()>0) - { - // Send one chat message - response.setContentType("text/json;charset=utf-8"); - StringBuilder buf=new StringBuilder(); - - buf.append("{\"action\":\"poll\","); - buf.append("\"from\":\""); - buf.append(member.getMessageQueue().poll()); - buf.append("\","); - - String message = member.getMessageQueue().poll(); - int quote=message.indexOf('"'); - while (quote>=0) - { - message=message.substring(0,quote)+'\\'+message.substring(quote); - quote=message.indexOf('"',quote+2); - } - buf.append("\"chat\":\""); - buf.append(message); - buf.append("\"}"); - byte[] bytes = buf.toString().getBytes("utf-8"); - response.setContentLength(bytes.length); - response.getOutputStream().write(bytes); - } - else - { - Continuation continuation = ContinuationSupport.getContinuation(request); - if (continuation.isInitial()) - { - // No chat in queue, so suspend and wait for timeout or chat - continuation.setTimeout(20000); - continuation.suspend(); - member.setContinuation(continuation); - } - else - { - // Timeout so send empty response - response.setContentType("text/json;charset=utf-8"); - PrintWriter out=response.getWriter(); - out.print("{action:\"poll\"}"); - } - } - } - } - - private synchronized void chat(HttpServletRequest request,HttpServletResponse response,String username,String message) - throws IOException - { - if (!message.endsWith("has joined!")) - { - _consoleSession.processCommand(message, false); - } - // Post chat to all members - onFlush(); - - response.setContentType("text/json;charset=utf-8"); - PrintWriter out=response.getWriter(); - out.print("{action:\"chat\"}"); - } - - /** - * Called right after the flush method on the output stream has been executed. - */ - public void onFlush() - { - Queue pendingConsoleOutputMessages = _support.processConsoleOutput(true, this); - for (ConsoleUser m:_consoleUsers.values()) - { - synchronized (m) - { -// m.getMessageQueue().add("osgi>"); // from -// m.getMessageQueue().add("something was printed"); // chat - m.getMessageQueue().addAll(pendingConsoleOutputMessages); - - // wakeup member if polling - if (m.getContinuation()!=null) - { - m.getContinuation().resume(); - m.setContinuation(null); - } - } - } - } - - class ConsoleUser - { - private String _name; - private Continuation _continuation; - private Queue _queue = new LinkedList(); - - public ConsoleUser(String name) - { - _name = name; - } - - public String getName() - { - return _name; - } - - public void setContinuation(Continuation continuation) - { - _continuation = continuation; - } - - public Continuation getContinuation() - { - return _continuation; - } - public Queue getMessageQueue() - { - return _queue; - } - - } -} diff --git a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleSyncServlet.java b/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleSyncServlet.java deleted file mode 100644 index 5ada26187e1..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleSyncServlet.java +++ /dev/null @@ -1,76 +0,0 @@ -// ======================================================================== -// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.equinoxtools.console; - -import java.io.IOException; -import java.io.PrintWriter; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - - -/** - * Take the example ChatServlet and use it to make an Equinox Console on the web. - */ -public class EquinoxConsoleSyncServlet extends HttpServlet -{ - - private static final long serialVersionUID = 1L; - - private WebConsoleSession _consoleSession; - - public EquinoxConsoleSyncServlet(WebConsoleSession consoleSession) - { - _consoleSession = consoleSession; - } - - @Override - protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - String cmd = request.getParameter("cmd"); - String Action = request.getParameter("Action"); - if (Action != null && Action.toLowerCase().indexOf("clear") != -1) - { - _consoleSession.clearOutput(); - } - if (cmd != null) - { - _consoleSession.processCommand(cmd, true); - } - - response.setContentType("text/html;charset=utf-8"); - PrintWriter p = response.getWriter(); - p.println("Equinox Console (Synchroneous)"); - p.println(""); - p.println("
"); - p.println("osgi> 
\n"); - p.println("
"); - p.println("
"); - p.println("
"); - p.println("
"); - } - - - private String getURI(HttpServletRequest request) - { - String uri= (String)request.getAttribute("javax.servlet.forward.request_uri"); - if (uri == null) - uri= request.getRequestURI(); - return uri; - } - -} diff --git a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleWebSocketServlet.java b/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleWebSocketServlet.java deleted file mode 100644 index f56e88fb5e2..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/EquinoxConsoleWebSocketServlet.java +++ /dev/null @@ -1,176 +0,0 @@ -// ======================================================================== -// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.equinoxtools.console; - -import java.io.IOException; -import java.util.Queue; -import java.util.Set; -import java.util.concurrent.CopyOnWriteArraySet; - -import javax.servlet.ServletException; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.osgi.equinoxtools.WebEquinoxToolsActivator; -import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener; -import org.eclipse.jetty.util.log.Log; -import org.eclipse.jetty.util.log.Logger; -import org.eclipse.jetty.websocket.WebSocket; -import org.eclipse.jetty.websocket.WebSocketServlet; -import org.eclipse.osgi.framework.console.ConsoleSession; - -/** - * Websocket version of the Chat with equinox. - * Ported from jetty's example 'WebSocketChatServlet' - */ -public class EquinoxConsoleWebSocketServlet extends WebSocketServlet implements OnFlushListener -{ - private static final Logger LOG = Log.getLogger(EquinoxConsoleWebSocketServlet.class); - - private final Set _members = new CopyOnWriteArraySet(); - private static final long serialVersionUID = 1L; - private WebConsoleSession _consoleSession; - private EquinoxChattingSupport _support; - - public EquinoxConsoleWebSocketServlet() - { - - } - public EquinoxConsoleWebSocketServlet(WebConsoleSession consoleSession, EquinoxChattingSupport support) - { - _consoleSession = consoleSession; - _support = support; - } - @Override - public void init() throws ServletException - { - if (_consoleSession == null) - { - _consoleSession = new WebConsoleSession(); - WebEquinoxToolsActivator.getContext().registerService(ConsoleSession.class.getName(), _consoleSession, null); - } - if (_support == null) - { - _support = new EquinoxChattingSupport(_consoleSession); - } - super.init(); - _consoleSession.addOnFlushListener(this); - } - - @Override - public void destroy() - { - _consoleSession.removeOnFlushListener(this); - } - - - protected void doGet(HttpServletRequest request, HttpServletResponse response) - throws javax.servlet.ServletException ,IOException - { - //getServletContext().getNamedDispatcher("default").forward(request,response); - response.sendRedirect(request.getContextPath() + request.getServletPath() - + (request.getPathInfo() != null ? request.getPathInfo() : "") + "/index.html"); - }; - - public WebSocket doWebSocketConnect(HttpServletRequest request, String protocol) - { - return new ChatWebSocket(); - } - - /* ------------------------------------------------------------ */ - /* ------------------------------------------------------------ */ - class ChatWebSocket implements WebSocket.OnTextMessage - { - Connection _connection; - String _username; - - public void onOpen(Connection connection) - { - // LOG.info(this+" onConnect"); - _connection=connection; - _members.add(this); - } - - public void onMessage(byte frame, byte[] data,int offset, int length) - { - // LOG.info(this+" onMessage: "+TypeUtil.toHexString(data,offset,length)); - } - - public void onMessage(String data) - { - LOG.info("onMessage: {}",data); - if (data.indexOf("disconnect")>=0) - _connection.disconnect(); - else - { - if (!data.endsWith(":has joined!")) - { - if (_username != null) - { - if (data.startsWith(_username + ":")) - { - data = data.substring(_username.length()+1); - } - else - { - //we should not be here? - } - } - _consoleSession.processCommand(data, false); - } - else - { - _username = data.substring(0, data.length()-":has joined!".length()); - } - // LOG.info(this+" onMessage: "+data); - onFlush(); - } - } - - public void onClose(int code, String message) - { - // LOG.info(this+" onDisconnect"); - _members.remove(this); - } - - public void onError(String message, Throwable ex) - { - - } - - } - - - /** - * Called right after the flush method on the output stream has been executed. - */ - public void onFlush() - { - Queue pendingConsoleOutputMessages = _support.processConsoleOutput(false, this); - for (ChatWebSocket member : _members) - { - try - { - for (String line : pendingConsoleOutputMessages) - { - member._connection.sendMessage(line); - } - } - catch(IOException e) - { - LOG.warn(e); - } - } - } - -} diff --git a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/WebConsoleSession.java b/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/WebConsoleSession.java deleted file mode 100644 index 614c0fc6c2f..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/WebConsoleSession.java +++ /dev/null @@ -1,183 +0,0 @@ -// ======================================================================== -// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.equinoxtools.console; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.PipedInputStream; -import java.io.PipedOutputStream; -import java.io.PrintStream; -import java.io.StringWriter; -import java.util.List; - -import org.eclipse.jetty.osgi.equinoxtools.console.WebConsoleWriterOutputStream.OnFlushListener; -import org.eclipse.osgi.framework.console.ConsoleSession; - -/** - * A simple console session for equinox. - * - * @author hmalphettes - */ -public class WebConsoleSession extends ConsoleSession -{ - - private OutputStream _out; - private StringWriter _outWriter; - private PrintStream _source; - private InputStream _in; - - public WebConsoleSession() - { - _outWriter = new StringWriter(); - _out = new WebConsoleWriterOutputStream(_outWriter,"UTF-8"); - try - { - PipedOutputStream source = new PipedOutputStream(); - PipedInputStream sink = new PipedInputStream(source); - _in = sink; - _source = new PrintStream(source); - } - catch (IOException e) - { - //this never happens? - e.printStackTrace(); - } - } - - @Override - protected void doClose() - { - if (_out != null) try { _out.close(); } catch (IOException e) {} - if (_in != null) try { _in.close(); } catch (IOException ioe) {} - } - - @Override - public InputStream getInput() - { - return _in; - } - - @Override - public OutputStream getOutput() - { - return _out; - } - - /** - * For the output we are using a string writer in fact. - * @return - */ - public StringWriter getOutputAsWriter() - { - return _outWriter; - } - - /** - * @return The print stream where commands can be written. - */ - public PrintStream getSource() - { - return _source; - } - - /** - * Issue a command on the console. - * @param cmd - */ - public void issueCommand(String cmd) - { - if (cmd != null) - { - getSource().println(cmd); - } - } - - /** - * @param flushListener Object that is called back when the outputstream is flushed. - */ - public void addOnFlushListener(OnFlushListener flushListener) - { - ((WebConsoleWriterOutputStream)_out).addOnFlushListener(flushListener); - } - /** - * @param flushListener Object that is called back when the outputstream is flushed. - */ - public boolean removeOnFlushListener(OnFlushListener flushListener) - { - return ((WebConsoleWriterOutputStream)_out).removeOnFlushListener(flushListener); - } - - /** - * Process command comming from a web UI - * @param cmd - */ - public void processCommand(String cmd, boolean wait) - { - cmd = cmd.trim(); - while (cmd.startsWith("osgi>")) - { - cmd = cmd.substring("osgi>".length()).trim(); - } - if (cmd.equals("clear")) - { - clearOutput(); - } - else - { - getOutputAsWriter().append(cmd + "\n"); - int originalOutputLength = getOutputAsWriter().getBuffer().length(); - issueCommand(cmd); - - if (wait) - { - //it does not get uglier than this: - //give a little time to equinox to interpret the command so we see the response - //we could do a lot better, but we might as well use the async servlets anyways. - int waitLoopNumber = 0; - int lastWaitOutputLength = -1; - while (waitLoopNumber < 10) - { - waitLoopNumber++; - try - { - Thread.sleep(100); - } - catch (InterruptedException e) - { - break; - } - int newOutputLength = getOutputAsWriter().getBuffer().length(); - if (newOutputLength > originalOutputLength && newOutputLength == lastWaitOutputLength) - { - break; - } - lastWaitOutputLength = newOutputLength; - } - } - } - - } - - public void clearOutput() - { - StringBuffer buf = getOutputAsWriter().getBuffer(); - if (buf.length() > 0) buf.delete(0,buf.length()-1); - } - - public List getOnFlushListeners() - { - return ((WebConsoleWriterOutputStream)_out).getOnFlushListeners(); - } - -} diff --git a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/WebConsoleWriterOutputStream.java b/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/WebConsoleWriterOutputStream.java deleted file mode 100644 index d9d26ea58a8..00000000000 --- a/jetty-osgi/jetty-osgi-equinoxtools/src/main/java/org/eclipse/jetty/osgi/equinoxtools/console/WebConsoleWriterOutputStream.java +++ /dev/null @@ -1,87 +0,0 @@ -// ======================================================================== -// Copyright (c) 2006-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.equinoxtools.console; - -import java.io.IOException; -import java.io.Writer; -import java.util.ArrayList; -import java.util.List; - -/** - * Can be set with a listener that is called back right after the flush method is called. - */ -public class WebConsoleWriterOutputStream extends org.eclipse.jetty.io.WriterOutputStream -{ - - /** - * Interface called back after the outputstream is flushed. - */ - public interface OnFlushListener - { - /** - * Called right after the flush method on the output stream has been executed. - */ - public void onFlush(); - - } - - public interface MessageBroadcaster - { - public void broadcast(); - } - - private List _callBacks; - - public WebConsoleWriterOutputStream(Writer writer, String encoding) - { - super(writer, encoding); - } - - @Override - public synchronized void flush() throws IOException - { - super.flush(); - if (_callBacks != null) - { - for (OnFlushListener listener : _callBacks) - { - listener.onFlush(); - } - } - } - - public synchronized void addOnFlushListener(OnFlushListener callback) - { - if (_callBacks == null) - { - _callBacks = new ArrayList(); - } - if (!_callBacks.contains(callback)) - { - _callBacks.add(callback); - } - } - public synchronized boolean removeOnFlushListener(OnFlushListener callback) - { - if (_callBacks != null) - { - return _callBacks.remove(callback); - } - return false; - } - public synchronized List getOnFlushListeners() - { - return _callBacks; - } - -} diff --git a/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF b/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF index e148da82193..688b721821c 100644 --- a/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF +++ b/jetty-osgi/jetty-osgi-httpservice/META-INF/MANIFEST.MF @@ -1,16 +1,17 @@ +Manifest-Version: 1.0 Bundle-ManifestVersion: 2 -Bundle-RequiredExecutionEnvironment: J2SE-1.5 -Bundle-SymbolicName: org.eclipse.jetty.osgi.httpservice -Bundle-Version: 7.4.2.qualifier -Bundle-Vendor: Mort Bay Consulting Bundle-Name: OSGi HttpService provided by equinox HttpServiceServlet deployed on jetty +Bundle-SymbolicName: org.eclipse.jetty.osgi.httpservice +Bundle-Version: 8.0.0.qualifier +Bundle-Vendor: Mort Bay Consulting +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Jetty-ContextFilePath: contexts/httpservice.xml -Import-Package: javax.servlet;version="2.5.0", - javax.servlet.http;version="2.5.0", +Import-Package: javax.servlet;version="3.0", + javax.servlet.http;version="3.0", org.eclipse.equinox.http.servlet, org.eclipse.jetty.server;version="7.0.0", org.eclipse.jetty.server.handler;version="7.0.0", org.eclipse.jetty.servlet;version="7.4.0", org.eclipse.jetty.util.component;version="7.0.0" -Export-Package: org.eclipse.jetty.osgi.httpservice;version="7.4.2" +Export-Package: org.eclipse.jetty.osgi.httpservice;version="8.0.0" diff --git a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml index 95757f6c80f..211a8e8ce28 100644 --- a/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml +++ b/jetty-osgi/jetty-osgi-httpservice/contexts/httpservice.xml @@ -1,7 +1,7 @@ - 7.5.2-SNAPSHOT - ../pom.xml - - 4.0.0 - org.eclipse.jetty.osgi - jetty-osgi-servletbridge - Jetty :: OSGi :: Servletbridge - Jetty OSGi Servletbridge webapp - war - false - - - org.eclipse.equinox - org.eclipse.equinox.servletbridge - 1.2.0.v20100503 - - - javax.servlet - servlet-api - provided - - - org.eclipse.osgi - org.eclipse.osgi - 3.6.0.v20100517 - provided - - - - - - intalio-org - http://intalio.org/public/maven2 - - - - - - org.apache.maven.plugins - maven-eclipse-plugin - - false - - - - - diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/nested/Dump.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/nested/Dump.java deleted file mode 100644 index dbb0e2a78c0..00000000000 --- a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/nested/Dump.java +++ /dev/null @@ -1,1143 +0,0 @@ -package org.eclipse.jetty.nested; -// ======================================================================== -// Copyright (c) 1996-2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - - -import java.io.BufferedWriter; -import java.io.File; -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.Reader; -import java.lang.reflect.Array; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.Statement; -import java.util.Date; -import java.util.Enumeration; -import java.util.Locale; -import java.util.Map.Entry; - -import javax.servlet.ServletConfig; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletRequestWrapper; -import javax.servlet.ServletResponse; -import javax.servlet.ServletResponseWrapper; -import javax.servlet.UnavailableException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; -import javax.sql.DataSource; - -//import org.eclipse.jetty.continuation.Continuation; -//import org.eclipse.jetty.continuation.ContinuationListener; -//import org.eclipse.jetty.continuation.ContinuationSupport; -//import org.eclipse.jetty.http.HttpHeaders; -//import org.eclipse.jetty.util.StringUtil; -//import org.eclipse.jetty.util.log.Log; -//import org.eclipse.jetty.util.log.Logger; - - - -/* ------------------------------------------------------------ */ -/** Dump Servlet Request. - * - */ -public class Dump extends HttpServlet -{ - //private static final Logger LOG = Log.getLogger(Dump.class); - - boolean fixed; - - /* ------------------------------------------------------------ */ - @Override - public void init(ServletConfig config) throws ServletException - { - super.init(config); - - if (config.getInitParameter("unavailable")!=null && !fixed) - { - - fixed=true; - throw new UnavailableException("Unavailable test",Integer.parseInt(config.getInitParameter("unavailable"))); - } - } - - /* ------------------------------------------------------------ */ - @Override - public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException - { - doGet(request, response); - } - - /* ------------------------------------------------------------ */ - @Override - public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException - { - // Handle a dump of data - final String data= request.getParameter("data"); - final String chars= request.getParameter("chars"); - final String block= request.getParameter("block"); - final String dribble= request.getParameter("dribble"); - final boolean flush= request.getParameter("flush")!=null?Boolean.parseBoolean(request.getParameter("flush")):false; - - - if(request.getPathInfo()!=null && request.getPathInfo().toLowerCase().indexOf("script")!=-1) - { - response.sendRedirect(response.encodeRedirectURL(getServletContext().getContextPath() + "/dump/info")); - return; - } - - request.setCharacterEncoding("UTF-8"); - - if (request.getParameter("empty")!=null) - { - response.setStatus(200); - response.flushBuffer(); - return; - } - -/* if (request.getParameter("sleep")!=null) - { - try - { - long s = Long.parseLong(request.getParameter("sleep")); - if (request.getHeader(HttpHeaders.EXPECT)!=null &&request.getHeader(HttpHeaders.EXPECT).indexOf("102")>=0) - { - Thread.sleep(s/2); - response.sendError(102); - Thread.sleep(s/2); - } - else - Thread.sleep(s); - } - catch (InterruptedException e) - { - return; - } - catch (Exception e) - { - throw new ServletException(e); - } - } - - if (request.getAttribute("RESUME")==null && request.getParameter("resume")!=null) - { - request.setAttribute("RESUME",Boolean.TRUE); - - final long resume=Long.parseLong(request.getParameter("resume")); - new Thread(new Runnable() - { - public void run() - { - try - { - Thread.sleep(resume); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - Continuation continuation = ContinuationSupport.getContinuation(request); - continuation.resume(); - } - - }).start(); - } - - if (request.getParameter("complete")!=null) - { - final long complete=Long.parseLong(request.getParameter("complete")); - new Thread(new Runnable() - { - public void run() - { - try - { - Thread.sleep(complete); - } - catch (InterruptedException e) - { - e.printStackTrace(); - } - try - { - response.setContentType("text/html"); - response.getOutputStream().println("

COMPLETED

"); - Continuation continuation = ContinuationSupport.getContinuation(request); - continuation.complete(); - } - catch (IOException e) - { - e.printStackTrace(); - } - } - - }).start(); - } - - if (request.getParameter("suspend")!=null && request.getAttribute("SUSPEND")!=Boolean.TRUE) - { - request.setAttribute("SUSPEND",Boolean.TRUE); - try - { - Continuation continuation = ContinuationSupport.getContinuation(request); - continuation.setTimeout(Long.parseLong(request.getParameter("suspend"))); - continuation.suspend(); - - continuation.addContinuationListener(new ContinuationListener() - { - public void onTimeout(Continuation continuation) - { - response.addHeader("Dump","onTimeout"); - try - { - dump(response,data,chars,block,dribble,flush); - continuation.complete(); - } - catch (IOException e) - { - LOG.ignore(e); - } - } - - public void onComplete(Continuation continuation) - { - response.addHeader("Dump","onComplete"); - } - }); - - continuation.undispatch(); - } - catch(Exception e) - { - throw new ServletException(e); - } - } */ - - request.setAttribute("Dump", this); - getServletContext().setAttribute("Dump",this); - // getServletContext().log("dump "+request.getRequestURI()); - - // Force a content length response - String length= request.getParameter("length"); - if (length != null && length.length() > 0) - { - response.setContentLength(Integer.parseInt(length)); - } - - // Handle a dump of data - if (dump(response,data,chars,block,dribble,flush)) - return; - - // handle an exception - String info= request.getPathInfo(); - if (info != null && info.endsWith("Exception")) - { - try - { - throw (Throwable) Thread.currentThread().getContextClassLoader().loadClass(info.substring(1)).newInstance(); - } - catch (Throwable th) - { - throw new ServletException(th); - } - } - - // test a reset - String reset= request.getParameter("reset"); - if (reset != null && reset.length() > 0) - { - response.getOutputStream().println("THIS SHOULD NOT BE SEEN!"); - response.setHeader("SHOULD_NOT","BE SEEN"); - response.reset(); - } - - - // handle an redirect - String redirect= request.getParameter("redirect"); - if (redirect != null && redirect.length() > 0) - { - response.getOutputStream().println("THIS SHOULD NOT BE SEEN!"); - response.sendRedirect(response.encodeRedirectURL(redirect)); - try - { - response.getOutputStream().println("THIS SHOULD NOT BE SEEN!"); - } - catch(IOException e) - { - // ignored as stream is closed. - } - return; - } - - // handle an error - String error= request.getParameter("error"); - if (error != null && error.length() > 0 && request.getAttribute("javax.servlet.error.status_code")==null) - { - response.getOutputStream().println("THIS SHOULD NOT BE SEEN!"); - response.sendError(Integer.parseInt(error)); - try - { - response.getOutputStream().println("THIS SHOULD NOT BE SEEN!"); - } - catch(IllegalStateException e) - { - try - { - response.getWriter().println("NOR THIS!!"); - } - catch(IOException e2){} - } - catch(IOException e){} - return; - } - - // Handle a extra headers - String headers= request.getParameter("headers"); - if (headers != null && headers.length() > 0) - { - long h=Long.parseLong(headers); - for (int i=0;i 0) - response.setBufferSize(Integer.parseInt(buffer)); - - String charset= request.getParameter("charset"); - if (charset==null) - charset="UTF-8"; - response.setCharacterEncoding(charset); - response.setContentType("text/html"); - - if (info != null && info.indexOf("Locale/") >= 0) - { - try - { - String locale_name= info.substring(info.indexOf("Locale/") + 7); - Field f= java.util.Locale.class.getField(locale_name); - response.setLocale((Locale)f.get(null)); - } - catch (Exception e) - { - e.printStackTrace(); - response.setLocale(Locale.getDefault()); - } - } - - String cn= request.getParameter("cookie"); - String cv=request.getParameter("cookiev"); - if (cn!=null && cv!=null) - { - Cookie cookie= new Cookie(cn, cv); - if (request.getParameter("version")!=null) - cookie.setVersion(Integer.parseInt(request.getParameter("version"))); - cookie.setComment("Cookie from dump servlet"); - response.addCookie(cookie); - } - - String pi= request.getPathInfo(); - if (pi != null && pi.startsWith("/ex")) - { - OutputStream out= response.getOutputStream(); - out.write("This text should be reset".getBytes()); - if ("/ex0".equals(pi)) - throw new ServletException("test ex0", new Throwable()); - else if ("/ex1".equals(pi)) - throw new IOException("test ex1"); - else if ("/ex2".equals(pi)) - throw new UnavailableException("test ex2"); - else if (pi.startsWith("/ex3/")) - throw new UnavailableException("test ex3",Integer.parseInt(pi.substring(5))); - throw new RuntimeException("test"); - } - - if ("true".equals(request.getParameter("close"))) - response.setHeader("Connection","close"); - - String buffered= request.getParameter("buffered"); - - PrintWriter pout=null; - - try - { - pout =response.getWriter(); - } - catch(IllegalStateException e) - { - pout=new PrintWriter(new OutputStreamWriter(response.getOutputStream(),charset)); - } - if (buffered!=null) - pout = new PrintWriter(new BufferedWriter(pout,Integer.parseInt(buffered))); - - try - { - pout.write("\n\n"); - pout.write("

Dump Servlet

\n"); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - - pout.write("\n"); - pout.write(""); - pout.write(""); - - pout.write("\n"); - pout.write(""); - pout.write(""); - - Enumeration locales= request.getLocales(); - while (locales.hasMoreElements()) - { - pout.write("\n"); - pout.write(""); - pout.write(""); - } - pout.write("\n"); - - pout.write(""); - Enumeration h= request.getHeaderNames(); - String name; - while (h.hasMoreElements()) - { - name= (String)h.nextElement(); - - Enumeration h2= request.getHeaders(name); - while (h2.hasMoreElements()) - { - String hv= (String)h2.nextElement(); - pout.write("\n"); - pout.write(""); - pout.write(""); - } - } - - //Test the system properties - if ("true".equals(request.getParameter("env"))) - { - pout.write("\n"); - pout.write(""); - for (Entry e : System.getenv().entrySet()) - { - pout.write("\n"); - pout.write(""); - pout.write(""); - } - - pout.write("\n"); - pout.write(""); - - for (Entry e : System.getProperties().entrySet()) - { - pout.write("\n"); - pout.write(""); - pout.write(""); - } - } - - //handle testing jdbc connections: - String jdbcUrl = request.getParameter("jdbc-url"); - String jdbcDriver = request.getParameter("jdbc-driver"); - if (jdbcUrl != null) - { - Connection con = null; - try - { - String user = request.getParameter("jdbc-user"); - String pass = request.getParameter("jdbc-pass"); - String query = request.getParameter("jdbc-query"); - if (user.length() == 0) user = null; - if (pass.length() == 0) pass = null; - if (query == null || query.length() == 0) query = "show tables;"; - pout.write("\n"); - pout.write(""); - - Class driver = Thread.currentThread().getContextClassLoader().loadClass(jdbcDriver); - - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - - con = user != null ? DriverManager.getConnection(jdbcUrl, user, pass) : DriverManager.getConnection(jdbcUrl); - - Statement statement = con.createStatement(); - boolean success = statement.execute(query); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - - } - catch (Throwable t) - { - pout.write("\n"); - pout.write(""); - pout.write(""); - } - finally - { - if (con != null) - { - try { con.close(); } catch (Throwable ee) {} - } - } - } - - - pout.write("\n"); - pout.write(""); - h= request.getParameterNames(); - while (h.hasMoreElements()) - { - name= (String)h.nextElement(); - pout.write("\n"); - pout.write(""); - pout.write(""); - String[] values= request.getParameterValues(name); - if (values == null) - { - pout.write("\n"); - pout.write(""); - pout.write(""); - } - else if (values.length > 1) - { - for (int i= 0; i < values.length; i++) - { - pout.write("\n"); - pout.write(""); - pout.write(""); - } - } - } - - pout.write("\n"); - pout.write(""); - Cookie[] cookies = request.getCookies(); - for (int i=0; cookies!=null && i\n"); - pout.write(""); - pout.write(""); - } - - String content_type=request.getContentType(); - if (content_type!=null && - !content_type.startsWith("application/x-www-form-urlencoded") && - !content_type.startsWith("multipart/form-data")) - { - pout.write("\n"); - pout.write(""); - pout.write("\n"); - pout.write(""); - } - - pout.write("\n"); - pout.write(""); - Enumeration a= request.getAttributeNames(); - while (a.hasMoreElements()) - { - name= (String)a.nextElement(); - pout.write("\n"); - pout.write(""); - Object value=request.getAttribute(name); - if (value instanceof File) - { - File file = (File)value; - pout.write(""); - } - else - pout.write(""); - } - request.setAttribute("org.eclipse.jetty.servlet.MultiPartFilter.files",null); - - - pout.write("\n"); - pout.write(""); - a= getInitParameterNames(); - while (a.hasMoreElements()) - { - name= (String)a.nextElement(); - pout.write("\n"); - pout.write(""); - pout.write(""); - } - - pout.write("\n"); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - - String webinfRealPath = getServletContext().getRealPath("/WEB-INF/"); - if (webinfRealPath != null) - { - try - { - File webInfRealPathFile = new File(webinfRealPath); - pout.write("\n"); - pout.write(""); - pout.write(""); - if (webInfRealPathFile.exists() && webInfRealPathFile.isDirectory()) - { - File webxml = new File(webInfRealPathFile, "web.xml"); - pout.write("\n"); - pout.write(""); - pout.write(""); - } - } - catch (Throwable t) - { - pout.write(""); - pout.write(""); - } - } - - - pout.write("\n"); - pout.write(""); - pout.write(""); - pout.write("\n"); - pout.write(""); - pout.write(""); - - pout.write("\n"); - pout.write(""); - a= getServletContext().getInitParameterNames(); - while (a.hasMoreElements()) - { - name= (String)a.nextElement(); - pout.write("\n"); - pout.write(""); - pout.write(""); - } - - pout.write("\n"); - pout.write(""); - a= getServletContext().getAttributeNames(); - while (a.hasMoreElements()) - { - name= (String)a.nextElement(); - pout.write("\n"); - pout.write(""); - pout.write(""); - } - - String res= request.getParameter("resource"); - if (res != null && res.length() > 0) - { - pout.write("\n"); - pout.write(""); - - pout.write("\n"); - pout.write(""); - - ServletContext context = getServletContext().getContext(res); - pout.write(""); - - if (context!=null) - { - String cp=context.getContextPath(); - if (cp==null || "/".equals(cp)) - cp=""; - pout.write("\n"); - pout.write(""); - pout.write(""); - } - - pout.write("\n"); - pout.write(""); - pout.write(""); - - pout.write("\n"); - pout.write(""); - pout.write(""); - - pout.write("\n"); - pout.write(""); - pout.write(""); - - pout.write("\n"); - pout.write(""); - try{pout.write("");} - catch(Exception e) {pout.write("");} - } - - - pout.write("
getMethod: " + notag(request.getMethod())+"
getContentLength: "+Integer.toString(request.getContentLength())+"
getContentType: "+notag(request.getContentType())+"
getRequestURI: "+notag(request.getRequestURI())+"
getRequestURL: "+notag(request.getRequestURL().toString())+"
getContextPath: "+request.getContextPath()+"
getServletPath: "+notag(request.getServletPath())+"
getPathInfo: "+notag(request.getPathInfo())+"
getPathTranslated: "+notag(request.getPathTranslated())+"
getQueryString: "+notag(request.getQueryString())+"
getProtocol: "+request.getProtocol()+"
getScheme: "+request.getScheme()+"
getServerName: "+notag(request.getServerName())+"
getServerPort: "+Integer.toString(request.getServerPort())+"
getLocalName: "+request.getLocalName()+"
getLocalAddr: "+request.getLocalAddr()+"
getLocalPort: "+Integer.toString(request.getLocalPort())+"
getRemoteUser: "+request.getRemoteUser()+"
getUserPrincipal: "+request.getUserPrincipal()+"
getRemoteAddr: "+request.getRemoteAddr()+"
getRemoteHost: "+request.getRemoteHost()+"
getRemotePort: "+request.getRemotePort()+"
getRequestedSessionId: "+request.getRequestedSessionId()+"
isSecure(): "+request.isSecure()+"
isUserInRole(admin): "+request.isUserInRole("admin")+"
getLocale: "+request.getLocale()+"
getLocales: "+locales.nextElement()+"

Other HTTP Headers:
"+notag(name)+": "+notag(hv)+"

Environment: 
" + notag(String.valueOf(e.getKey())) + ": "+notag(String.valueOf(e.getValue()))+"

System-Properties: 
" + notag(String.valueOf(e.getKey())) + ": "+notag(String.valueOf(e.getValue()))+"

JDBC test: 
Driver class: "+driver.getName()+" loaded by " + driver.getClassLoader()+"
Connection url: "+jdbcUrl+"
User (optional): "+user+"
Is there a password (optional): "+(pass != null ? "yes" : "no" )+"
Query: "+query+"
Successful query: "+success+"
JDBC test error: "+t+"

Request Parameters:
"+notag(name)+": "+notag(request.getParameter(name))+"
"+notag(name)+" Values: "+"NULL!"+"
"+notag(name)+"["+i+"]: "+notag(values[i])+"

Cookies:
"+notag(cookie.getName())+": "+notag(cookie.getValue())+"

Content:
");
-                char[] content= new char[4096];
-                int len;
-                try{
-                    Reader in=request.getReader();
-                    
-                    while((len=in.read(content))>=0)
-                        pout.write(notag(new String(content,0,len)));
-                }
-                catch(IOException e)
-                {
-                    pout.write(e.toString());
-                }
-                
-                pout.write("

Request Attributes:
"+name.replace("."," .")+": "+"
" + file.getName()+" ("+file.length()+" "+new Date(file.lastModified())+ ")
"+"
"+"
" + toString(request.getAttribute(name)) + "
"+"

Servlet InitParameters:
"+name+": "+ toString(getInitParameter(name)) +"

ServletContext Misc:
"+"servletContext.getContextPath()"+": "+ getServletContext().getContextPath() + "
"+"getServletContext().getRealPath(\"/WEB-INF/\")"+": "+ getServletContext().getRealPath("/WEB-INF/") + "
"+"new File(getServletContext().getRealPath(\"/WEB-INF/\"))"+": exists()="+ webInfRealPathFile.exists() - + "; isFile()="+webInfRealPathFile.isFile() - + "; isDirectory()="+webInfRealPathFile.isDirectory() - + "; isAbsolute()=" + webInfRealPathFile.isAbsolute() - + "; canRead()=" + webInfRealPathFile.canRead() - + "; canWrite()=" + webInfRealPathFile.canWrite() - +"
"+"new File(getServletContext().getRealPath(\"/WEB-INF/web.xml\"))"+": exists()="+ webxml.exists() - + "; isFile()="+webxml.isFile() - + "; isDirectory()="+webxml.isDirectory() - + "; isAbsolute()=" + webxml.isAbsolute() - + "; canRead()=" + webxml.canRead() - + "; canWrite()=" + webxml.canWrite() - +""+"Error probing the java.io.File(getServletContext().getRealPath(\"/WEB-INF/\"))"+": "+ t + "
"+"getServletContext().getServerInfo()"+": "+ getServletContext().getServerInfo() + "
"+"getServletContext().getServletContextName()"+": "+ getServletContext().getServletContextName() + "

Context InitParameters:
"+name.replace("."," .")+": "+ toString(getServletContext().getInitParameter(name)) + "

Context Attributes:
"+name.replace("."," .")+": "+"
" + toString(getServletContext().getAttribute(name)) + "
"+"

Get Resource: \""+res+"\"
getServletContext().getContext(...): "+context+"
getServletContext().getContext(...),getRequestDispatcher(...): "+getServletContext().getContext(res).getRequestDispatcher(res.substring(cp.length()))+"
this.getClass().getResource(...): "+this.getClass().getResource(res)+"
this.getClass().getClassLoader().getResource(...): "+this.getClass().getClassLoader().getResource(res)+"
Thread.currentThread().getContextClassLoader().getResource(...): "+Thread.currentThread().getContextClassLoader().getResource(res)+"
getServletContext().getResource(...): "+getServletContext().getResource(res)+""+"" +e+"
\n"); - - /* ------------------------------------------------------------ */ - pout.write("

Request Wrappers

\n"); - ServletRequest rw=request; - int w=0; - while (rw !=null) - { - pout.write((w++)+": "+rw.getClass().getName()+"
"); - if (rw instanceof HttpServletRequestWrapper) - rw=((HttpServletRequestWrapper)rw).getRequest(); - else if (rw instanceof ServletRequestWrapper) - rw=((ServletRequestWrapper)rw).getRequest(); - else - rw=null; - } - - /* ------------------------------------------------------------ */ - pout.write("

Response Wrappers

\n"); - ServletResponse rsw=response; - w=0; - while (rsw !=null) - { - pout.write((w++)+": "+rsw.getClass().getName()+"
"); - if (rsw instanceof HttpServletResponseWrapper) - rsw=((HttpServletResponseWrapper)rsw).getResponse(); - else if (rsw instanceof ServletResponseWrapper) - rsw=((ServletResponseWrapper)rsw).getResponse(); - else - rsw=null; - } - - pout.write("
"); - pout.write("

International Characters (UTF-8)

"); - pout.write("LATIN LETTER SMALL CAPITAL AE
\n"); - pout.write("Directly uni encoded(\\u1d01): \u1d01
"); - pout.write("HTML reference (&AElig;): Æ
"); - pout.write("Decimal (&#7425;): ᴁ
"); - pout.write("Javascript unicode (\\u1d01) :
"); - pout.write("
"); - pout.write("

Form to generate GET content

"); - pout.write("
"); - pout.write("TextField:
\n"); - pout.write(""); - pout.write("
"); - - pout.write("
"); - - pout.write("

Form to generate POST content

"); - pout.write("
"); - pout.write("TextField:
\n"); - pout.write("Select:
"); - pout.write("
"); - pout.write("
"); - pout.write("
"); - - pout.write("

Form to generate UPLOAD content

"); - pout.write("
"); - pout.write("TextField:
\n"); - pout.write("File 1:
\n"); - pout.write("File 2:
\n"); - pout.write("
"); - pout.write("
"); - - pout.write("

Form to set Cookie

"); - pout.write("
"); - pout.write("cookie:
\n"); - pout.write("value:
\n"); - pout.write(""); - pout.write("
\n"); - - pout.write("

Form to get Resource

"); - pout.write("
"); - pout.write("resource:
\n"); - pout.write(""); - pout.write("
\n"); - - pout.write("

Form to test a JDBC connection URL

"); - String jdbcUser = request.getParameter("jdbc-user"); - if (jdbcUser == null || jdbcUser.length() == 0) jdbcUser = "root"; - String jdbcPass = request.getParameter("jdbc-pass"); - if (jdbcPass == null) jdbcPass = ""; - String jdbcDriverr = request.getParameter("jdbc-driver"); - if (jdbcDriverr == null || jdbcDriverr.length() == 0) jdbcDriverr = "com.mysql.jdbc.Driver"; - String jdbcQuery = request.getParameter("jdbc-query"); - if (jdbcQuery == null || jdbcQuery.length() == 0) jdbcQuery = "show tables;"; - String jdbcUrll = request.getParameter("jdbc-url"); - if (jdbcUrll == null || jdbcUrll.length() == 0) jdbcUrll = "jdbc:mysql://127.0.0.1:3306/example"; - pout.write("
"); - pout.write("JDBC Driver class:
\n"); - pout.write("JDBC URL:
\n"); - pout.write("JDBC Username:
\n"); - pout.write("JDBC Password:
\n"); - pout.write("JDBC Query:
\n"); - pout.write("
"); - pout.write("
"); - pout.write("
"); - - } - catch (Exception e) - { - getServletContext().log("dump", e); - } - - String lines= request.getParameter("lines"); - if (lines!=null) - { - char[] line = "A line of characters. Blah blah blah blah. blooble blooble
\n".toCharArray(); - for (int l=Integer.parseInt(lines);l-->0;) - { - pout.write(""+l+" "); - pout.write(line); - } - } - - pout.write("\n\n"); - - pout.close(); - - if (pi != null) - { - if ("/ex4".equals(pi)) - throw new ServletException("test ex4", new Throwable()); - if ("/ex5".equals(pi)) - throw new IOException("test ex5"); - if ("/ex6".equals(pi)) - throw new UnavailableException("test ex6"); - } - - - } - - - /* ------------------------------------------------------------ */ - @Override - public String getServletInfo() - { - return "Dump Servlet"; - } - - /* ------------------------------------------------------------ */ - @Override - public synchronized void destroy() - { - } - - /* ------------------------------------------------------------ */ - private String getURI(HttpServletRequest request) - { - String uri= (String)request.getAttribute("javax.servlet.forward.request_uri"); - if (uri == null) - uri= request.getRequestURI(); - return uri; - } - - /* ------------------------------------------------------------ */ - private static String toString(Object o) - { - if (o == null) - return null; - - try - { - if (o.getClass().isArray()) - { - StringBuffer sb = new StringBuffer(); - if (!o.getClass().getComponentType().isPrimitive()) - { - Object[] array= (Object[])o; - for (int i= 0; i < array.length; i++) - { - if (i > 0) - sb.append("\n"); - sb.append(array.getClass().getComponentType().getName()); - sb.append("["); - sb.append(i); - sb.append("]="); - sb.append(toString(array[i])); - } - return sb.toString(); - } - else - { - int length = Array.getLength(o); - for (int i=0;i 0) - sb.append("\n"); - sb.append(o.getClass().getComponentType().getName()); - sb.append("["); - sb.append(i); - sb.append("]="); - sb.append(toString(Array.get(o, i))); - } - return sb.toString(); - } - } - else - return o.toString(); - } - catch (Exception e) - { - return e.toString(); - } - } - - private boolean dump(HttpServletResponse response, String data, String chars, String block, String dribble, boolean flush) throws IOException - { - if (data != null && data.length() > 0) - { - long d=Long.parseLong(data); - int b=(block!=null&&block.length()>0)?Integer.parseInt(block):50; - byte[] buf=new byte[b]; - for (int i=0;i 0) - { - if (b==1) - { - out.write(d%80==0?'\n':'.'); - d--; - } - else if (d>=b) - { - out.write(buf); - d=d-b; - } - else - { - out.write(buf,0,(int)d); - d=0; - } - - if (dribble!=null) - { - out.flush(); - try - { - Thread.sleep(Long.parseLong(dribble)); - } - catch (Exception e) - { - e.printStackTrace(); - break; - } - } - - } - - if (flush) - out.flush(); - - return true; - } - - // Handle a dump of data - if (chars != null && chars.length() > 0) - { - long d=Long.parseLong(chars); - int b=(block!=null&&block.length()>0)?Integer.parseInt(block):50; - char[] buf=new char[b]; - for (int i=0;i 0 && !out.checkError()) - { - if (b==1) - { - out.write(d%80==0?'\n':'.'); - d--; - } - else if (d>=b) - { - out.write(buf); - d=d-b; - } - else - { - out.write(buf,0,(int)d); - d=0; - } - } - return true; - } - return false; - } - - private String notag(String s) - { - if (s==null) - return "null"; - s=replace(s,"&","&"); - s=replace(s,"<","<"); - s=replace(s,">",">"); - return s; - } - - /** - * replace substrings within string. - */ - public static String replace(String s, String sub, String with) - { - int c=0; - int i=s.indexOf(sub,c); - if (i == -1) - return s; - - StringBuffer buf = new StringBuffer(s.length()+with.length()); - - synchronized(buf) - { - do - { - buf.append(s.substring(c,i)); - buf.append(with); - c=i+sub.length(); - } while ((i=s.indexOf(sub,c))!=-1); - - if (c ind2 + 1 ? value.substring(ind2+1) : ""; - reminder = resolveSystemProperty(reminder); - if (v != null) - { - return value.substring(0, ind) + v + reminder; - } - else - { - return value.substring(0, ind) + defaultValue + reminder; - } - } - - - - // introspection trick to be able to set the private field platformDirectory - private static Field _field; - void __setPlatformDirectory(File platformDirectory) - { - try - { - if (_field == null) - { - _field = org.eclipse.equinox.servletbridge.FrameworkLauncher.class.getDeclaredField("platformDirectory"); //$NON-NLS-1$ - _field.setAccessible(true); - } - _field.set(this,platformDirectory); - } - catch (SecurityException e) - { - e.printStackTrace(); - } - catch (NoSuchFieldException e) - { - e.printStackTrace(); - } - catch (IllegalArgumentException e) - { - e.printStackTrace(); - } - catch (IllegalAccessException e) - { - e.printStackTrace(); - } - } - - //introspection trick to invoke the generateExtensionBundle method - private static Method _deployExtensionBundleMethod; - private void __deployExtensionBundle(File plugins) - { - //look for the extensionbundle - //if it is already there no need to do something: - for (String file : plugins.list()) - { - if (file.startsWith("org.eclipse.equinox.servletbridge.extensionbundle"))//EXTENSIONBUNDLE_DEFAULT_BSN - { - return; - } - } - - try - { - //invoke deployExtensionBundle(File plugins) - if (_deployExtensionBundleMethod == null) - { - _deployExtensionBundleMethod = FrameworkLauncher.class.getDeclaredMethod("deployExtensionBundle", File.class); - _deployExtensionBundleMethod.setAccessible(true); - } - _deployExtensionBundleMethod.invoke(this, plugins); - } - catch (Throwable t) - { - t.printStackTrace(); - } - } -//--end of introspection to invoke deployExtensionBundle - -//from Framework with support for the equinox hook - private static final String EXTENSIONBUNDLE_DEFAULT_BSN = "org.eclipse.equinox.servletbridge.extensionbundle"; //$NON-NLS-1$ - private static final String EXTENSIONBUNDLE_DEFAULT_VERSION = "1.2.0"; //$NON-NLS-1$ - private static final String MANIFEST_VERSION = "Manifest-Version"; //$NON-NLS-1$ - private static final String BUNDLE_MANIFEST_VERSION = "Bundle-ManifestVersion"; //$NON-NLS-1$ - private static final String BUNDLE_NAME = "Bundle-Name"; //$NON-NLS-1$ - private static final String BUNDLE_SYMBOLIC_NAME = "Bundle-SymbolicName"; //$NON-NLS-1$ - private static final String BUNDLE_VERSION = "Bundle-Version"; //$NON-NLS-1$ - private static final String FRAGMENT_HOST = "Fragment-Host"; //$NON-NLS-1$ - private static final String EXPORT_PACKAGE = "Export-Package"; //$NON-NLS-1$ - - private static final String CONFIG_EXTENDED_FRAMEWORK_EXPORTS = "extendedFrameworkExports"; //$NON-NLS-1$ - - private void deployExtensionBundle(File plugins, boolean configureEquinoxHook) { - // we might want to parameterize the extension bundle BSN in the future - final String extensionBundleBSN = EXTENSIONBUNDLE_DEFAULT_BSN; - File extensionBundleFile = findExtensionBundleFile(plugins, extensionBundleBSN); - - if (extensionBundleFile == null) - generateExtensionBundle(plugins, extensionBundleBSN, EXTENSIONBUNDLE_DEFAULT_VERSION, configureEquinoxHook); - else /*if (Boolean.valueOf(config.getInitParameter(CONFIG_OVERRIDE_AND_REPLACE_EXTENSION_BUNDLE)).booleanValue())*/ { - String extensionBundleVersion = findExtensionBundleVersion(extensionBundleFile, extensionBundleBSN); - if (extensionBundleFile.isDirectory()) { - deleteDirectory(extensionBundleFile); - } else { - extensionBundleFile.delete(); - } - generateExtensionBundle(plugins, extensionBundleBSN, extensionBundleVersion, true); -// } else { -// processExtensionBundle(extensionBundleFile); - } - } - - private File findExtensionBundleFile(File plugins, final String extensionBundleBSN) { - FileFilter extensionBundleFilter = new FileFilter() { - public boolean accept(File candidate) { - return candidate.getName().startsWith(extensionBundleBSN + "_"); //$NON-NLS-1$ - } - }; - File[] extensionBundles = plugins.listFiles(extensionBundleFilter); - if (extensionBundles.length == 0) - return null; - - if (extensionBundles.length > 1) { - for (int i = 1; i < extensionBundles.length; i++) { - if (extensionBundles[i].isDirectory()) { - deleteDirectory(extensionBundles[i]); - } else { - extensionBundles[i].delete(); - } - } - } - return extensionBundles[0]; - } - - private String findExtensionBundleVersion(File extensionBundleFile, String extensionBundleBSN) { - String fileName = extensionBundleFile.getName(); - if (fileName.endsWith(".jar")) { - return fileName.substring(extensionBundleBSN.length() + 1, fileName.length() - ".jar".length()); - } - return fileName.substring(extensionBundleBSN.length() + 1); - } - - - private void generateExtensionBundle(File plugins, String extensionBundleBSN, String extensionBundleVersion, - boolean configureEquinoxHook) { - Manifest mf = new Manifest(); - Attributes attribs = mf.getMainAttributes(); - attribs.putValue(MANIFEST_VERSION, "1.0"); //$NON-NLS-1$ - attribs.putValue(BUNDLE_MANIFEST_VERSION, "2"); //$NON-NLS-1$ - attribs.putValue(BUNDLE_NAME, "Servletbridge Extension Bundle"); //$NON-NLS-1$ - attribs.putValue(BUNDLE_SYMBOLIC_NAME, extensionBundleBSN); - attribs.putValue(BUNDLE_VERSION, extensionBundleVersion); - attribs.putValue(FRAGMENT_HOST, "system.bundle; extension:=framework"); //$NON-NLS-1$ - - String servletVersion = context.getMajorVersion() + "." + context.getMinorVersion(); //$NON-NLS-1$ - String packageExports = "org.eclipse.equinox.servletbridge; version=1.1" + //$NON-NLS-1$ - ", javax.servlet; version=" + servletVersion + //$NON-NLS-1$ - ", javax.servlet.http; version=" + servletVersion + //$NON-NLS-1$ - ", javax.servlet.resources; version=" + servletVersion; //$NON-NLS-1$ - - String extendedExports = config.getInitParameter(CONFIG_EXTENDED_FRAMEWORK_EXPORTS); - if (extendedExports != null && extendedExports.trim().length() != 0) - packageExports += ", " + extendedExports; //$NON-NLS-1$ - - attribs.putValue(EXPORT_PACKAGE, packageExports); - writeJarFile(new File(plugins, extensionBundleBSN + "_" + extensionBundleVersion + ".jar"), mf, configureEquinoxHook); //$NON-NLS-1$ - } - - private void writeJarFile(File jarFile, Manifest mf, boolean configureEquinoxHook) { - try { - JarOutputStream jos = null; - try { - jos = new JarOutputStream(new FileOutputStream(jarFile), mf); - - if (configureEquinoxHook) { - //hook configurator properties: - ZipEntry e = new ZipEntry("hookconfigurators.properties"); - jos.putNextEntry(e); - Properties props = new Properties(); - props.put("hook.configurators", "org.eclipse.jetty.osgi.servletbridge.hook.ServletBridgeClassLoaderDelegateHook"); - props.store(jos, ""); - jos.closeEntry(); - - //the hook class - e = new ZipEntry("org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.class"); - jos.putNextEntry(e); - InputStream in = getClass().getResourceAsStream("/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.class"); - - byte[] buffer = new byte[512]; - try { - int n; - while ((n = in.read(buffer)) != -1) - { - jos.write(buffer, 0, n); - } - } finally { - in.close(); - } - jos.closeEntry(); - } - - jos.finish(); - } finally { - if (jos != null) - jos.close(); - } - } catch (IOException e) { - context.log("Error writing extension bundle", e); //$NON-NLS-1$ - } - } -//--from Framework with support for the equinox hook - -} diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.java b/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.java deleted file mode 100644 index 7bc82a566ae..00000000000 --- a/jetty-osgi/jetty-osgi-servletbridge/src/main/java/org/eclipse/jetty/osgi/servletbridge/hook/ServletBridgeClassLoaderDelegateHook.java +++ /dev/null @@ -1,106 +0,0 @@ -// ======================================================================== -// Copyright (c) 2010-2011 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== -package org.eclipse.jetty.osgi.servletbridge.hook; - -import java.io.FileNotFoundException; -import java.net.URL; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Set; - -import org.eclipse.core.runtime.adaptor.EclipseStarter; -import org.eclipse.osgi.baseadaptor.HookConfigurator; -import org.eclipse.osgi.baseadaptor.HookRegistry; -import org.eclipse.osgi.framework.adaptor.BundleClassLoader; -import org.eclipse.osgi.framework.adaptor.BundleData; -import org.eclipse.osgi.framework.adaptor.ClassLoaderDelegateHook; -import org.eclipse.osgi.internal.loader.BundleLoader; - -/** - * With some complex osgi products, experience shows that using - * a system bundle extension to pass certain packages from the bootstrapping - * server to equinox fails. - * The bundles keep loading javax.servlet.http from the javax.servlet bundle. - * This class is in fact copied into the servletbridge.extensionbundle; it is not loaded by the webapp. - */ -public class ServletBridgeClassLoaderDelegateHook implements ClassLoaderDelegateHook, HookConfigurator -{ - - private static Set packagesInBootstrapClassLoader = new HashSet(); - static - { - packagesInBootstrapClassLoader.add("javax.servlet"); - packagesInBootstrapClassLoader.add("javax.servlet.http"); - } - - public void addHooks(HookRegistry hookRegistry) - { - hookRegistry.addClassLoaderDelegateHook(this); - } - - public Class preFindClass(String name, BundleClassLoader classLoader, - BundleData data) throws ClassNotFoundException - { - String pkgName = BundleLoader.getPackageName(name); - if (packagesInBootstrapClassLoader.contains(pkgName)) - { - return EclipseStarter.class.getClassLoader().loadClass(name); - } - return null; - } - - public Class postFindClass(String name, BundleClassLoader classLoader, - BundleData data) throws ClassNotFoundException - { - return null; - } - - public URL preFindResource(String name, BundleClassLoader classLoader, - BundleData data) throws FileNotFoundException - { - return null; - } - - public URL postFindResource(String name, BundleClassLoader classLoader, - BundleData data) throws FileNotFoundException - { - return null; - } - - public Enumeration preFindResources(String name, - BundleClassLoader classLoader, BundleData data) - throws FileNotFoundException - { - return null; - } - - public Enumeration postFindResources(String name, - BundleClassLoader classLoader, BundleData data) - throws FileNotFoundException - { - return null; - } - - public String preFindLibrary(String name, BundleClassLoader classLoader, - BundleData data) throws FileNotFoundException - { - return null; - } - - public String postFindLibrary(String name, BundleClassLoader classLoader, - BundleData data) - { - return null; - } - -} diff --git a/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml b/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml deleted file mode 100644 index c61dee582d1..00000000000 --- a/jetty-osgi/jetty-osgi-servletbridge/src/main/webapp/WEB-INF/web.xml +++ /dev/null @@ -1,67 +0,0 @@ - - - jettyservletbridge - - proxy - Transparent Proxy Servlet and Equinox Framework Controller - Transparent Proxy Servlet and Equinox Framework Controller - org.eclipse.jetty.osgi.servletbridge.BridgeServletExtended - - - osgi.install.area - /WEB-INF/eclipse - - - - asyncStart - true - - - commandline - -console - - - enableFrameworkControls - true - - - - extendedFrameworkExports - - - - - - frameworkLauncherClass - org.eclipse.jetty.osgi.servletbridge.FrameworkLauncherExtended - - - 1 - - - - dump - org.eclipse.jetty.nested.Dump - 1 - - - - dump - /dump/* - - - proxy - /* - - - \ No newline at end of file diff --git a/jetty-osgi/pom.xml b/jetty-osgi/pom.xml index ae30fdd313e..a5e6fc8c87d 100644 --- a/jetty-osgi/pom.xml +++ b/jetty-osgi/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT ../pom.xml org.eclipse.jetty.osgi @@ -15,17 +15,16 @@ 3.2.100.v20100503 1.0.0-v20070606 - 2.1.v20100127 + 7.0.8 + 7.0.8 0.9.18 1.5.11 jetty-osgi-boot jetty-osgi-boot-jsp - jetty-osgi-boot-logback jetty-osgi-boot-warurl jetty-osgi-httpservice - jetty-osgi-equinoxtools test-jetty-osgi @@ -73,6 +72,11 @@ + + org.eclipse.jetty + jetty-annotations + ${project.version} + org.eclipse.jetty jetty-continuation @@ -138,15 +142,20 @@ servletbridge ${equinox-servletbridge-version} - + + + org.apache.tomcat + tomcat-jsp-api + ${jsp-api-2.2-tomcat-version} - org.mortbay.jetty - jsp-api-2.1-glassfish - ${jsp-2.1-glassfish-version} + org.apache.tomcat + tomcat-el-api + ${el-api-2.2-tomcat-version} org.slf4j diff --git a/jetty-osgi/test-jetty-osgi/pom.xml b/jetty-osgi/test-jetty-osgi/pom.xml index f0ae38a1230..90fa3bc5320 100644 --- a/jetty-osgi/test-jetty-osgi/pom.xml +++ b/jetty-osgi/test-jetty-osgi/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty.osgi jetty-osgi-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT ../pom.xml 4.0.0 @@ -12,20 +12,21 @@ Jetty OSGi Integration test ${project.groupId}.boot.test - http://download.eclipse.org/jetty/orbit/ + http://download.eclipse.org/jetty/orbit target/distribution 3.6 - ${javax-activation-version}.0.v201005080500 - 1.0.0.v20100513-0750 - 2.1.0.v201004190952 + ${javax-activation-version}.0.v201105071233 + 1.1.0.v201105051105 + 2.2.0.v201105051105 ${javax-mail-version}.v201005082020 - 2.5.0.v200910301333 - 2.1.0.v201004190952 + 3.0.0.v201103241727 + 2.2.0.v201103241009 1.2.0.v201004190952 - 1.0.0.v201004190952 + 2.2.0.v201105051105 2.1.0.v201007080150 1.2.0.v201004190952 - 3.1.0.v200803061910 + 3.3.1.v201101071600 + 1.1.1.v201004190952 @@ -103,9 +104,9 @@ - org.mortbay.jetty - servlet-api - 2.5-20081211 + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + ${servlet.spec.version} runtime diff --git a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java index d6c2a52284d..1e9a0941c3f 100644 --- a/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java +++ b/jetty-osgi/test-jetty-osgi/src/test/java/org/eclipse/jetty/osgi/boot/TestJettyOSGiBootWithJsp.java @@ -96,7 +96,7 @@ public class TestJettyOSGiBootWithJsp for( Bundle b : bundleContext.getBundles() ) { bundlesIndexedBySymbolicName.put(b.getSymbolicName(), b); - System.err.println("Got " + b.getSymbolicName() + " " + b.getVersion().toString() + " " + b.getState()); + //System.err.println("Got " + b.getSymbolicName()); } Bundle osgiBoot = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.osgi.boot"); @@ -105,11 +105,11 @@ public class TestJettyOSGiBootWithJsp Bundle osgiBootJsp = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.osgi.boot.jsp"); Assert.assertNotNull("Could not find the org.eclipse.jetty.osgi.boot.jsp bundle", osgiBootJsp); - Assert.assertTrue("The fragment jsp is not correctly resolved " + osgiBootJsp.getState(), osgiBootJsp.getState() == Bundle.RESOLVED); + Assert.assertTrue("The fragment jsp is not correctly resolved", osgiBootJsp.getState() == Bundle.RESOLVED); Bundle testWebBundle = bundlesIndexedBySymbolicName.get("org.eclipse.jetty.test-jetty-webapp"); - Assert.assertNotNull("Could not find the org.eclipse.jetty.test-jetty-webapp bundle", osgiBootJsp); - Assert.assertTrue("The bundle org.eclipse.jetty.test-jetty-webapp is not correctly resolved", testWebBundle.getState() == Bundle.ACTIVE); + Assert.assertNotNull("Could not find the org.eclipse.jetty.osgi.boot.jsp bundle", osgiBootJsp); + Assert.assertTrue("The fragment jsp is not correctly resolved", testWebBundle.getState() == Bundle.ACTIVE); //now test the jsp/dump.jsp HttpClient client = new HttpClient(); diff --git a/jetty-overlay-deployer/pom.xml b/jetty-overlay-deployer/pom.xml index 75b8349308e..788affa1110 100644 --- a/jetty-overlay-deployer/pom.xml +++ b/jetty-overlay-deployer/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-overlay-deployer diff --git a/jetty-plus/pom.xml b/jetty-plus/pom.xml index 391eb9691c7..c267bfb8e9b 100644 --- a/jetty-plus/pom.xml +++ b/jetty-plus/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-plus @@ -28,7 +28,7 @@ <_versionpolicy> - javax.sql.*,javax.security.*,javax.naming.*,javax.servlet.*;version="[2.5,3.0)",javax.transaction.*;version="[1.1,1.2)",* + !javax.sql.*;!javax.security.*;!javax.naming.*;javax.servlet.*;version="[3.0,4.0)",javax.transaction.*;version="[1.1,1.2)",* diff --git a/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java new file mode 100644 index 00000000000..bd03d291cc1 --- /dev/null +++ b/jetty-plus/src/main/java/org/eclipse/jetty/plus/annotation/ContainerInitializer.java @@ -0,0 +1,108 @@ +// ======================================================================== +// Copyright (c) 2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== +package org.eclipse.jetty.plus.annotation; + +import java.util.HashSet; +import java.util.Set; + +import javax.servlet.ServletContainerInitializer; +import javax.servlet.ServletContext; + +import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.webapp.WebAppContext; + +public class ContainerInitializer +{ + protected ServletContainerInitializer _target; + protected Class[] _interestedTypes; + protected Set _applicableTypeNames; + protected Set _annotatedTypeNames; + + + public void setTarget (ServletContainerInitializer target) + { + _target = target; + } + + public ServletContainerInitializer getTarget () + { + return _target; + } + + public Class[] getInterestedTypes () + { + return _interestedTypes; + } + + public void setInterestedTypes (Class[] interestedTypes) + { + _interestedTypes = interestedTypes; + } + + /** + * A class has been found that has an annotation of interest + * to this initializer. + * @param className + */ + public void addAnnotatedTypeName (String className) + { + if (_annotatedTypeNames == null) + _annotatedTypeNames = new HashSet(); + _annotatedTypeNames.add(className); + } + + public Set getAnnotatedTypeNames () + { + return _annotatedTypeNames; + } + + public void addApplicableTypeName (String className) + { + if (_applicableTypeNames == null) + _applicableTypeNames = new HashSet(); + _applicableTypeNames.add(className); + } + + public Set getApplicableTypeNames () + { + return _applicableTypeNames; + } + + + public void callStartup(WebAppContext context) + throws Exception + { + if (_target != null) + { + Set> classes = new HashSet>(); + + ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(context.getClassLoader()); + + try + { + if (_applicableTypeNames != null) + { + for (String s : _applicableTypeNames) + classes.add(Loader.loadClass(context.getClass(), s)); + } + + _target.onStartup(classes, context.getServletContext()); + } + finally + { + Thread.currentThread().setContextClassLoader(oldLoader); + } + } + } +} diff --git a/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.java b/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.java new file mode 100644 index 00000000000..2c34856e362 --- /dev/null +++ b/jetty-plus/src/test/java/org/eclipse/jetty/plus/webapp/PlusDescriptorProcessorTest.java @@ -0,0 +1,171 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.plus.webapp; + + + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.net.URL; + +import javax.naming.Context; +import javax.naming.InitialContext; + +import org.eclipse.jetty.webapp.Descriptor; +import org.eclipse.jetty.webapp.FragmentDescriptor; +import org.eclipse.jetty.webapp.Origin; +import org.eclipse.jetty.webapp.WebAppClassLoader; +import org.eclipse.jetty.webapp.WebAppContext; +import org.eclipse.jetty.webapp.WebDescriptor; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * PlusDescriptorProcessorTest + * + * + */ +public class PlusDescriptorProcessorTest +{ + protected WebDescriptor webDescriptor; + protected FragmentDescriptor fragDescriptor1; + protected FragmentDescriptor fragDescriptor2; + protected FragmentDescriptor fragDescriptor3; + protected WebAppContext context; + /** + * @throws java.lang.Exception + */ + @Before + public void setUp() throws Exception + { + context = new WebAppContext(); + context.setClassLoader(new WebAppClassLoader(Thread.currentThread().getContextClassLoader(), context)); + ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(context.getClassLoader()); + Context icontext = new InitialContext(); + Context compCtx = (Context)icontext.lookup ("java:comp"); + compCtx.createSubcontext("env"); + Thread.currentThread().setContextClassLoader(oldLoader); + + org.eclipse.jetty.plus.jndi.Resource ds = new org.eclipse.jetty.plus.jndi.Resource (context, "jdbc/mydatasource", new Object()); + + URL webXml = Thread.currentThread().getContextClassLoader().getResource("web.xml"); + webDescriptor = new WebDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(webXml)); + webDescriptor.parse(); + + URL frag1Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-1.xml"); + fragDescriptor1 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag1Xml)); + fragDescriptor1.parse(); + URL frag2Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-2.xml"); + fragDescriptor2 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag2Xml)); + fragDescriptor2.parse(); + URL frag3Xml = Thread.currentThread().getContextClassLoader().getResource("web-fragment-3.xml"); + fragDescriptor3 = new FragmentDescriptor(org.eclipse.jetty.util.resource.Resource.newResource(frag3Xml)); + fragDescriptor3.parse(); + } + + @After + public void tearDown() throws Exception + { + ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(context.getClassLoader()); + Context ic = new InitialContext(); + Context compCtx = (Context)ic.lookup ("java:comp"); + compCtx.destroySubcontext("env"); + Thread.currentThread().setContextClassLoader(oldLoader); + } + + @Test + public void testWebXmlResourceDeclarations() + throws Exception + { + //if declared in web.xml, fragment declarations ignored + ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(context.getClassLoader()); + try + { + PlusDescriptorProcessor pdp = new PlusDescriptorProcessor(); + pdp.process(context, webDescriptor); + Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref.jdbc/mydatasource"); + assertNotNull(d); + assertTrue(d == webDescriptor); + + pdp.process(context, fragDescriptor1); + pdp.process(context, fragDescriptor2); + } + finally + { + Thread.currentThread().setContextClassLoader(oldLoader); + } + } + + + @Test + public void testMismatchedFragmentResourceDeclarations () + throws Exception + { + //if declared in more than 1 fragment, declarations must be the same + ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(context.getClassLoader()); + try + { + PlusDescriptorProcessor pdp = new PlusDescriptorProcessor(); + pdp.process(context, fragDescriptor1); + Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref.jdbc/mydatasource"); + assertNotNull(d); + assertTrue(d == fragDescriptor1); + assertEquals(Origin.WebFragment, context.getMetaData().getOrigin("resource-ref.jdbc/mydatasource")); + + pdp.process(context, fragDescriptor2); + fail("Expected conflicting resource-ref declaration"); + } + catch (Exception e) + { + //expected + } + finally + { + Thread.currentThread().setContextClassLoader(oldLoader); + } + } + + @Test + public void testMatchingFragmentResourceDeclarations () + throws Exception + { + //if declared in more than 1 fragment, declarations must be the same + ClassLoader oldLoader = Thread.currentThread().getContextClassLoader(); + Thread.currentThread().setContextClassLoader(context.getClassLoader()); + try + { + PlusDescriptorProcessor pdp = new PlusDescriptorProcessor(); + pdp.process(context, fragDescriptor1); + Descriptor d = context.getMetaData().getOriginDescriptor("resource-ref.jdbc/mydatasource"); + assertNotNull(d); + assertTrue(d == fragDescriptor1); + assertEquals(Origin.WebFragment, context.getMetaData().getOrigin("resource-ref.jdbc/mydatasource")); + pdp.process(context, fragDescriptor3); + } + + finally + { + Thread.currentThread().setContextClassLoader(oldLoader); + } + } +} diff --git a/jetty-plus/src/test/resources/web-fragment-1.xml b/jetty-plus/src/test/resources/web-fragment-1.xml new file mode 100644 index 00000000000..b213172ef01 --- /dev/null +++ b/jetty-plus/src/test/resources/web-fragment-1.xml @@ -0,0 +1,27 @@ + + + + + Fragment1 + + + others + + + + jdbc/mydatasource + javax.sql.DataSource + Container + + + + diff --git a/jetty-plus/src/test/resources/web-fragment-2.xml b/jetty-plus/src/test/resources/web-fragment-2.xml new file mode 100644 index 00000000000..e2fff6786f1 --- /dev/null +++ b/jetty-plus/src/test/resources/web-fragment-2.xml @@ -0,0 +1,27 @@ + + + + + Fragment2 + + + others + + + + jdbc/mydatasource + javax.sql.DataSource + User + + + + diff --git a/jetty-plus/src/test/resources/web-fragment-3.xml b/jetty-plus/src/test/resources/web-fragment-3.xml new file mode 100644 index 00000000000..da1f3d5add7 --- /dev/null +++ b/jetty-plus/src/test/resources/web-fragment-3.xml @@ -0,0 +1,27 @@ + + + + + Fragment3 + + + others + + + + jdbc/mydatasource + javax.sql.DataSource + Container + + + + diff --git a/jetty-plus/src/test/resources/web.xml b/jetty-plus/src/test/resources/web.xml new file mode 100644 index 00000000000..aa40eb3fbad --- /dev/null +++ b/jetty-plus/src/test/resources/web.xml @@ -0,0 +1,23 @@ + + + + Test WebApp + + + jdbc/mydatasource + javax.sql.DataSource + Container + + + + diff --git a/jetty-policy/pom.xml b/jetty-policy/pom.xml index 64548024678..568369662c9 100644 --- a/jetty-policy/pom.xml +++ b/jetty-policy/pom.xml @@ -3,7 +3,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT org.eclipse.jetty jetty-policy diff --git a/jetty-rewrite/pom.xml b/jetty-rewrite/pom.xml index cdfe6d1c5b0..faa740608e7 100644 --- a/jetty-rewrite/pom.xml +++ b/jetty-rewrite/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-rewrite @@ -79,10 +79,6 @@ jetty-client ${project.version} - - javax.servlet - servlet-api - org.eclipse.jetty test-jetty-servlet diff --git a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java index ae3a1f71e64..6559d03c693 100644 --- a/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java +++ b/jetty-rewrite/src/test/java/org/eclipse/jetty/rewrite/handler/HeaderPatternRuleTest.java @@ -13,7 +13,7 @@ package org.eclipse.jetty.rewrite.handler; import java.io.IOException; -import java.util.Enumeration; +import java.util.Iterator; import org.junit.Before; import org.junit.Test; @@ -80,11 +80,11 @@ public class HeaderPatternRuleTest extends AbstractRuleTestCase }; assertHeaders(headers); - Enumeration e = _response.getHeaders("size"); + Iterator e = _response.getHeaders("size").iterator(); int count = 0; - while (e.hasMoreElements()) + while (e.hasNext()) { - e.nextElement(); + e.next(); count++; } diff --git a/jetty-security/pom.xml b/jetty-security/pom.xml index 397991f6299..2515958c0f6 100644 --- a/jetty-security/pom.xml +++ b/jetty-security/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-security @@ -24,7 +24,7 @@
- javax.servlet.*;version="[2.5,3.0)",javax.security.cert,* + javax.servlet.*;version="[3.0,4.0)",javax.security.cert,* diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java index 13361cf1e46..36c82fe0d8b 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/ConstraintMapping.java @@ -18,6 +18,7 @@ import org.eclipse.jetty.util.security.Constraint; public class ConstraintMapping { String _method; + String[] _methodOmissions; String _pathSpec; @@ -76,4 +77,19 @@ public class ConstraintMapping { this._pathSpec = pathSpec; } + + /* ------------------------------------------------------------ */ + /** + * @param omissions The http-method-omission + */ + public void setMethodOmissions(String[] omissions) + { + _methodOmissions = omissions; + } + + /* ------------------------------------------------------------ */ + public String[] getMethodOmissions() + { + return _methodOmissions; + } } diff --git a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java index e1aabf587ce..2ec515ca6a7 100644 --- a/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java +++ b/jetty-security/src/main/java/org/eclipse/jetty/security/authentication/DeferredAuthentication.java @@ -16,6 +16,8 @@ package org.eclipse.jetty.security.authentication; import java.io.IOException; import java.io.PrintWriter; +import java.util.Collection; +import java.util.Collections; import java.util.Locale; import javax.servlet.ServletOutputStream; @@ -113,7 +115,7 @@ public class DeferredAuthentication implements Authentication.Deferred { LOG.debug(e); } - return Authentication.UNAUTHENTICATED; + return this; } /* ------------------------------------------------------------ */ @@ -133,7 +135,7 @@ public class DeferredAuthentication implements Authentication.Deferred { LOG.debug(e); } - return Authentication.UNAUTHENTICATED; + return this; } /* ------------------------------------------------------------ */ @@ -317,6 +319,29 @@ public class DeferredAuthentication implements Authentication.Deferred { } + public Collection getHeaderNames() + { + return Collections.emptyList(); + } + + @Override + public String getHeader(String arg0) + { + return null; + } + + @Override + public Collection getHeaders(String arg0) + { + return Collections.emptyList(); + } + + @Override + public int getStatus() + { + return 0; + } + }; /* ------------------------------------------------------------ */ @@ -338,4 +363,4 @@ public class DeferredAuthentication implements Authentication.Deferred }; -} \ No newline at end of file +} diff --git a/jetty-server/pom.xml b/jetty-server/pom.xml index 8e71f15966d..7f5c17aacc7 100644 --- a/jetty-server/pom.xml +++ b/jetty-server/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-server @@ -26,7 +26,7 @@ - javax.servlet.*;version="[2.5,3.0)",org.eclipse.jetty.jmx.*;version="[7.3,8)";resolution:=optional,* + javax.servlet.*;version="[3.0,4.0)",org.eclipse.jetty.jmx.*;version="[7.3,8)";resolution:=optional,* @@ -88,9 +88,14 @@ test - javax.servlet - servlet-api + junit + junit + test + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + org.eclipse.jetty jetty-continuation diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java index b589d22278b..26db3ab9d86 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractHttpConnection.java @@ -16,7 +16,7 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; - +import javax.servlet.DispatcherType; import javax.servlet.ServletInputStream; import javax.servlet.ServletOutputStream; import javax.servlet.http.HttpServletResponse; @@ -388,6 +388,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection boolean error = false; String threadName=null; + Throwable async_exception=null; try { if (LOG.isDebugEnabled()) @@ -441,12 +442,14 @@ public abstract class AbstractHttpConnection extends AbstractConnection } catch (EofException e) { + async_exception=e; LOG.debug(e); error=true; _request.setHandled(true); } catch (RuntimeIOException e) { + async_exception=e; LOG.debug(e); error=true; _request.setHandled(true); @@ -460,6 +463,7 @@ public abstract class AbstractHttpConnection extends AbstractConnection } catch (Throwable e) { + async_exception=e; LOG.warn(String.valueOf(_uri),e); error=true; _request.setHandled(true); @@ -478,7 +482,8 @@ public abstract class AbstractHttpConnection extends AbstractConnection if (_request._async.isUncompleted()) { - _request._async.doComplete(); + + _request._async.doComplete(async_exception); if (_expect100Continue) { diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContext.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContext.java deleted file mode 100644 index 2f6ed1e9aba..00000000000 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContext.java +++ /dev/null @@ -1,43 +0,0 @@ -// ======================================================================== -// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - -package org.eclipse.jetty.server; - -import javax.servlet.ServletContext; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; - -import org.eclipse.jetty.continuation.ContinuationListener; - -/* temporary interface in anticipation of servlet 3.0 */ -public interface AsyncContext -{ - static final String ASYNC_REQUEST_URI = "javax.servlet.async.request_uri"; - static final String ASYNC_CONTEXT_PATH = "javax.servlet.async.context_path"; - static final String ASYNC_PATH_INFO = "javax.servlet.async.path_info"; - static final String ASYNC_SERVLET_PATH = "javax.servlet.async.servlet_path"; - static final String ASYNC_QUERY_STRING = "javax.servlet.async.query_string"; - - public ServletRequest getRequest(); - public ServletResponse getResponse(); - public boolean hasOriginalRequestAndResponse(); - public void dispatch(); - public void dispatch(String path); - public void dispatch(ServletContext context, String path); - public void complete(); - public void start(Runnable run); - public void setTimeout(long ms); - public void addContinuationListener(ContinuationListener listener); -} - - diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java index 25e94d976ce..c6b14213442 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java @@ -13,6 +13,12 @@ package org.eclipse.jetty.server; +import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.ServletResponseWrapper; +import javax.servlet.ServletException; + import java.util.ArrayList; import java.util.List; @@ -21,8 +27,8 @@ import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import org.eclipse.jetty.continuation.Continuation; -import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationThrowable; +import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.io.AsyncEndPoint; import org.eclipse.jetty.io.EndPoint; import org.eclipse.jetty.server.handler.ContextHandler; @@ -32,7 +38,7 @@ import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.thread.Timeout; /* ------------------------------------------------------------ */ -/** Implementation of Continuation and AsyncContext interfaces. +/** Implementation of Continuation and AsyncContext interfaces * */ public class AsyncContinuation implements AsyncContext, Continuation @@ -67,9 +73,10 @@ public class AsyncContinuation implements AsyncContext, Continuation private static final int __UNCOMPLETED=8; // Request is completable private static final int __COMPLETED=9; // Request is complete - /* ------------------------------------------------------------ */ protected AbstractHttpConnection _connection; + private List _lastAsyncListeners; + private List _asyncListeners; private List _continuationListeners; /* ------------------------------------------------------------ */ @@ -80,7 +87,8 @@ public class AsyncContinuation implements AsyncContext, Continuation private volatile boolean _responseWrapped; private long _timeoutMs=DEFAULT_TIMEOUT; private AsyncEventState _event; - private volatile long _expireAt; + private volatile long _expireAt; + private volatile boolean _continuation; /* ------------------------------------------------------------ */ protected AsyncContinuation() @@ -98,6 +106,29 @@ public class AsyncContinuation implements AsyncContext, Continuation } } + /* ------------------------------------------------------------ */ + public void addListener(AsyncListener listener) + { + synchronized(this) + { + if (_asyncListeners==null) + _asyncListeners=new ArrayList(); + _asyncListeners.add(listener); + } + } + + /* ------------------------------------------------------------ */ + public void addListener(AsyncListener listener,ServletRequest request, ServletResponse response) + { + synchronized(this) + { + // TODO handle the request/response ??? + if (_asyncListeners==null) + _asyncListeners=new ArrayList(); + _asyncListeners.add(listener); + } + } + /* ------------------------------------------------------------ */ public void addContinuationListener(ContinuationListener listener) { @@ -245,6 +276,7 @@ public class AsyncContinuation implements AsyncContext, Continuation { synchronized (this) { + _continuation=false; _responseWrapped=false; switch(_state) @@ -252,6 +284,15 @@ public class AsyncContinuation implements AsyncContext, Continuation case __IDLE: _initial=true; _state=__DISPATCHED; + if (_lastAsyncListeners!=null) + _lastAsyncListeners.clear(); + if (_asyncListeners!=null) + _asyncListeners.clear(); + else + { + _asyncListeners=_lastAsyncListeners; + _lastAsyncListeners=null; + } return true; case __COMPLETING: @@ -288,7 +329,7 @@ public class AsyncContinuation implements AsyncContext, Continuation _resumed=false; _expired=false; - if (_event==null || request!=_event.getRequest() || response != _event.getResponse() || context != _event.getServletContext()) + if (_event==null || request!=_event.getSuppliedRequest() || response != _event.getSuppliedResponse() || context != _event.getServletContext()) _event=new AsyncEventState(context,request,response); else { @@ -297,6 +338,11 @@ public class AsyncContinuation implements AsyncContext, Continuation } _state=__ASYNCSTARTED; + List recycle=_lastAsyncListeners; + _lastAsyncListeners=_asyncListeners; + _asyncListeners=recycle; + if (_asyncListeners!=null) + _asyncListeners.clear(); break; default: @@ -304,6 +350,21 @@ public class AsyncContinuation implements AsyncContext, Continuation } } + if (_lastAsyncListeners!=null) + { + for (AsyncListener listener : _lastAsyncListeners) + { + try + { + listener.onStartAsync(_event); + } + catch(Exception e) + { + LOG.warn(e); + } + } + } + } /* ------------------------------------------------------------ */ @@ -318,8 +379,6 @@ public class AsyncContinuation implements AsyncContext, Continuation { synchronized (this) { - List listeners=_continuationListeners; - switch(_state) { case __REDISPATCHED: @@ -340,7 +399,7 @@ public class AsyncContinuation implements AsyncContext, Continuation { _state=__UNCOMPLETED; return true; - } + } _initial=false; _state=__REDISPATCHED; return false; @@ -398,27 +457,43 @@ public class AsyncContinuation implements AsyncContext, Continuation /* ------------------------------------------------------------ */ protected void expired() { - final List listeners; + final List cListeners; + final List aListeners; synchronized (this) { switch(_state) { case __ASYNCSTARTED: case __ASYNCWAIT: - listeners=_continuationListeners; + cListeners=_continuationListeners; + aListeners=_asyncListeners; break; default: - listeners=null; + cListeners=null; + aListeners=null; return; } _expired=true; } - if (listeners!=null) + if (aListeners!=null) { - for (int i=0;i T createListener(Class clazz) throws ServletException + { + try + { + // TODO inject + return clazz.newInstance(); + } + catch(Exception e) + { + throw new ServletException(e); + } + } + + /* ------------------------------------------------------------ */ /* (non-Javadoc) * @see javax.servlet.ServletRequest#complete() */ - protected void doComplete() + protected void doComplete(Throwable ex) { - final List listeners; + final List cListeners; + final List aListeners; synchronized (this) { switch(_state) { case __UNCOMPLETED: _state=__COMPLETED; - listeners=_continuationListeners; + cListeners=_continuationListeners; + aListeners=_asyncListeners; break; default: - listeners=null; + cListeners=null; + aListeners=null; throw new IllegalStateException(this.getStatusString()); } } - if (listeners!=null) + if (aListeners!=null) { - for(int i=0;i getParts() throws IOException, ServletException + { + if (getContentType() == null || !getContentType().startsWith("multipart/form-data")) + return Collections.emptyList(); + + if (_multiPartInputStream == null) + { + _multiPartInputStream = new MultiPartInputStream(getInputStream(), + getContentType(),(MultipartConfigElement)getAttribute(__MULTIPART_CONFIG_ELEMENT), + (_context != null?(File)_context.getAttribute("javax.servlet.context.tempdir"):null)); + } + return _multiPartInputStream.getParts(); + } + + /* ------------------------------------------------------------ */ + public void login(String username, String password) throws ServletException + { + if (_authentication instanceof Authentication.Deferred) + { + _authentication=((Authentication.Deferred)_authentication).login(username,password); + if (_authentication == null) + throw new ServletException(); + } + else + { + throw new ServletException("Authenticated as "+_authentication); + } + } + + /* ------------------------------------------------------------ */ + public void logout() throws ServletException + { + if (_authentication instanceof Authentication.User) + ((Authentication.User)_authentication).logout(); + _authentication=Authentication.UNAUTHENTICATED; + } /* ------------------------------------------------------------ */ /** Merge in a new query string. diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java index d5fa8321d62..a29f4bf730b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Response.java @@ -15,8 +15,9 @@ package org.eclipse.jetty.server; import java.io.IOException; import java.io.PrintWriter; +import java.util.Collection; import java.util.Collections; -import java.util.Enumeration; +import java.util.List; import java.util.Locale; import javax.servlet.ServletOutputStream; @@ -148,7 +149,7 @@ public class Response implements HttpServletResponse cookie.getMaxAge(), comment, cookie.getSecure(), - http_only,// || cookie.isHttpOnly(), + http_only || cookie.isHttpOnly(), cookie.getVersion()); } @@ -522,6 +523,14 @@ public class Response implements HttpServletResponse } } + + /* ------------------------------------------------------------ */ + public Collection getHeaderNames() + { + final HttpFields fields=_connection.getResponseFields(); + return fields.getFieldNamesCollection(); + } + /* ------------------------------------------------------------ */ /* */ @@ -533,12 +542,13 @@ public class Response implements HttpServletResponse /* ------------------------------------------------------------ */ /* */ - public Enumeration getHeaders(String name) + public Collection getHeaders(String name) { - Enumeration e = _connection.getResponseFields().getValues(name); - if (e==null) - return Collections.enumeration(Collections.EMPTY_LIST); - return e; + final HttpFields fields=_connection.getResponseFields(); + Collection i = fields.getValuesCollection(name); + if (i==null) + return Collections.EMPTY_LIST; + return i; } /* ------------------------------------------------------------ */ diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java index e62fad56c79..90f94dc3641 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java @@ -17,6 +17,7 @@ import java.io.IOException; import java.net.InetSocketAddress; import java.util.Enumeration; +import javax.servlet.AsyncContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -61,7 +62,7 @@ public class Server extends HandlerWrapper implements Attributes Server.class.getPackage().getImplementationVersion()!=null) __version=Server.class.getPackage().getImplementationVersion(); else - __version=System.getProperty("jetty.version","7.x.y-SNAPSHOT"); + __version=System.getProperty("jetty.version","8.0.y.z-SNAPSHOT"); } private final Container _container=new Container(); diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java index f57c92f6846..8c36053fd34 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletRequestHttpWrapper.java @@ -14,14 +14,19 @@ package org.eclipse.jetty.server; +import java.io.IOException; import java.security.Principal; +import java.util.Collection; import java.util.Enumeration; +import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletRequestWrapper; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.servlet.http.Part; /* ------------------------------------------------------------ */ /** Class to tunnel a ServletRequest via a HttpServletRequest @@ -158,5 +163,45 @@ public class ServletRequestHttpWrapper extends ServletRequestWrapper implements return false; } + /** + * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse) + */ + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException + { + return false; + } + + /** + * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String) + */ + public Part getPart(String name) throws IOException, ServletException + { + return null; + } + + /** + * @see javax.servlet.http.HttpServletRequest#getParts() + */ + public Collection getParts() throws IOException, ServletException + { + return null; + } + + /** + * @see javax.servlet.http.HttpServletRequest#login(java.lang.String, java.lang.String) + */ + public void login(String username, String password) throws ServletException + { + + } + + /** + * @see javax.servlet.http.HttpServletRequest#logout() + */ + public void logout() throws ServletException + { + + } + } \ No newline at end of file diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java index 94038d9a971..12595c594ad 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/ServletResponseHttpWrapper.java @@ -1,6 +1,7 @@ package org.eclipse.jetty.server; import java.io.IOException; +import java.util.Collection; import javax.servlet.ServletResponse; import javax.servlet.ServletResponseWrapper; @@ -91,4 +92,36 @@ public class ServletResponseHttpWrapper extends ServletResponseWrapper implement { } + /** + * @see javax.servlet.http.HttpServletResponse#getHeader(java.lang.String) + */ + public String getHeader(String name) + { + return null; + } + + /** + * @see javax.servlet.http.HttpServletResponse#getHeaderNames() + */ + public Collection getHeaderNames() + { + return null; + } + + /** + * @see javax.servlet.http.HttpServletResponse#getHeaders(java.lang.String) + */ + public Collection getHeaders(String name) + { + return null; + } + + /** + * @see javax.servlet.http.HttpServletResponse#getStatus() + */ + public int getStatus() + { + return 0; + } + } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java index 159dcf03579..c675b1432a9 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/SessionManager.java @@ -14,7 +14,10 @@ package org.eclipse.jetty.server; import java.util.EventListener; +import java.util.Set; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; @@ -104,11 +107,6 @@ public interface SessionManager extends LifeCycle */ public HttpSession newHttpSession(HttpServletRequest request); - /* ------------------------------------------------------------ */ - /** - * @return true if session cookies should be secure - */ - public boolean getSecureCookies(); /* ------------------------------------------------------------ */ /** @@ -252,19 +250,6 @@ public interface SessionManager extends LifeCycle */ public void complete(HttpSession session); - /** - * Sets the session cookie name. - * @param cookieName the session cookie name - * @see #getSessionCookie() - */ - public void setSessionCookie(String cookieName); - - /** - * @return the session cookie name, by default "JSESSIONID". - * @see #setSessionCookie(String) - */ - public String getSessionCookie(); - /** * Sets the session id URL path parameter name. * @@ -287,50 +272,24 @@ public interface SessionManager extends LifeCycle */ public String getSessionIdPathParameterNamePrefix(); - /** - * Sets the domain to set on the session cookie - * @param domain the domain to set on the session cookie - * @see #getSessionDomain() - */ - public void setSessionDomain(String domain); - - /** - * @return the domain to set on the session cookie - * @see #setSessionDomain(String) - */ - public String getSessionDomain(); - - /** - * Sets the path to set on the session cookie - * @param path the path to set on the session cookie - * @see #getSessionPath() - */ - public void setSessionPath(String path); - - /** - * @return the path to set on the session cookie - * @see #setSessionPath(String) - */ - public String getSessionPath(); - - /** - * Sets the max age to set on the session cookie, in seconds - * @param maxCookieAge the max age to set on the session cookie, in seconds - * @see #getMaxCookieAge() - */ - public void setMaxCookieAge(int maxCookieAge); - - /** - * @return the max age to set on the session cookie, in seconds - * @see #setMaxCookieAge(int) - */ - public int getMaxCookieAge(); - /** * @return whether the session management is handled via cookies. */ public boolean isUsingCookies(); + /** + * @return whether the session management is handled via URLs. + */ + public boolean isUsingURLs(); + + public Set getDefaultSessionTrackingModes(); + + public Set getEffectiveSessionTrackingModes(); + + public void setSessionTrackingModes(Set sessionTrackingModes); + + public SessionCookieConfig getSessionCookieConfig(); + /** * @return True if absolute URLs are check for remoteness before being session encoded. */ @@ -340,5 +299,4 @@ public interface SessionManager extends LifeCycle * @param remote True if absolute URLs are check for remoteness before being session encoded. */ public void setCheckingRemoteSessionIdEncoding(boolean remote); - } diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java index 01cf65535c0..7a02ac52ca6 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/ContextHandler.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; +import java.security.AccessController; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -30,7 +31,9 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.EnumSet; +import javax.servlet.DispatcherType; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; @@ -39,9 +42,16 @@ import javax.servlet.ServletContextAttributeListener; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; import javax.servlet.ServletRequestAttributeListener; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.Filter; +import javax.servlet.FilterRegistration; +import javax.servlet.FilterRegistration.Dynamic; +import javax.servlet.descriptor.JspConfigDescriptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -50,7 +60,6 @@ import org.eclipse.jetty.http.MimeTypes; import org.eclipse.jetty.io.Buffer; import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Dispatcher; -import org.eclipse.jetty.server.DispatcherType; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HandlerContainer; import org.eclipse.jetty.server.Request; @@ -569,6 +578,19 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. { setEventListeners((EventListener[])LazyList.addToArray(getEventListeners(),listener,EventListener.class)); } + + + /** + * Apply any necessary restrictions on a programmatically added + * listener. + * + * Superclasses should implement. + * + * @param listener + */ + public void restrictEventListener (EventListener listener) + { + } /* ------------------------------------------------------------ */ /** @@ -727,13 +749,24 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. ServletContextEvent event = new ServletContextEvent(_scontext); for (int i = 0; i < LazyList.size(_contextListeners); i++) { - ((ServletContextListener)LazyList.get(_contextListeners,i)).contextInitialized(event); + callContextInitialized(((ServletContextListener)LazyList.get(_contextListeners, i)), event); } } + } + /* ------------------------------------------------------------ */ + public void callContextInitialized (ServletContextListener l, ServletContextEvent e) + { + l.contextInitialized(e); LOG.info("started {}",this); } + /* ------------------------------------------------------------ */ + public void callContextDestroyed (ServletContextListener l, ServletContextEvent e) + { + l.contextDestroyed(e); + } + /* ------------------------------------------------------------ */ /* * @see org.eclipse.thread.AbstractLifeCycle#doStop() @@ -1419,6 +1452,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. _localeEncodingMap.put(locale,encoding); } + /* ------------------------------------------------------------ */ public String getLocaleEncoding(String locale) { if (_localeEncodingMap == null) @@ -1562,6 +1596,10 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. */ public class Context implements ServletContext { + protected int _majorVersion = 3; + protected int _minorVersion = 0; + protected boolean _enabled = true; //whether or not the dynamic API is enabled for callers + /* ------------------------------------------------------------ */ protected Context() { @@ -1578,6 +1616,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getContext(java.lang.String) */ + @Override public ServletContext getContext(String uripath) { List contexts = new ArrayList(); @@ -1663,15 +1702,18 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getMajorVersion() */ + @Override public int getMajorVersion() { - return 2; + return 3; } + /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getMimeType(java.lang.String) */ + @Override public String getMimeType(String file) { if (_mimeTypes == null) @@ -1686,15 +1728,17 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getMinorVersion() */ + @Override public int getMinorVersion() { - return 5; + return 0; } /* ------------------------------------------------------------ */ /* * @see javax.servlet.ServletContext#getNamedDispatcher(java.lang.String) */ + @Override public RequestDispatcher getNamedDispatcher(String name) { return null; @@ -1704,6 +1748,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getRequestDispatcher(java.lang.String) */ + @Override public RequestDispatcher getRequestDispatcher(String uriInContext) { if (uriInContext == null) @@ -1740,6 +1785,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getRealPath(java.lang.String) */ + @Override public String getRealPath(String path) { if (path == null) @@ -1768,6 +1814,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ + @Override public URL getResource(String path) throws MalformedURLException { Resource resource = ContextHandler.this.getResource(path); @@ -1780,6 +1827,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getResourceAsStream(java.lang.String) */ + @Override public InputStream getResourceAsStream(String path) { try @@ -1800,6 +1848,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getResourcePaths(java.lang.String) */ + @Override public Set getResourcePaths(String path) { return ContextHandler.this.getResourcePaths(path); @@ -1809,6 +1858,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getServerInfo() */ + @Override public String getServerInfo() { return "jetty/" + Server.getVersion(); @@ -1818,6 +1868,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getServlet(java.lang.String) */ + @Override + @Deprecated public Servlet getServlet(String name) throws ServletException { return null; @@ -1828,6 +1880,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. * @see javax.servlet.ServletContext#getServletNames() */ @SuppressWarnings("unchecked") + @Override + @Deprecated public Enumeration getServletNames() { return Collections.enumeration(Collections.EMPTY_LIST); @@ -1838,6 +1892,8 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. * @see javax.servlet.ServletContext#getServlets() */ @SuppressWarnings("unchecked") + @Override + @Deprecated public Enumeration getServlets() { return Collections.enumeration(Collections.EMPTY_LIST); @@ -1847,6 +1903,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#log(java.lang.Exception, java.lang.String) */ + @Override public void log(Exception exception, String msg) { _logger.warn(msg,exception); @@ -1856,6 +1913,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#log(java.lang.String) */ + @Override public void log(String msg) { _logger.info(msg); @@ -1865,6 +1923,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#log(java.lang.String, java.lang.Throwable) */ + @Override public void log(String message, Throwable throwable) { _logger.warn(message,throwable); @@ -1874,6 +1933,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getInitParameter(java.lang.String) */ + @Override public String getInitParameter(String name) { return ContextHandler.this.getInitParameter(name); @@ -1884,6 +1944,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. * @see javax.servlet.ServletContext#getInitParameterNames() */ @SuppressWarnings("unchecked") + @Override public Enumeration getInitParameterNames() { return ContextHandler.this.getInitParameterNames(); @@ -1893,6 +1954,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getAttribute(java.lang.String) */ + @Override public synchronized Object getAttribute(String name) { Object o = ContextHandler.this.getAttribute(name); @@ -1906,6 +1968,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. * @see javax.servlet.ServletContext#getAttributeNames() */ @SuppressWarnings("unchecked") + @Override public synchronized Enumeration getAttributeNames() { HashSet set = new HashSet(); @@ -1926,6 +1989,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#setAttribute(java.lang.String, java.lang.Object) */ + @Override public synchronized void setAttribute(String name, Object value) { checkManagedAttribute(name,value); @@ -1958,6 +2022,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#removeAttribute(java.lang.String) */ + @Override public synchronized void removeAttribute(String name) { checkManagedAttribute(name,null); @@ -1987,6 +2052,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. /* * @see javax.servlet.ServletContext#getServletContextName() */ + @Override public String getServletContextName() { String name = ContextHandler.this.getDisplayName(); @@ -1996,6 +2062,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ + @Override public String getContextPath() { if ((_contextPath != null) && _contextPath.equals(URIUtil.SLASH)) @@ -2012,6 +2079,7 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. } /* ------------------------------------------------------------ */ + @Override public boolean setInitParameter(String name, String value) { if (ContextHandler.this.getInitParameter(name) != null) @@ -2020,6 +2088,236 @@ public class ContextHandler extends ScopedHandler implements Attributes, Server. return true; } + /* ------------------------------------------------------------ */ + final private static String __unimplmented="Unimplemented - use org.eclipse.jetty.servlet.ServletContextHandler"; + + @Override + public Dynamic addFilter(String filterName, Class filterClass) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public Dynamic addFilter(String filterName, Filter filter) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public Dynamic addFilter(String filterName, String className) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public javax.servlet.ServletRegistration.Dynamic addServlet(String servletName, String className) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public T createFilter(Class c) throws ServletException + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public T createServlet(Class c) throws ServletException + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public Set getDefaultSessionTrackingModes() + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public Set getEffectiveSessionTrackingModes() + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public FilterRegistration getFilterRegistration(String filterName) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public Map getFilterRegistrations() + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public ServletRegistration getServletRegistration(String servletName) + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public Map getServletRegistrations() + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public SessionCookieConfig getSessionCookieConfig() + { + LOG.warn(__unimplmented); + return null; + } + + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) + { + LOG.warn(__unimplmented); + } + + @Override + public void addListener(String className) + { + if (!_enabled) + throw new UnsupportedOperationException(); + + try + { + Class clazz = _classLoader==null?Loader.loadClass(ContextHandler.class,className):_classLoader.loadClass(className); + addListener(clazz); + } + catch (ClassNotFoundException e) + { + throw new IllegalArgumentException(e); + } + } + + @Override + public void addListener(T t) + { + if (!_enabled) + throw new UnsupportedOperationException(); + ContextHandler.this.addEventListener(t); + } + + @Override + public void addListener(Class listenerClass) + { + if (!_enabled) + throw new UnsupportedOperationException(); + + try + { + EventListener e = createListener(listenerClass); + ContextHandler.this.addEventListener(e); + ContextHandler.this.restrictEventListener(e); + } + catch (ServletException e) + { + throw new IllegalArgumentException(e); + } + } + + @Override + public T createListener(Class clazz) throws ServletException + { + try + { + return clazz.newInstance(); + } + catch (InstantiationException e) + { + throw new ServletException(e); + } + catch (IllegalAccessException e) + { + throw new ServletException(e); + } + } + + @Override + public ClassLoader getClassLoader() + { + AccessController.checkPermission(new RuntimePermission("getClassLoader")); + return _classLoader; + } + + @Override + public int getEffectiveMajorVersion() + { + return _majorVersion; + } + + @Override + public int getEffectiveMinorVersion() + { + return _minorVersion; + } + + public void setEffectiveMajorVersion (int v) + { + _majorVersion = v; + } + + public void setEffectiveMinorVersion (int v) + { + _minorVersion = v; + } + + @Override + public JspConfigDescriptor getJspConfigDescriptor() + { + return null; + } + + @Override + public void declareRoles(String... roleNames) + { + if (!isStarting()) + throw new IllegalStateException (); + if (!_enabled) + throw new UnsupportedOperationException(); + + // TODO Auto-generated method stub + + } + + public void setEnabled(boolean enabled) + { + _enabled = enabled; + } + + public boolean isEnabled() + { + return _enabled; + } } private static class CLDump implements Dumpable diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java index 44e71c3907e..66a6a93887e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/RequestLogHandler.java @@ -15,12 +15,12 @@ package org.eclipse.jetty.server.handler; import java.io.IOException; +import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.AsyncContinuation; -import org.eclipse.jetty.server.DispatcherType; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.RequestLog; import org.eclipse.jetty.server.Response; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java index b6c1a381668..9f84f6df8ec 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/AbstractSessionManager.java @@ -15,14 +15,19 @@ package org.eclipse.jetty.server.session; import static java.lang.Math.round; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.EventListener; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import javax.servlet.ServletRequest; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSessionAttributeListener; @@ -57,7 +62,12 @@ import org.eclipse.jetty.util.statistic.SampleStatistic; public abstract class AbstractSessionManager extends AbstractLifeCycle implements SessionManager { final static Logger __log = SessionHandler.LOG; - + + public Set __defaultSessionTrackingModes = + Collections.unmodifiableSet( + new HashSet( + Arrays.asList(new SessionTrackingMode[]{SessionTrackingMode.COOKIE,SessionTrackingMode.URL}))); + /* ------------------------------------------------------------ */ public final static int __distantFuture=60*60*24*7*52*20; @@ -85,6 +95,8 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement protected boolean _httpOnly=false; protected SessionIdManager _sessionIdManager; protected boolean _secureCookies=false; + protected boolean _secureRequestOnly=true; + protected final List _sessionAttributeListeners = new CopyOnWriteArrayList(); protected final List _sessionListeners= new CopyOnWriteArrayList(); @@ -99,13 +111,19 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement protected int _refreshCookieAge; protected boolean _nodeIdInSessionId; protected boolean _checkingRemoteSessionIdEncoding; + protected String _sessionComment; + public Set _sessionTrackingModes; + + private boolean _usingURLs; + protected final CounterStatistic _sessionsStats = new CounterStatistic(); protected final SampleStatistic _sessionTimeStats = new SampleStatistic(); /* ------------------------------------------------------------ */ public AbstractSessionManager() { + setSessionTrackingModes(__defaultSessionTrackingModes); } /* ------------------------------------------------------------ */ @@ -127,14 +145,14 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement AbstractSession s = ((SessionIf)session).getSession(); - if (s.access(now)) - { + if (s.access(now)) + { // Do we need to refresh the cookie? if (isUsingCookies() && - (s.isIdChanged() || - (getMaxCookieAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge())) - ) - ) + (s.isIdChanged() || + (getSessionCookieConfig().getMaxAge()>0 && getRefreshCookieAge()>0 && ((now-s.getCookieSetTime())/1000>getRefreshCookieAge())) + ) + ) { HttpCookie cookie=getSessionCookie(session,_context==null?"/":(_context.getContextPath()),secure); s.cookieSet(); @@ -276,16 +294,12 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement return _sessionIdManager; } - /* ------------------------------------------------------------ */ - public int getMaxCookieAge() - { - return _maxCookieAge; - } /* ------------------------------------------------------------ */ /** * @return seconds */ + @Override public int getMaxInactiveInterval() { return _dftMaxIdleSecs; @@ -348,13 +362,38 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement /* ------------------------------------------------------------ */ /** - * @return Returns the secureCookies. + * @return same as SessionCookieConfig.getSecure(). If true, session + * cookies are ALWAYS marked as secure. If false, a session cookie is + * ONLY marked as secure if _secureRequestOnly == true and it is a HTTPS request. */ public boolean getSecureCookies() { return _secureCookies; } + + /* ------------------------------------------------------------ */ + /** + * @return true if session cookie is to be marked as secure only on HTTPS requests + */ + public boolean isSecureRequestOnly() + { + return _secureRequestOnly; + } + + + /* ------------------------------------------------------------ */ + /** + * @return if true, session cookie will be marked as secure only iff + * HTTPS request. Can be overridden by setting SessionCookieConfig.setSecure(true), + * in which case the session cookie will be marked as secure on both HTTPS and HTTP. + */ + public void setSecureRequestOnly(boolean secureRequestOnly) + { + _secureRequestOnly = secureRequestOnly; + } + + /* ------------------------------------------------------------ */ public String getSessionCookie() { @@ -362,6 +401,31 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement } /* ------------------------------------------------------------ */ + /** + * A sessioncookie is marked as secure IFF any of the following conditions are true: + *
    + *
  1. SessionCookieConfig.setSecure == true
  2. + *
  3. SessionCookieConfig.setSecure == false && _secureRequestOnly==true && request is HTTPS
  4. + *
+ * According to SessionCookieConfig javadoc, case 1 can be used when: + * "... even though the request that initiated the session came over HTTP, + * is to support a topology where the web container is front-ended by an + * SSL offloading load balancer. In this case, the traffic between the client + * and the load balancer will be over HTTPS, whereas the traffic between the + * load balancer and the web container will be over HTTP." + * + * For case 2, you can use _secureRequestOnly to determine if you want the + * Servlet Spec 3.0 default behaviour when SessionCookieConfig.setSecure==false, + * which is: + * "they shall be marked as secure only if the request that initiated the + * corresponding session was also secure" + * + * The default for _secureRequestOnly is true, which gives the above behaviour. If + * you set it to false, then a session cookie is NEVER marked as secure, even if + * the initiating request was secure. + * + * @see org.eclipse.jetty.server.SessionManager#getSessionCookie(javax.servlet.http.HttpSession, java.lang.String, boolean) + */ public HttpCookie getSessionCookie(HttpSession session, String contextPath, boolean requestIsSecure) { if (isUsingCookies()) @@ -369,15 +433,32 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement String sessionPath = (_sessionPath==null) ? contextPath : _sessionPath; sessionPath = (sessionPath==null||sessionPath.length()==0) ? "/" : sessionPath; String id = getNodeId(session); - HttpCookie cookie=new HttpCookie( - _sessionCookie, - id, - _sessionDomain, - sessionPath, - getMaxCookieAge(), - getHttpOnly(), - requestIsSecure&&getSecureCookies()); - + HttpCookie cookie = null; + if (_sessionComment == null) + { + cookie = new HttpCookie( + _sessionCookie, + id, + _sessionDomain, + sessionPath, + _cookieConfig.getMaxAge(), + _cookieConfig.isHttpOnly(), + _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure)); + } + else + { + cookie = new HttpCookie( + _sessionCookie, + id, + _sessionDomain, + sessionPath, + _cookieConfig.getMaxAge(), + _cookieConfig.isHttpOnly(), + _cookieConfig.isSecure() || (isSecureRequestOnly() && requestIsSecure), + _sessionComment, + 1); + } + return cookie; } return null; @@ -407,11 +488,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement throw new UnsupportedOperationException(); } - /* ------------------------------------------------------------ */ - public String getSessionPath() - { - return _sessionPath; - } + /* ------------------------------------------------------------ */ public int getSessions() @@ -531,15 +608,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement _sessionIdManager=metaManager; } - /* ------------------------------------------------------------ */ - public void setMaxCookieAge(int maxCookieAgeInSeconds) - { - _maxCookieAge=maxCookieAgeInSeconds; - if (_maxCookieAge>0 && _refreshCookieAge==0) - _refreshCookieAge=_maxCookieAge/3; - - } /* ------------------------------------------------------------ */ /** @@ -550,15 +619,6 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement _dftMaxIdleSecs=seconds; } - /* ------------------------------------------------------------ */ - /** - * @deprecated use {@link #setSessionIdManager(SessionIdManager)} - */ - @Deprecated - public void setMetaManager(SessionIdManager metaManager) - { - setSessionIdManager(metaManager); - } /* ------------------------------------------------------------ */ public void setRefreshCookieAge(int ageInSeconds) @@ -567,34 +627,13 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement } - /* ------------------------------------------------------------ */ - /** - * Set if the session manager should use SecureCookies. - * A secure cookie will only be sent by a browser on a secure (https) connection to - * avoid the concern of cookies being intercepted on non secure channels. - * For the cookie to be issued as secure, the {@link ServletRequest#isSecure()} method must return true. - * If SSL offload is used, then the {@link AbstractConnector#customize(org.eclipse.jetty.io.EndPoint, Request)} - * method can be used to force the request to be https, or the {@link AbstractConnector#setForwarded(boolean)} - * can be set to true, so that the X-Forwarded-Proto header is respected. - *

- * If secure session cookies are used, then a session may not be shared between http and https requests. - * - * @param secureCookies If true, use secure cookies. - */ - public void setSecureCookies(boolean secureCookies) - { - _secureCookies=secureCookies; - } public void setSessionCookie(String cookieName) { _sessionCookie=cookieName; } - public void setSessionDomain(String domain) - { - _sessionDomain=domain; - } + /* ------------------------------------------------------------ */ /** @@ -606,15 +645,7 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement _sessionHandler=sessionHandler; } - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.server.SessionManager#setSessionPath(java.lang.String) - */ - public void setSessionPath(String path) - { - _sessionPath=path; - } - + /* ------------------------------------------------------------ */ public void setSessionIdPathParameterName(String param) { @@ -751,6 +782,132 @@ public abstract class AbstractSessionManager extends AbstractLifeCycle implement return _sessionTimeStats.getMax(); } + /* ------------------------------------------------------------ */ + public Set getDefaultSessionTrackingModes() + { + return __defaultSessionTrackingModes; + } + + /* ------------------------------------------------------------ */ + public Set getEffectiveSessionTrackingModes() + { + return Collections.unmodifiableSet(_sessionTrackingModes); + } + + /* ------------------------------------------------------------ */ + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) + { + _sessionTrackingModes=new HashSet(sessionTrackingModes); + _usingCookies=_sessionTrackingModes.contains(SessionTrackingMode.COOKIE); + _usingURLs=_sessionTrackingModes.contains(SessionTrackingMode.URL); + } + + /* ------------------------------------------------------------ */ + @Override + public boolean isUsingURLs() + { + return _usingURLs; + } + + + /* ------------------------------------------------------------ */ + public SessionCookieConfig getSessionCookieConfig() + { + return _cookieConfig; + } + + /* ------------------------------------------------------------ */ + private SessionCookieConfig _cookieConfig = + new SessionCookieConfig() + { + @Override + public String getComment() + { + return _sessionComment; + } + + @Override + public String getDomain() + { + return _sessionDomain; + } + + @Override + public int getMaxAge() + { + return _maxCookieAge; + } + + @Override + public String getName() + { + return _sessionCookie; + } + + @Override + public String getPath() + { + return _sessionPath; + } + + @Override + public boolean isHttpOnly() + { + return _httpOnly; + } + + @Override + public boolean isSecure() + { + return _secureCookies; + } + + @Override + public void setComment(String comment) + { + _sessionComment = comment; + } + + @Override + public void setDomain(String domain) + { + _sessionDomain=domain; + } + + @Override + public void setHttpOnly(boolean httpOnly) + { + _httpOnly=httpOnly; + } + + @Override + public void setMaxAge(int maxAge) + { + _maxCookieAge=maxAge; + } + + @Override + public void setName(String name) + { + _sessionCookie=name; + } + + @Override + public void setPath(String path) + { + _sessionPath=path; + } + + @Override + public void setSecure(boolean secure) + { + _secureCookies=secure; + } + + }; + + /* ------------------------------------------------------------ */ /** * @return total amount of time all sessions remained valid diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java index 3b59213b516..1f3c3d0443b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/HashSessionManager.java @@ -22,6 +22,7 @@ import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; +import java.util.Set; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java index bcf443eb8d4..f09dab5ea91 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/JDBCSessionManager.java @@ -28,9 +28,11 @@ import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicReference; +import javax.servlet.SessionTrackingMode; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener; diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java index a18a6e7553b..9e1d6b9917d 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/session/SessionHandler.java @@ -14,16 +14,18 @@ package org.eclipse.jetty.server.session; import java.io.IOException; +import java.util.EnumSet; import java.util.EventListener; +import javax.servlet.DispatcherType; import javax.servlet.ServletException; +import javax.servlet.SessionTrackingMode; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import org.eclipse.jetty.http.HttpCookie; -import org.eclipse.jetty.server.DispatcherType; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.SessionManager; @@ -37,6 +39,10 @@ import org.eclipse.jetty.util.log.Logger; public class SessionHandler extends ScopedHandler { final static Logger LOG = Log.getLogger("org.eclipse.jetty.server.session"); + + public final static EnumSet DEFAULT_TRACKING = EnumSet.of(SessionTrackingMode.COOKIE,SessionTrackingMode.URL); + + /* -------------------------------------------------------------- */ private SessionManager _sessionManager; @@ -258,9 +264,10 @@ public class SessionHandler extends ScopedHandler Cookie[] cookies=request.getCookies(); if (cookies!=null && cookies.length>0) { + final String sessionCookie=sessionManager.getSessionCookieConfig().getName(); for (int i=0;i=0) { final AsyncContext asyncContext = baseRequest.startAsync(); - asyncContext.addContinuationListener(__asyncListener); + asyncContext.addListener(__asyncListener); if (suspend_for>0) asyncContext.setTimeout(suspend_for); - if (complete_after>0) { TimerTask complete = new TimerTask() @@ -320,18 +322,31 @@ public class AsyncStressTest } } } - - - private static ContinuationListener __asyncListener = new ContinuationListener() + + + private static AsyncListener __asyncListener = new AsyncListener() { - public void onComplete(Continuation continuation) + @Override + public void onComplete(AsyncEvent event) throws IOException { } - public void onTimeout(Continuation continuation) + @Override + public void onTimeout(AsyncEvent event) throws IOException + { + event.getSuppliedRequest().setAttribute("TIMEOUT",Boolean.TRUE); + event.getSuppliedRequest().getAsyncContext().dispatch(); + } + + @Override + public void onError(AsyncEvent event) throws IOException + { + + } + + @Override + public void onStartAsync(AsyncEvent event) throws IOException { - continuation.setAttribute("TIMEOUT",Boolean.TRUE); - continuation.resume(); } }; } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java index e5b13f6dc52..58cbec78514 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/LocalAsyncContextTest.java @@ -18,7 +18,11 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.InputStream; - +import java.util.concurrent.atomic.AtomicInteger; +import javax.servlet.AsyncContext; +import javax.servlet.AsyncEvent; +import javax.servlet.AsyncListener; +import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -65,71 +69,116 @@ public class LocalAsyncContextTest @Test public void testSuspendResume() throws Exception { + String response; + __completed.set(0); + __completed1.set(0); _handler.setRead(0); _handler.setSuspendFor(1000); _handler.setResumeAfter(-1); _handler.setCompleteAfter(-1); - check("TIMEOUT",process(null)); + response=process(null); + check(response,"TIMEOUT"); + assertEquals(1,__completed.get()); + assertEquals(1,__completed1.get()); _handler.setSuspendFor(10000); _handler.setResumeAfter(0); _handler.setCompleteAfter(-1); - check("RESUMED",process(null)); + response=process(null); + check(response,"DISPATCHED"); _handler.setResumeAfter(100); _handler.setCompleteAfter(-1); - check("RESUMED",process(null)); + response=process(null); + check(response,"DISPATCHED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(0); - check("COMPLETED",process(null)); + response=process(null); + check(response,"COMPLETED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(200); - check("COMPLETED",process(null)); + response=process(null); + check(response,"COMPLETED"); _handler.setRead(-1); _handler.setResumeAfter(0); _handler.setCompleteAfter(-1); - check("RESUMED",process("wibble")); + response=process("wibble"); + check(response,"DISPATCHED"); _handler.setResumeAfter(100); _handler.setCompleteAfter(-1); - check("RESUMED",process("wibble")); + check(response,"DISPATCHED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(0); - check("COMPLETED",process("wibble")); + response=process("wibble"); + check(response,"COMPLETED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(100); - check("COMPLETED",process("wibble")); + response=process("wibble"); + check(response,"COMPLETED"); _handler.setRead(6); _handler.setResumeAfter(0); _handler.setCompleteAfter(-1); - check("RESUMED",process("wibble")); + response=process("wibble"); + check(response,"DISPATCHED"); _handler.setResumeAfter(100); _handler.setCompleteAfter(-1); - check("RESUMED",process("wibble")); + response=process("wibble"); + check(response,"DISPATCHED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(0); - check("COMPLETED",process("wibble")); + response=process("wibble"); + check(response,"COMPLETED"); _handler.setResumeAfter(-1); _handler.setCompleteAfter(100); - check("COMPLETED",process("wibble")); + response=process("wibble"); + check(response,"COMPLETED"); } - protected void check(String content,String response) + public void testTwoCycles() throws Exception + { + String response; + + __completed.set(0); + __completed1.set(0); + + _handler.setRead(0); + _handler.setSuspendFor(1000); + _handler.setResumeAfter(100); + _handler.setCompleteAfter(-1); + _handler.setSuspendFor2(1000); + _handler.setResumeAfter2(200); + _handler.setCompleteAfter2(-1); + response=process(null); + check(response,"STARTASYNC","DISPATCHED","startasync","STARTASYNC","DISPATCHED"); + assertEquals(1,__completed.get()); + assertEquals(0,__completed1.get()); + + } + + protected void check(String response,String... content) { assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); - assertTrue(response.contains(content)); + int i=0; + for (String m:content) + { + i=response.indexOf(m,i); + assertTrue(i>=0); + i+=m.length(); + } + } private synchronized String process(String content) throws Exception @@ -157,6 +206,9 @@ public class LocalAsyncContextTest private long _suspendFor=-1; private long _resumeAfter=-1; private long _completeAfter=-1; + private long _suspendFor2=-1; + private long _resumeAfter2=-1; + private long _completeAfter2=-1; public SuspendHandler() { @@ -201,108 +253,287 @@ public class LocalAsyncContextTest { _completeAfter = completeAfter; } + + + + /* ------------------------------------------------------------ */ + /** Get the suspendFor2. + * @return the suspendFor2 + */ + public long getSuspendFor2() + { + return _suspendFor2; + } + + + /* ------------------------------------------------------------ */ + /** Set the suspendFor2. + * @param suspendFor2 the suspendFor2 to set + */ + public void setSuspendFor2(long suspendFor2) + { + _suspendFor2 = suspendFor2; + } + + + /* ------------------------------------------------------------ */ + /** Get the resumeAfter2. + * @return the resumeAfter2 + */ + public long getResumeAfter2() + { + return _resumeAfter2; + } + + + /* ------------------------------------------------------------ */ + /** Set the resumeAfter2. + * @param resumeAfter2 the resumeAfter2 to set + */ + public void setResumeAfter2(long resumeAfter2) + { + _resumeAfter2 = resumeAfter2; + } + + + /* ------------------------------------------------------------ */ + /** Get the completeAfter2. + * @return the completeAfter2 + */ + public long getCompleteAfter2() + { + return _completeAfter2; + } + + + /* ------------------------------------------------------------ */ + /** Set the completeAfter2. + * @param completeAfter2 the completeAfter2 to set + */ + public void setCompleteAfter2(long completeAfter2) + { + _completeAfter2 = completeAfter2; + } + @Override public void handle(String target, final Request baseRequest, final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException { - if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) + try { - if (_read>0) + if (DispatcherType.REQUEST.equals(baseRequest.getDispatcherType())) { - byte[] buf=new byte[_read]; - request.getInputStream().read(buf); - } - else if (_read<0) - { - InputStream in = request.getInputStream(); - int b=in.read(); - while(b!=-1) - b=in.read(); - } + if (_read>0) + { + byte[] buf=new byte[_read]; + request.getInputStream().read(buf); + } + else if (_read<0) + { + InputStream in = request.getInputStream(); + int b=in.read(); + while(b!=-1) + b=in.read(); + } - final AsyncContext asyncContext = baseRequest.startAsync(); - asyncContext.addContinuationListener(__asyncListener); - if (_suspendFor>0) - asyncContext.setTimeout(_suspendFor); - if (_completeAfter>0) + final AsyncContext asyncContext = baseRequest.startAsync(); + response.getOutputStream().println("STARTASYNC"); + asyncContext.addListener(__asyncListener); + asyncContext.addListener(__asyncListener1); + if (_suspendFor>0) + asyncContext.setTimeout(_suspendFor); + + + if (_completeAfter>0) + { + new Thread() { + @Override + public void run() + { + try + { + Thread.sleep(_completeAfter); + response.getOutputStream().println("COMPLETED"); + response.setStatus(200); + baseRequest.setHandled(true); + asyncContext.complete(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }.start(); + } + else if (_completeAfter==0) + { + response.getOutputStream().println("COMPLETED"); + response.setStatus(200); + baseRequest.setHandled(true); + asyncContext.complete(); + } + + if (_resumeAfter>0) + { + new Thread() { + @Override + public void run() + { + try + { + Thread.sleep(_resumeAfter); + if(((HttpServletRequest)asyncContext.getRequest()).getSession(true).getId()!=null) + asyncContext.dispatch(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }.start(); + } + else if (_resumeAfter==0) + { + asyncContext.dispatch(); + } + } + else { - new Thread() { - @Override - public void run() + if (request.getAttribute("TIMEOUT")!=null) + response.getOutputStream().println("TIMEOUT"); + else + response.getOutputStream().println("DISPATCHED"); + + if (_suspendFor2>=0) + { + final AsyncContext asyncContext = baseRequest.startAsync(); + response.getOutputStream().println("STARTASYNC2"); + if (_suspendFor2>0) + asyncContext.setTimeout(_suspendFor2); + _suspendFor2=-1; + + if (_completeAfter2>0) { - try - { - Thread.sleep(_completeAfter); - response.getOutputStream().print("COMPLETED"); - response.setStatus(200); - baseRequest.setHandled(true); - asyncContext.complete(); - } - catch(Exception e) - { - e.printStackTrace(); - } + new Thread() { + @Override + public void run() + { + try + { + Thread.sleep(_completeAfter2); + response.getOutputStream().println("COMPLETED2"); + response.setStatus(200); + baseRequest.setHandled(true); + asyncContext.complete(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }.start(); } - }.start(); - } - else if (_completeAfter==0) - { - response.getOutputStream().print("COMPLETED"); - response.setStatus(200); - baseRequest.setHandled(true); - asyncContext.complete(); - } - - if (_resumeAfter>0) - { - new Thread() { - @Override - public void run() + else if (_completeAfter2==0) { - try - { - Thread.sleep(_resumeAfter); - if(((HttpServletRequest)asyncContext.getRequest()).getSession(true).getId()!=null) - asyncContext.dispatch(); - } - catch(Exception e) - { - e.printStackTrace(); - } + response.getOutputStream().println("COMPLETED2"); + response.setStatus(200); + baseRequest.setHandled(true); + asyncContext.complete(); } - }.start(); - } - else if (_resumeAfter==0) - { - asyncContext.dispatch(); + + if (_resumeAfter2>0) + { + new Thread() { + @Override + public void run() + { + try + { + Thread.sleep(_resumeAfter2); + asyncContext.dispatch(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }.start(); + } + else if (_resumeAfter2==0) + { + asyncContext.dispatch(); + } + } + else + { + response.setStatus(200); + baseRequest.setHandled(true); + } } } - else if (request.getAttribute("TIMEOUT")!=null) + finally { - response.setStatus(200); - response.getOutputStream().print("TIMEOUT"); - baseRequest.setHandled(true); - } - else - { - response.setStatus(200); - response.getOutputStream().print("RESUMED"); - baseRequest.setHandled(true); } } } - private static ContinuationListener __asyncListener = new ContinuationListener() + static AtomicInteger __completed = new AtomicInteger(); + static AtomicInteger __completed1 = new AtomicInteger(); + + private static AsyncListener __asyncListener = new AsyncListener() { - public void onComplete(Continuation continuation) + + @Override + public void onComplete(AsyncEvent event) throws IOException + { + __completed.incrementAndGet(); + } + + @Override + public void onError(AsyncEvent event) throws IOException + { + __completed.incrementAndGet(); + } + + @Override + public void onStartAsync(AsyncEvent event) throws IOException + { + event.getSuppliedResponse().getOutputStream().println("startasync"); + event.getAsyncContext().addListener(this); + } + + @Override + public void onTimeout(AsyncEvent event) throws IOException + { + event.getSuppliedRequest().setAttribute("TIMEOUT",Boolean.TRUE); + event.getAsyncContext().dispatch(); + } + + }; + + private static AsyncListener __asyncListener1 = new AsyncListener() + { + + @Override + public void onComplete(AsyncEvent event) throws IOException + { + __completed1.incrementAndGet(); + } + + @Override + public void onError(AsyncEvent event) throws IOException + { + } + @Override + public void onStartAsync(AsyncEvent event) throws IOException { } - public void onTimeout(Continuation continuation) + @Override + public void onTimeout(AsyncEvent event) throws IOException { - continuation.setAttribute("TIMEOUT",Boolean.TRUE); - continuation.resume(); } + }; } diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java index 71cfdcd236f..e69ece5b7e1 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/RequestTest.java @@ -638,10 +638,12 @@ public class RequestTest assertNotSame(cookies.get(1), cookies.get(3)); cookies.clear(); +//NOTE: the javax.servlet.http.Cookie class sets the system property org.glassfish.web.rfc2109_cookie_names_enforced +//to TRUE by default, and rejects all cookie names containing punctuation.Therefore this test cannot use "name2". response=_connector.getResponses( "POST / HTTP/1.1\r\n"+ "Host: whatever\r\n"+ - "Cookie: name0=value0; name1 = value1 ; \"\\\"name2\\\"\" = \"\\\"value2\\\"\" \n" + + "Cookie: name0=value0; name1 = value1 ; \"name2\" = \"\\\"value2\\\"\" \n" + "Cookie: $Version=2; name3=value3=value3;$path=/path;$domain=acme.com;$port=8080, name4=; name5 = ; name6\n" + "Cookie: name7=value7;\n" + "Connection: close\r\n"+ @@ -651,7 +653,7 @@ public class RequestTest assertEquals("value0", cookies.get(0).getValue()); assertEquals("name1", cookies.get(1).getName()); assertEquals("value1", cookies.get(1).getValue()); - assertEquals("\"name2\"", cookies.get(2).getName()); + assertEquals("name2", cookies.get(2).getName()); assertEquals("\"value2\"", cookies.get(2).getValue()); assertEquals("name3", cookies.get(3).getName()); assertEquals("value3=value3", cookies.get(3).getValue()); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java index 6f2b1172f44..497e081dd00 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ResponseTest.java @@ -24,6 +24,7 @@ import java.io.LineNumberReader; import java.io.PrintWriter; import java.net.Socket; import java.util.Enumeration; +import java.util.Iterator; import java.util.Locale; import java.util.Map; @@ -96,14 +97,15 @@ public class ResponseTest response.setContentType("foo2/bar2"); assertEquals("foo2/bar2;charset=ISO-8859-1",response.getContentType()); response.setHeader("name","foo"); - Enumeration en=response.getHeaders("name"); - assertEquals("foo",en.nextElement()); - assertFalse(en.hasMoreElements()); + + Iterator en = response.getHeaders("name").iterator(); + assertEquals("foo",en.next()); + assertFalse(en.hasNext()); response.addHeader("name","bar"); - en=response.getHeaders("name"); - assertEquals("foo",en.nextElement()); - assertEquals("bar",en.nextElement()); - assertFalse(en.hasMoreElements()); + en=response.getHeaders("name").iterator(); + assertEquals("foo",en.next()); + assertEquals("bar",en.next()); + assertFalse(en.hasNext()); response.recycle(); diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java new file mode 100644 index 00000000000..7f952d01e51 --- /dev/null +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionCookieTest.java @@ -0,0 +1,194 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.server.session; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import javax.servlet.SessionCookieConfig; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpSession; + +import org.eclipse.jetty.http.HttpCookie; +import org.junit.Test; +/** + * SessionCookieTest + * + * + */ +public class SessionCookieTest +{ + + public class MockSession extends AbstractSession + { + + + /** + * @param abstractSessionManager + * @param created + * @param accessed + * @param clusterId + */ + protected MockSession(AbstractSessionManager abstractSessionManager, long created, long accessed, String clusterId) + { + super(abstractSessionManager, created, accessed, clusterId); + } + + } + + public class MockSessionIdManager extends AbstractSessionIdManager + { + + /** + * @see org.eclipse.jetty.server.SessionIdManager#idInUse(java.lang.String) + */ + public boolean idInUse(String id) + { + return false; + } + + /** + * @see org.eclipse.jetty.server.SessionIdManager#addSession(javax.servlet.http.HttpSession) + */ + public void addSession(HttpSession session) + { + + } + + /** + * @see org.eclipse.jetty.server.SessionIdManager#removeSession(javax.servlet.http.HttpSession) + */ + public void removeSession(HttpSession session) + { + + } + + /** + * @see org.eclipse.jetty.server.SessionIdManager#invalidateAll(java.lang.String) + */ + public void invalidateAll(String id) + { + + } + + /** + * @see org.eclipse.jetty.server.SessionIdManager#getClusterId(java.lang.String) + */ + public String getClusterId(String nodeId) + { + int dot=nodeId.lastIndexOf('.'); + return (dot>0)?nodeId.substring(0,dot):nodeId; + } + + /** + * @see org.eclipse.jetty.server.SessionIdManager#getNodeId(java.lang.String, javax.servlet.http.HttpServletRequest) + */ + public String getNodeId(String clusterId, HttpServletRequest request) + { + return clusterId+'.'+_workerName; + } + + } + + public class MockSessionManager extends AbstractSessionManager + { + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionManager#addSession(org.eclipse.jetty.server.session.AbstractSession) + */ + protected void addSession(AbstractSession session) + { + + } + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionManager#getSession(java.lang.String) + */ + public AbstractSession getSession(String idInCluster) + { + return null; + } + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionManager#invalidateSessions() + */ + protected void invalidateSessions() throws Exception + { + + } + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionManager#newSession(javax.servlet.http.HttpServletRequest) + */ + protected AbstractSession newSession(HttpServletRequest request) + { + return null; + } + + /** + * @see org.eclipse.jetty.server.session.AbstractSessionManager#removeSession(java.lang.String) + */ + protected boolean removeSession(String idInCluster) + { + return false; + } + + } + + @Test + public void testSecureSessionCookie () throws Exception + { + MockSessionIdManager idMgr = new MockSessionIdManager(); + idMgr.setWorkerName("node1"); + MockSessionManager mgr = new MockSessionManager(); + mgr.setSessionIdManager(idMgr); + MockSession session = new MockSession(mgr, System.currentTimeMillis(), System.currentTimeMillis(), "node1123"); //clusterId + + SessionCookieConfig sessionCookieConfig = mgr.getSessionCookieConfig(); + sessionCookieConfig.setSecure(true); + + //sessionCookieConfig.secure == true, always mark cookie as secure, irrespective of if requestIsSecure + HttpCookie cookie = mgr.getSessionCookie(session, "/foo", true); + assertTrue(cookie.isSecure()); + //sessionCookieConfig.secure == true, always mark cookie as secure, irrespective of if requestIsSecure + cookie = mgr.getSessionCookie(session, "/foo", false); + assertTrue(cookie.isSecure()); + + //sessionCookieConfig.secure==false, setSecureRequestOnly==true, requestIsSecure==true + //cookie should be secure: see SessionCookieConfig.setSecure() javadoc + sessionCookieConfig.setSecure(false); + cookie = mgr.getSessionCookie(session, "/foo", true); + assertTrue(cookie.isSecure()); + + //sessionCookieConfig.secure=false, setSecureRequestOnly==true, requestIsSecure==false + //cookie is not secure: see SessionCookieConfig.setSecure() javadoc + cookie = mgr.getSessionCookie(session, "/foo", false); + assertFalse(cookie.isSecure()); + + //sessionCookieConfig.secure=false, setSecureRequestOnly==false, requestIsSecure==false + //cookie is not secure: not a secure request + mgr.setSecureRequestOnly(false); + cookie = mgr.getSessionCookie(session, "/foo", false); + assertFalse(cookie.isSecure()); + + //sessionCookieConfig.secure=false, setSecureRequestOnly==false, requestIsSecure==true + //cookie is not secure: not on secured requests and request is secure + cookie = mgr.getSessionCookie(session, "/foo", true); + assertFalse(cookie.isSecure()); + + + } + +} diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java index ba0f58a407a..c413a1a7be0 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/session/SessionHandlerTest.java @@ -8,20 +8,29 @@ import java.io.BufferedReader; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.security.Principal; +import java.util.Collection; import java.util.Enumeration; import java.util.EventListener; import java.util.Locale; import java.util.Map; - +import java.util.Set; +import javax.servlet.AsyncContext; import javax.servlet.RequestDispatcher; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; import javax.servlet.ServletInputStream; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import javax.servlet.http.Part; +import javax.servlet.DispatcherType; import org.eclipse.jetty.http.HttpCookie; -import org.eclipse.jetty.server.DispatcherType; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.SessionIdManager; import org.eclipse.jetty.server.SessionManager; @@ -50,6 +59,98 @@ public class SessionHandlerTest SessionHandler sessionHandler = new SessionHandler(); sessionHandler.setSessionManager(new MockSessionManager() { + + + public SessionCookieConfig getSessionCookieConfig() + { + return new SessionCookieConfig() + { + + public String getComment() + { + // TODO Auto-generated method stub + return null; + } + + public String getDomain() + { + // TODO Auto-generated method stub + return null; + } + + public int getMaxAge() + { + // TODO Auto-generated method stub + return 0; + } + + public String getName() + { + return cookieName; + } + + public String getPath() + { + // TODO Auto-generated method stub + return null; + } + + public boolean isHttpOnly() + { + // TODO Auto-generated method stub + return false; + } + + public boolean isSecure() + { + // TODO Auto-generated method stub + return false; + } + + public void setComment(String comment) + { + // TODO Auto-generated method stub + + } + + public void setDomain(String domain) + { + // TODO Auto-generated method stub + + } + + public void setHttpOnly(boolean httpOnly) + { + // TODO Auto-generated method stub + + } + + public void setMaxAge(int maxAge) + { + // TODO Auto-generated method stub + + } + + public void setName(String name) + { + // TODO Auto-generated method stub + + } + + public void setPath(String path) + { + // TODO Auto-generated method stub + + } + + public void setSecure(boolean secure) + { + // TODO Auto-generated method stub + + } + + }; + } public boolean isUsingCookies() { return true; @@ -86,7 +187,8 @@ public class SessionHandlerTest SessionHandler sessionHandler = new SessionHandler(); sessionHandler.setSessionManager(new MockSessionManager() - { + { + @Override public String getSessionIdPathParameterName() { @@ -378,6 +480,114 @@ public class SessionHandlerTest public void setCharacterEncoding(String env) throws UnsupportedEncodingException { } + + /** + * @see javax.servlet.http.HttpServletRequest#authenticate(javax.servlet.http.HttpServletResponse) + */ + public boolean authenticate(HttpServletResponse response) throws IOException, ServletException + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see javax.servlet.http.HttpServletRequest#getPart(java.lang.String) + */ + public Part getPart(String name) throws IOException, ServletException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see javax.servlet.http.HttpServletRequest#getParts() + */ + public Collection getParts() throws IOException, ServletException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see javax.servlet.http.HttpServletRequest#login(java.lang.String, java.lang.String) + */ + public void login(String username, String password) throws ServletException + { + // TODO Auto-generated method stub + + } + + /** + * @see javax.servlet.http.HttpServletRequest#logout() + */ + public void logout() throws ServletException + { + // TODO Auto-generated method stub + + } + + /** + * @see javax.servlet.ServletRequest#getAsyncContext() + */ + public AsyncContext getAsyncContext() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see javax.servlet.ServletRequest#getDispatcherType() + */ + public DispatcherType getDispatcherType() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see javax.servlet.ServletRequest#getServletContext() + */ + public ServletContext getServletContext() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see javax.servlet.ServletRequest#isAsyncStarted() + */ + public boolean isAsyncStarted() + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see javax.servlet.ServletRequest#isAsyncSupported() + */ + public boolean isAsyncSupported() + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see javax.servlet.ServletRequest#startAsync() + */ + public AsyncContext startAsync() throws IllegalStateException + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see javax.servlet.ServletRequest#startAsync(javax.servlet.ServletRequest, javax.servlet.ServletResponse) + */ + public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse) throws IllegalStateException + { + // TODO Auto-generated method stub + return null; + } } /** @@ -574,6 +784,50 @@ public class SessionHandlerTest { } + /** + * @see org.eclipse.jetty.server.SessionManager#getDefaultSessionTrackingModes() + */ + public Set getDefaultSessionTrackingModes() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.server.SessionManager#getEffectiveSessionTrackingModes() + */ + public Set getEffectiveSessionTrackingModes() + { + // TODO Auto-generated method stub + return null; + } + + /** + * @see org.eclipse.jetty.server.SessionManager#getSessionCookieConfig() + */ + public SessionCookieConfig getSessionCookieConfig() + { + return null; + } + + /** + * @see org.eclipse.jetty.server.SessionManager#isUsingURLs() + */ + public boolean isUsingURLs() + { + // TODO Auto-generated method stub + return false; + } + + /** + * @see org.eclipse.jetty.server.SessionManager#setSessionTrackingModes(java.util.Set) + */ + public void setSessionTrackingModes(Set sessionTrackingModes) + { + // TODO Auto-generated method stub + + } + private boolean _checkRemote=false; public boolean isCheckingRemoteSessionIdEncoding() diff --git a/jetty-servlet/pom.xml b/jetty-servlet/pom.xml index 70ab5daf8a3..7ef1a382193 100644 --- a/jetty-servlet/pom.xml +++ b/jetty-servlet/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-servlet diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java index 937dba53f18..81d6cba14a2 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterHolder.java @@ -19,12 +19,13 @@ import java.util.Collection; import java.util.EnumSet; import java.util.List; +import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterConfig; +import javax.servlet.FilterRegistration; import javax.servlet.ServletException; -import org.eclipse.jetty.server.DispatcherType; -import org.eclipse.jetty.servlet.api.FilterRegistration; +import org.eclipse.jetty.servlet.Holder.Source; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -47,14 +48,24 @@ public class FilterHolder extends Holder */ public FilterHolder() { + super (Source.EMBEDDED); } + /* ---------------------------------------------------------------- */ + /** Constructor + */ + public FilterHolder(Holder.Source source) + { + super (source); + } + /* ---------------------------------------------------------------- */ /** Constructor */ public FilterHolder(Class filter) { + super (Source.EMBEDDED); setHeldClass(filter); } @@ -63,6 +74,7 @@ public class FilterHolder extends Holder */ public FilterHolder(Filter filter) { + super (Source.EMBEDDED); setFilter(filter); } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java index 7bd6559d6d8..4d75f048a83 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/FilterMapping.java @@ -16,8 +16,8 @@ package org.eclipse.jetty.servlet; import java.io.IOException; import java.util.EnumSet; +import javax.servlet.DispatcherType; import org.eclipse.jetty.http.PathMap; -import org.eclipse.jetty.server.DispatcherType; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.component.AggregateLifeCycle; @@ -167,8 +167,6 @@ public class FilterMapping implements Dumpable } } - - /* ------------------------------------------------------------ */ /** * @param dispatches The dispatches to set. diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java index cbbbb02ec9b..2936f381015 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/Holder.java @@ -21,11 +21,11 @@ import java.util.HashSet; import java.util.Map; import java.util.Set; +import javax.servlet.Registration; import javax.servlet.ServletContext; import javax.servlet.UnavailableException; import org.eclipse.jetty.server.handler.ContextHandler; -import org.eclipse.jetty.servlet.api.Registration; import org.eclipse.jetty.util.Loader; import org.eclipse.jetty.util.component.AbstractLifeCycle; import org.eclipse.jetty.util.component.AggregateLifeCycle; @@ -40,6 +40,8 @@ import org.eclipse.jetty.util.log.Logger; */ public class Holder extends AbstractLifeCycle implements Dumpable { + public enum Source { EMBEDDED, JAVAX_API, DESCRIPTOR, ANNOTATION }; + final private Source _source; private static final Logger LOG = Log.getLogger(Holder.class); protected transient Class _class; @@ -54,10 +56,16 @@ public class Holder extends AbstractLifeCycle implements Dumpable protected ServletHandler _servletHandler; /* ---------------------------------------------------------------- */ - protected Holder() + protected Holder(Source source) { + _source=source; } - + + public Source getSource() + { + return _source; + } + /* ------------------------------------------------------------ */ /** * @return True if this holder was created for a specific instance. @@ -335,6 +343,12 @@ public class Holder extends AbstractLifeCycle implements Dumpable public boolean setInitParameter(String name, String value) { illegalStateIfContextStarted(); + if (name == null) { + throw new IllegalArgumentException("init parameter name required"); + } + if (value == null) { + throw new IllegalArgumentException("non-null value required for init parameter " + name); + } if (Holder.this.getInitParameter(name)!=null) return false; Holder.this.setInitParameter(name,value); @@ -345,20 +359,28 @@ public class Holder extends AbstractLifeCycle implements Dumpable { illegalStateIfContextStarted(); Set clash=null; - for (String name : initParameters.keySet()) + for (Map.Entry entry : initParameters.entrySet()) { - if (Holder.this.getInitParameter(name)!=null) + if (entry.getKey() == null) { + throw new IllegalArgumentException("init parameter name required"); + } + if (entry.getValue() == null) { + throw new IllegalArgumentException("non-null value required for init parameter " + entry.getKey()); + } + if (Holder.this.getInitParameter(entry.getKey())!=null) { if (clash==null) clash=new HashSet(); - clash.add(name); + clash.add(entry.getKey()); } } if (clash!=null) return clash; - Holder.this.setInitParameters(initParameters); + Holder.this.getInitParameters().putAll(initParameters); return Collections.emptySet(); - }; + } + + } } diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java index 43ad5d6542d..e07f805a07c 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletContextHandler.java @@ -24,19 +24,25 @@ import java.util.List; import java.util.Map; import java.util.Set; +import javax.servlet.DispatcherType; import javax.servlet.Filter; +import javax.servlet.FilterRegistration; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.ServletSecurityElement; +import javax.servlet.SessionCookieConfig; +import javax.servlet.SessionTrackingMode; +import javax.servlet.descriptor.JspConfigDescriptor; import org.eclipse.jetty.security.ConstraintAware; import org.eclipse.jetty.security.ConstraintSecurityHandler; import org.eclipse.jetty.security.SecurityHandler; import org.eclipse.jetty.server.Dispatcher; -import org.eclipse.jetty.server.DispatcherType; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.HandlerContainer; import org.eclipse.jetty.server.handler.ContextHandler; @@ -44,9 +50,7 @@ import org.eclipse.jetty.server.handler.ErrorHandler; import org.eclipse.jetty.server.handler.HandlerCollection; import org.eclipse.jetty.server.handler.HandlerWrapper; import org.eclipse.jetty.server.session.SessionHandler; -import org.eclipse.jetty.servlet.api.FilterRegistration; -import org.eclipse.jetty.servlet.api.ServletRegistration; -import org.eclipse.jetty.util.Loader; +import org.eclipse.jetty.util.LazyList; /* ------------------------------------------------------------ */ @@ -74,8 +78,10 @@ public class ServletContextHandler extends ContextHandler protected ServletHandler _servletHandler; protected HandlerWrapper _wrapper; protected int _options; + protected JspConfigDescriptor _jspConfig; protected Object _restrictedContextListeners; - + private boolean _restrictListeners = true; + /* ------------------------------------------------------------ */ public ServletContextHandler() { @@ -331,46 +337,85 @@ public class ServletContextHandler extends ContextHandler { return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches); } + + /** + * notification that a ServletRegistration has been created so we can track the annotations + * @param holder new holder created through the api. + * @return the ServletRegistration.Dynamic + */ + protected ServletRegistration.Dynamic dynamicHolderAdded(ServletHolder holder) { + return holder.getRegistration(); + } + + /** + * delegate for ServletContext.declareRole method + * @param roleNames role names to add + */ + protected void addRoles(String... roleNames) { + //Get a reference to the SecurityHandler, which must be ConstraintAware + if (_securityHandler != null && _securityHandler instanceof ConstraintAware) + { + HashSet union = new HashSet(); + Set existing = ((ConstraintAware)_securityHandler).getRoles(); + if (existing != null) + union.addAll(existing); + union.addAll(Arrays.asList(roleNames)); + ((ConstraintSecurityHandler)_securityHandler).setRoles(union); + } + } + + /** + * Delegate for ServletRegistration.Dynamic.setServletSecurity method + * @param registration ServletRegistration.Dynamic instance that setServletSecurity was called on + * @param servletSecurityElement new security info + * @return the set of exact URL mappings currently associated with the registration that are also present in the web.xml + * security constratins and thus will be unaffected by this call. + */ + public Set setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement) + { + return Collections.emptySet(); + } + + - - /* ------------------------------------------------------------ */ - /** conveniance method to add a filter - */ - public void addFilter(FilterHolder holder,String pathSpec,int dispatches) + public void restrictEventListener (EventListener e) { - getServletHandler().addFilterWithMapping(holder,pathSpec,dispatches); + if (_restrictListeners && e instanceof ServletContextListener) + _restrictedContextListeners = LazyList.add(_restrictedContextListeners, e); } - /* ------------------------------------------------------------ */ - /** convenience method to add a filter - */ - public FilterHolder addFilter(Class filterClass,String pathSpec,int dispatches) - { - return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches); + public boolean isRestrictListeners() { + return _restrictListeners; } - /* ------------------------------------------------------------ */ - /** convenience method to add a filter - */ - public FilterHolder addFilter(String filterClass,String pathSpec,int dispatches) - { - return getServletHandler().addFilterWithMapping(filterClass,pathSpec,dispatches); + public void setRestrictListeners(boolean restrictListeners) { + this._restrictListeners = restrictListeners; } - - public void callContextInitialized(ServletContextListener l, ServletContextEvent e) - { - l.contextInitialized(e); + { + try + { + //toggle state of the dynamic API so that the listener cannot use it + if (LazyList.contains(_restrictedContextListeners, l)) + this.getServletContext().setEnabled(false); + + super.callContextInitialized(l, e); + } + finally + { + //untoggle the state of the dynamic API + this.getServletContext().setEnabled(true); + } } - + public void callContextDestroyed(ServletContextListener l, ServletContextEvent e) { - l.contextDestroyed(e); + super.callContextDestroyed(l, e); } - + /* ------------------------------------------------------------ */ /** @@ -461,7 +506,10 @@ public class ServletContextHandler extends ContextHandler public RequestDispatcher getNamedDispatcher(String name) { ContextHandler context=org.eclipse.jetty.servlet.ServletContextHandler.this; - if (_servletHandler==null || _servletHandler.getServlet(name)==null) + if (_servletHandler==null) + return null; + ServletHolder holder = _servletHandler.getServlet(name); + if (holder==null || !holder.isEnabled()) return null; return new Dispatcher(context, name); } @@ -470,13 +518,17 @@ public class ServletContextHandler extends ContextHandler /** * @since servlet-api-3.0 */ + @Override public FilterRegistration.Dynamic addFilter(String filterName, Class filterClass) { if (isStarted()) throw new IllegalStateException(); + + if (!_enabled) + throw new UnsupportedOperationException(); final ServletHandler handler = ServletContextHandler.this.getServletHandler(); - final FilterHolder holder= handler.newFilterHolder(); + final FilterHolder holder= handler.newFilterHolder(Holder.Source.JAVAX_API); holder.setName(filterName); holder.setHeldClass(filterClass); handler.addFilter(holder); @@ -487,13 +539,17 @@ public class ServletContextHandler extends ContextHandler /** * @since servlet-api-3.0 */ + @Override public FilterRegistration.Dynamic addFilter(String filterName, String className) { if (isStarted()) throw new IllegalStateException(); + + if (!_enabled) + throw new UnsupportedOperationException(); final ServletHandler handler = ServletContextHandler.this.getServletHandler(); - final FilterHolder holder= handler.newFilterHolder(); + final FilterHolder holder= handler.newFilterHolder(Holder.Source.JAVAX_API); holder.setName(filterName); holder.setClassName(className); handler.addFilter(holder); @@ -505,13 +561,17 @@ public class ServletContextHandler extends ContextHandler /** * @since servlet-api-3.0 */ + @Override public FilterRegistration.Dynamic addFilter(String filterName, Filter filter) { if (isStarted()) throw new IllegalStateException(); + if (!_enabled) + throw new UnsupportedOperationException(); + final ServletHandler handler = ServletContextHandler.this.getServletHandler(); - final FilterHolder holder= handler.newFilterHolder(); + final FilterHolder holder= handler.newFilterHolder(Holder.Source.JAVAX_API); holder.setName(filterName); holder.setFilter(filter); handler.addFilter(holder); @@ -522,64 +582,81 @@ public class ServletContextHandler extends ContextHandler /** * @since servlet-api-3.0 */ + @Override public ServletRegistration.Dynamic addServlet(String servletName, Class servletClass) { if (!isStarting()) throw new IllegalStateException(); + + if (!_enabled) + throw new UnsupportedOperationException(); final ServletHandler handler = ServletContextHandler.this.getServletHandler(); - final ServletHolder holder= handler.newServletHolder(); + final ServletHolder holder= handler.newServletHolder(Holder.Source.JAVAX_API); holder.setName(servletName); holder.setHeldClass(servletClass); handler.addServlet(holder); - return holder.getRegistration(); + return dynamicHolderAdded(holder); } /* ------------------------------------------------------------ */ /** * @since servlet-api-3.0 */ + @Override public ServletRegistration.Dynamic addServlet(String servletName, String className) { if (!isStarting()) throw new IllegalStateException(); + if (!_enabled) + throw new UnsupportedOperationException(); + final ServletHandler handler = ServletContextHandler.this.getServletHandler(); - final ServletHolder holder= handler.newServletHolder(); + final ServletHolder holder= handler.newServletHolder(Holder.Source.JAVAX_API); holder.setName(servletName); holder.setClassName(className); handler.addServlet(holder); - return holder.getRegistration(); + return dynamicHolderAdded(holder); } /* ------------------------------------------------------------ */ /** * @since servlet-api-3.0 */ + @Override public ServletRegistration.Dynamic addServlet(String servletName, Servlet servlet) { if (!isStarting()) throw new IllegalStateException(); + if (!_enabled) + throw new UnsupportedOperationException(); + final ServletHandler handler = ServletContextHandler.this.getServletHandler(); - final ServletHolder holder= handler.newServletHolder(); + final ServletHolder holder= handler.newServletHolder(Holder.Source.JAVAX_API); holder.setName(servletName); holder.setServlet(servlet); handler.addServlet(holder); - return holder.getRegistration(); + return dynamicHolderAdded(holder); } /* ------------------------------------------------------------ */ + @Override public boolean setInitParameter(String name, String value) { // TODO other started conditions if (!isStarting()) throw new IllegalStateException(); + if (!_enabled) + throw new UnsupportedOperationException(); + return super.setInitParameter(name,value); } /* ------------------------------------------------------------ */ + @Override public T createFilter(Class c) throws ServletException { try @@ -603,6 +680,7 @@ public class ServletContextHandler extends ContextHandler } /* ------------------------------------------------------------ */ + @Override public T createServlet(Class c) throws ServletException { try @@ -624,16 +702,39 @@ public class ServletContextHandler extends ContextHandler throw new ServletException(e); } } - + + @Override + public Set getDefaultSessionTrackingModes() + { + if (_sessionHandler!=null) + return _sessionHandler.getSessionManager().getDefaultSessionTrackingModes(); + return null; + } + + @Override + public Set getEffectiveSessionTrackingModes() + { + if (_sessionHandler!=null) + return _sessionHandler.getSessionManager().getEffectiveSessionTrackingModes(); + return null; + } + + @Override public FilterRegistration getFilterRegistration(String filterName) - { + { + if (!_enabled) + throw new UnsupportedOperationException(); + final FilterHolder holder=ServletContextHandler.this.getServletHandler().getFilter(filterName); return (holder==null)?null:holder.getRegistration(); } - + @Override public Map getFilterRegistrations() { + if (!_enabled) + throw new UnsupportedOperationException(); + HashMap registrations = new HashMap(); ServletHandler handler=ServletContextHandler.this.getServletHandler(); FilterHolder[] holders=handler.getFilters(); @@ -645,16 +746,22 @@ public class ServletContextHandler extends ContextHandler return registrations; } - + @Override public ServletRegistration getServletRegistration(String servletName) - { + { + if (!_enabled) + throw new UnsupportedOperationException(); + final ServletHolder holder=ServletContextHandler.this.getServletHandler().getServlet(servletName); return (holder==null)?null:holder.getRegistration(); } - + @Override public Map getServletRegistrations() - { + { + if (!_enabled) + throw new UnsupportedOperationException(); + HashMap registrations = new HashMap(); ServletHandler handler=ServletContextHandler.this.getServletHandler(); ServletHolder[] holders=handler.getServlets(); @@ -666,67 +773,71 @@ public class ServletContextHandler extends ContextHandler return registrations; } - + @Override + public SessionCookieConfig getSessionCookieConfig() + { + // TODO other started conditions + if (!_enabled) + throw new UnsupportedOperationException(); + + if (_sessionHandler!=null) + return _sessionHandler.getSessionManager().getSessionCookieConfig(); + return null; + } + + @Override + public void setSessionTrackingModes(Set sessionTrackingModes) + { + // TODO other started conditions + if (!isStarting()) + throw new IllegalStateException(); + if (!_enabled) + throw new UnsupportedOperationException(); + + + if (_sessionHandler!=null) + _sessionHandler.getSessionManager().setSessionTrackingModes(sessionTrackingModes); + } + + @Override public void addListener(String className) { // TODO other started conditions if (!isStarting()) throw new IllegalStateException(); - try - { - Class clazz = getClassLoader()==null?Loader.loadClass(ContextHandler.class,className):getClassLoader().loadClass(className); - addListener(clazz); - } - catch (ClassNotFoundException e) - { - throw new IllegalArgumentException(e); - } + if (!_enabled) + throw new UnsupportedOperationException(); + super.addListener(className); } - + @Override public void addListener(T t) { + // TODO other started conditions if (!isStarting()) throw new IllegalStateException(); - - ServletContextHandler.this.addEventListener(t); + if (!_enabled) + throw new UnsupportedOperationException(); + super.addListener(t); } - + @Override public void addListener(Class listenerClass) { + // TODO other started conditions if (!isStarting()) throw new IllegalStateException(); - - try - { - EventListener l = createListener(listenerClass); - ServletContextHandler.this.addEventListener(l); - } - catch (ServletException e) - { - throw new IllegalStateException(e); - } + if (!_enabled) + throw new UnsupportedOperationException(); + super.addListener(listenerClass); } - + @Override public T createListener(Class clazz) throws ServletException { try { - T l = null; - try - { - l = clazz.newInstance(); - } - catch (InstantiationException e) - { - throw new ServletException(e); - } - catch (IllegalAccessException e) - { - throw new ServletException(e); - } + T l = super.createListener(clazz); for (int i=_decorators.size()-1; i>=0; i--) { @@ -745,26 +856,29 @@ public class ServletContextHandler extends ContextHandler } } - + + @Override + public JspConfigDescriptor getJspConfigDescriptor() + { + return _jspConfig; + } + + @Override public void declareRoles(String... roleNames) { if (!isStarting()) throw new IllegalStateException(); - - //Get a reference to the SecurityHandler, which must be ConstraintAware - if (_securityHandler != null && _securityHandler instanceof ConstraintAware) - { - HashSet union = new HashSet(); - Set existing = ((ConstraintAware)_securityHandler).getRoles(); - if (existing != null) - union.addAll(existing); - union.addAll(Arrays.asList(roleNames)); - ((ConstraintSecurityHandler)_securityHandler).setRoles(union); - } + if (!_enabled) + throw new UnsupportedOperationException(); + addRoles(roleNames); + + } + } - - + + + /* ------------------------------------------------------------ */ /** Interface to decorate loaded classes. */ diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java index 1129ed50bec..42d080ba7d7 100644 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java +++ b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/ServletHandler.java @@ -16,8 +16,11 @@ package org.eclipse.jetty.servlet; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; import java.util.List; import java.util.Map; import java.util.Queue; @@ -25,14 +28,17 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentMap; +import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.RequestDispatcher; import javax.servlet.Servlet; import javax.servlet.ServletContext; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; +import javax.servlet.ServletSecurityElement; import javax.servlet.UnavailableException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @@ -46,7 +52,7 @@ import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.SecurityHandler; import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Dispatcher; -import org.eclipse.jetty.server.DispatcherType; +import org.eclipse.jetty.server.AbstractHttpConnection; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.ServletRequestHttpWrapper; @@ -398,6 +404,9 @@ public class ServletHandler extends ScopedHandler { old_scope=baseRequest.getUserIdentityScope(); baseRequest.setUserIdentityScope(servlet_holder); + + //if this servlet supports multipart-mime, configure the request with it + baseRequest.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, ((ServletHolder.Registration)servlet_holder.getRegistration()).getMultipartConfig()); // start manual inline of nextScope(target,baseRequest,request,response); if (never()) @@ -792,12 +801,13 @@ public class ServletHandler extends ScopedHandler /** * see also newServletHolder(Class) */ - public ServletHolder newServletHolder() + public ServletHolder newServletHolder(Holder.Source source) { - return new ServletHolder(); + return new ServletHolder(source); } /* ------------------------------------------------------------ */ + /** Convenience method to add a servlet Holder. public ServletHolder newServletHolder(Class servlet) { return new ServletHolder(servlet); @@ -822,7 +832,7 @@ public class ServletHandler extends ScopedHandler */ public ServletHolder addServletWithMapping (Class servlet,String pathSpec) { - ServletHolder holder = newServletHolder(); + ServletHolder holder = newServletHolder(Holder.Source.EMBEDDED); holder.setHeldClass(servlet); setServlets((ServletHolder[])LazyList.addToArray(getServlets(), holder, ServletHolder.class)); addServletWithMapping(holder,pathSpec); @@ -877,23 +887,23 @@ public class ServletHandler extends ScopedHandler { setServletMappings((ServletMapping[])LazyList.addToArray(getServletMappings(), mapping, ServletMapping.class)); } - - /* ------------------------------------------------------------ */ - public FilterHolder newFilterHolder(Class filter) - { - return new FilterHolder(filter); + + public Set setServletSecurity(ServletRegistration.Dynamic registration, ServletSecurityElement servletSecurityElement) { + if (_contextHandler != null) { + return _contextHandler.setServletSecurity(registration, servletSecurityElement); + } + return Collections.emptySet(); } - + /* ------------------------------------------------------------ */ /** * @see #newFilterHolder(Class) */ - public FilterHolder newFilterHolder() + public FilterHolder newFilterHolder(Holder.Source source) { - return new FilterHolder(); + return new FilterHolder(source); } - /* ------------------------------------------------------------ */ public FilterHolder getFilter(String name) { @@ -910,7 +920,7 @@ public class ServletHandler extends ScopedHandler */ public FilterHolder addFilterWithMapping (Class filter,String pathSpec,EnumSet dispatches) { - FilterHolder holder = newFilterHolder(); + FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED); holder.setHeldClass(filter); addFilterWithMapping(holder,pathSpec,dispatches); @@ -926,7 +936,7 @@ public class ServletHandler extends ScopedHandler */ public FilterHolder addFilterWithMapping (String className,String pathSpec,EnumSet dispatches) { - FilterHolder holder = newFilterHolder(); + FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED); holder.setName(className+"-"+_filters.length); holder.setClassName(className); @@ -969,7 +979,6 @@ public class ServletHandler extends ScopedHandler } - /* ------------------------------------------------------------ */ /** Convenience method to add a filter. * @param filter class of filter to create @@ -979,7 +988,8 @@ public class ServletHandler extends ScopedHandler */ public FilterHolder addFilterWithMapping (Class filter,String pathSpec,int dispatches) { - FilterHolder holder = newFilterHolder(filter); + FilterHolder holder = newFilterHolder(Holder.Source.EMBEDDED); + holder.setHeldClass(filter); addFilterWithMapping(holder,pathSpec,dispatches); return holder; @@ -1037,14 +1047,13 @@ public class ServletHandler extends ScopedHandler } - /* ------------------------------------------------------------ */ /** Convenience method to add a filter with a mapping * @param className * @param pathSpec * @param dispatches * @return the filter holder created - * @deprecated use {@link #addFilterWithMapping(Class, String, int)} instead + * @deprecated use {@link #addFilterWithMapping(Class, String, EnumSet)} instead */ public FilterHolder addFilter (String className,String pathSpec,EnumSet dispatches) { @@ -1183,7 +1192,7 @@ public class ServletHandler extends ScopedHandler ServletHolder servlet_holder = (ServletHolder)_servletNameMap.get(_servletMappings[i].getServletName()); if (servlet_holder==null) throw new IllegalStateException("No such servlet: "+_servletMappings[i].getServletName()); - else if (_servletMappings[i].getPathSpecs()!=null) + else if (servlet_holder.isEnabled() && _servletMappings[i].getPathSpecs()!=null) { String[] pathSpecs = _servletMappings[i].getPathSpecs(); for (int j=0;j implements UserIdentity.Scope private transient Servlet _servlet; private transient Config _config; private transient long _unavailable; + private transient boolean _enabled = true; private transient UnavailableException _unavailableEx; public static final Map NO_MAPPED_ROLES = Collections.emptyMap(); @@ -80,14 +83,24 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder() { + super (Source.EMBEDDED); } + /* ---------------------------------------------------------------- */ + /** Constructor . + */ + public ServletHolder(Holder.Source creator) + { + super (creator); + } + /* ---------------------------------------------------------------- */ /** Constructor for existing servlet. */ public ServletHolder(Servlet servlet) { + super (Source.EMBEDDED); setServlet(servlet); } @@ -96,6 +109,7 @@ public class ServletHolder extends Holder implements UserIdentity.Scope */ public ServletHolder(Class servlet) { + super (Source.EMBEDDED); setHeldClass(servlet); } @@ -233,11 +247,26 @@ public class ServletHolder extends Holder implements UserIdentity.Scope _forcedPath = forcedPath; } + public boolean isEnabled() + { + return _enabled; + } + + + public void setEnabled(boolean enabled) + { + _enabled = enabled; + } + + /* ------------------------------------------------------------ */ public void doStart() throws Exception { _unavailable=0; + if (!_enabled) + return; + try { super.doStart(); @@ -583,7 +612,9 @@ public class ServletHolder extends Holder implements UserIdentity.Scope /* -------------------------------------------------------- */ /* -------------------------------------------------------- */ public class Registration extends HolderRegistration implements ServletRegistration.Dynamic - { + { + protected MultipartConfigElement _multipartConfig; + public Set addMapping(String... urlPatterns) { illegalStateIfContextStarted(); @@ -613,22 +644,27 @@ public class ServletHolder extends Holder implements UserIdentity.Scope { ServletMapping[] mappings =_servletHandler.getServletMappings(); List patterns=new ArrayList(); - for (ServletMapping mapping : mappings) + if (mappings!=null) { - if (!mapping.getServletName().equals(getName())) - continue; - String[] specs=mapping.getPathSpecs(); - if (specs!=null && specs.length>0) - patterns.addAll(Arrays.asList(specs)); + for (ServletMapping mapping : mappings) + { + if (!mapping.getServletName().equals(getName())) + continue; + String[] specs=mapping.getPathSpecs(); + if (specs!=null && specs.length>0) + patterns.addAll(Arrays.asList(specs)); + } } return patterns; } + @Override public String getRunAsRole() { return _runAsRole; } + @Override public void setLoadOnStartup(int loadOnStartup) { illegalStateIfContextStarted(); @@ -639,17 +675,35 @@ public class ServletHolder extends Holder implements UserIdentity.Scope { return ServletHolder.this.getInitOrder(); } - + + @Override + public void setMultipartConfig(MultipartConfigElement element) + { + _multipartConfig = element; + } + + public MultipartConfigElement getMultipartConfig() + { + return _multipartConfig; + } + + @Override public void setRunAsRole(String role) { _runAsRole = role; } + + @Override + public Set setServletSecurity(ServletSecurityElement securityElement) + { + return _servletHandler.setServletSecurity(this, securityElement); + } } public ServletRegistration.Dynamic getRegistration() { if (_registration == null) - _registration = new Registration(); + _registration = new Registration(); return _registration; } @@ -769,8 +823,3 @@ public class ServletHolder extends Holder implements UserIdentity.Scope } } } - - - - - diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/FilterRegistration.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/FilterRegistration.java deleted file mode 100644 index 6ff1b97afd5..00000000000 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/FilterRegistration.java +++ /dev/null @@ -1,27 +0,0 @@ -package org.eclipse.jetty.servlet.api; - -import java.util.Collection; -import java.util.EnumSet; - -import org.eclipse.jetty.server.DispatcherType; - -/** - * FilterRegistration - * - * Mimics the javax.servlet.FilterRegistration class to ease - * jetty-7/jetty-8 compatibility - */ -public interface FilterRegistration -{ - public void addMappingForServletNames(EnumSet dispatcherTypes, boolean isMatchAfter, String... servletNames); - - public Collection getServletNameMappings(); - - public void addMappingForUrlPatterns(EnumSet dispatcherTypes, boolean isMatchAfter, String... urlPatterns); - - public Collection getUrlPatternMappings(); - - interface Dynamic extends FilterRegistration, Registration.Dynamic - { - } -} diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/Registration.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/Registration.java deleted file mode 100644 index d83bd2ceb34..00000000000 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/Registration.java +++ /dev/null @@ -1,25 +0,0 @@ -package org.eclipse.jetty.servlet.api; - -import java.util.Map; -import java.util.Set; - -public interface Registration -{ - - public String getName(); - - public String getClassName(); - - public boolean setInitParameter(String name, String value); - - public String getInitParameter(String name); - - public Set setInitParameters(Map initParameters); - - public Map getInitParameters(); - - interface Dynamic extends Registration - { - public void setAsyncSupported(boolean isAsyncSupported); - } -} diff --git a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/ServletRegistration.java b/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/ServletRegistration.java deleted file mode 100644 index c6f231dff2f..00000000000 --- a/jetty-servlet/src/main/java/org/eclipse/jetty/servlet/api/ServletRegistration.java +++ /dev/null @@ -1,21 +0,0 @@ -package org.eclipse.jetty.servlet.api; - -import java.util.Collection; -import java.util.Set; - -public interface ServletRegistration -{ - public Set addMapping(String... urlPatterns); - - public Collection getMappings(); - - public String getRunAsRole(); - - interface Dynamic extends ServletRegistration, Registration.Dynamic - { - public void setLoadOnStartup(int loadOnStartup); - - public void setRunAsRole(String roleName); - } - -} diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java index 4a4f2fad1b5..3164aaab4e3 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DefaultServletTest.java @@ -5,7 +5,8 @@ import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; - +import java.util.EnumSet; +import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -544,7 +545,7 @@ public class DefaultServletTest assertResponseContains("Content-Length: 12", response); assertResponseNotContains("Extra Info", response); - context.addFilter(OutputFilter.class, "/*", 0); + context.addFilter(OutputFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); response = connector.getResponses("GET /context/data0.txt HTTP/1.1\r\nHost:localhost:8080\r\n\r\n"); assertResponseContains("Content-Length: 2", response); // 20 something long assertResponseContains("Extra Info", response); @@ -553,7 +554,7 @@ public class DefaultServletTest context.getServletHandler().setFilterMappings(new FilterMapping[]{}); context.getServletHandler().setFilters(new FilterHolder[]{}); - context.addFilter(WriterFilter.class, "/*", 0); + context.addFilter(WriterFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); response = connector.getResponses("GET /context/data0.txt HTTP/1.1\r\nHost:localhost:8080\r\n\r\n"); assertResponseContains("Content-Length: 2", response); // 20 something long assertResponseContains("Extra Info", response); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java index b17796f0d4d..80d891e5448 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/DispatcherTest.java @@ -19,8 +19,11 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Arrays; import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; import java.util.List; +import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; @@ -253,7 +256,7 @@ public class DispatcherTest _contextHandler.addServlet(RogerThatServlet.class, "/*"); _contextHandler.addServlet(ReserveEchoServlet.class,"/recho/*"); _contextHandler.addServlet(EchoServlet.class, "/echo/*"); - _contextHandler.addFilter(ForwardFilter.class, "/*", FilterMapping.REQUEST); + _contextHandler.addFilter(ForwardFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); String rogerResponse = _connector.getResponses("GET /context/ HTTP/1.0\n" + "Host: localhost\n\n"); diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/HolderTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/HolderTest.java new file mode 100644 index 00000000000..9bcdfe38621 --- /dev/null +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/HolderTest.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +package org.eclipse.jetty.servlet; + +import java.util.Collections; +import java.util.Set; + +import javax.servlet.Registration; +import javax.servlet.ServletRegistration; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +/** + * @version $Rev$ $Date$ + */ +public class HolderTest { + + @Test + public void testInitParams() throws Exception { + ServletHolder holder = new ServletHolder(Holder.Source.JAVAX_API); + ServletRegistration reg = holder.getRegistration(); + try { + reg.setInitParameter(null, "foo"); + fail("null name accepted"); + } catch (IllegalArgumentException e) { + } + try { + reg.setInitParameter("foo", null); + fail("null value accepted"); + } catch (IllegalArgumentException e) { + } + reg.setInitParameter("foo", "bar"); + assertFalse(reg.setInitParameter("foo", "foo")); + + Set clash = reg.setInitParameters(Collections.singletonMap("foo", "bax")); + assertTrue("should be one clash", clash != null && clash.size() == 1); + + try { + reg.setInitParameters(Collections.singletonMap((String)null, "bax")); + fail("null name in map accepted"); + } catch (IllegalArgumentException e) { + } + try { + reg.setInitParameters(Collections.singletonMap("foo", (String)null)); + fail("null value in map accepted"); + } catch (IllegalArgumentException e) { + } + + Set clash2 = reg.setInitParameters(Collections.singletonMap("FOO", "bax")); + assertTrue("should be no clash", clash2.isEmpty()); + assertEquals("setInitParameters should not replace existing non-clashing init parameters", 2, reg.getInitParameters().size()); + + } +} diff --git a/jetty-servlets/pom.xml b/jetty-servlets/pom.xml index 9e112abff9e..3be25d852e3 100644 --- a/jetty-servlets/pom.xml +++ b/jetty-servlets/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-servlets @@ -79,11 +79,11 @@ jetty-util ${project.version} - - javax.servlet - servlet-api - provided - + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + provided + org.eclipse.jetty test-jetty-servlet diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java index 69bd7d89265..0f752198216 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/DoSFilter.java @@ -335,17 +335,18 @@ public class DoSFilter implements Filter // Reject this request if (_insertHeaders) ((HttpServletResponse)response).addHeader("DoSFilter","unavailable"); + ((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } case 0: { - // fall through to throttle code + // fall through to throttle code request.setAttribute(__TRACKER,tracker); break; } default: - { + { // insert a delay before throttling the request if (_insertHeaders) ((HttpServletResponse)response).addHeader("DoSFilter","delayed"); @@ -353,12 +354,22 @@ public class DoSFilter implements Filter request.setAttribute(__TRACKER,tracker); if (_delayMs > 0) continuation.setTimeout(_delayMs); + continuation.addContinuationListener(new ContinuationListener() + { + + public void onComplete(Continuation continuation) + { + } + + public void onTimeout(Continuation continuation) + { + } + }); continuation.suspend(); return; } } } - // Throttle the request boolean accepted = false; try @@ -412,6 +423,10 @@ public class DoSFilter implements Filter _context.log("DoS",e); ((HttpServletResponse)response).sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } + catch (Exception e) + { + e.printStackTrace(); + } finally { if (accepted) diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java index 049f37072b1..25c0e4635a9 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/MultiPartFilter.java @@ -14,17 +14,15 @@ package org.eclipse.jetty.servlets; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; -import java.io.BufferedReader; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; -import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; @@ -34,16 +32,20 @@ import java.util.Map; import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; +import javax.servlet.MultipartConfigElement; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.Part; -import org.eclipse.jetty.util.B64Code; + +import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.LazyList; import org.eclipse.jetty.util.MultiMap; +import org.eclipse.jetty.util.MultiPartInputStream; import org.eclipse.jetty.util.QuotedStringTokenizer; import org.eclipse.jetty.util.StringUtil; import org.eclipse.jetty.util.TypeUtil; @@ -60,6 +62,10 @@ import org.eclipse.jetty.util.TypeUtil; * If the init parameter "delete" is set to "true", any files created will be deleted when the * current request returns. * + * Use init parameter "maxFileSize" to set the max size file that can be uploaded. + * + * Use init parameter "maxRequestSize" to limit the size of the multipart request. + * */ public class MultiPartFilter implements Filter { @@ -69,6 +75,8 @@ public class MultiPartFilter implements Filter private boolean _deleteFiles; private ServletContext _context; private int _fileOutputBuffer = 0; + private long _maxFileSize = -1L; + private long _maxRequestSize = -1L; /* ------------------------------------------------------------------------------- */ /** @@ -81,6 +89,13 @@ public class MultiPartFilter implements Filter String fileOutputBuffer = filterConfig.getInitParameter("fileOutputBuffer"); if(fileOutputBuffer!=null) _fileOutputBuffer = Integer.parseInt(fileOutputBuffer); + String maxFileSize = filterConfig.getInitParameter("maxFileSize"); + if (maxFileSize != null) + _maxFileSize = Long.parseLong(maxFileSize.trim()); + String maxRequestSize = filterConfig.getInitParameter("maxRequestSize"); + if (maxRequestSize != null) + _maxRequestSize = Long.parseLong(maxRequestSize.trim()); + _context=filterConfig.getServletContext(); } @@ -102,15 +117,11 @@ public class MultiPartFilter implements Filter InputStream in = new BufferedInputStream(request.getInputStream()); String content_type=srequest.getContentType(); - // TODO - handle encodings - String boundary="--"+QuotedStringTokenizer.unquote(value(content_type.substring(content_type.indexOf("boundary="))).trim()); - - byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1); - - MultiMap params = new MultiMap(); - for (Iterator i = request.getParameterMap().entrySet().iterator();i.hasNext();) + //Get current parameters so we can merge into them + MultiMap params = new MultiMap(); + for (Iterator> i = request.getParameterMap().entrySet().iterator();i.hasNext();) { - Map.Entry entry=(Map.Entry)i.next(); + Map.Entry entry=i.next(); Object value=entry.getValue(); if (value instanceof String[]) params.addValues(entry.getKey(),(String[])value); @@ -118,231 +129,45 @@ public class MultiPartFilter implements Filter params.add(entry.getKey(),value); } + MultipartConfigElement config = new MultipartConfigElement(tempdir.getCanonicalPath(), _maxFileSize, _maxRequestSize, _fileOutputBuffer); + MultiPartInputStream mpis = new MultiPartInputStream(in, content_type, config, tempdir); + + try { - // Get first boundary - byte[] bytes=TypeUtil.readLine(in); - String line=bytes==null?null:new String(bytes,"UTF-8"); - if(line==null || !line.equals(boundary)) + Collection parts = mpis.getParts(); + if (parts != null) { - throw new IOException("Missing initial multi part boundary"); - } - - // Read each part - boolean lastPart=false; - String content_disposition=null; - String content_transfer_encoding=null; - - - outer:while(!lastPart) - { - String type_content=null; - - while(true) + for (Part p:parts) { - // read a line - bytes=TypeUtil.readLine(in); - if (bytes==null) - break outer; - - // If blank line, end of part headers - if(bytes.length==0) - break; - line=new String(bytes,"UTF-8"); - - // place part header key and value in map - int c=line.indexOf(':',0); - if(c>0) + MultiPartInputStream.MultiPart mp = (MultiPartInputStream.MultiPart)p; + if (mp.getFile() != null) { - String key=line.substring(0,c).trim().toLowerCase(); - String value=line.substring(c+1,line.length()).trim(); - if(key.equals("content-disposition")) - content_disposition=value; - else if(key.equals("content-transfer-encoding")) - content_transfer_encoding=value; - else if (key.equals("content-type")) - type_content = value; - } - } - // Extract content-disposition - boolean form_data=false; - if(content_disposition==null) - { - throw new IOException("Missing content-disposition"); - } - - QuotedStringTokenizer tok=new QuotedStringTokenizer(content_disposition,";"); - String name=null; - String filename=null; - while(tok.hasMoreTokens()) - { - String t=tok.nextToken().trim(); - String tl=t.toLowerCase(); - if(t.startsWith("form-data")) - form_data=true; - else if(tl.startsWith("name=")) - name=value(t); - else if(tl.startsWith("filename=")) - filename=value(t); - } - - // Check disposition - if(!form_data) - { - continue; - } - //It is valid for reset and submit buttons to have an empty name. - //If no name is supplied, the browser skips sending the info for that field. - //However, if you supply the empty string as the name, the browser sends the - //field, with name as the empty string. So, only continue this loop if we - //have not yet seen a name field. - if(name==null) - { - continue; - } - - OutputStream out=null; - File file=null; - try - { - if (filename!=null && filename.length()>0) - { - file = File.createTempFile("MultiPart", "", tempdir); - out = new FileOutputStream(file); - if(_fileOutputBuffer>0) - out = new BufferedOutputStream(out, _fileOutputBuffer); - request.setAttribute(name,file); - params.add(name, filename); - if (type_content != null) - params.add(name+CONTENT_TYPE_SUFFIX, type_content); - + request.setAttribute(mp.getName(),mp.getFile()); + if (mp.getContentDispositionFilename() != null) + params.add(mp.getName(), mp.getContentDispositionFilename()); if (_deleteFiles) { - file.deleteOnExit(); + mp.getFile().deleteOnExit(); + ArrayList files = (ArrayList)request.getAttribute(FILES); if (files==null) { files=new ArrayList(); request.setAttribute(FILES,files); } - files.add(file); - } + files.add(mp.getFile()); + } } else { - out=new ByteArrayOutputStream(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + IO.copy(p.getInputStream(), bytes); + params.add(p.getName(), bytes.toByteArray()); } - - - if ("base64".equalsIgnoreCase(content_transfer_encoding)) - { - in = new Base64InputStream(in); - } - else if ("quoted-printable".equalsIgnoreCase(content_transfer_encoding)) - { - in = new FilterInputStream(in) - { - @Override - public int read() throws IOException - { - int c = in.read(); - if (c >= 0 && c == '=') - { - int hi = in.read(); - int lo = in.read(); - if (hi < 0 || lo < 0) - { - throw new IOException("Unexpected end to quoted-printable byte"); - } - char[] chars = new char[] { (char)hi, (char)lo }; - c = Integer.parseInt(new String(chars),16); - } - return c; - } - }; - } - - int state=-2; - int c; - boolean cr=false; - boolean lf=false; - - // loop for all lines` - while(true) - { - int b=0; - while((c=(state!=-2)?state:in.read())!=-1) - { - state=-2; - // look for CR and/or LF - if(c==13||c==10) - { - if(c==13) - state=in.read(); - break; - } - // look for boundary - if(b>=0&&b0) - out.write(byteBoundary,0,b); - b=-1; - out.write(c); - } - } - // check partial boundary - if((b>0&&b0||c==-1) - { - if(b==byteBoundary.length) - lastPart=true; - if(state==10) - state=-2; - break; - } - // handle CR LF - if(cr) - out.write(13); - if(lf) - out.write(10); - cr=(c==13); - lf=(c==10||state==10); - if(state==10) - state=-2; - } - } - finally - { - out.close(); - } - - if (file==null) - { - bytes = ((ByteArrayOutputStream)out).toByteArray(); - params.add(name,bytes); - if (type_content != null) - params.add(name+CONTENT_TYPE_SUFFIX, type_content); } } - + // handle request chain.doFilter(new Wrapper(srequest,params),response); } @@ -504,37 +329,4 @@ public class MultiPartFilter implements Filter _encoding=enc; } } - - private static class Base64InputStream extends InputStream - { - BufferedReader _in; - String _line; - byte[] _buffer; - int _pos; - - public Base64InputStream (InputStream in) - { - _in = new BufferedReader(new InputStreamReader(in)); - } - - @Override - public int read() throws IOException - { - if (_buffer==null || _pos>= _buffer.length) - { - _line = _in.readLine(); - if (_line==null) - return -1; - if (_line.startsWith("--")) - _buffer=(_line+"\r\n").getBytes(); - else if (_line.length()==0) - _buffer="\r\n".getBytes(); - else - _buffer=B64Code.decode(_line); - - _pos=0; - } - return _buffer[_pos++]; - } - } } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java index 3774a28bf8f..307438accad 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AbstractDoSFilterTest.java @@ -5,7 +5,8 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Socket; - +import java.util.EnumSet; +import javax.servlet.DispatcherType; import javax.servlet.Filter; import javax.servlet.Servlet; import javax.servlet.ServletException; @@ -44,7 +45,7 @@ public abstract class AbstractDoSFilterTest _tester.setContextPath("/ctx"); _tester.addServlet(TestServlet.class, "/*"); - _dosFilter = _tester.addFilter(filter, "/dos/*", 0); + _dosFilter = _tester.addFilter(filter, "/dos/*", EnumSet.allOf(DispatcherType.class)); _dosFilter.setInitParameter("maxRequestsPerSec", "4"); _dosFilter.setInitParameter("delayMs", "200"); _dosFilter.setInitParameter("throttledRequests", "1"); @@ -53,7 +54,7 @@ public abstract class AbstractDoSFilterTest _dosFilter.setInitParameter("remotePort", "false"); _dosFilter.setInitParameter("insertHeaders", "true"); - _timeoutFilter = _tester.addFilter(filter, "/timeout/*", 0); + _timeoutFilter = _tester.addFilter(filter, "/timeout/*", EnumSet.allOf(DispatcherType.class)); _timeoutFilter.setInitParameter("maxRequestsPerSec", "4"); _timeoutFilter.setInitParameter("delayMs", "200"); _timeoutFilter.setInitParameter("throttledRequests", "1"); @@ -190,7 +191,7 @@ public abstract class AbstractDoSFilterTest String request="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\n\r\n"; String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; String responses = doRequests(request+request+request+request,1,0,0,last); - //System.out.println("responses are " + responses); + System.out.println("responses are " + responses); assertEquals("200 OK responses", 5,count(responses,"HTTP/1.1 200 OK")); assertEquals("delayed responses", 1,count(responses,"DoSFilter: delayed")); assertEquals("throttled responses", 1,count(responses,"DoSFilter: throttled")); @@ -226,6 +227,8 @@ public abstract class AbstractDoSFilterTest String last="GET /ctx/dos/test HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n"; String responses = doRequests(request+request+request+request,1,0,0,last); + System.err.println("RESPONSES: \n"+responses); + assertEquals(4,count(responses,"HTTP/1.1 200 OK")); assertEquals(1,count(responses,"HTTP/1.1 503")); assertEquals(1,count(responses,"DoSFilter: delayed")); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java index 252783d68e8..c30133c1ab2 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/AsyncProxyServer.java @@ -13,6 +13,10 @@ package org.eclipse.jetty.servlets; +import java.util.EnumSet; + +import javax.servlet.DispatcherType; + import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.nio.SelectChannelConnector; @@ -32,7 +36,7 @@ public class AsyncProxyServer ServletHandler handler=new ServletHandler(); server.setHandler(handler); - //FilterHolder gzip = handler.addFilterWithMapping("org.eclipse.jetty.servlets.GzipFilter","/*",0); + //FilterHolder gzip = handler.addFilterWithMapping("org.eclipse.jetty.servlet.GzipFilter","/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); //gzip.setAsyncSupported(true); //gzip.setInitParameter("minGzipSize","256"); ServletHolder proxy = handler.addServletWithMapping("org.eclipse.jetty.servlets.ProxyServlet","/"); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java index 3039a4d787a..fa48e85af41 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CloseableDoSFilterTest.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.servlets; + import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java index e59051ffbf0..bd9bfb576b0 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/CrossOriginFilterTest.java @@ -1,8 +1,11 @@ package org.eclipse.jetty.servlets; import java.io.IOException; +import java.util.EnumSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; + +import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -38,7 +41,7 @@ public class CrossOriginFilterTest @Test public void testRequestWithNoOriginArrivesToApplication() throws Exception { - tester.getContext().addFilter(CrossOriginFilter.class, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(CrossOriginFilter.class, "/*", EnumSet.of(DispatcherType.REQUEST)); final CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -58,7 +61,7 @@ public class CrossOriginFilterTest FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); String origin = "http://localhost"; filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -82,7 +85,7 @@ public class CrossOriginFilterTest FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); String origin = "http://localhost"; filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -106,7 +109,7 @@ public class CrossOriginFilterTest String origin = "http://localhost"; String otherOrigin = origin.replace("localhost", "127.0.0.1"); filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_ORIGINS_PARAM, origin + "," + otherOrigin); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -129,7 +132,7 @@ public class CrossOriginFilterTest { FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); filterHolder.setInitParameter(CrossOriginFilter.ALLOW_CREDENTIALS_PARAM, "false"); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -154,7 +157,7 @@ public class CrossOriginFilterTest // will contain the CORS response headers. FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -179,7 +182,7 @@ public class CrossOriginFilterTest // will contain the CORS response headers. FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -201,7 +204,7 @@ public class CrossOriginFilterTest { FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "PUT"); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -240,7 +243,7 @@ public class CrossOriginFilterTest FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,HEAD,POST,PUT,DELETE"); filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_HEADERS_PARAM, "X-Requested-With,Content-Type,Accept,Origin,X-Custom"); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*",EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -281,7 +284,7 @@ public class CrossOriginFilterTest { FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); filterHolder.setInitParameter(CrossOriginFilter.ALLOWED_METHODS_PARAM, "GET,HEAD,POST,PUT,DELETE"); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); @@ -306,7 +309,7 @@ public class CrossOriginFilterTest public void testCrossOriginFilterDisabledForWebSocketUpgrade() throws Exception { FilterHolder filterHolder = new FilterHolder(new CrossOriginFilter()); - tester.getContext().addFilter(filterHolder, "/*", FilterMapping.DEFAULT); + tester.getContext().addFilter(filterHolder, "/*", EnumSet.of(DispatcherType.REQUEST)); CountDownLatch latch = new CountDownLatch(1); tester.getContext().addServlet(new ServletHolder(new ResourceServlet(latch)), "/*"); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java index a68c11f7569..a79ed0e85e7 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/DoSFilterTest.java @@ -35,7 +35,8 @@ public class DoSFilterTest extends AbstractDoSFilterTest { public void closeConnection(HttpServletRequest request, HttpServletResponse response, Thread thread) { - try { + try + { response.getWriter().append("DoSFilter: timeout"); super.closeConnection(request,response,thread); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java index 63b0dd9d262..3ad66eab23f 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java @@ -73,7 +73,7 @@ public class IncludableGzipFilterTest tester.setContextPath("/context"); tester.setResourceBase(testdir.getDir().getCanonicalPath()); tester.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/"); - FilterHolder holder = tester.addFilter(IncludableGzipFilter.class,"/*",0); + FilterHolder holder = tester.addFilter(IncludableGzipFilter.class,"/*",null); holder.setInitParameter("mimeTypes","text/plain"); tester.start(); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java index 0dfd6f17bf8..9e197341e6e 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/MultipartFilterTest.java @@ -20,7 +20,13 @@ import static org.junit.Assert.assertNotNull; import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.io.OutputStream; +import java.net.Socket; +import java.net.URL; +import java.util.EnumSet; +import java.util.Enumeration; +import javax.servlet.DispatcherType; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; @@ -40,21 +46,7 @@ public class MultipartFilterTest private File _dir; private ServletTester tester; - - public static class TestServlet extends DumpServlet - { - - @Override - protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException - { - assertNotNull(req.getParameter("fileup")); - assertNotNull(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX)); - assertEquals(req.getParameter("fileup"+MultiPartFilter.CONTENT_TYPE_SUFFIX), "application/octet-stream"); - - super.doPost(req, resp); - } - - } + @Before public void setUp() throws Exception { @@ -67,8 +59,9 @@ public class MultipartFilterTest tester=new ServletTester(); tester.setContextPath("/context"); tester.setResourceBase(_dir.getCanonicalPath()); - tester.addServlet(TestServlet.class, "/"); - FilterHolder multipartFilter = tester.addFilter(MultiPartFilter.class,"/*",FilterMapping.DEFAULT); + tester.addServlet(DumpServlet.class, "/"); + tester.setAttribute("javax.servlet.context.tempdir", _dir); + FilterHolder multipartFilter = tester.addFilter(MultiPartFilter.class,"/*", EnumSet.of(DispatcherType.REQUEST)); multipartFilter.setInitParameter("deleteFiles", "true"); tester.start(); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java index c92cc007f80..9d59bddc48d 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PutFilterTest.java @@ -21,6 +21,8 @@ import java.io.FileInputStream; import java.io.OutputStream; import java.net.Socket; import java.net.URL; +import java.util.EnumSet; +import javax.servlet.DispatcherType; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -53,7 +55,7 @@ public class PutFilterTest tester.setContextPath("/context"); tester.setResourceBase(_dir.getCanonicalPath()); tester.addServlet(org.eclipse.jetty.servlet.DefaultServlet.class, "/"); - FilterHolder holder = tester.addFilter(PutFilter.class,"/*",0); + FilterHolder holder = tester.addFilter(PutFilter.class,"/*",EnumSet.of(DispatcherType.REQUEST)); holder.setInitParameter("delAllowed","true"); // Bloody Windows does not allow file renaming if (!System.getProperty("os.name").toLowerCase().contains("windows")) diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java index 85141c21852..5ce86b6be34 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/QoSFilterTest.java @@ -17,9 +17,10 @@ import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.URL; +import java.util.EnumSet; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; - +import javax.servlet.DispatcherType; import javax.servlet.Servlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; @@ -93,7 +94,7 @@ public class QoSFilterTest FilterHolder holder = new FilterHolder(QoSFilter2.class); holder.setAsyncSupported(true); holder.setInitParameter(QoSFilter.MAX_REQUESTS_INIT_PARAM, ""+MAX_QOS); - _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",FilterMapping.DEFAULT); + _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); for(int i = 0; i < NUM_CONNECTIONS; ++i ) { @@ -111,8 +112,7 @@ public class QoSFilterTest FilterHolder holder = new FilterHolder(QoSFilter2.class); holder.setAsyncSupported(true); holder.setInitParameter(QoSFilter.MAX_REQUESTS_INIT_PARAM, ""+MAX_QOS); - _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",FilterMapping.DEFAULT); - + _tester.getContext().getServletHandler().addFilterWithMapping(holder,"/*",EnumSet.of(DispatcherType.REQUEST,DispatcherType.ASYNC)); for(int i = 0; i < NUM_CONNECTIONS; ++i ) { new Thread(new Worker2(i)).start(); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java index d0d3e09531a..2ebedf60cdc 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java @@ -15,11 +15,13 @@ import java.io.IOException; import java.io.InputStream; import java.security.DigestOutputStream; import java.security.MessageDigest; +import java.util.EnumSet; import java.util.Enumeration; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; +import javax.servlet.DispatcherType; import javax.servlet.Servlet; import javax.servlet.http.HttpServletResponse; @@ -348,7 +350,7 @@ public class GzipTester servletTester.setResourceBase(testdir.getDir().getCanonicalPath()); ServletHolder servletHolder = servletTester.addServlet(servletClass,"/"); servletHolder.setInitParameter("baseDir",testdir.getDir().getAbsolutePath()); - FilterHolder holder = servletTester.addFilter(GzipFilter.class,"/*",0); + FilterHolder holder = servletTester.addFilter(GzipFilter.class,"/*",EnumSet.allOf(DispatcherType.class)); return holder; } diff --git a/jetty-start/pom.xml b/jetty-start/pom.xml index 9fcfa2c2cc8..1da4b7e8138 100644 --- a/jetty-start/pom.xml +++ b/jetty-start/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-start diff --git a/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config b/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config index c75ffd022c3..ca2d0ae5eac 100644 --- a/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config +++ b/jetty-start/src/main/resources/org/eclipse/jetty/start/start.config @@ -92,7 +92,7 @@ $(jetty.home)/lib/jetty-io-$(version).jar $(jetty.home)/lib/jetty-xml-$(version).jar ! available org.eclipse.jetty.xml.XmlParser [Server,All,server,default] -$(jetty.home)/lib/servlet-api-2.5.jar ! available javax.servlet.ServletContext +$(jetty.home)/lib/servlet-api-3.0.jar ! available javax.servlet.ServletContext $(jetty.home)/lib/jetty-http-$(version).jar ! available org.eclipse.jetty.http.HttpParser $(jetty.home)/lib/jetty-continuation-$(version).jar ! available org.eclipse.jetty.continuation.Continuation $(jetty.home)/lib/jetty-server-$(version).jar ! available org.eclipse.jetty.server.Server @@ -101,7 +101,7 @@ $(jetty.home)/lib/jetty-server-$(version).jar $(jetty.home)/lib/jetty-security-$(version).jar ! available org.eclipse.jetty.security.LoginService [Server,All,servlet,default] -$(jetty.home)/lib/servlet-api-2.5.jar ! available javax.servlet.ServletContext +$(jetty.home)/lib/servlet-api-3.0.jar ! available javax.servlet.ServletContext $(jetty.home)/lib/jetty-servlet-$(version).jar ! available org.eclipse.jetty.servlet.ServletHandler [Server,All,webapp,default] @@ -141,6 +141,9 @@ $(jetty.home)/lib/jetty-policy-$(version).jar [All,Client,client] $(jetty.home)/lib/jetty-http-$(version).jar ! available org.eclipse.jetty.http.HttpParser $(jetty.home)/lib/jetty-client-$(version).jar ! available org.eclipse.jetty.client.HttpClient + +[All,websocket] +$(jetty.home)/lib/jetty-websocket-$(version).jar ! available org.eclipse.jetty.websocket.WebSocket [Client] $(jetty.home)/lib/jetty-http-$(version).jar ! available org.eclipse.jetty.http.HttpParser diff --git a/jetty-util/pom.xml b/jetty-util/pom.xml index 9e5dc45445a..fbd408a9b86 100644 --- a/jetty-util/pom.xml +++ b/jetty-util/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-util @@ -74,6 +74,16 @@ jetty-test-helper test + + junit + junit + test + + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + provided + org.slf4j slf4j-api diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java index 61f9eeaec91..d5b5b50fc23 100644 --- a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiMap.java @@ -81,7 +81,7 @@ public class MultiMap implements ConcurrentMap, Serializable * @param name The entry key. * @return Unmodifieable List of values. */ - public List getValues(Object name) + public List getValues(Object name) { return LazyList.getList(_map.get(name),true); } diff --git a/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java new file mode 100644 index 00000000000..a8b87de377b --- /dev/null +++ b/jetty-util/src/main/java/org/eclipse/jetty/util/MultiPartInputStream.java @@ -0,0 +1,628 @@ +// ======================================================================== +// Copyright (c) 2006-2010 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.util; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.ServletException; +import javax.servlet.http.Part; + + + +/** + * MultiPartInputStream + * + * Handle a MultiPart Mime input stream, breaking it up on the boundary into files and strings. + */ +public class MultiPartInputStream +{ + public static final MultipartConfigElement __DEFAULT_MULTIPART_CONFIG = new MultipartConfigElement(System.getProperty("java.io.tmpdir")); + protected InputStream _in; + protected MultipartConfigElement _config; + protected String _contentType; + protected MultiMap _parts; + protected File _tmpDir; + protected File _contextTmpDir; + + + + + public class MultiPart implements Part + { + protected String _name; + protected String _filename; + protected File _file; + protected OutputStream _out; + protected String _contentType; + protected MultiMap _headers; + protected long _size = 0; + + public MultiPart (String name, String filename) + throws IOException + { + _name = name; + _filename = filename; + } + + protected void setContentType (String contentType) + { + _contentType = contentType; + } + + + protected void open() + throws FileNotFoundException, IOException + { + //We will either be writing to a file, if it has a filename on the content-disposition + //and otherwise a byte-array-input-stream, OR if we exceed the getFileSizeThreshold, we + //will need to change to write to a file. + if (_filename != null && _filename.trim().length() > 0) + { + createFile(); + } + else + { + //Write to a buffer in memory until we discover we've exceed the + //MultipartConfig fileSizeThreshold + _out = new ByteArrayOutputStream(); + } + } + + protected void close() + throws IOException + { + _out.close(); + } + + + protected void write (int b) + throws IOException, ServletException + { + if (MultiPartInputStream.this._config.getMaxFileSize() > 0 && _size + 1 > MultiPartInputStream.this._config.getMaxFileSize()) + throw new ServletException ("Multipart Mime part "+_name+" exceeds max filesize"); + + if (MultiPartInputStream.this._config.getFileSizeThreshold() > 0 && _size + 1 > MultiPartInputStream.this._config.getFileSizeThreshold() && _file==null) + createFile(); + _out.write(b); + _size ++; + } + + protected void write (byte[] bytes, int offset, int length) + throws IOException, ServletException + { + if (MultiPartInputStream.this._config.getMaxFileSize() > 0 && _size + length > MultiPartInputStream.this._config.getMaxFileSize()) + throw new ServletException ("Multipart Mime part "+_name+" exceeds max filesize"); + + if (MultiPartInputStream.this._config.getFileSizeThreshold() > 0 && _size + length > MultiPartInputStream.this._config.getFileSizeThreshold() && _file==null) + createFile(); + + _out.write(bytes, offset, length); + _size += length; + } + + protected void createFile () + throws IOException + { + _file = File.createTempFile("MultiPart", "", MultiPartInputStream.this._tmpDir); + FileOutputStream fos = new FileOutputStream(_file); + BufferedOutputStream bos = new BufferedOutputStream(fos); + + if (_size > 0 && _out != null) + { + //already written some bytes, so need to copy them into the file + _out.flush(); + ((ByteArrayOutputStream)_out).writeTo(bos); + _out.close(); + } + _out = bos; + } + + + + protected void setHeaders(MultiMap headers) + { + _headers = headers; + } + + /** + * @see javax.servlet.http.Part#getContentType() + */ + public String getContentType() + { + return _contentType; + } + + /** + * @see javax.servlet.http.Part#getHeader(java.lang.String) + */ + public String getHeader(String name) + { + return (String)_headers.getValue(name, 0); + } + + /** + * @see javax.servlet.http.Part#getHeaderNames() + */ + public Collection getHeaderNames() + { + return _headers.keySet(); + } + + /** + * @see javax.servlet.http.Part#getHeaders(java.lang.String) + */ + public Collection getHeaders(String name) + { + return _headers.getValues(name); + } + + /** + * @see javax.servlet.http.Part#getInputStream() + */ + public InputStream getInputStream() throws IOException + { + if (_file != null) + { + return new BufferedInputStream (new FileInputStream(_file)); + } + else + { + //part content is in a ByteArrayOutputStream + return new ByteArrayInputStream(((ByteArrayOutputStream)_out).toByteArray()); + } + } + + /** + * @see javax.servlet.http.Part#getName() + */ + public String getName() + { + return _name; + } + + /** + * @see javax.servlet.http.Part#getSize() + */ + public long getSize() + { + return _size; + } + + /** + * @see javax.servlet.http.Part#write(java.lang.String) + */ + public void write(String fileName) throws IOException + { + if (_file == null) + { + //part data is only in the ByteArrayOutputStream and never been written to disk + _file = new File (_tmpDir, fileName); + BufferedOutputStream bos = null; + try + { + bos = new BufferedOutputStream(new FileOutputStream(_file)); + ((ByteArrayOutputStream)_out).writeTo(bos); + bos.flush(); + } + finally + { + if (bos != null) + bos.close(); + } + } + else + { + //the part data is already written to a temporary file, just rename it + _file.renameTo(new File(_tmpDir, fileName)); + } + } + + /** + * @see javax.servlet.http.Part#delete() + */ + public void delete() throws IOException + { + if (_file != null) + _file.delete(); + } + + + /** + * Get the file, if any, the data has been written to. + * @return + */ + public File getFile () + { + return _file; + } + + + /** + * Get the filename from the content-disposition. + * @return null or the filename + */ + public String getContentDispositionFilename () + { + return _filename; + } + } + + + + + /** + * @param in Request input stream + * @param contentType Content-Type header + * @param config MultipartConfigElement + * @param contextTmpDir javax.servlet.context.tempdir + */ + public MultiPartInputStream (InputStream in, String contentType, MultipartConfigElement config, File contextTmpDir) + { + _in = new BufferedInputStream(in); + _contentType = contentType; + _config = config; + _contextTmpDir = contextTmpDir; + if (_contextTmpDir == null) + _contextTmpDir = new File (System.getProperty("java.io.tmpdir")); + if (_config == null) + _config = new MultipartConfigElement(_contextTmpDir.getAbsolutePath()); + } + + + + public Collection getParts() + throws IOException, ServletException + { + parse(); + Collection values = _parts.values(); + List parts = new ArrayList(); + for (Object o: values) + { + List asList = LazyList.getList(o, false); + parts.addAll(asList); + } + return parts; + } + + + public Part getPart(String name) + throws IOException, ServletException + { + parse(); + return (Part)_parts.getValue(name, 0); + } + + + protected void parse () + throws IOException, ServletException + { + //have we already parsed the input? + if (_parts != null) + return; + + //initialize + long total = 0; //keep running total of size of bytes read from input and throw an exception if exceeds MultipartConfigElement._maxRequestSize + _parts = new MultiMap(); + + //if its not a multipart request, don't parse it + if (_contentType == null || !_contentType.startsWith("multipart/form-data")) + return; + + //sort out the location to which to write the files + + if (_config.getLocation() == null) + _tmpDir = _contextTmpDir; + else if ("".equals(_config.getLocation())) + _tmpDir = _contextTmpDir; + else + { + File f = new File (_config.getLocation()); + if (f.isAbsolute()) + _tmpDir = f; + else + _tmpDir = new File (_contextTmpDir, _config.getLocation()); + } + + if (!_tmpDir.exists()) + _tmpDir.mkdirs(); + + String boundary="--"+QuotedStringTokenizer.unquote(value(_contentType.substring(_contentType.indexOf("boundary="))).trim()); + byte[] byteBoundary=(boundary+"--").getBytes(StringUtil.__ISO_8859_1); + + // Get first boundary + byte[] bytes=TypeUtil.readLine(_in); + String line=bytes==null?null:new String(bytes,"UTF-8"); + if(line==null || !line.equals(boundary)) + { + throw new IOException("Missing initial multi part boundary"); + } + + // Read each part + boolean lastPart=false; + String contentDisposition=null; + String contentType=null; + String contentTransferEncoding=null; + outer:while(!lastPart) + { + MultiMap headers = new MultiMap(); + while(true) + { + bytes=TypeUtil.readLine(_in); + if(bytes==null) + break outer; + + // If blank line, end of part headers + if(bytes.length==0) + break; + + total += bytes.length; + if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) + throw new ServletException ("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); + + line=new String(bytes,"UTF-8"); + + //get content-disposition and content-type + int c=line.indexOf(':',0); + if(c>0) + { + String key=line.substring(0,c).trim().toLowerCase(); + String value=line.substring(c+1,line.length()).trim(); + headers.put(key, value); + if (key.equalsIgnoreCase("content-disposition")) + contentDisposition=value; + if (key.equalsIgnoreCase("content-type")) + contentType = value; + if(key.equals("content-transfer-encoding")) + contentTransferEncoding=value; + + } + } + + // Extract content-disposition + boolean form_data=false; + if(contentDisposition==null) + { + throw new IOException("Missing content-disposition"); + } + + QuotedStringTokenizer tok=new QuotedStringTokenizer(contentDisposition,";"); + String name=null; + String filename=null; + while(tok.hasMoreTokens()) + { + String t=tok.nextToken().trim(); + String tl=t.toLowerCase(); + if(t.startsWith("form-data")) + form_data=true; + else if(tl.startsWith("name=")) + name=value(t); + else if(tl.startsWith("filename=")) + filename=value(t); + } + + // Check disposition + if(!form_data) + { + continue; + } + //It is valid for reset and submit buttons to have an empty name. + //If no name is supplied, the browser skips sending the info for that field. + //However, if you supply the empty string as the name, the browser sends the + //field, with name as the empty string. So, only continue this loop if we + //have not yet seen a name field. + if(name==null) + { + continue; + } + + if ("base64".equalsIgnoreCase(contentTransferEncoding)) + { + _in = new Base64InputStream(_in); + } + else if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) + { + _in = new FilterInputStream(_in) + { + @Override + public int read() throws IOException + { + int c = in.read(); + if (c >= 0 && c == '=') + { + int hi = in.read(); + int lo = in.read(); + if (hi < 0 || lo < 0) + { + throw new IOException("Unexpected end to quoted-printable byte"); + } + char[] chars = new char[] { (char)hi, (char)lo }; + c = Integer.parseInt(new String(chars),16); + } + return c; + } + }; + } + + + + //Have a new Part + MultiPart part = new MultiPart(name, filename); + part.setHeaders(headers); + part.setContentType(contentType); + _parts.add(name, part); + + part.open(); + + try + { + int state=-2; + int c; + boolean cr=false; + boolean lf=false; + + // loop for all lines` + while(true) + { + int b=0; + while((c=(state!=-2)?state:_in.read())!=-1) + { + total ++; + if (_config.getMaxRequestSize() > 0 && total > _config.getMaxRequestSize()) + throw new ServletException("Request exceeds maxRequestSize ("+_config.getMaxRequestSize()+")"); + + state=-2; + // look for CR and/or LF + if(c==13||c==10) + { + if(c==13) + state=_in.read(); + break; + } + // look for boundary + if(b>=0&&b0) + part.write(byteBoundary,0,b); + + b=-1; + part.write(c); + } + } + // check partial boundary + if((b>0&&b0||c==-1) + { + if(b==byteBoundary.length) + lastPart=true; + if(state==10) + state=-2; + break; + } + // handle CR LF + if(cr) + part.write(13); + + if(lf) + part.write(10); + + cr=(c==13); + lf=(c==10||state==10); + if(state==10) + state=-2; + } + } + finally + { + + part.close(); + } + } + } + + + /* ------------------------------------------------------------ */ + private String value(String nameEqualsValue) + { + String value=nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim(); + int i=value.indexOf(';'); + if(i>0) + value=value.substring(0,i); + if(value.startsWith("\"")) + { + value=value.substring(1,value.indexOf('"',1)); + } + else + { + i=value.indexOf(' '); + if(i>0) + value=value.substring(0,i); + } + return value; + } + + private static class Base64InputStream extends InputStream + { + BufferedReader _in; + String _line; + byte[] _buffer; + int _pos; + + public Base64InputStream (InputStream in) + { + _in = new BufferedReader(new InputStreamReader(in)); + } + + @Override + public int read() throws IOException + { + if (_buffer==null || _pos>= _buffer.length) + { + _line = _in.readLine(); + if (_line==null) + return -1; + if (_line.startsWith("--")) + _buffer=(_line+"\r\n").getBytes(); + else if (_line.length()==0) + _buffer="\r\n".getBytes(); + else + _buffer=B64Code.decode(_line); + + _pos=0; + } + return _buffer[_pos++]; + } + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java new file mode 100644 index 00000000000..c66a14eac11 --- /dev/null +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/MultiPartInputStreamTest.java @@ -0,0 +1,187 @@ +// ======================================================================== +// Copyright (c) 2006-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.util.Collection; + +import javax.servlet.MultipartConfigElement; +import javax.servlet.ServletException; +import javax.servlet.http.Part; + +import junit.framework.TestCase; + +/** + * MultiPartInputStreamTest + * + * + */ +public class MultiPartInputStreamTest extends TestCase +{ + protected String _contentType = "multipart/form-data, boundary=AaB03x"; + protected String _multi = + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"field1\"\r\n"+ + "\r\n"+ + "Joe Blow\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"stuff.txt\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "000000000000000000000000000000000000000000000000000\r\n"+ + "--AaB03x--\r\n"; + + protected String _dirname = System.getProperty("java.io.tmpdir")+File.separator+"myfiles-"+System.currentTimeMillis(); + + + public void testNonMultiPartRequest() + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), + "Content-type: text/plain", + config, + new File(_dirname)); + assertTrue(mpis.getParts().isEmpty()); + } + + public void testNoLimits() + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + new File(_dirname)); + Collection parts = mpis.getParts(); + assertFalse(parts.isEmpty()); + } + + public void testRequestTooBig () + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 60, 100, 50); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + new File(_dirname)); + + try + { + mpis.getParts(); + fail("Request should have exceeded maxRequestSize"); + } + catch (ServletException e) + { + assertTrue(e.getMessage().startsWith("Request exceeds maxRequestSize")); + } + } + + public void testFileTooBig() + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 40, 1024, 30); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + new File(_dirname)); + + try + { + mpis.getParts(); + fail("stuff.txt should have been larger than maxFileSize"); + } + catch (ServletException e) + { + assertTrue(e.getMessage().startsWith("Multipart Mime part")); + } + } + + + public void testMulti () + throws Exception + { + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(_multi.getBytes()), + _contentType, + config, + new File(_dirname)); + + Collection parts = mpis.getParts(); + assertEquals(2, parts.size()); + Part field1 = mpis.getPart("field1"); + assertNotNull(field1); + assertEquals("field1", field1.getName()); + InputStream is = field1.getInputStream(); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + IO.copy(is, os); + assertEquals("Joe Blow", new String(os.toByteArray())); + assertEquals(8, field1.getSize()); + field1.write("field1.txt"); + File f = new File (_dirname+File.separator+"field1.txt"); + assertTrue(f.exists()); + field1.delete(); + assertFalse(f.exists()); + + Part stuff = mpis.getPart("stuff"); + assertEquals("text/plain", stuff.getContentType()); + assertEquals("text/plain", stuff.getHeader("content-type")); + assertEquals(1, stuff.getHeaders("content-type").size()); + assertEquals("form-data; name=\"stuff\"; filename=\"stuff.txt\"", stuff.getHeader("content-disposition")); + assertEquals(2, stuff.getHeaderNames().size()); + assertEquals(51, stuff.getSize()); + f = ((MultiPartInputStream.MultiPart)stuff).getFile(); + assertNotNull(f); // longer than 100 bytes, should already be a file + assertTrue(f.exists()); + assertNotSame("stuff.txt", f.getName()); + stuff.write("stuff.txt"); + f = new File(_dirname+File.separator+"stuff.txt"); + assertTrue(f.exists()); + } + + public void testMultiSameNames () + throws Exception + { + String sameNames = "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"stuff1.txt\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "00000\r\n"+ + "--AaB03x\r\n"+ + "content-disposition: form-data; name=\"stuff\"; filename=\"stuff2.txt\"\r\n"+ + "Content-Type: text/plain\r\n"+ + "\r\n"+ + "000000000000000000000000000000000000000000000000000\r\n"+ + "--AaB03x--\r\n"; + + MultipartConfigElement config = new MultipartConfigElement(_dirname, 1024, 3072, 50); + MultiPartInputStream mpis = new MultiPartInputStream(new ByteArrayInputStream(sameNames.getBytes()), + _contentType, + config, + new File(_dirname)); + + Collection parts = mpis.getParts(); + assertEquals(2, parts.size()); + for (Part p:parts) + assertEquals("stuff", p.getName()); + + //if they all have the name name, then only retrieve the first one + Part p = mpis.getPart("stuff"); + assertNotNull(p); + assertEquals(5, p.getSize()); + } +} diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java index aa5c14815a2..355c3b12d6c 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java @@ -105,21 +105,21 @@ public class ResourceTest /* ------------------------------------------------------------ */ @BeforeClass public static void setUp() - throws Exception + throws Exception { if (data!=null) return; - + File file = new File(__userDir); file=new File(file.getCanonicalPath()); URI uri = file.toURI(); __userURL=uri.toURL(); - + __userURL = new URL(__userURL.toString() + "src/test/java/org/eclipse/jetty/util/resource/"); - FilePermission perm = (FilePermission) __userURL.openConnection().getPermission(); - __userDir = new File(perm.getName()).getCanonicalPath() + File.separatorChar; - __relDir = "src/test/java/org/eclipse/jetty/util/resource/".replace('/', File.separatorChar); - + FilePermission perm = (FilePermission) __userURL.openConnection().getPermission(); + __userDir = new File(perm.getName()).getCanonicalPath() + File.separatorChar; + __relDir = "src/test/java/org/eclipse/jetty/util/resource/".replace('/', File.separatorChar); + System.err.println("User Dir="+__userDir); System.err.println("Rel Dir="+__relDir); System.err.println("User URL="+__userURL); diff --git a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java index ab7883818fc..e38b56d5209 100644 --- a/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java +++ b/jetty-util/src/test/java/org/eclipse/jetty/util/thread/TimeoutTest.java @@ -24,6 +24,8 @@ import org.junit.Test; public class TimeoutTest { + private boolean _stress=Boolean.getBoolean("STRESS"); + Object lock = new Object(); Timeout timeout = new Timeout(null); Timeout.Task[] tasks; @@ -131,6 +133,9 @@ public class TimeoutTest @Test public void testStress() throws Exception { + if ( !_stress ) + return; + final int LOOP=250; final AtomicBoolean running=new AtomicBoolean(true); final AtomicIntegerArray count = new AtomicIntegerArray( 4 ); diff --git a/jetty-webapp/pom.xml b/jetty-webapp/pom.xml index eb1971c5043..cf6109dfedf 100644 --- a/jetty-webapp/pom.xml +++ b/jetty-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-webapp diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java index 57df7945011..7fcd495c2b7 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/JettyWebXmlConfiguration.java @@ -13,6 +13,7 @@ package org.eclipse.jetty.webapp; +import java.util.HashMap; import java.util.Map; import org.eclipse.jetty.util.log.Log; @@ -25,7 +26,7 @@ import org.eclipse.jetty.xml.XmlConfiguration; * * JettyWebConfiguration. * - * Looks for Xmlconfiguration files in WEB-INF. Searches in order for the first of jettyX-web.xml, jetty-web.xml or web-jetty.xml + * Looks for Xmlconfiguration files in WEB-INF. Searches in order for the first of jetty6-web.xml, jetty-web.xml or web-jetty.xml * * * @@ -65,7 +66,7 @@ public class JettyWebXmlConfiguration extends AbstractConfiguration if(web_inf!=null&&web_inf.isDirectory()) { // do jetty.xml file - Resource jetty=web_inf.addPath("jetty7-web.xml"); + Resource jetty=web_inf.addPath("jetty8-web.xml"); if(!jetty.exists()) jetty=web_inf.addPath(JETTY_WEB_XML); if(!jetty.exists()) @@ -128,6 +129,13 @@ public class JettyWebXmlConfiguration extends AbstractConfiguration private void setupXmlConfiguration(XmlConfiguration jetty_config, Resource web_inf) { Map props = jetty_config.getProperties(); + if (props == null) + { + props = new HashMap(); + jetty_config.setProperties(props); + } + + // TODO - should this be an id rather than a property? props.put(PROPERTY_THIS_WEB_INF_URL, String.valueOf(web_inf.getURL())); } } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java index e06733d54e0..8635ce82e7b 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaData.java @@ -19,6 +19,8 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.servlet.ServletContext; + import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.resource.Resource; @@ -163,6 +165,8 @@ public class MetaData _webXmlRoot.parse(); _metaDataComplete=_webXmlRoot.getMetaDataComplete() == MetaDataComplete.True; + + if (_webXmlRoot.isOrdered()) { if (_ordering == null) @@ -312,7 +316,14 @@ public class MetaData int j = fullname.lastIndexOf("/", i); orderedLibs.add(fullname.substring(j+1,i+4)); } - context.setAttribute(ORDERED_LIBS, orderedLibs); + context.setAttribute(ServletContext.ORDERED_LIBS, orderedLibs); + } + + // set the webxml version + if (_webXmlRoot != null) + { + context.getServletContext().setEffectiveMajorVersion(_webXmlRoot.getMajorVersion()); + context.getServletContext().setEffectiveMinorVersion(_webXmlRoot.getMinorVersion()); } for (DescriptorProcessor p:_descriptorProcessors) diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java index fac15a444a1..3295ad55b14 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/MetaInfConfiguration.java @@ -78,6 +78,17 @@ public class MetaInfConfiguration extends AbstractConfiguration scanner.scan(null, uris, true); } } + @Override + public void configure(WebAppContext context) throws Exception + { + + } + + @Override + public void deconfigure(WebAppContext context) throws Exception + { + + } @Override public void postConfigure(WebAppContext context) throws Exception diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java index 2f07404f2ba..b0566a5fd68 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/Ordering.java @@ -56,6 +56,7 @@ public interface Ordering * Order the list of jars in WEB-INF/lib according to the ordering declarations in the descriptors * @see org.eclipse.jetty.webapp.Ordering#order(java.util.List) */ + @Override public List order(List jars) { List orderedList = new ArrayList(); @@ -93,7 +94,7 @@ public interface Ordering return orderedList; } - + @Override public boolean isAbsolute() { return true; @@ -113,7 +114,7 @@ public interface Ordering _order.add(OTHER); } - + @Override public boolean hasOther () { return _hasOther; @@ -140,7 +141,7 @@ public interface Ordering * in the various web-fragment.xml files. * @see org.eclipse.jetty.webapp.Ordering#order(java.util.List) */ - + @Override public List order(List jars) { //for each jar, put it into the ordering according to the fragment ordering @@ -210,13 +211,13 @@ public interface Ordering return orderedList; } - + @Override public boolean isAbsolute () { return false; } - + @Override public boolean hasOther () { return !_beforeOthers.isEmpty() || !_afterOthers.isEmpty(); diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java index db5ec955afa..745137cfb43 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/StandardDescriptorProcessor.java @@ -20,19 +20,25 @@ import java.net.URLClassLoader; import java.util.ArrayList; import java.util.EnumSet; import java.util.EventListener; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; +import javax.servlet.DispatcherType; +import javax.servlet.MultipartConfigElement; import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.SessionTrackingMode; import org.eclipse.jetty.security.ConstraintAware; import org.eclipse.jetty.security.ConstraintMapping; import org.eclipse.jetty.security.authentication.FormAuthenticator; -import org.eclipse.jetty.server.DispatcherType; import org.eclipse.jetty.servlet.ErrorPageErrorHandler; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.FilterMapping; +import org.eclipse.jetty.servlet.Holder; import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletMapping; @@ -188,7 +194,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor */ if (holder == null) { - holder = context.getServletHandler().newServletHolder(); + holder = context.getServletHandler().newServletHolder(Holder.Source.DESCRIPTOR); holder.setName(servlet_name); context.getServletHandler().addServlet(holder); } @@ -467,6 +473,136 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor } } } + + String async=node.getString("async-supported",false,true); + if (async!=null) + { + boolean val = async.length()==0||Boolean.valueOf(async); + Origin o =context.getMetaData().getOrigin(servlet_name+".servlet.async-supported"); + switch (o) + { + case NotSet: + { + //set it + holder.setAsyncSupported(val); + context.getMetaData().setOrigin(servlet_name+".servlet.async-supported", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //async-supported set by previous web xml descriptor, only allow override if we're parsing another web descriptor(web.xml/web-override.xml/web-default.xml) + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.setAsyncSupported(val); + context.getMetaData().setOrigin(servlet_name+".servlet.async-supported", descriptor); + } + break; + } + case WebFragment: + { + //async-supported set by another fragment, this fragment's value must match + if (holder.isAsyncSupported() != val) + throw new IllegalStateException("Conflicting async-supported="+async+" for servlet "+servlet_name+" in "+descriptor.getResource()); + break; + } + } + } + + String enabled = node.getString("enabled", false, true); + if (enabled!=null) + { + boolean is_enabled = enabled.length()==0||Boolean.valueOf(enabled); + Origin o = context.getMetaData().getOrigin(servlet_name+".servlet.enabled"); + switch (o) + { + case NotSet: + { + //hasn't been set yet, so set it + holder.setEnabled(is_enabled); + context.getMetaData().setOrigin(servlet_name+".servlet.enabled", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //was set in a web xml descriptor, only allow override from another web xml descriptor + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.setEnabled(is_enabled); + context.getMetaData().setOrigin(servlet_name+".servlet.enabled", descriptor); + } + break; + } + case WebFragment: + { + //was set by another fragment, this fragment's value must match + if (holder.isEnabled() != is_enabled) + throw new IllegalStateException("Conflicting value of servlet enabled for servlet "+servlet_name+" in "+descriptor.getResource()); + break; + } + } + } + + /* + * If multipart config not set, then set it and record it was by the web.xml or fragment. + * If it was set by web.xml then if this is a fragment, ignore the settings. + * If it was set by a fragment, if this is a fragment and the values are different, error! + */ + XmlParser.Node multipart = node.get("multipart-config"); + if (multipart != null) + { + String location = multipart.getString("location", false, true); + String maxFile = multipart.getString("max-file-size", false, true); + String maxRequest = multipart.getString("max-request-size", false, true); + String threshold = multipart.getString("file-size-threshold",false,true); + MultipartConfigElement element = new MultipartConfigElement(location, + (maxFile==null||"".equals(maxFile)?-1L:Long.parseLong(maxFile)), + (maxRequest==null||"".equals(maxRequest)?-1L:Long.parseLong(maxRequest)), + (threshold==null||"".equals(threshold)?0:Integer.parseInt(threshold))); + + Origin o = context.getMetaData().getOrigin(servlet_name+".servlet.multipart-config"); + switch (o) + { + case NotSet: + { + //hasn't been set, so set it + holder.getRegistration().setMultipartConfig(element); + context.getMetaData().setOrigin(servlet_name+".servlet.multipart-config", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + //was set in a web xml, only allow changes if we're parsing another web xml (web.xml/web-default.xml/web-override.xml) + if (!(descriptor instanceof FragmentDescriptor)) + { + holder.getRegistration().setMultipartConfig(element); + context.getMetaData().setOrigin(servlet_name+".servlet.multipart-config", descriptor); + } + break; + } + case WebFragment: + { + //another fragment set the value, this fragment's values must match exactly or it is an error + MultipartConfigElement cfg = ((ServletHolder.Registration)holder.getRegistration()).getMultipartConfig(); + + if (cfg.getMaxFileSize() != element.getMaxFileSize()) + throw new IllegalStateException("Conflicting multipart-config max-file-size for servlet "+servlet_name+" in "+descriptor.getResource()); + if (cfg.getMaxRequestSize() != element.getMaxRequestSize()) + throw new IllegalStateException("Conflicting multipart-config max-request-size for servlet "+servlet_name+" in "+descriptor.getResource()); + if (cfg.getFileSizeThreshold() != element.getFileSizeThreshold()) + throw new IllegalStateException("Conflicting multipart-config file-size-threshold for servlet "+servlet_name+" in "+descriptor.getResource()); + if ((cfg.getLocation() != null && (element.getLocation() == null || element.getLocation().length()==0)) + || (cfg.getLocation() == null && (element.getLocation()!=null || element.getLocation().length() > 0))) + throw new IllegalStateException("Conflicting multipart-config location for servlet "+servlet_name+" in "+descriptor.getResource()); + break; + } + } + } } @@ -531,6 +667,282 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor int timeout = Integer.parseInt(tNode.toString(false, true)); context.getSessionHandler().getSessionManager().setMaxInactiveInterval(timeout * 60); } + + //Servlet Spec 3.0 + // + // this is additive across web-fragments + Iterator iter = node.iterator("tracking-mode"); + Set modes = new HashSet(); + modes.addAll(context.getSessionHandler().getSessionManager().getEffectiveSessionTrackingModes()); + while (iter.hasNext()) + { + XmlParser.Node mNode = (XmlParser.Node) iter.next(); + String trackMode = mNode.toString(false, true); + modes.add(SessionTrackingMode.valueOf(trackMode)); + } + context.getSessionHandler().getSessionManager().setSessionTrackingModes(modes); + + + //Servlet Spec 3.0 + // + XmlParser.Node cookieConfig = node.get("cookie-config"); + if (cookieConfig != null) + { + // + String name = cookieConfig.getString("name", false, true); + if (name != null) + { + Origin o = context.getMetaData().getOrigin("cookie-config.name"); + switch (o) + { + case NotSet: + { + //no set yet, accept it + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setName(name); + context.getMetaData().setOrigin("cookie-config.name", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + // set in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setName(name); + context.getMetaData().setOrigin("cookie-config.name", descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getName().equals(name)) + throw new IllegalStateException("Conflicting cookie-config name "+name+" in "+descriptor.getResource()); + break; + } + } + } + + // + String domain = cookieConfig.getString("domain", false, true); + if (domain != null) + { + Origin o = context.getMetaData().getOrigin("cookie-config.domain"); + switch (o) + { + case NotSet: + { + //no set yet, accept it + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setDomain(domain); + context.getMetaData().setOrigin("cookie-config.domain", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + // set in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setDomain(domain); + context.getMetaData().setOrigin("cookie-config.domain", descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getDomain().equals(domain)) + throw new IllegalStateException("Conflicting cookie-config domain "+domain+" in "+descriptor.getResource()); + break; + } + } + } + + // + String path = cookieConfig.getString("path", false, true); + if (path != null) + { + Origin o = context.getMetaData().getOrigin("cookie-config.path"); + switch (o) + { + case NotSet: + { + //no set yet, accept it + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setPath(path); + context.getMetaData().setOrigin("cookie-config.path", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + // set in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setPath(path); + context.getMetaData().setOrigin("cookie-config.path", descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getPath().equals(path)) + throw new IllegalStateException("Conflicting cookie-config path "+path+" in "+descriptor.getResource()); + break; + } + } + } + + // + String comment = cookieConfig.getString("comment", false, true); + if (comment != null) + { + Origin o = context.getMetaData().getOrigin("cookie-config.comment"); + switch (o) + { + case NotSet: + { + //no set yet, accept it + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setComment(comment); + context.getMetaData().setOrigin("cookie-config.comment", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + // set in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setComment(comment); + context.getMetaData().setOrigin("cookie-config.comment", descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (!context.getSessionHandler().getSessionManager().getSessionCookieConfig().getComment().equals(comment)) + throw new IllegalStateException("Conflicting cookie-config comment "+comment+" in "+descriptor.getResource()); + break; + } + } + } + + // true/false + tNode = cookieConfig.get("http-only"); + if (tNode != null) + { + boolean httpOnly = Boolean.parseBoolean(tNode.toString(false,true)); + Origin o = context.getMetaData().getOrigin("cookie-config.http-only"); + switch (o) + { + case NotSet: + { + //no set yet, accept it + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setHttpOnly(httpOnly); + context.getMetaData().setOrigin("cookie-config.http-only", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + // set in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setHttpOnly(httpOnly); + context.getMetaData().setOrigin("cookie-config.http-only", descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (context.getSessionHandler().getSessionManager().getSessionCookieConfig().isHttpOnly() != httpOnly) + throw new IllegalStateException("Conflicting cookie-config http-only "+httpOnly+" in "+descriptor.getResource()); + break; + } + } + } + + // true/false + tNode = cookieConfig.get("secure"); + if (tNode != null) + { + boolean secure = Boolean.parseBoolean(tNode.toString(false,true)); + Origin o = context.getMetaData().getOrigin("cookie-config.secure"); + switch (o) + { + case NotSet: + { + //no set yet, accept it + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setSecure(secure); + context.getMetaData().setOrigin("cookie-config.secure", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + // set in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setSecure(secure); + context.getMetaData().setOrigin("cookie-config.secure", descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (context.getSessionHandler().getSessionManager().getSessionCookieConfig().isSecure() != secure) + throw new IllegalStateException("Conflicting cookie-config secure "+secure+" in "+descriptor.getResource()); + break; + } + } + } + + // + tNode = cookieConfig.get("max-age"); + if (tNode != null) + { + int maxAge = Integer.parseInt(tNode.toString(false,true)); + Origin o = context.getMetaData().getOrigin("cookie-config.max-age"); + switch (o) + { + case NotSet: + { + //no set yet, accept it + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setMaxAge(maxAge); + context.getMetaData().setOrigin("cookie-config.max-age", descriptor); + break; + } + case WebXml: + case WebDefaults: + case WebOverride: + { + // set in a web xml, only allow web-default/web-override to change + if (!(descriptor instanceof FragmentDescriptor)) + { + context.getSessionHandler().getSessionManager().getSessionCookieConfig().setMaxAge(maxAge); + context.getMetaData().setOrigin("cookie-config.max-age", descriptor); + } + break; + } + case WebFragment: + { + //a web-fragment set the value, all web-fragments must have the same value + if (context.getSessionHandler().getSessionManager().getSessionCookieConfig().getMaxAge() != maxAge) + throw new IllegalStateException("Conflicting cookie-config max-age "+maxAge+" in "+descriptor.getResource()); + break; + } + } + } + } } @@ -671,7 +1083,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { //a value was set by a web-fragment, all fragments must have the same value if (!encoding.equals(context.getLocaleEncoding(locale))) - throw new IllegalStateException("Conflicting locale-encoding mapping for locale "+locale+" in "+descriptor.getResource()); + throw new IllegalStateException("Conflicting loacle-encoding mapping for locale "+locale+" in "+descriptor.getResource()); break; } } @@ -1167,7 +1579,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor FilterHolder holder = context.getServletHandler().getFilter(name); if (holder == null) { - holder = context.getServletHandler().newFilterHolder(); + holder = context.getServletHandler().newFilterHolder(Holder.Source.DESCRIPTOR); holder.setName(name); context.getServletHandler().addFilter(holder); } @@ -1408,7 +1820,7 @@ public class StandardDescriptorProcessor extends IterativeDescriptorProcessor { try { - return ((ServletContextHandler.Context)context.getServletContext()).createListener(clazz); + return context.getServletContext().createListener(clazz); } catch (ServletException se) { diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java index ec4d2b4a649..3aa22e2b8f8 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppClassLoader.java @@ -440,5 +440,4 @@ public class WebAppClassLoader extends URLClassLoader { return "WebAppClassLoader=" + _name+"@"+Long.toHexString(hashCode()); } - } diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java index 60ff124635f..1fc937e1256 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebAppContext.java @@ -82,8 +82,8 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL "org.eclipse.jetty.webapp.WebXmlConfiguration", "org.eclipse.jetty.webapp.MetaInfConfiguration", "org.eclipse.jetty.webapp.FragmentConfiguration", - "org.eclipse.jetty.webapp.JettyWebXmlConfiguration", - "org.eclipse.jetty.webapp.TagLibConfiguration" + "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"//, + //"org.eclipse.jetty.webapp.TagLibConfiguration" } ; // System classes are classes that cannot be replaced by @@ -151,7 +151,6 @@ public class WebAppContext extends ServletContextHandler implements WebAppClassL private boolean _allowDuplicateFragmentNames = false; private boolean _throwUnavailableOnStartupException = false; - private MetaData _metadata=new MetaData(); public static WebAppContext getCurrentWebAppContext() diff --git a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java index 63b2ae18794..699e21aa36d 100644 --- a/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java +++ b/jetty-webapp/src/main/java/org/eclipse/jetty/webapp/WebXmlConfiguration.java @@ -53,6 +53,8 @@ public class WebXmlConfiguration extends AbstractConfiguration if (webxml != null) { context.getMetaData().setWebXml(webxml); + context.getServletContext().setEffectiveMajorVersion(context.getMetaData().getWebXml().getMajorVersion()); + context.getServletContext().setEffectiveMinorVersion(context.getMetaData().getWebXml().getMinorVersion()); } //parse but don't process override-web.xml diff --git a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java index 359da247524..52894e37a83 100644 --- a/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java +++ b/jetty-webapp/src/test/java/org/eclipse/jetty/webapp/WebAppContextTest.java @@ -87,24 +87,6 @@ public class WebAppContextTest assertTrue(Arrays.equals(configs,wac.getConfigurations())); } - @Test - public void testRealPathDoesNotExist() throws Exception - { - Server server = new Server(0); - WebAppContext context = new WebAppContext(".", "/"); - server.setHandler(context); - server.start(); - - // When - ServletContext ctx = context.getServletContext(); - - // Then - // This passes: - assertNotNull(ctx.getRealPath("/doesnotexist")); - // This fails: - assertNotNull(ctx.getRealPath("/doesnotexist/")); - } - /** * tests that the servlet context white list works * diff --git a/jetty-websocket/pom.xml b/jetty-websocket/pom.xml index 1bc5214b513..c366dd019d0 100644 --- a/jetty-websocket/pom.xml +++ b/jetty-websocket/pom.xml @@ -3,7 +3,7 @@ jetty-project org.eclipse.jetty - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 @@ -16,8 +16,8 @@ - javax.servlet - servlet-api + ${servlet.spec.groupId} + ${servlet.spec.artifactId} provided @@ -94,5 +94,4 @@ - diff --git a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java index bcd513657a0..e941abbaeb0 100644 --- a/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java +++ b/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/WebSocketParserD06Test.java @@ -13,6 +13,7 @@ import org.eclipse.jetty.io.BufferCache.CachedBuffer; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.io.ByteArrayEndPoint; import org.eclipse.jetty.util.StringUtil; +import org.eclipse.jetty.util.TypeUtil; import org.eclipse.jetty.util.Utf8StringBuilder; import org.junit.Before; import org.junit.Test; @@ -117,7 +118,7 @@ public class WebSocketParserD06Test _in.put((byte)0x84); _in.put((byte)11); _in.put("Hello World".getBytes(StringUtil.__UTF8)); - // System.err.println("tosend="+TypeUtil.toHexString(_in.asArray())); + System.err.println("tosend="+TypeUtil.toHexString(_in.asArray())); int filled =_parser.parseNext(); diff --git a/jetty-xml/pom.xml b/jetty-xml/pom.xml index b2a39954309..920ac955e4c 100644 --- a/jetty-xml/pom.xml +++ b/jetty-xml/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 jetty-xml diff --git a/pom.xml b/pom.xml index dcc7fb7a289..a888268063e 100644 --- a/pom.xml +++ b/pom.xml @@ -6,19 +6,21 @@ 19 jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT Jetty :: Project ${jetty.url} pom 1.1 1.4.1 - 2.1.v20100127 1.1.1 http://www.eclipse.org/jetty 4.8.1 UTF-8 1.6.1 + org.mortbay.jetty + servlet-api + 3.0.20100224 1.1 1.6 1.2 @@ -34,8 +36,8 @@ maven-compiler-plugin - 1.5 - 1.5 + 1.6 + 1.6 false @@ -166,7 +168,7 @@ - 1.5 + 1.6 jetty/pmd_logging_ruleset.xml @@ -347,6 +349,7 @@ jetty-start jetty-nested jetty-overlay-deployer + jetty-osgi jetty-nosql jetty-http-spi jetty-distribution @@ -356,14 +359,15 @@ test-jetty-webapp test-jetty-nested example-jetty-embedded + example-async-rest tests - javax.servlet - servlet-api - 2.5 + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + ${servlet.spec.version} org.apache.maven @@ -585,8 +589,8 @@ com.acme - http://java.sun.com/j2se/1.5.0/docs/api - http://java.sun.com/javaee/5/docs/api + http://java.sun.com/javase/6/docs/api/ + http://java.sun.com/javaee/6/docs/api http://junit.sourceforge.net/javadoc/ diff --git a/test-continuation-jetty6/pom.xml b/test-continuation-jetty6/pom.xml index 02fa6e29176..d853b66d602 100644 --- a/test-continuation-jetty6/pom.xml +++ b/test-continuation-jetty6/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 test-continuation-jetty6 @@ -27,17 +27,35 @@ junit test + + org.mortbay.jetty + servlet-api + 2.5-20081211 + test + org.eclipse.jetty jetty-servlet ${project.version} test + + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + + org.eclipse.jetty test-continuation ${project.version} test + + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + + org.mortbay.jetty diff --git a/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java new file mode 100644 index 00000000000..9e311d569d6 --- /dev/null +++ b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/ContinuationBase.java @@ -0,0 +1,423 @@ +// ======================================================================== +// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.continuation; + +import java.io.IOException; +import java.io.InputStream; +import java.net.Socket; +import java.util.Timer; +import java.util.TimerTask; + +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import junit.framework.TestCase; + + + +public abstract class ContinuationBase extends TestCase +{ + protected SuspendServlet _servlet=new SuspendServlet(); + protected int _port; + + protected void doit(String type) throws Exception + { + String response; + + response=process(null,null); + assertContains(type,response); + assertContains("NORMAL",response); + assertNotContains("history: onTimeout",response); + assertNotContains("history: onComplete",response); + + response=process("sleep=200",null); + assertContains("SLEPT",response); + assertNotContains("history: onTimeout",response); + assertNotContains("history: onComplete",response); + + response=process("suspend=200",null); + assertContains("TIMEOUT",response); + assertContains("history: onTimeout",response); + assertContains("history: onComplete",response); + + response=process("suspend=200&resume=10",null); + assertContains("RESUMED",response); + assertNotContains("history: onTimeout",response); + assertContains("history: onComplete",response); + + response=process("suspend=200&resume=0",null); + assertContains("RESUMED",response); + assertNotContains("history: onTimeout",response); + assertContains("history: onComplete",response); + + response=process("suspend=200&complete=10",null); + assertContains("COMPLETED",response); + assertNotContains("history: onTimeout",response); + assertContains("history: onComplete",response); + + response=process("suspend=200&complete=0",null); + assertContains("COMPLETED",response); + assertNotContains("history: onTimeout",response); + assertContains("history: onComplete",response); + + + response=process("suspend=1000&resume=10&suspend2=1000&resume2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(2,count(response,"history: resume")); + assertEquals(0,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("RESUMED",response); + + response=process("suspend=1000&resume=10&suspend2=1000&resume2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(2,count(response,"history: resume")); + assertEquals(0,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("RESUMED",response); + + response=process("suspend=1000&resume=10&suspend2=1000&complete2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(1,count(response,"history: resume")); + assertEquals(0,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("COMPLETED",response); + + response=process("suspend=1000&resume=10&suspend2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(1,count(response,"history: resume")); + assertEquals(1,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("TIMEOUT",response); + + + + response=process("suspend=10&suspend2=1000&resume2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(1,count(response,"history: resume")); + assertEquals(1,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("RESUMED",response); + + response=process("suspend=10&suspend2=1000&resume2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(1,count(response,"history: resume")); + assertEquals(1,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("RESUMED",response); + + response=process("suspend=10&suspend2=1000&complete2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(0,count(response,"history: resume")); + assertEquals(1,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("COMPLETED",response); + + response=process("suspend=10&suspend2=10",null); + assertEquals(2,count(response,"history: suspend")); + assertEquals(0,count(response,"history: resume")); + assertEquals(2,count(response,"history: onTimeout")); + assertEquals(1,count(response,"history: onComplete")); + assertContains("TIMEOUT",response); + + } + + + private int count(String responses,String substring) + { + int count=0; + int i=responses.indexOf(substring); + while (i>=0) + { + count++; + i=responses.indexOf(substring,i+substring.length()); + } + + return count; + } + + protected void assertContains(String content,String response) + { + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + if (response.indexOf(content,15)<0) + { + System.err.println(content+" NOT IN '"+response+"'"); + assertTrue(false); + } + } + + protected void assertNotContains(String content,String response) + { + assertEquals("HTTP/1.1 200 OK",response.substring(0,15)); + if (response.indexOf(content,15)>=0) + { + System.err.println(content+" IS IN '"+response+"'"); + assertTrue(false); + } + } + + public synchronized String process(String query,String content) throws Exception + { + String request = "GET /"; + + if (query!=null) + request+="?"+query; + request+=" HTTP/1.1\r\n"+ + "Host: localhost\r\n"+ + "Connection: close\r\n"; + if (content!=null) + request+="Content-Length: "+content.length()+"\r\n"; + request+="\r\n" + content; + + Socket socket = new Socket("localhost",_port); + socket.getOutputStream().write(request.getBytes("UTF-8")); + + String response = toString(socket.getInputStream()); + return response; + } + + + protected abstract String toString(InputStream in) throws IOException; + + + private static class SuspendServlet extends HttpServlet + { + private Timer _timer=new Timer(); + + public SuspendServlet() + {} + + /* ------------------------------------------------------------ */ + protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException + { + final Continuation continuation = ContinuationSupport.getContinuation(request,response); + + response.addHeader("history",continuation.getClass().toString()); + + int read_before=0; + long sleep_for=-1; + long suspend_for=-1; + long suspend2_for=-1; + long resume_after=-1; + long resume2_after=-1; + long complete_after=-1; + long complete2_after=-1; + + if (request.getParameter("read")!=null) + read_before=Integer.parseInt(request.getParameter("read")); + if (request.getParameter("sleep")!=null) + sleep_for=Integer.parseInt(request.getParameter("sleep")); + if (request.getParameter("suspend")!=null) + suspend_for=Integer.parseInt(request.getParameter("suspend")); + if (request.getParameter("suspend2")!=null) + suspend2_for=Integer.parseInt(request.getParameter("suspend2")); + if (request.getParameter("resume")!=null) + resume_after=Integer.parseInt(request.getParameter("resume")); + if (request.getParameter("resume2")!=null) + resume2_after=Integer.parseInt(request.getParameter("resume2")); + if (request.getParameter("complete")!=null) + complete_after=Integer.parseInt(request.getParameter("complete")); + if (request.getParameter("complete2")!=null) + complete2_after=Integer.parseInt(request.getParameter("complete2")); + + if (continuation.isInitial()) + { + if (read_before>0) + { + byte[] buf=new byte[read_before]; + request.getInputStream().read(buf); + } + else if (read_before<0) + { + InputStream in = request.getInputStream(); + int b=in.read(); + while(b!=-1) + b=in.read(); + } + + if (suspend_for>=0) + { + if (suspend_for>0) + continuation.setTimeout(suspend_for); + continuation.addContinuationListener(__listener); + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","suspend"); + continuation.suspend(); + + if (complete_after>0) + { + TimerTask complete = new TimerTask() + { + public void run() + { + try + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + continuation.complete(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }; + synchronized (_timer) + { + _timer.schedule(complete,complete_after); + } + } + else if (complete_after==0) + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + continuation.complete(); + } + else if (resume_after>0) + { + TimerTask resume = new TimerTask() + { + public void run() + { + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume"); + continuation.resume(); + } + }; + synchronized (_timer) + { + _timer.schedule(resume,resume_after); + } + } + else if (resume_after==0) + { + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume"); + continuation.resume(); + } + } + else if (sleep_for>=0) + { + try + { + Thread.sleep(sleep_for); + } + catch (InterruptedException e) + { + e.printStackTrace(); + } + response.setStatus(200); + response.getOutputStream().println("SLEPT\n"); + } + else + { + response.setStatus(200); + response.getOutputStream().println("NORMAL\n"); + } + } + else if (suspend2_for>=0 && request.getAttribute("2nd")==null) + { + request.setAttribute("2nd","cycle"); + + if (suspend2_for>0) + continuation.setTimeout(suspend2_for); + // continuation.addContinuationListener(__listener); + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","suspend"); + continuation.suspend(); + + if (complete2_after>0) + { + TimerTask complete = new TimerTask() + { + public void run() + { + try + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + continuation.complete(); + } + catch(Exception e) + { + e.printStackTrace(); + } + } + }; + synchronized (_timer) + { + _timer.schedule(complete,complete2_after); + } + } + else if (complete2_after==0) + { + response.setStatus(200); + response.getOutputStream().println("COMPLETED\n"); + continuation.complete(); + } + else if (resume2_after>0) + { + TimerTask resume = new TimerTask() + { + public void run() + { + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume"); + continuation.resume(); + } + }; + synchronized (_timer) + { + _timer.schedule(resume,resume2_after); + } + } + else if (resume2_after==0) + { + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","resume"); + continuation.resume(); + } + return; + } + else if (continuation.isExpired()) + { + response.setStatus(200); + response.getOutputStream().println("TIMEOUT\n"); + } + else if (continuation.isResumed()) + { + response.setStatus(200); + response.getOutputStream().println("RESUMED\n"); + } + else + { + response.setStatus(200); + response.getOutputStream().println("unknown???\n"); + } + } + } + + + + private static ContinuationListener __listener = + new ContinuationListener() + { + public void onComplete(Continuation continuation) + { + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","onComplete"); + } + + public void onTimeout(Continuation continuation) + { + ((HttpServletResponse)continuation.getServletResponse()).addHeader("history","onTimeout"); + continuation.resume(); + } + + }; +} diff --git a/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java new file mode 100644 index 00000000000..0f788b1698e --- /dev/null +++ b/test-continuation-jetty6/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java @@ -0,0 +1,78 @@ +// ======================================================================== +// Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.continuation; + +import java.io.IOException; +import java.io.InputStream; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; + +import org.mortbay.jetty.Connector; +import org.mortbay.jetty.Server; +import org.mortbay.jetty.nio.SelectChannelConnector; +import org.mortbay.jetty.servlet.Context; +import org.mortbay.jetty.servlet.FilterHolder; +import org.mortbay.jetty.servlet.ServletHandler; +import org.mortbay.jetty.servlet.ServletHolder; +import org.mortbay.util.IO; + + +public class FauxContinuationTest extends ContinuationBase +{ + protected Server _server = new Server(); + protected ServletHandler _servletHandler; + protected SelectChannelConnector _connector; + FilterHolder _filter; + + protected void setUp() throws Exception + { + _connector = new SelectChannelConnector(); + _server.setConnectors(new Connector[]{ _connector }); + Context servletContext = new Context(Context.NO_SECURITY|Context.NO_SESSIONS); + _server.setHandler(servletContext); + _servletHandler=servletContext.getServletHandler(); + ServletHolder holder=new ServletHolder(_servlet); + _servletHandler.addServletWithMapping(holder,"/"); + _filter=_servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",0); + } + + protected void tearDown() throws Exception + { + _server.stop(); + } + + public void testFaux() throws Exception + { + _filter.setInitParameter("debug","true"); + _filter.setInitParameter("faux","true"); + _server.start(); + _port=_connector.getLocalPort(); + + doit("FauxContinuation"); + } + + + + protected String toString(InputStream in) throws IOException + { + return IO.toString(in); + } +} diff --git a/test-continuation/pom.xml b/test-continuation/pom.xml index 498bf751457..53b9ea39939 100644 --- a/test-continuation/pom.xml +++ b/test-continuation/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 test-continuation diff --git a/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java b/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java index f70727d03e0..74525841828 100644 --- a/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java +++ b/test-continuation/src/test/java/org/eclipse/jetty/continuation/ContinuationTest.java @@ -15,6 +15,7 @@ package org.eclipse.jetty.continuation; import java.io.IOException; import java.io.InputStream; +import java.util.EnumSet; import org.eclipse.jetty.continuation.test.ContinuationBase; import org.eclipse.jetty.server.Connector; @@ -44,6 +45,7 @@ public class ContinuationTest extends ContinuationBase _server.setHandler(servletContext); _servletHandler=servletContext.getServletHandler(); ServletHolder holder=new ServletHolder(_servlet); + holder.setAsyncSupported(true); _servletHandler.addServletWithMapping(holder,"/"); _server.start(); diff --git a/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java b/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java index 9820e71c6f0..d6f50fc4a41 100644 --- a/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java +++ b/test-continuation/src/test/java/org/eclipse/jetty/continuation/FauxContinuationTest.java @@ -15,6 +15,9 @@ package org.eclipse.jetty.continuation; import java.io.IOException; import java.io.InputStream; +import java.util.EnumSet; + +import javax.servlet.DispatcherType; import org.eclipse.jetty.continuation.test.ContinuationBase; import org.eclipse.jetty.server.Connector; @@ -44,7 +47,7 @@ public class FauxContinuationTest extends ContinuationBase ServletHolder holder=new ServletHolder(_servlet); _servletHandler.addServletWithMapping(holder,"/"); - _filter=_servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",0); + _filter=_servletHandler.addFilterWithMapping(ContinuationFilter.class,"/*",null); _filter.setInitParameter("debug","true"); _filter.setInitParameter("faux","true"); _server.start(); diff --git a/test-jetty-nested/pom.xml b/test-jetty-nested/pom.xml index 2f5b334f991..bec379b2bb3 100644 --- a/test-jetty-nested/pom.xml +++ b/test-jetty-nested/pom.xml @@ -4,7 +4,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-jetty-nested Jetty :: Nested Test diff --git a/test-jetty-servlet/pom.xml b/test-jetty-servlet/pom.xml index 65f98aa0f62..26921378c25 100644 --- a/test-jetty-servlet/pom.xml +++ b/test-jetty-servlet/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 test-jetty-servlet diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java index 46e31be676b..ea894ef4fe3 100644 --- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java +++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/HttpTester.java @@ -377,7 +377,7 @@ public class HttpTester cookie.getMaxAge(), cookie.getComment(), cookie.getSecure(), - false, + cookie.isHttpOnly(), cookie.getVersion()); } diff --git a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java index 47cb401bd60..1e58cfedebf 100644 --- a/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java +++ b/test-jetty-servlet/src/main/java/org/eclipse/jetty/testing/ServletTester.java @@ -14,9 +14,12 @@ package org.eclipse.jetty.testing; import java.net.InetAddress; +import java.util.EnumSet; import java.util.Enumeration; import java.util.EventListener; +import javax.servlet.DispatcherType; + import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.server.LocalConnector; import org.eclipse.jetty.server.Server; @@ -234,7 +237,7 @@ public class ServletTester * @return the FilterHolder * @see org.eclipse.jetty.servlet.ServletContextHandler#addFilter(java.lang.Class, java.lang.String, int) */ - public FilterHolder addFilter(Class filterClass, String pathSpec, int dispatches) + public FilterHolder addFilter(Class filterClass, String pathSpec, EnumSet dispatches) { return _context.addFilter(filterClass,pathSpec,dispatches); } @@ -247,7 +250,7 @@ public class ServletTester * @return the FilterHolder * @see org.eclipse.jetty.servlet.ServletContextHandler#addFilter(java.lang.String, java.lang.String, int) */ - public FilterHolder addFilter(String filterClass, String pathSpec, int dispatches) + public FilterHolder addFilter(String filterClass, String pathSpec, EnumSet dispatches) { return _context.addFilter(filterClass,pathSpec,dispatches); } diff --git a/test-jetty-webapp/pom.xml b/test-jetty-webapp/pom.xml index 5c9fbf6c19b..7b6f6ddc504 100644 --- a/test-jetty-webapp/pom.xml +++ b/test-jetty-webapp/pom.xml @@ -2,7 +2,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 org.eclipse.jetty @@ -163,11 +163,11 @@ jetty-servlets ${project.version} - - javax.servlet - servlet-api - provided - + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + provided + org.eclipse.jetty jetty-websocket diff --git a/test-jetty-webapp/src/main/java/com/acme/Dump.java b/test-jetty-webapp/src/main/java/com/acme/Dump.java index 063e38b3b13..fbb3c13be95 100644 --- a/test-jetty-webapp/src/main/java/com/acme/Dump.java +++ b/test-jetty-webapp/src/main/java/com/acme/Dump.java @@ -114,6 +114,18 @@ public class Dump extends HttpServlet @Override public void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { + if (!request.isUserInRole("user")) + { + try + { + request.login("user", "password"); + } + catch(ServletException se) + { + se.printStackTrace(); + } + } + // Handle a dump of data final String data= request.getParameter("data"); final String chars= request.getParameter("chars"); diff --git a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml index c08ca7fdbd9..9ccb222c0ae 100644 --- a/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml +++ b/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml @@ -2,8 +2,9 @@ + xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" + metadata-complete="false" + version="3.0"> Test WebApp @@ -20,6 +21,7 @@ TestFilter com.acme.TestFilter + true remote false @@ -34,6 +36,7 @@ QoSFilter org.eclipse.jetty.servlets.QoSFilter + true maxRequests 10000 @@ -52,6 +55,7 @@ MultiPart org.eclipse.jetty.servlets.MultiPartFilter + true deleteFiles true @@ -66,6 +70,7 @@ GzipFilter org.eclipse.jetty.servlets.IncludableGzipFilter + true bufferSize 8192 @@ -130,6 +135,7 @@ Dump com.acme.Dump + true 1 admin @@ -165,6 +171,7 @@ Dispatch com.acme.DispatchServlet + true 1 @@ -187,6 +194,7 @@ Chat com.acme.ChatServlet + true 1 @@ -234,11 +242,12 @@ TransparentProxy org.eclipse.jetty.servlets.ProxyServlet$Transparent + true Prefix/javadoc-proxy - ProxyTohttp://download.eclipse.org/jetty/stable-7/apidocs + ProxyTohttp://download.eclipse.org/jetty/stable-8/apidocs HostHeaderdownload.eclipse.org diff --git a/test-jetty-webapp/src/main/webapp/index.html b/test-jetty-webapp/src/main/webapp/index.html index 74ef907a75a..630bc1da19c 100644 --- a/test-jetty-webapp/src/main/webapp/index.html +++ b/test-jetty-webapp/src/main/webapp/index.html @@ -11,9 +11,9 @@ -

Welcome to Jetty 7

+

Welcome to Jetty 8

-This is the Test webapp for the Jetty 7 HTTP Server and Servlet Container. +This is the Test webapp for the Jetty 8 HTTP Server and Servlet Container. For more information about Jetty, please visit our website or wiki or see the bundled javadoc.
diff --git a/tests/pom.xml b/tests/pom.xml index 28cee13d78b..1893c488d3a 100644 --- a/tests/pom.xml +++ b/tests/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty jetty-project - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT org.eclipse.jetty.tests tests-parent diff --git a/tests/test-integration/pom.xml b/tests/test-integration/pom.xml index bf1daf62b96..561d51a27aa 100644 --- a/tests/test-integration/pom.xml +++ b/tests/test-integration/pom.xml @@ -20,7 +20,7 @@ org.eclipse.jetty.tests tests-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT 4.0.0 test-integration diff --git a/tests/test-loginservice/pom.xml b/tests/test-loginservice/pom.xml index a5e08c91017..c5088ad2ef6 100644 --- a/tests/test-loginservice/pom.xml +++ b/tests/test-loginservice/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-loginservice Jetty Tests :: Login Service diff --git a/tests/test-sessions/pom.xml b/tests/test-sessions/pom.xml index 8c829fa6935..fe494aa8f75 100644 --- a/tests/test-sessions/pom.xml +++ b/tests/test-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-sessions-parent Jetty Tests :: Sessions :: Parent diff --git a/tests/test-sessions/test-hash-sessions/pom.xml b/tests/test-sessions/test-hash-sessions/pom.xml index 1152f8a40e2..dbb395bd466 100644 --- a/tests/test-sessions/test-hash-sessions/pom.xml +++ b/tests/test-sessions/test-hash-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-hash-sessions Jetty Tests :: Sessions :: Hash diff --git a/tests/test-sessions/test-jdbc-sessions/pom.xml b/tests/test-sessions/test-jdbc-sessions/pom.xml index 567cfad6daa..56d6de5f1b1 100644 --- a/tests/test-sessions/test-jdbc-sessions/pom.xml +++ b/tests/test-sessions/test-jdbc-sessions/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-jdbc-sessions Jetty Tests :: Sessions :: JDBC diff --git a/tests/test-sessions/test-sessions-common/pom.xml b/tests/test-sessions/test-sessions-common/pom.xml index 2979f679288..b2efee46064 100644 --- a/tests/test-sessions/test-sessions-common/pom.xml +++ b/tests/test-sessions/test-sessions-common/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-sessions-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-sessions-common Jetty Tests :: Sessions :: Common diff --git a/tests/test-webapps/pom.xml b/tests/test-webapps/pom.xml index c34dda4cdc9..c2d2cff2108 100644 --- a/tests/test-webapps/pom.xml +++ b/tests/test-webapps/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests tests-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-webapps-parent Jetty Tests :: WebApps :: Parent diff --git a/tests/test-webapps/test-webapp-rfc2616/pom.xml b/tests/test-webapps/test-webapp-rfc2616/pom.xml index fcc140014f9..cfeab21f82a 100644 --- a/tests/test-webapps/test-webapp-rfc2616/pom.xml +++ b/tests/test-webapps/test-webapp-rfc2616/pom.xml @@ -21,7 +21,7 @@ org.eclipse.jetty.tests test-webapps-parent - 7.6.0-SNAPSHOT + 8.1.0-SNAPSHOT test-webapp-rfc2616 Jetty Tests :: WebApp :: RFC2616 @@ -44,11 +44,10 @@ jetty-servlets ${project.version} - - javax.servlet - servlet-api - 2.5 - provided - + + ${servlet.spec.groupId} + ${servlet.spec.artifactId} + provided +