costin 00/02/16 23:52:24 Modified: src/examples/WEB-INF web.xml src/share/org/apache/tomcat/context DefaultCMSetter.java LoadOnStartupInterceptor.java src/share/org/apache/tomcat/core ContextManager.java HttpServletResponseFacade.java Request.java RequestDispatcherImpl.java RequestImpl.java ServletWrapper.java src/share/org/apache/tomcat/request SecurityCheck.java src/share/org/apache/tomcat/service Ajp11ConnectionHandler.java src/share/org/apache/tomcat/service/connector Ajp12ConnectionHandler.java Ajp23ConnectionHandler.java JNIConnectionHandler.java src/share/org/apache/tomcat/service/http HttpConnectionHandler.java src/share/org/apache/tomcat/servlets AuthServlet.java DefaultErrorPage.java Added: src/examples/jsp/security login.jsp src/examples/jsp/security/protected index.jsp src/share/org/apache/tomcat/servlets JSecurityCheck.java Log: Ok, I hope this is the last "big" change for 3.1 Error handling was broken ( i.e. error-page was not called for error codes, exceptions were handled at-hoc). Added a single method that handles that, in ContextManager, added code to redirect to error pages for special HTTP errors, try hard to avoid loops. We have a bit too much debugging on, but that's not a but and will be removed before 3.1 ( since we are bug-fixing we should keep it until everything works ) Implemented form login, added an example. Now we should have BASIC and FORM working ( except that no auth repository is plugged in, any user/password will be accepted ). I'll add users.xml before 3.1 ( as a bug-fix, not a feature :-) Revision Changes Path 1.3 +34 -0 jakarta-tomcat/src/examples/WEB-INF/web.xml Index: web.xml =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/examples/WEB-INF/web.xml,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- web.xml 1999/10/20 22:07:58 1.2 +++ web.xml 2000/02/17 07:52:16 1.3 @@ -64,4 +64,38 @@ /WEB-INF/jsp/example-taglib.tld + + + FORM + examples + /jsp/security/login.jsp + + + + + + a + /jsp/security/protected/* + /jsp/security/protected1/ + GET + POST + + + + a + /foo2/* + /bar2/* + + + + tomcat + role1 + + + + + 1.1 jakarta-tomcat/src/examples/jsp/security/login.jsp Index: login.jsp ===================================================================

Login page for examples

1.1 jakarta-tomcat/src/examples/jsp/security/protected/index.jsp Index: index.jsp ===================================================================

Great, you logged in

1.16 +8 -2 jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java Index: DefaultCMSetter.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/DefaultCMSetter.java,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- DefaultCMSetter.java 2000/02/16 00:48:44 1.15 +++ DefaultCMSetter.java 2000/02/17 07:52:18 1.16 @@ -107,13 +107,19 @@ // Set default session manager if none set if( ctx.getSessionManager() == null ) ctx.setSessionManager(new org.apache.tomcat.session.StandardSessionManager()); - // Alternative: org.apache.tomcat.session.ServerSessionManager.getManager(); + ServletWrapper authWrapper=new ServletWrapper(); authWrapper.setContext( ctx ); authWrapper.setServletClass( "org.apache.tomcat.servlets.AuthServlet" ); - authWrapper.setServletName( "authServlet"); + authWrapper.setServletName( "tomcat.authServlet"); ctx.addServlet( authWrapper ); + + ServletWrapper errorWrapper=new ServletWrapper(); + errorWrapper.setContext( ctx ); + errorWrapper.setServletClass( "org.apache.tomcat.servlets.DefaultErrorPage" ); + errorWrapper.setServletName( "tomcat.errorPage"); + ctx.addServlet( errorWrapper ); // XXX Loader properties - need to be set on loader!! //ctx.setServletLoader( new org.apache.tomcat.loader.ServletClassLoaderImpl()); 1.9 +1 -0 jakarta-tomcat/src/share/org/apache/tomcat/context/LoadOnStartupInterceptor.java Index: LoadOnStartupInterceptor.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/context/LoadOnStartupInterceptor.java,v retrieving revision 1.8 retrieving revision 1.9 diff -u -r1.8 -r1.9 --- LoadOnStartupInterceptor.java 2000/02/14 04:59:38 1.8 +++ LoadOnStartupInterceptor.java 2000/02/17 07:52:18 1.9 @@ -159,6 +159,7 @@ String path=result.getPath(); RequestImpl request = new RequestImpl(); ResponseImpl response = new ResponseImpl(); + request.setContextManager( context.getContextManager()); request.recycle(); response.recycle(); 1.47 +122 -48 jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java Index: ContextManager.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java,v retrieving revision 1.46 retrieving revision 1.47 diff -u -r1.46 -r1.47 --- ContextManager.java 2000/02/16 17:13:22 1.46 +++ ContextManager.java 2000/02/17 07:52:19 1.47 @@ -66,6 +66,8 @@ import org.apache.tomcat.request.*; import org.apache.tomcat.util.*; import org.apache.tomcat.logging.*; +import javax.servlet.*; +import javax.servlet.http.*; import java.io.*; import java.net.*; import java.util.*; @@ -479,71 +481,43 @@ */ public void service( Request rrequest, Response rresponse ) { try { + rrequest.setContextManager( this ); rrequest.setResponse(rresponse); rresponse.setRequest(rrequest); - // XXX - // return if an error was detected in processing the - // request line - if (rresponse.getStatus() >= 400) { - rresponse.finish(); - rrequest.recycle(); - rresponse.recycle(); - return; - } - - // XXX Hardcoded - it will be changed in the next step.( costin ) - processRequest( rrequest ); + // wront request - parsing error + int status=rresponse.getStatus(); - authenticate( rrequest, rresponse ); - - int err=authorize( rrequest, rresponse ); - if( err != 0 ) { - // redirect to the right servlet - Context ctx=rrequest.getContext(); - String authMethod=ctx.getAuthMethod(); - ServletWrapper authWrapper=ctx.getServletByName( "authServlet" ); - rrequest.setWrapper( authWrapper ); - - // unauthorized access, redirect to login page. - // XXX authorize will set request - } - + if( status < 400 ) + status= processRequest( rrequest ); - if( rrequest.getWrapper() == null ) { - log("ERROR: mapper returned no wrapper "); - log(rrequest.toString() ); - // XXX send an error - it shouldn't happen, mapper is broken + if(status==0) + status=authenticate( rrequest, rresponse ); + if(status == 0) + status=authorize( rrequest, rresponse ); + if( status == 0 ) { + rrequest.getWrapper().handleRequest(rrequest, + rresponse); } else { - // do it - rrequest.getWrapper().handleRequest(rrequest.getFacade(), - rresponse.getFacade()); + // something went wrong + handleError( rrequest, rresponse, null, status ); } - // finish and clean up rresponse.finish(); - - } catch (Exception e) { - if(e instanceof IOException && "Broken pipe".equals(e.getMessage()) ) { - log("Broken pipe " + rrequest.getRequestURI()); - return; - } - // XXX - // this isn't what we want, we want to log the problem somehow - log("HANDLER THREAD PROBLEM: " + e); - log("Request: " + rrequest); - e.printStackTrace(); + rrequest.recycle(); + rresponse.recycle(); + } catch (Throwable t) { + handleError( rrequest, rresponse, t, 0 ); } + return; } - // XXX need to be changed to use a full sub-request model (costin) - /** Will find the ServletWrapper for a servlet, assuming we already have * the Context. This is used by Dispatcher and getResource - where the Context * is already known. */ int processRequest( Request req ) { - + req.setContextManager( this ); log("ProcessRequest: "+req.toString(), Logger.DEBUG); for( int i=0; i< requestInterceptors.size(); i++ ) { @@ -580,6 +554,106 @@ ((RequestInterceptor)requestInterceptors.elementAt(i)).beforeBody( req, res ); } return 0; + } + + void handleError( Request req, Response res , Throwable t, int code ) { + Context ctx = req.getContext(); + if(ctx==null) { + ///*DEBUG*/ try {throw new Exception(); } catch(Exception ex) {ex.printStackTrace();} + ctx=getContext(""); + } + + if( code!=0) + ctx.log("Status: " + code + " in " + req ); + if( t!=null) + ctx.log("Exception: " + t.getMessage() + " in " + req ); + + String path=null; + ServletWrapper errorServlet=null; + + // normal redirects or non-errors + if( code!=0 && code < 400 ) { + errorServlet=ctx.getServletByName("tomcat.errorPage"); + } else if( req.getAttribute("javax.servlet.error.status_code") != null || + req.getAttribute("javax.servlet.error.exception_type")!=null) { + + if( ctx.getDebug() > 0 ) ctx.log( "Error: exception inside exception servlet " + + req.getAttribute("javax.servlet.error.status_code") + " " + + req.getAttribute("javax.servlet.error.exception_type")); + errorServlet=ctx.getServletByName("tomcat.errorPage"); + } + + if( t==null) { + if( code==0 ) + code=res.getStatus(); + // we can't support error pages for non-errors, it's to + // complex and insane + if( code >= 400 ) + path = ctx.getErrorPage( code ); + + if( code==HttpServletResponse.SC_UNAUTHORIZED ) { + // set extra info for login page + if( errorServlet==null) + errorServlet=ctx.getServletByName("tomcat.authServlet"); + if( ctx.getDebug() > 0 ) ctx.log( "Setting auth servlet " + errorServlet ); + } + req.setAttribute("javax.servlet.error.status_code",new Integer( code)); + } else { + // Scan the exception's inheritance tree looking for a rule + // that this type of exception should be forwarded + Class clazz = t.getClass(); + while (path == null && clazz != null) { + String name = clazz.getName(); + path = ctx.getErrorPage(name); + clazz = clazz.getSuperclass(); + } + req.setAttribute("javax.servlet.error.exception_type", t.getClass()); + req.setAttribute("javax.servlet.error.message", t.getMessage()); + req.setAttribute("tomcat.servlet.error.throwable", t); + } + + // Save the original request, we want to report it + // and we need to use it in the "authentication" case to implement + // the strange requirements for login pages + req.setAttribute("tomcat.servlet.error.request", req); + + + // No error page or "Exception in exception handler", call internal servlet + if( path==null && errorServlet==null) + errorServlet=ctx.getServletByName("tomcat.errorPage"); + + // Try a normal "error page" + if( errorServlet==null && path != null ) { + try { + RequestDispatcher rd = ctx.getRequestDispatcher(path); + + // try a forward + res.reset(); + if (res.isStarted()) + rd.include(req.getFacade(), res.getFacade()); + else + rd.forward(req.getFacade(), res.getFacade()); + return ; + } catch( Throwable t1 ) { + // nothing - we'll call DefaultErrorPage + } + } + + // If No handler or an error happened in handler + // Default handler + // loop control + if( req.getAttribute("tomcat.servlet.error.handler") != null && + code >= 400 ) { + // error page for 404 doesn't exist... ( or watchdog tests :-) + ctx.log( "Error/loop in default error handler " + req ); + ctx.log( "Error/loop " + code + " " + t + " " + path ); + } else { + if( ctx.getDebug() > 0 ) ctx.log( "Error: Calling servlet " + errorServlet ); + req.setAttribute("tomcat.servlet.error.handler", errorServlet); + errorServlet.handleRequest(req.getFacade(),res.getFacade()); + // will call this if any error happens + } + return; } // -------------------- Sub-Request mechanism -------------------- 1.4 +5 -14 jakarta-tomcat/src/share/org/apache/tomcat/core/HttpServletResponseFacade.java Index: HttpServletResponseFacade.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/HttpServletResponseFacade.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- HttpServletResponseFacade.java 2000/02/01 21:39:38 1.3 +++ HttpServletResponseFacade.java 2000/02/17 07:52:19 1.4 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/HttpServletResponseFacade.java,v 1.3 2000/02/01 21:39:38 costin Exp $ - * $Revision: 1.3 $ - * $Date: 2000/02/01 21:39:38 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/HttpServletResponseFacade.java,v 1.4 2000/02/17 07:52:19 costin Exp $ + * $Revision: 1.4 $ + * $Date: 2000/02/17 07:52:19 $ * * ==================================================================== * @@ -157,18 +157,9 @@ public void sendError(int sc, String msg) throws IOException { setStatus( sc ); Request request=response.getRequest(); - request.setAttribute("javax.servlet.error.status_code", - String.valueOf(sc)); request.setAttribute("javax.servlet.error.message", msg); - - // XXX need to customize it - Servlet errorP=new org.apache.tomcat.servlets.DefaultErrorPage(); - try { - errorP.service(request.getFacade(),this); - } catch (ServletException ex ) { - // shouldn't happen! - ex.printStackTrace(); - } + ContextManager cm=request.getContextManager(); + cm.handleError( request, response, null, sc ); } public void sendRedirect(String location) 1.29 +6 -0 jakarta-tomcat/src/share/org/apache/tomcat/core/Request.java Index: Request.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/Request.java,v retrieving revision 1.28 retrieving revision 1.29 diff -u -r1.28 -r1.29 --- Request.java 2000/02/16 17:56:11 1.28 +++ Request.java 2000/02/17 07:52:19 1.29 @@ -241,6 +241,12 @@ */ public HttpServletRequestFacade getFacade() ; + /** Pointer to the server engine - for errors, etc + */ + public void setContextManager( ContextManager cm ); + + public ContextManager getContextManager(); + // -------------------- Internal/deprecated-------------------- // Derived from parsing query string and body (for POST) 1.18 +3 -3 jakarta-tomcat/src/share/org/apache/tomcat/core/RequestDispatcherImpl.java Index: RequestDispatcherImpl.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestDispatcherImpl.java,v retrieving revision 1.17 retrieving revision 1.18 diff -u -r1.17 -r1.18 --- RequestDispatcherImpl.java 2000/02/16 17:13:22 1.17 +++ RequestDispatcherImpl.java 2000/02/17 07:52:19 1.18 @@ -157,8 +157,8 @@ // CM should have set the wrapper - call it // LOG System.out.println("Forward " + realRequest.getServletPath()); - realRequest.getWrapper().handleRequest((HttpServletRequestFacade)request, - (HttpServletResponseFacade)response); + realRequest.getWrapper().handleRequest(realRequest, + realResponse); } public void include(ServletRequest request, ServletResponse response) @@ -253,7 +253,7 @@ // now it's really strange: we call the wrapper on the subrequest // for the realRequest ( since the real request will still have the // original handler/wrapper ) - subRequest.getWrapper().handleRequest(realRequest.getFacade() , (HttpServletResponseFacade)response); + subRequest.getWrapper().handleRequest(realRequest , realResponse); // After request, we want to restore the include attributes - for // chained includes. 1.19 +12 -3 jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java Index: RequestImpl.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- RequestImpl.java 2000/02/16 00:30:29 1.18 +++ RequestImpl.java 2000/02/17 07:52:19 1.19 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java,v 1.18 2000/02/16 00:30:29 costin Exp $ - * $Revision: 1.18 $ - * $Date: 2000/02/16 00:30:29 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/RequestImpl.java,v 1.19 2000/02/17 07:52:19 costin Exp $ + * $Revision: 1.19 $ + * $Date: 2000/02/17 07:52:19 $ * * ==================================================================== * @@ -108,6 +108,7 @@ protected Response response; protected HttpServletRequestFacade requestFacade; protected Context context; + protected ContextManager contextM; protected Hashtable attributes = new Hashtable(); protected boolean didReadFormData; @@ -342,6 +343,14 @@ public void setContext(Context context) { this.context = context; + } + + public void setContextManager( ContextManager cm ) { + contextM=cm; + } + + public ContextManager getContextManager() { + return contextM; } public Cookie[] getCookies() { 1.29 +131 -262 jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java Index: ServletWrapper.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java,v retrieving revision 1.28 retrieving revision 1.29 diff -u -r1.28 -r1.29 --- ServletWrapper.java 2000/02/16 17:13:23 1.28 +++ ServletWrapper.java 2000/02/17 07:52:20 1.29 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java,v 1.28 2000/02/16 17:13:23 costin Exp $ - * $Revision: 1.28 $ - * $Date: 2000/02/16 17:13:23 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ServletWrapper.java,v 1.29 2000/02/17 07:52:20 costin Exp $ + * $Revision: 1.29 $ + * $Date: 2000/02/17 07:52:20 $ * * ==================================================================== * @@ -82,6 +82,7 @@ protected StringManager sm = StringManager.getManager("org.apache.tomcat.core"); protected Context context; + protected ContextManager contextM; // servletName is stored in config! protected String servletClassName; // required @@ -95,6 +96,7 @@ // optional informations protected String description = null; + boolean initialized=false; // Usefull info for class reloading protected boolean isReloadable = false; // information + make sure destroy is called when no other servlet @@ -118,6 +120,7 @@ public void setContext( Context context) { this.context = context; + contextM=context.getContextManager(); config.setContext( context ); isReloadable=context.getReloadable(); } @@ -206,16 +209,45 @@ } void destroy() { + initialized=false; if (servlet != null) { synchronized (this) { - waitForDestroy(); + // Fancy sync logic is to make sure that no threads are in the + // handlerequest when this is called and, furthermore, that + // no threads go through handle request after this method starts! + // Wait until there are no outstanding service calls, + // or until 30 seconds have passed (to avoid a hang) + + //XXX I don't think it works ( costin ) + while (serviceCount > 0) { + try { + wait(30000); + + break; + } catch (InterruptedException e) { } + } + try { - handleDestroy( context, servlet ); - } catch(IOException ioe) { - ioe.printStackTrace(); - // Should never come here... - } catch(ServletException se) { - se.printStackTrace(); + ContextInterceptor cI[]=context.getContextInterceptors(); + for( int i=0; i=0; i-- ) { + try { + cI[i].postServletDestroy( context, this ); // ignore the error - like in the original code + } catch( TomcatException ex) { + ex.printStackTrace(); + } + + } + } catch(Exception ex) { + ex.printStackTrace(); // Should never come here... } } @@ -236,58 +268,52 @@ } servlet = (Servlet)servletClass.newInstance(); - + config.setServletClassName(servlet.getClass().getName()); + initServlet(); + } + + void initServlet() + throws ClassNotFoundException, InstantiationException, + IllegalAccessException, ServletException + { try { final Servlet sinstance = servlet; final ServletConfigImpl servletConfig = config; - handleInit(context, servlet, servletConfig); - } catch(IOException ioe) { - ioe.printStackTrace(); - // Should never come here... - } - } - - // XXX XXX need to go directly to Jsp API - void handleJspRequest(final HttpServletRequestFacade request, - final HttpServletResponseFacade response) - throws IOException - { - // "Special" JSP - String requestURI = path + request.getPathInfo(); - RequestDispatcher rd = request.getRequestDispatcher(requestURI); - - try { - if (! response.getRealResponse().isStarted()) - rd.forward(request, response); - else - rd.include(request, response); + ContextInterceptor cI[]=context.getContextInterceptors(); + for( int i=0; i=0; i-- ) { + try { + cI[i].postServletInit( context, this ); // ignore the error - like in the original code + } catch( TomcatException ex) { + ex.printStackTrace(); + } - } catch (ServletException se) { - se.printStackTrace(); - response.sendError(404); - } catch (IOException ioe) { + } + initialized=true; + } catch(Exception ioe) { ioe.printStackTrace(); - response.sendError(404); + // Should never come here... } - return; } - - public void handleRequest(final HttpServletRequestFacade request, - final HttpServletResponseFacade response) - throws IOException - { - if( path != null ) handleJspRequest( request, response ); - Context context = getContext(); - - // Reloading - // XXX ugly - should find a better way to deal with invoker - // The problem is that we are just clearing up invoker, not - // the class loaded by invoker. - + // Reloading + // XXX ugly - should find a better way to deal with invoker + // The problem is that we are just clearing up invoker, not + // the class loaded by invoker. + void handleReload() { // That will be reolved after we reset the context - and many // other conflicts. if( isReloadable && ! "invoker".equals( getServletName())) { @@ -295,6 +321,7 @@ if( loader!=null) { // XXX no need to check after we remove the old loader if( loader.shouldReload() ) { + initialized=false; loader.reload(); servlet=null; servletClass=null; @@ -312,232 +339,74 @@ } } } - - - if (servlet == null) { - synchronized (this) { - try { - loadServlet(); - } catch (ClassNotFoundException e) { - response.sendError(404, "Class not found " + servletClassName); - return; - } catch (Exception e) { - // Make sure the servlet will never - // service a request - servlet = null; - sendInternalServletError(e, request, response); - return; - } - } - } - - try { - synchronized(this) { - // logic for un-loading - serviceCount++; - } - - - handleInvocation( context, servlet, request, response ); - - } catch (ServletException e) { - // XXX - // if it's an unvailable exception, we probably want - // to paint a different screen - handleException(request, response, e); - } catch (SocketException e) { - // replace with Log: - System.out.println("Socket Exception : " + e.getMessage()); - } catch (Throwable e) { - // XXX - // decide which exceptions we should not eat at this point - handleException(request, response, e); - } finally { - synchronized(this) { - serviceCount--; - notifyAll(); - } - } } - - public void handleException(HttpServletRequestFacade request, - HttpServletResponseFacade response, - Throwable t) - { - Context context = request.getRealRequest().getContext(); - ServletContextFacade contextFacade = context.getFacade(); - - // Scan the exception's inheritance tree looking for a rule - // that this type of exception should be forwarded - - String path = null; - Class clazz = t.getClass(); - - while (path == null && clazz != null) { - String name = clazz.getName(); - path = context.getErrorPage(name); - clazz = clazz.getSuperclass(); - } - - // If path is non-null, we should do a forward - // Don't do a forward if exception_type is already defined though to - // avoid an infinite loop. - - if (path != null && - request.getAttribute( - Constants.ATTRIBUTE_ERROR_EXCEPTION_TYPE) == null) { - RequestDispatcher rd = contextFacade.getRequestDispatcher(path); - - // XXX - // The spec should really be changed to allow us to include - // the full exception object. Oh well. - - request.setAttribute(Constants.ATTRIBUTE_ERROR_EXCEPTION_TYPE, - t.getClass().getName()); - request.setAttribute(Constants.ATTRIBUTE_ERROR_MESSAGE, - t.getMessage()); - - try { - // A forward would be ideal, so reset and try it - - response.getRealResponse().reset(); - - if (response.getRealResponse().isStarted()) - rd.include(request, response); - else - rd.forward(request, response); - } catch (IOException e) { - e.printStackTrace(); - // Shouldn't get here - } catch (ServletException e) { - e.printStackTrace(); - // Shouldn't get here - } - } else { - try { - sendInternalServletError( t, request, response); - } catch (IOException e) { - e.printStackTrace(); - // ??? - } - } - } - - void sendInternalServletError( Throwable t, HttpServletRequestFacade request, - HttpServletResponseFacade response ) - throws IOException - { - // Used to communicate with Default Error Page - request.setAttribute("tomcat.error.throwable", t); - // XXX need to make this configurable, any servlet - // can act as the default error handler - - // Need to do a normal servlet invocation! - try { - Servlet errorP=new org.apache.tomcat.servlets.DefaultErrorPage(); - errorP.service(request,response); - } catch(Exception ex) { - System.out.println("FATAL: error in error handler"); - ex.printStackTrace(); - } - } - /** Call the init method and all init interceptors - */ - protected void handleInit(Context context, Servlet servlet, ServletConfig servletConfig ) - throws ServletException, IOException + public void handleRequest(Request req, Response res) { - ContextInterceptor cI[]=context.getContextInterceptors(); - for( int i=0; i=0; i-- ) { - try { - cI[i].postServletInit( context, this ); // ignore the error - like in the original code - } catch( TomcatException ex) { - ex.printStackTrace(); + if( ! initialized ) + loadServlet(); + + // XXX to expensive per/request, un-load is not so frequent and + // the API doesn't require a special state for destroy + // synchronized(this) { + // // logic for un-loading + // serviceCount++; + // + + RequestInterceptor cI[]=context.getRequestInterceptors(); + for( int i=0; i=0; i-- ) { - try { - cI[i].postServletDestroy( context, this ); // ignore the error - like in the original code - } catch( TomcatException ex) { - ex.printStackTrace(); + + for( int i=cI.length-1; i>=0; i-- ) { + cI[i].postService( req , res ); // ignore the error - like in the original code } - + // } finally { + // synchronized(this) { + // serviceCount--; + // notifyAll(); + // } + // } + } catch( Throwable t ) { + contextM.handleError( req, res, t, 0 ); } } - - /** Call service(), with all interceptors before and after in the - right order; - */ - protected void handleInvocation(Context ctx, Servlet servlet, - HttpServletRequestFacade request, HttpServletResponseFacade response ) - throws ServletException, IOException + /** @deprecated + */ + public void handleRequest(final HttpServletRequestFacade request, + final HttpServletResponseFacade response) { - RequestInterceptor cI[]=context.getRequestInterceptors(); - for( int i=0; i=0; i-- ) { - cI[i].postService( request.getRealRequest() , response.getRealResponse() ); // ignore the error - like in the original code - } - } + Request rrequest=request.getRealRequest(); + Response rresponse=rrequest.getResponse(); - // Fancy sync logic is to make sure that no threads are in the - // handlerequest when this is called and, furthermore, that - // no threads go through handle request after this method starts! - protected void waitForDestroy() { - // Wait until there are no outstanding service calls, - // or until 30 seconds have passed (to avoid a hang) - - // XXX wrong logic ! - while (serviceCount > 0) { - try { - wait(30000); - - break; - } catch (InterruptedException e) { } - } + handleRequest( rrequest, rresponse ); } + public String toString() { String toS="Wrapper(" + config.getServletName() + " "; if( servlet!=null ) toS=toS+ "S:" + servlet.getClass().getName(); 1.4 +38 -7 jakarta-tomcat/src/share/org/apache/tomcat/request/SecurityCheck.java Index: SecurityCheck.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/SecurityCheck.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- SecurityCheck.java 2000/02/16 00:48:45 1.3 +++ SecurityCheck.java 2000/02/17 07:52:21 1.4 @@ -81,12 +81,43 @@ public SecurityCheck() { } + public void contextInit( Context ctx) + throws TomcatException + { + if( "FORM".equals( ctx.getAuthMethod() )) { + ServletWrapper jcheck=new ServletWrapper(); + jcheck.setContext( ctx ); + jcheck.setServletClass( "org.apache.tomcat.servlets.JSecurityCheck" ); + jcheck.setServletName( "tomcat.jcheck"); + ctx.addServlet( jcheck ); + + // If you understand the spec you'll understand the code. + // I don't understand the spec enough, so I can't comment the code + + String form=ctx.getFormLoginPage(); + ctx.log( "Adding form login " + form ); + if( form!= null ) { + int lastS=form.lastIndexOf( "/" ); + if( lastS<=0 ) { + ctx.addServletMapping( "/j_security_check", "tomcat.jcheck" ); + ctx.log( "Map /j_security_check to tomcat.jcheck" ); + } else { + String dir=form.substring( 0, lastS); + ctx.addServletMapping( dir + "/j_security_check", "tomcat.jcheck"); + ctx.log( "Map " + dir + "/j_security_check to tomcat.jcheck"); + } + } + } + } + + public int authenticate( Request req, Response response ) { Context ctx=req.getContext(); if( req.getRemoteUser() != null) return 0; // already authenticated String authMethod=ctx.getAuthMethod(); + // if( ctx.getDebug() > 0 ) ctx.log( "Auth: " + authMethod ); if( authMethod==null || "BASIC".equals(authMethod) ) { String authorization = req.getHeader("Authorization"); // XXX we may have multiple headers ? @@ -101,7 +132,7 @@ String password = unencoded.substring(colon + 1); if( checkPassword( username, password ) ) { req.setRemoteUser( username ); - if( ctx.getDebug() > 0 ) ctx.log( "BASEIC Auth: " + username ); + if( ctx.getDebug() > 0 ) ctx.log( "BASIC Auth: " + username ); } else { // wrong password errorPage( req, response ); @@ -120,16 +151,16 @@ HttpSession session=req.getSession( false ); if( session == null ) return 0; // not authenticated - String username=(String)session.getAttribute( "j_username" ); - String password=(String)session.getAttribute( "j_password" ); + String username=(String)session.getAttribute("j_username"); + String password=(String)session.getAttribute("j_password"); + + if( ctx.getDebug() > 0 ) ctx.log( "Form Auth: " + username + " " + password); if( checkPassword( username, password ) ) { req.setRemoteUser( username ); - if( ctx.getDebug() > 0 ) ctx.log( "Form Auth: " + username ); } else { - // wrong password and user + // wrong password errorPage( req, response ); } - if( ctx.getDebug() > 0 ) ctx.log( "FORM auth " + username + " " + password ); } return 0; @@ -160,7 +191,7 @@ } } - if( ctx.getDebug() > 0 ) ctx.log( "Unauthorized " ); + if( ctx.getDebug() > 0 ) ctx.log( "Unauthorized " + user); return HttpServletResponse.SC_UNAUTHORIZED; // XXX check transport } 1.16 +4 -3 jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java Index: Ajp11ConnectionHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java,v retrieving revision 1.15 retrieving revision 1.16 diff -u -r1.15 -r1.16 --- Ajp11ConnectionHandler.java 2000/02/11 02:21:48 1.15 +++ Ajp11ConnectionHandler.java 2000/02/17 07:52:21 1.16 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java,v 1.15 2000/02/11 02:21:48 costin Exp $ - * $Revision: 1.15 $ - * $Date: 2000/02/11 02:21:48 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/Ajp11ConnectionHandler.java,v 1.16 2000/02/17 07:52:21 costin Exp $ + * $Revision: 1.16 $ + * $Date: 2000/02/17 07:52:21 $ * * ==================================================================== * @@ -111,6 +111,7 @@ // RequestImpl request=new RequestImpl(); AJPRequestAdapter reqA = new AJPRequestAdapter(socket); // todo: clean ConnectionHandler, make it abstract + reqA.setContextManager( contextM ); //request.setRequestAdapter( reqA ); Ajp11ResponseAdapter resA=new Ajp11ResponseAdapter(); 1.14 +1 -0 jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp12ConnectionHandler.java Index: Ajp12ConnectionHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp12ConnectionHandler.java,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- Ajp12ConnectionHandler.java 2000/02/11 02:21:48 1.13 +++ Ajp12ConnectionHandler.java 2000/02/17 07:52:22 1.14 @@ -110,6 +110,7 @@ // RequestImpl request = new RequestImpl(); AJP12RequestAdapter reqA = new AJP12RequestAdapter(contextM, socket); + reqA.setContextManager( contextM ); // ResponseImpl response=new ResponseImpl(); AJP12ResponseAdapter resA=new AJP12ResponseAdapter(); 1.7 +4 -3 jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp23ConnectionHandler.java Index: Ajp23ConnectionHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp23ConnectionHandler.java,v retrieving revision 1.6 retrieving revision 1.7 diff -u -r1.6 -r1.7 --- Ajp23ConnectionHandler.java 2000/01/15 23:30:24 1.6 +++ Ajp23ConnectionHandler.java 2000/02/17 07:52:22 1.7 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp23ConnectionHandler.java,v 1.6 2000/01/15 23:30:24 costin Exp $ - * $Revision: 1.6 $ - * $Date: 2000/01/15 23:30:24 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/Ajp23ConnectionHandler.java,v 1.7 2000/02/17 07:52:22 costin Exp $ + * $Revision: 1.7 $ + * $Date: 2000/02/17 07:52:22 $ * * ==================================================================== * @@ -108,6 +108,7 @@ ConnectorResponse rresponse=new ConnectorResponse(con); // RequestImpl rrequest=new RequestImpl(); ConnectorRequest reqA=new ConnectorRequest(con); + reqA.setContextManager( contextM ); //rrequest.setRequestAdapter( reqA ); boolean moreRequests=true; 1.2 +4 -3 jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java Index: JNIConnectionHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- JNIConnectionHandler.java 2000/02/09 12:00:53 1.1 +++ JNIConnectionHandler.java 2000/02/17 07:52:22 1.2 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java,v 1.1 2000/02/09 12:00:53 rubys Exp $ - * $Revision: 1.1 $ - * $Date: 2000/02/09 12:00:53 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/connector/JNIConnectionHandler.java,v 1.2 2000/02/17 07:52:22 costin Exp $ + * $Revision: 1.2 $ + * $Date: 2000/02/17 07:52:22 $ * * ==================================================================== * @@ -100,6 +100,7 @@ try { JNIRequestAdapter reqA = new JNIRequestAdapter(contextM, this); + reqA.setContextManager( contextM ); JNIResponseAdapter resA =new JNIResponseAdapter(this); reqA.setResponse(resA); 1.12 +4 -3 jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpConnectionHandler.java Index: HttpConnectionHandler.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpConnectionHandler.java,v retrieving revision 1.11 retrieving revision 1.12 diff -u -r1.11 -r1.12 --- HttpConnectionHandler.java 2000/01/15 23:30:26 1.11 +++ HttpConnectionHandler.java 2000/02/17 07:52:23 1.12 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpConnectionHandler.java,v 1.11 2000/01/15 23:30:26 costin Exp $ - * $Revision: 1.11 $ - * $Date: 2000/01/15 23:30:26 $ + * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/service/http/HttpConnectionHandler.java,v 1.12 2000/02/17 07:52:23 costin Exp $ + * $Revision: 1.12 $ + * $Date: 2000/02/17 07:52:23 $ * * ==================================================================== * @@ -110,6 +110,7 @@ OutputStream out=socket.getOutputStream(); // RequestImpl request=new RequestImpl(); HttpRequestAdapter reqA=new HttpRequestAdapter(); + reqA.setContextManager( contextM ); // ResponseImpl response=new ResponseImpl(); HttpResponseAdapter resA=new HttpResponseAdapter(); 1.2 +29 -1 jakarta-tomcat/src/share/org/apache/tomcat/servlets/AuthServlet.java Index: AuthServlet.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/servlets/AuthServlet.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- AuthServlet.java 2000/02/16 00:30:30 1.1 +++ AuthServlet.java 2000/02/17 07:52:24 1.2 @@ -79,10 +79,38 @@ throws ServletException, IOException { Request req=((HttpServletRequestFacade)request).getRealRequest(); + Context ctx=req.getContext(); + String realm=ctx.getRealmName(); + if( "FORM".equals( ctx.getAuthMethod() )) { + // the code is not uglier that the spec, we are just implementing it. + // if you don't understand what's here - you're not alone ! + // ( it helps to read the spec > 10 times !) - String realm=req.getContext().getRealmName(); + String page=ctx.getFormLoginPage(); + if(page!=null) { + HttpSession session=request.getSession( true ); + // Because of _stupid_ "j_security_check" we have + // to start the session ( since login page migh not do it ), + // then save the current page ( since we'll have to return here + // and the obvious solution is too ... simple, and we need to + // do something realy complex ). + + // We can't forward to the page - because we set some headers in getSession + // RequestDispatcher rd= ctx.getRequestDispatcher( page ); + // rd.include( request, response ); + + session.setAttribute( "tomcat.auth.originalLocation", req.getRequestURI()); + ctx.log("Setting orig location " + req.getRequestURI()); + if( ! page.startsWith("/")) page="/" + page; + response.sendRedirect( ctx.getPath() + page ); + return; + } + } + + // Default is BASIC if(realm==null) realm="default"; response.setHeader( "WWW-Authenticate", "Basic \"" + realm + "\""); response.sendError(HttpServletResponse.SC_UNAUTHORIZED); } + } 1.4 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/servlets/DefaultErrorPage.java Index: DefaultErrorPage.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/servlets/DefaultErrorPage.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- DefaultErrorPage.java 2000/02/16 17:13:25 1.3 +++ DefaultErrorPage.java 2000/02/17 07:52:24 1.4 @@ -92,7 +92,7 @@ int status=response.getStatus(); String msg=(String)request.getAttribute("javax.servlet.error.message"); - Throwable e= (Throwable)request.getAttribute("tomcat.error.throwable"); + Throwable e= (Throwable)request.getAttribute("tomcat.servlet.error.throwable"); if( e!=null ) { sendError(request, response, 500, exceptionString( e )); return; 1.1 jakarta-tomcat/src/share/org/apache/tomcat/servlets/JSecurityCheck.java Index: JSecurityCheck.java =================================================================== /* * ==================================================================== * * The Apache Software License, Version 1.1 * * Copyright (c) 1999 The Apache Software Foundation. All rights * reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. The end-user documentation included with the redistribution, if * any, must include the following acknowlegement: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowlegement may appear in the software itself, * if and wherever such third-party acknowlegements normally appear. * * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software * Foundation" must not be used to endorse or promote products derived * from this software without prior written permission. For written * permission, please contact apache@apache.org. * * 5. Products derived from this software may not be called "Apache" * nor may "Apache" appear in their names without prior written * permission of the Apache Group. * * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Software Foundation. For more * information on the Apache Software Foundation, please see * . * * [Additional notices, if required by prior licensing conditions] * */ package org.apache.tomcat.servlets; import org.apache.tomcat.util.*; import org.apache.tomcat.core.*; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; /** * Will authenticate the request for non-form auth * ( sort of "default form auth" ); * */ public class JSecurityCheck extends HttpServlet { public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Request req=((HttpServletRequestFacade)request).getRealRequest(); Context ctx=req.getContext(); ctx.log( "In JSecurityCheck"); HttpSession session=req.getSession( false ); if( session == null ) { ctx.log("TRY TO AUTHENTICATE WITHOUT A SESSION " + req); return; } String username=req.getFacade().getParameter( "j_username" ); String password=req.getFacade().getParameter( "j_password" ); if( ctx.getDebug() > 0 ) ctx.log( "FORM auth " + username + " " + password ); session.setAttribute( "j_username", username ); session.setAttribute( "j_password", password ); String origLocation=(String)session.getAttribute( "tomcat.auth.originalLocation"); ctx.log("Back to orig location " + origLocation); response.sendRedirect( origLocation ); } }