You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@apache.org on 2002/01/12 05:10:14 UTC

cvs commit: jakarta-tomcat-connectors/jk/java/org/apache/jk/server/tomcat40 JkConnector.java JkRequest40.java JkResponse40.java Worker40.java

costin      02/01/11 20:10:14

  Added:       jk/java/org/apache/jk/server/tomcat40 JkConnector.java
                        JkRequest40.java JkResponse40.java Worker40.java
  Log:
  Jk2-style connector for 4.0.
  
  I couldn't find any way to make it work as a servlet ( class loader is a nightmare ),
  so JkConnector must be added to server.xml and the jar files must be copied.
  
  However we do use the JkServlet and web.xml for all the config - so configuration
  will be identical and more importanly standard webapp tools ( and knowledge ) can be used.
  
  Of course, there are other options as well - server.xml settings, workers.properties
  ( I'll try this later - it would be a nice idea to jave a single file for both C and java,
  and set things like port only there ).
  
  Webapp features like reloading ( or hot update, etc ) will probably not work with
  4.0 ( probably not very usefull for most people anyway ).
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat-connectors/jk/java/org/apache/jk/server/tomcat40/JkConnector.java
  
  Index: JkConnector.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
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  package org.apache.jk.server.tomcat40;
  
  import java.io.*;
  import java.net.*;
  import java.security.*;
  import java.util.*;
  
  import org.apache.catalina.*;
  import org.apache.catalina.core.*;
  import org.apache.catalina.net.DefaultServerSocketFactory;
  import org.apache.catalina.net.ServerSocketFactory;
  import org.apache.catalina.util.LifecycleSupport;
  import org.apache.catalina.util.StringManager;
  
  import org.apache.jk.server.*;
  
  import org.apache.catalina.jk.*;
  
  /**
   * Implementation of an Jk connector.
   *
   * @author Kevin Seguin
   * @author Costin Manolache
   */
  public final class JkConnector
      implements Connector, Lifecycle {
  
      /**
       * The Container used for processing requests received by this Connector.
       */
      protected Container container = null;
      protected LifecycleSupport lifecycle = new LifecycleSupport(this);
      private boolean started = false;
      private boolean stopped = false;
      private Service service = null;
  
  
      // ------------------------------------------------------------- Properties
  
      /**
       * Return the Container used for processing requests received by this
       * Connector.
       */
      public Container getContainer() {
  	return container;
      }
  
      /**
       * Set the Container used for processing requests received by this
       * Connector.
       *
       * @param container The new Container to use
       */
      public void setContainer(Container container) {
  	this.container = container;
      }
  
  
      /**
       * Return descriptive information about this Connector implementation.
       */
      public String getInfo() {
  	return "JkConnector/2.0dev";
      }
  
      /**
       * Returns the <code>Service</code> with which we are associated.
       */
      public Service getService() {
  	return service;
      }
  
      /**
       * Set the <code>Service</code> with which we are associated.
       */
      public void setService(Service service) {
  	this.service = service;
      }
  
      // --------------------------------------------------------- Public Methods
  
      /**
       * Invoke a pre-startup initialization. This is used to allow connectors
       * to bind to restricted ports under Unix operating environments.
       * ServerSocket (we start as root and change user? or I miss something?).
       */
      public void initialize() throws LifecycleException {
      }
  
      // ------------------------------------------------------ Lifecycle Methods
  
  
      /**
       * Add a lifecycle event listener to this component.
       *
       * @param listener The listener to add
       */
      public void addLifecycleListener(LifecycleListener listener) {
  	lifecycle.addLifecycleListener(listener);
      }
  
  
      /**
       * Get the lifecycle listeners associated with this lifecycle. If this
       * Lifecycle has no listeners registered, a zero-length array is returned.
       */
      public LifecycleListener[] findLifecycleListeners() {
          return null; // FIXME: lifecycle.findLifecycleListeners();
      }
  
  
      /**
       * Remove a lifecycle event listener from this component.
       *
       * @param listener The listener to add
       */
      public void removeLifecycleListener(LifecycleListener listener) {
  	lifecycle.removeLifecycleListener(listener);
      }
  
      Properties props=new Properties();
  
      /**
       * Begin processing requests via this Connector.
       *
       * @exception LifecycleException if a fatal startup error occurs
       */
      public void start() throws LifecycleException {
          JkConfig40 config=new JkConfig40();
  	lifecycle.fireLifecycleEvent(START_EVENT, null);
          if( dL > 0 )
              d( "Start " + container + " " + service );
  
          Worker40 worker=new Worker40();
          Container ct=service.getContainer();
          worker.setContainer( ct );
  
          ((ContainerBase)ct).addLifecycleListener(config);
          config.loadExisting( ct );
  
          JkMain jkMain=new JkMain();
          jkMain.setProperties( props );
          jkMain.setDefaultWorker( worker );
  
          String catalinaHome=System.getProperty("catalina.home");
          File f=new File( catalinaHome );
          File jkHomeF=new File( f, "webapps/jk" );
          
          d("Setting jkHome " + jkHomeF );
          jkMain.setJkHome( jkHomeF.getAbsolutePath() );
                          
          try {
              jkMain.start();
          } catch( Exception ex ) {
              ex.printStackTrace();
          }
  
      }
  
  
      /**
       * Terminate processing requests via this Connector.
       *
       * @exception LifecycleException if a fatal shutdown error occurs
       */
      public void stop() throws LifecycleException {
  	lifecycle.fireLifecycleEvent(STOP_EVENT, null);
      }
  
  
      private static final int dL=10;
      private static void d(String s ) {
          System.err.println( "JkConnector: " + s );
      }
  
      // -------------------- Not used --------------------
      
      public void setConnectionTimeout(int connectionTimeout) {}
      public boolean getEnableLookups() { return false;}
      public void setEnableLookups(boolean enableLookups) {}
      public org.apache.catalina.net.ServerSocketFactory getFactory() { return null; }
      public void setFactory(org.apache.catalina.net.ServerSocketFactory s) {}
      public int getRedirectPort() { return -1; }
      public void setRedirectPort(int i ) {}
      public java.lang.String getScheme() { return null; }
      public void setScheme(java.lang.String s ) {}
      public boolean getSecure() { return false; }
      public void setSecure(boolean b) {}
      public org.apache.catalina.Request createRequest() { return null; }
      public org.apache.catalina.Response createResponse() { return null; }
      
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/java/org/apache/jk/server/tomcat40/JkRequest40.java
  
  Index: JkRequest40.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
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  package org.apache.jk.server.tomcat40;
  
  import java.io.*;
  
  import java.util.List;
  import java.util.Iterator;
  
  import javax.servlet.ServletInputStream;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.Cookie;
  
  import org.apache.catalina.connector.*;
  import org.apache.catalina.*;
  import org.apache.catalina.util.RequestUtil;
  
  import org.apache.tomcat.util.buf.MessageBytes;
  import org.apache.tomcat.util.http.Cookies;
  import org.apache.tomcat.util.http.ServerCookie;
  import org.apache.tomcat.util.http.BaseRequest;
  import org.apache.tomcat.util.http.MimeHeaders;
  
  import org.apache.jk.core.*;
  import org.apache.jk.common.*;
  
  
  public class JkRequest40 extends HttpRequestBase {
  
      private static final String match =
  	";" + Globals.SESSION_PARAMETER_NAME + "=";
  
      private static int id = 1;
      Channel ch;
      Endpoint ep;
      
      public JkRequest40() {
          super();
      }
  
      public void recycle() {
          // save response - we're a pair
          Response res=response;
          super.recycle();
          response=res;
      }
      
      public void setEndpoint( Channel ch, Endpoint ep ) {
          this.ch=ch;
          this.ep=ep;
      }
      
      void setBaseRequest(BaseRequest ajp) throws UnsupportedEncodingException {
          // XXX make this guy wrap AjpRequest so
          // we're more efficient (that's the whole point of
          // all of the MessageBytes in AjpRequest)
          setMethod(ajp.method().toString());
          setProtocol(ajp.protocol().toString());
          setRequestURI(ajp.requestURI().toString());
          setRemoteAddr(ajp.remoteAddr().toString());
          setRemoteHost(ajp.remoteHost().toString());
          setServerName(ajp.serverName().toString());
          setServerPort(ajp.getServerPort());
  
          String remoteUser = ajp.remoteUser().toString();
          if (remoteUser != null) {
              setUserPrincipal(new Ajp13Principal(remoteUser));
          }
  
          setAuthType(ajp.authType().toString());
          setQueryString(ajp.queryString().toString());
          setScheme(ajp.getScheme());
          setSecure(ajp.getSecure());
          setContentLength(ajp.getContentLength());
  
          String contentType = ajp.contentType().toString();
          if (contentType != null) {
              setContentType(contentType);
          }
  
          MimeHeaders mheaders = ajp.headers();
          int nheaders = mheaders.size();
          for (int i = 0; i < nheaders; ++i) {
              MessageBytes name = mheaders.getName(i);
              MessageBytes value = mheaders.getValue(i);
              addHeader(name.toString(), value.toString());
          }
  
          Iterator itr = ajp.getAttributeNames();
          while (itr.hasNext()) {
              String name = (String)itr.next();
              setAttribute(name, ajp.getAttribute(name));
          }
  
          addCookies(ajp.cookies());
      }
  
  //      public Object getAttribute(String name) {
  //          return ajp.getAttribute(name);
  //      }
  
  //      public Enumeration getAttributeNames() {
  //          return new Enumerator(ajp.getAttributeNames());
  //      }
  
      public void setRequestURI(String uri) {
  	int semicolon = uri.indexOf(match);
  	if (semicolon >= 0) {
  	    String rest = uri.substring(semicolon + match.length());
  	    int semicolon2 = rest.indexOf(";");
  	    if (semicolon2 >= 0) {
  		setRequestedSessionId(rest.substring(0, semicolon2));
  		rest = rest.substring(semicolon2);
  	    } else {
  		setRequestedSessionId(rest);
  		rest = "";
  	    }
  	    setRequestedSessionURL(true);
  	    uri = uri.substring(0, semicolon) + rest;
  	    if (dL > 0)
  	        d(" Requested URL session id is " +
                    ((HttpServletRequest) getRequest())
                    .getRequestedSessionId());
  	} else {
  	    setRequestedSessionId(null);
  	    setRequestedSessionURL(false);
  	}
  
          super.setRequestURI(uri);
      }
  
      private void addCookies(Cookies cookies) {
          int ncookies = cookies.getCookieCount();
          for (int j = 0; j < ncookies; j++) {
              ServerCookie scookie = cookies.getCookie(j);
              Cookie cookie = new Cookie(scookie.getName().toString(),
                                         scookie.getValue().toString());
              if (cookie.getName().equals(Globals.SESSION_COOKIE_NAME)) {
                  // Override anything requested in the URL
                  if (!isRequestedSessionIdFromCookie()) {
                                  // Accept only the first session id cookie
                      setRequestedSessionId(cookie.getValue());
                      setRequestedSessionCookie(true);
                      setRequestedSessionURL(false);
                      if (dL > 0) 
                          d(" Requested cookie session id is " +
                            ((HttpServletRequest) getRequest())
                            .getRequestedSessionId());
                  }
              }
              if (dL > 0) {
                  d(" Adding cookie " + cookie.getName() + "=" +
                    cookie.getValue());
              }
              addCookie(cookie);                    
          }        
      }
  
      public ServletInputStream createInputStream() throws IOException {
          return (ServletInputStream)getStream();
      }
  
      private static final int dL=0;
      private static void d(String s ) {
          System.err.println( "JkRequest40: " + s );
      }
  }
  
  class Ajp13Principal implements java.security.Principal {
      String user;
      
      Ajp13Principal(String user) {
          this.user = user;
      }
      public boolean equals(Object o) {
          if (o == null) {
              return false;
          } else if (!(o instanceof Ajp13Principal)) {
              return false;
          } else if (o == this) {
              return true;
          } else if (this.user == null && ((Ajp13Principal)o).user == null) {
              return true;
          } else if (user != null) {
              return user.equals( ((Ajp13Principal)o).user);
          } else {
              return false;
          }
      }
      
      public String getName() {
          return user;
      }
      
      public int hashCode() {
          if (user == null) return 0;
          else return user.hashCode();
      }
      
      public String toString() {
          return getName();
      }
  
  }
  
  class JkInputStream extends InputStream {
  
      JkInputStream() {
      }
  
      public int available() throws IOException {
          return 0;
      }
  
      public void close() throws IOException {
      }
  
      public void mark(int readLimit) {
      }
  
      public boolean markSupported() {
          return false;
      }
  
      public void reset() throws IOException {
          throw new IOException("reset() not supported");
      }
  
      byte singleRead[]=new byte[1];
      
      public int read() throws IOException {
          int rc=read( singleRead, 0, 1 );
          if( rc== 1 )
              return singleRead[0];
          return -1;
      }
  
      public int read(byte[] b, int off, int len) throws IOException {
          return -1;// ajp13.doRead(b, off, len);
      }
  
      public long skip(long n) throws IOException {
          if (n > Integer.MAX_VALUE) {
              throw new IOException("can't skip than many:  " + n);
          }
          // XXX if n is big, split this in multiple reads
          byte[] b = new byte[(int)n];
          return read(b, 0, b.length);
      }
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/java/org/apache/jk/server/tomcat40/JkResponse40.java
  
  Index: JkResponse40.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
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  package org.apache.jk.server.tomcat40;
  
  import java.io.*;
  
  import java.util.Iterator;
  
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
  
  import org.apache.catalina.connector.HttpResponseBase;
  import org.apache.catalina.*;
  import org.apache.catalina.util.CookieTools;
  
  import org.apache.jk.core.*;
  import org.apache.jk.common.*;
  import org.apache.tomcat.util.http.MimeHeaders;
  
  public class JkResponse40 extends HttpResponseBase {
  
      private boolean finished = false;
      private boolean headersSent = false;
      private MimeHeaders headers = new MimeHeaders();
      private StringBuffer cookieValue = new StringBuffer();
      Channel ch;
      Endpoint ep;
      int headersMsgNote;
      int utfC2bNote;
      
      public JkResponse40(WorkerEnv we) 
      {
  	super();
          headersMsgNote=we.getNoteId( WorkerEnv.ENDPOINT_NOTE, "headerMsg" );
          utfC2bNote=we.getNoteId( WorkerEnv.ENDPOINT_NOTE, "utfC2B" );
      }
      
      String getStatusMessage() {
          return getStatusMessage(getStatus());
      }
  
      public void recycle() {
          // We're a pair - preserve
          Request req=request;
          super.recycle();
          request=req;
          this.finished = false;
          this.headersSent = false;
          this.stream=null;
          this.headers.recycle();
      }
  
      protected void sendHeaders()  throws IOException {
          if( dL>0 ) d("sendHeaders " + headersSent);
          if (headersSent) {
              // don't send headers twice
              return;
          }
          headersSent = true;
  
          int numHeaders = 0;
  
          if (getContentType() != null) {
              numHeaders++;
  	}
          
  	if (getContentLength() >= 0) {
              numHeaders++;
  	}
  
  	// Add the session ID cookie if necessary
  	HttpServletRequest hreq = (HttpServletRequest)request.getRequest();
  	HttpSession session = hreq.getSession(false);
  
  	if ((session != null) && session.isNew() && (getContext() != null) 
              && getContext().getCookies()) {
  	    Cookie cookie = new Cookie(Globals.SESSION_COOKIE_NAME,
  				       session.getId());
  	    cookie.setMaxAge(-1);
  	    String contextPath = null;
              if (context != null)
                  contextPath = context.getPath();
  	    if ((contextPath != null) && (contextPath.length() > 0))
  		cookie.setPath(contextPath);
  	    else
  	        cookie.setPath("/");
  	    if (hreq.isSecure())
  		cookie.setSecure(true);
  	    addCookie(cookie);
  	}
  
          // Send all specified cookies (if any)
  	synchronized (cookies) {
  	    Iterator items = cookies.iterator();
  	    while (items.hasNext()) {
  		Cookie cookie = (Cookie) items.next();
  
                  cookieValue.delete(0, cookieValue.length());
                  CookieTools.getCookieHeaderValue(cookie, cookieValue);
                  
                  addHeader(CookieTools.getCookieHeaderName(cookie),
                            cookieValue.toString());
  	    }
  	}
  
          // figure out how many headers...
          // can have multiple headers of the same name...
          // need to loop through headers once to get total
          // count, once to add header to outBuf
          String[] hnames = getHeaderNames();
          Object[] hvalues = new Object[hnames.length];
  
          int i;
          for (i = 0; i < hnames.length; ++i) {
              String[] tmp = getHeaderValues(hnames[i]);
              numHeaders += tmp.length;
              hvalues[i] = tmp;
          }
  
          C2B c2b=(C2B)ep.getNote( utfC2bNote );
          if( c2b==null ) {
              c2b=new C2B(  "UTF8" );
              ep.setNote( utfC2bNote, c2b );
          }
          
          if( dL>0 ) d("sendHeaders " + numHeaders );
          MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote );
          msg.reset();
          msg.appendByte(HandlerRequest.JK_AJP13_SEND_HEADERS);
          msg.appendInt( getStatus() );
          
          c2b.convert( getStatusMessage(getStatus()));
          c2b.flushBuffer();
          msg.appendByteChunk(c2b.getByteChunk());
          c2b.recycle();
  
          String contentType=getContentType();
          int cl=getContentLength();
          
          msg.appendInt(numHeaders);
  
          if ( contentType != null) {
              sendHeader(msg, c2b, "Content-Type", contentType );
   	}
   	if ( cl >= 0) {
              sendHeader(msg, c2b, "Content-Length", String.valueOf(cl));
          }
          
          // XXX do we need this  ? If so, we need to adjust numHeaders
          // and avoid duplication
  
          for (i = 0; i < hnames.length; ++i) {
  	    String name = hnames[i];
              String[] values = (String[])hvalues[i];
              for (int j = 0; j < values.length; ++j) {
                  sendHeader( msg, c2b, name, values[j] );
              }
          }
  
          msg.send( ch, ep );
  
          // The response is now committed
          committed = true;
      }
  
      private void sendHeader( Msg msg, C2B c2b, String n, String v )
          throws IOException
      {
          if( dL > 0 ) d( "SendHeader " + n + " " + v );
          c2b.convert( n );
          c2b.flushBuffer();
          msg.appendByteChunk(c2b.getByteChunk());
          c2b.recycle();
          c2b.convert( v );
          c2b.flushBuffer();
          msg.appendByteChunk(c2b.getByteChunk());
          c2b.recycle();
      }
  
      public void finishResponse() throws IOException {
          if( dL>0 ) d("finishResponse " + this.finished ); 
  	if(!this.finished) {
  	    super.finishResponse();
              this.finished = true; // Avoid END_OF_RESPONSE sent 2 times
  
              MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote );
              msg.reset();
              msg.appendByte( HandlerRequest.JK_AJP13_END_RESPONSE );
              msg.appendInt( 1 );
              
              msg.send(ch, ep );
  	}        
      }
  
      public void write(byte b[], int off, int len ) throws IOException {
          if( dL>0 ) d("write " + len); 
          if( !headersSent ) sendHeaders();
          MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote );
          msg.reset();
          msg.appendByte( HandlerRequest.JK_AJP13_SEND_BODY_CHUNK);
          msg.appendBytes( b, off, len );
          msg.send( ch, ep );
       }
  
      void setEndpoint(Channel ch, Endpoint ep) {
          this.ch=ch;
          this.ep=ep;
          MsgAjp msg=(MsgAjp)ep.getNote( headersMsgNote );
          if( msg==null ) {
              msg=new MsgAjp();
              ep.setNote( headersMsgNote, msg );
          }
          setStream( new JkOutputStream( this ));
      }
  
      private static final int dL=10;
      private static void d(String s ) {
          System.err.println( "JkResponse40: " + s );
      }
  
  }
  
  class JkOutputStream extends OutputStream {
      JkResponse40 resp;
      
      JkOutputStream(JkResponse40 resp) {
          this.resp=resp;
      }
  
      //XXX buffer
      byte singeByteWrite[]=new byte[1];
      
      public void write(int b) throws IOException {
          singeByteWrite[0]=(byte)b;
          write(singeByteWrite, 0, 1);
      }
  
      public void write(byte[] b, int off, int len) throws IOException {
          resp.write( b, off, len );
      }
  
      public void close() throws IOException {
      }
  
      public void flush() throws IOException {
      }
  }
  
  
  
  1.1                  jakarta-tomcat-connectors/jk/java/org/apache/jk/server/tomcat40/Worker40.java
  
  Index: Worker40.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
   * <http://www.apache.org/>.
   *
   * [Additional notices, if required by prior licensing conditions]
   *
   */
  package org.apache.jk.server.tomcat40;
  
  import java.io.*;
  import java.net.*;
  import java.util.*;
  
  import org.apache.jk.*;
  import org.apache.tomcat.modules.server.PoolTcpConnector;
  
  import org.apache.tomcat.util.net.*;
  import org.apache.tomcat.util.buf.*;
  import org.apache.tomcat.util.log.*;
  import org.apache.tomcat.util.http.*;
  
  import org.apache.jk.core.*;
  
  import org.apache.catalina.*;
  
  /** Tomcat 40 worker
   *
   */
  public class Worker40 extends Worker
  {
      private int reqNote;
      Container container;
      
      public Worker40()
      {
          super();
      }
  
      public void setContainer( Container ct40 ) {
          this.container=ct40;
      }
  
      public void init(WorkerEnv we) throws IOException {
          reqNote=we.getNoteId( WorkerEnv.REQUEST_NOTE, "tomcat40Request" );
      }
      
      public void service( BaseRequest req, Channel ch, Endpoint ep )
          throws IOException
      {
          d("Incoming request " );
                  
          JkRequest40 treq=(JkRequest40)req.getNote( reqNote );
          JkResponse40  tres;
          if( treq==null ) {
              treq=new JkRequest40();
              req.setNote( reqNote, treq );
              tres=new JkResponse40(we);
              treq.setResponse( tres );
              tres.setRequest( treq );
          }
          tres=(JkResponse40)treq.getResponse();
          treq.setEndpoint( ch, ep );
          treq.setBaseRequest( req );
          tres.setEndpoint( ch, ep );
  
          try {
              container.invoke( treq, tres );
          } catch(Throwable ex ) {
              ex.printStackTrace();
          }
          d("Finishing response");
          tres.finishResponse();
          treq.finishRequest();
  
          treq.recycle();
          tres.recycle();
      }
  
      private static final int dL=0;
      private static void d(String s ) {
          System.err.println( "Worker40: " + s );
      }
  
      
      // -------------------- Handler implementation --------------------
  
  //     /** Construct the request object, with probably unnecesary
  // 	sanity tests ( should work without thread pool - but that is
  // 	not supported in PoolTcpConnector, maybe in future )
  //     */
  //     private Ajp14Request initRequest(Object thData[] ) {
  // 	if( ajp14_note < 0 ) throw new RuntimeException( "assert: ajp14_note>0" );
  // 	Ajp14Request req=null;
  // 	if( thData != null ) {
  // 	    req=(Ajp14Request)thData[0];
  // 	}
  // 	if( req != null ) {
  // 	    Response res=req.getResponse();
  // 	    req.recycle();
  // 	    res.recycle();
  // 	    // make the note available to other modules
  // 	    req.setNote( ajp14_note, req.ajp13);
  // 	    return req;
  // 	}
  // 	// either thData==null or broken ( req==null)
  //        	Ajp13 ajp13=new Ajp13(reqHandler);
  //         negHandler.init( ajp13 );
  
  // 	negHandler.setContainerSignature( ContextManager.TOMCAT_NAME +
  //                                           " v" + ContextManager.TOMCAT_VERSION);
  // 	if( password!= null ) {
  //             negHandler.setPassword( password );
  //             ajp13.setBackward(false); 
  //         }
  
  // 	BaseRequest ajpreq=new BaseRequest();
  
  // 	req=new Ajp14Request(ajp13, ajpreq);
  // 	Ajp14Response res=new Ajp14Response(ajp13);
  // 	cm.initRequest(req, res);
  // 	return  req;
  //     }
      
  //     /** Called whenever a new TCP connection is received. The connection
  // 	is reused.
  //      */
  //     public void processConnection(TcpConnection connection, Object thData[])
  //     {
  //         try {
  // 	    if( debug>0)
  // 		log( "Received ajp14 connection ");
  //             Socket socket = connection.getSocket();
  // 	    // assert: socket!=null, connection!=null ( checked by PoolTcpEndpoint )
  	    
  //             socket.setSoLinger( true, 100);
  
  //             Ajp14Request req=initRequest( thData );
  //             Ajp14Response res= (Ajp14Response)req.getResponse();
  //             Ajp13 ajp13=req.ajp13;
  // 	    BaseRequest ajpReq=req.ajpReq;
  
  //             ajp13.setSocket(socket);
  
  // 	    // first request should be the loginit.
  // 	    int status=ajp13.receiveNextRequest( ajpReq );
  // 	    if( status != 304 )  { // XXX use better codes
  // 		log( "Failure in logInit ");
  // 		return;
  // 	    }
  
  // 	    status=ajp13.receiveNextRequest( ajpReq );
  // 	    if( status != 304 ) { // XXX use better codes
  // 		log( "Failure in login ");
  // 		return;
  // 	    }
  	    
  //             boolean moreRequests = true;
  //             while(moreRequests) {
  // 		status=ajp13.receiveNextRequest( ajpReq );
  
  // 		if( status==-2) {
  // 		    // special case - shutdown
  // 		    // XXX need better communication, refactor it
  // 		    if( !doShutdown(socket.getLocalAddress(),
  // 				    socket.getInetAddress())) {
  // 			moreRequests = false;
  // 			continue;
  // 		    }                        
  // 		}
  		
  // 		if( status  == 200)
  // 		    cm.service(req, res);
  // 		else if (status == 500) {
  // 		    log( "Invalid request received " + req );
  // 		    break;
  // 		}
  		
  // 		req.recycle();
  // 		res.recycle();
  //             }
  //             if( debug > 0 ) log("Closing ajp14 connection");
  //             ajp13.close();
  // 	    socket.close();
  //         } catch (Exception e) {
  // 	    log("Processing connection " + connection, e);
  //         }
  //     }
  
  //     // We don't need to check isSameAddress if we authenticate !!!
  //     protected boolean doShutdown(InetAddress serverAddr,
  //                                  InetAddress clientAddr)
  //     {
  //         try {
  // 	    // close the socket connection before handling any signal
  // 	    // but get the addresses first so they are not corrupted			
  //             if(isSameAddress(serverAddr, clientAddr)) {
  // 		cm.stop();
  // 		// same behavior as in past, because it seems that
  // 		// stopping everything doesn't work - need to figure
  // 		// out what happens with the threads ( XXX )
  
  // 		// XXX It should work now - but will fail if servlets create
  // 		// threads
  // 		System.exit(0);
  // 	    }
  // 	} catch(Exception ignored) {
  // 	    log("Ignored " + ignored);
  // 	}
  // 	log("Shutdown command ignored");
  // 	return false;
  //     }
  
  //     // legacy, should be removed 
  //     public void setServer(Object contextM)
  //     {
  //         this.cm=(ContextManager)contextM;
  //     }
      
  
  }
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>