From 9f57be5f0317dfcb44294ab542b332e550811b5b Mon Sep 17 00:00:00 2001
From: zzz <zzz@mail.i2p>
Date: Sun, 9 Nov 2008 16:05:13 +0000
Subject: [PATCH]     * Jetty: Add a I2PRequestLog class to log request dest
 hash

---
 apps/jetty/build.xml                          |  39 +-
 .../src/org/mortbay/http/I2PRequestLog.java   | 182 +++++++
 .../src/org/mortbay/http/NCSARequestLog.java  | 505 ++++++++++++++++++
 installer/resources/jetty.xml                 |   2 +-
 4 files changed, 723 insertions(+), 5 deletions(-)
 create mode 100644 apps/jetty/java/src/org/mortbay/http/I2PRequestLog.java
 create mode 100644 apps/jetty/java/src/org/mortbay/http/NCSARequestLog.java

diff --git a/apps/jetty/build.xml b/apps/jetty/build.xml
index 49a1064d36..13d3f92e07 100644
--- a/apps/jetty/build.xml
+++ b/apps/jetty/build.xml
@@ -80,13 +80,44 @@
         <delete dir="jetty-5.1.12" />
     </target>
 
-    <target name="build" depends="ensureJettylib" />
+    <target name="build" depends="jar" />
     <target name="builddep" />
-    <target name="compile" />
-    <target name="jar" />
-    <target name="clean" />
+    <target name="compile" depends="builddep, ensureJettylib" >
+        <mkdir dir="./build" />
+        <mkdir dir="./build/obj" />
+        <javac 
+            srcdir="./java/src" 
+            debug="true" deprecation="on" source="1.5" target="1.5" 
+            destdir="./build/obj" 
+            classpath="./jettylib/commons-logging.jar:./jettylib/javax.servlet.jar:./jettylib/org.mortbay.jetty.jar" />
+    </target>
+    <target name="jar" depends="compile">
+        <jar destfile="./jettylib/org.mortbay.jetty.jar" basedir="./build/obj" includes="**/*.class" update="true" >
+        </jar>
+    </target>    
+    <target name="clean" >
+        <delete dir="./build" />
+    </target>    
     <target name="cleandep" depends="clean" />
     <target name="distclean" depends="clean">
         <echo message="Not actually deleting the jetty libs (since they're so large)" />
     </target>
+    <target name="javadoc" >
+        <available property="jetty.zip.available" file="${jetty.filename}" type="file" />
+        <available property="jetty.zip.javadocExtracted" file="build/javadoc" type="dir" />
+        <ant target="fetchJettylib" />
+        <ant target="verifyJettylib" />
+        <ant target="extractJavadoc" />
+    </target>
+    <target name="extractJavadoc" unless="jetty.zip.javadocExtracted" >
+        <mkdir dir="./build" />
+        <mkdir dir="./build/javadoc" />
+        <unzip src="${jetty.filename}" dest="./build/javadoc" >
+            <patternset>
+                <include name="jetty-5.1.12/javadoc/" />
+            </patternset>
+            <mapper type="glob" from="jetty-5.1.12/javadoc/*" to="javadoc/*" />
+        </unzip>
+    </target>
+
 </project>
diff --git a/apps/jetty/java/src/org/mortbay/http/I2PRequestLog.java b/apps/jetty/java/src/org/mortbay/http/I2PRequestLog.java
new file mode 100644
index 0000000000..4c96e49f2b
--- /dev/null
+++ b/apps/jetty/java/src/org/mortbay/http/I2PRequestLog.java
@@ -0,0 +1,182 @@
+// ========================================================================
+// $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
+// Copyright 2000-2004 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.mortbay.http;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.servlet.http.Cookie;
+
+import org.apache.commons.logging.Log;
+import org.mortbay.log.LogFactory;
+import org.mortbay.util.DateCache;
+import org.mortbay.util.LogSupport;
+import org.mortbay.util.RolloverFileOutputStream;
+import org.mortbay.util.StringUtil;
+
+
+/* ------------------------------------------------------------ */
+/** NCSA HTTP Request Log.
+ *
+ * Override log() to put in the requestor's destination hash,
+ * instead of 127.0.0.1,
+ * which is placed in the X-I2P-DestHash field in the request headers
+ * by I2PTunnelHTTPServer.
+ *
+ * NCSA common or NCSA extended (combined) request log.
+ * @version $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
+ * @author Tony Thompson
+ * @author Greg Wilkins
+ */
+public class I2PRequestLog extends NCSARequestLog
+{
+    /* ------------------------------------------------------------ */
+    /** Constructor.
+     */
+    public I2PRequestLog()
+    {
+        super();
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Constructor. 
+     * @param filename Filename, which can be in
+     * rolloverFileOutputStream format
+     * @see org.mortbay.util.RolloverFileOutputStream
+     * @exception IOException 
+     */
+    public I2PRequestLog(String filename)
+        throws IOException
+    {
+        super(filename);
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Log a request.
+     * @param request The request
+     * @param response The response to this request.
+     * @param responseLength The bytes written to the response.
+     */
+    public void log(HttpRequest request,
+                    HttpResponse response,
+                    int responseLength)
+    {
+        try{
+            // ignore ignorables
+            if (_ignorePathMap != null &&
+                _ignorePathMap.getMatch(request.getPath()) != null)
+                return;
+
+            // log the rest
+            if (_fileOut==null)
+                return;
+
+            StringBuffer buf = new StringBuffer(160);
+            
+            String addr = request.getField("X-I2P-DestHash");
+            if(addr != null)
+                buf.append(addr).append(".i2p");
+            else
+                buf.append(request.getRemoteAddr());
+            
+            buf.append(" - ");
+            String user = request.getAuthUser();
+            buf.append((user==null)?"-":user);
+            buf.append(" [");
+            buf.append(_logDateCache.format(request.getTimeStamp()));
+            buf.append("] \"");
+            buf.append(request.getMethod());
+            buf.append(' ');
+            buf.append(request.getURI());
+            buf.append(' ');
+            buf.append(request.getVersion());
+            buf.append("\" ");
+            int status=response.getStatus();    
+            buf.append((char)('0'+((status/100)%10)));
+            buf.append((char)('0'+((status/10)%10)));
+            buf.append((char)('0'+(status%10)));
+            if (responseLength>=0)
+            {
+                buf.append(' ');
+                if (responseLength>99999)
+                    buf.append(Integer.toString(responseLength));
+                else
+                {
+                    if (responseLength>9999) 
+                        buf.append((char)('0'+((responseLength/10000)%10)));
+                    if (responseLength>999) 
+                        buf.append((char)('0'+((responseLength/1000)%10)));
+                    if (responseLength>99) 
+                        buf.append((char)('0'+((responseLength/100)%10)));
+                    if (responseLength>9) 
+                        buf.append((char)('0'+((responseLength/10)%10)));
+                    buf.append((char)('0'+(responseLength%10)));
+                }
+                buf.append(' ');
+            }
+            else
+                buf.append(" - ");
+
+            String log =buf.toString();
+            synchronized(_writer)
+            {
+                _writer.write(log);
+                if (isExtended())
+                {
+                    logExtended(request,response,_writer);
+                    if (!getLogCookies())
+                        _writer.write(" -");
+                }
+                
+                if (getLogCookies())
+                {
+                    Cookie[] cookies = request.getCookies();
+                    if (cookies==null || cookies.length==0)
+                        _writer.write(" -");
+                    else
+                    {
+                        _writer.write(" \"");
+                        for (int i=0;i<cookies.length;i++)
+                        {
+                            if (i!=0)
+                                _writer.write(';');
+                            _writer.write(cookies[i].getName());
+                            _writer.write('=');
+                            _writer.write(cookies[i].getValue());
+                        }
+                        _writer.write("\"");
+                    }
+                }
+                
+                if (getLogLatency())
+                    _writer.write(" "+(System.currentTimeMillis()-request.getTimeStamp()));
+                
+                _writer.write(StringUtil.__LINE_SEPARATOR);
+                _writer.flush();
+            }
+        }
+        catch(IOException e)
+        {
+            log.warn(LogSupport.EXCEPTION,e);
+        }
+    }
+
+}
+
diff --git a/apps/jetty/java/src/org/mortbay/http/NCSARequestLog.java b/apps/jetty/java/src/org/mortbay/http/NCSARequestLog.java
new file mode 100644
index 0000000000..a898624eaa
--- /dev/null
+++ b/apps/jetty/java/src/org/mortbay/http/NCSARequestLog.java
@@ -0,0 +1,505 @@
+// ========================================================================
+// $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
+// Copyright 2000-2004 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.mortbay.http;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import javax.servlet.http.Cookie;
+
+import org.apache.commons.logging.Log;
+import org.mortbay.log.LogFactory;
+import org.mortbay.util.DateCache;
+import org.mortbay.util.LogSupport;
+import org.mortbay.util.RolloverFileOutputStream;
+import org.mortbay.util.StringUtil;
+
+
+/* ------------------------------------------------------------ */
+/** NCSA HTTP Request Log.
+ * NCSA common or NCSA extended (combined) request log.
+ *
+ * Taken from 5.1.12 source and modded to change some private vars to protected
+ * so we can extend it for I2P.
+ *
+ * @version $Id: NCSARequestLog.java,v 1.35 2005/08/13 00:01:24 gregwilkins Exp $
+ * @author Tony Thompson
+ * @author Greg Wilkins
+ */
+public class NCSARequestLog implements RequestLog
+{
+    protected static Log log = LogFactory.getLog(NCSARequestLog.class);
+
+    private String _filename;
+    private boolean _extended;
+    private boolean _append;
+    private int _retainDays;
+    private boolean _closeOut;
+    private boolean _preferProxiedForAddress;
+    private String _logDateFormat="dd/MMM/yyyy:HH:mm:ss ZZZ";
+    private Locale _logLocale=Locale.getDefault();
+    private String _logTimeZone=TimeZone.getDefault().getID();
+    private String[] _ignorePaths;
+    private boolean _logLatency=false;
+    private boolean _logCookies=false;
+    
+    protected transient OutputStream _out;
+    protected transient OutputStream _fileOut;
+    protected transient DateCache _logDateCache;
+    protected transient PathMap _ignorePathMap;
+    protected transient Writer _writer;
+    
+    /* ------------------------------------------------------------ */
+    /** Constructor.
+     */
+    public NCSARequestLog()
+    {
+        _extended=true;
+        _append=true;
+        _retainDays=31;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Constructor. 
+     * @param filename Filename, which can be in
+     * rolloverFileOutputStream format
+     * @see org.mortbay.util.RolloverFileOutputStream
+     * @exception IOException 
+     */
+    public NCSARequestLog(String filename)
+        throws IOException
+    {
+        _extended=true;
+        _append=true;
+        _retainDays=31;
+        setFilename(filename);
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Set the log filename.
+     * @see NCSARequestLog#setRetainDays(int)
+     * @param filename The filename to use. If the filename contains the
+     * string "yyyy_mm_dd", then a RolloverFileOutputStream is used and the
+     * log is rolled over nightly and aged according setRetainDays. If no
+     * filename is set or a null filename
+     * passed, then requests are logged to System.err.
+     */
+    public void setFilename(String filename)
+    {
+        if (filename!=null)
+        {
+            filename=filename.trim();
+            if (filename.length()==0)
+                filename=null;
+        }
+        _filename=filename;        
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get the log filename.
+     * @see NCSARequestLog#getDatedFilename()
+     * @return The log filename without any date expansion.
+     */
+    public String getFilename()
+    {
+        return _filename;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Get the dated log filename.
+     * @see NCSARequestLog#getFilename()
+     * @return The log filename with any date encoding expanded.
+     */
+    public String getDatedFilename()
+    {
+        if (_fileOut instanceof RolloverFileOutputStream)
+            return ((RolloverFileOutputStream)_fileOut).getDatedFilename();
+        return null;
+    }
+    
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @param format The date format to use within the log file.
+     */
+    public void setLogDateFormat(String format)
+    {
+        _logDateFormat=format;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return The date format to use within the log file.
+     */
+    public String getLogDateFormat()
+    {
+        return _logDateFormat;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @param tz The date format timezone to use within the log file.
+     */
+    public void setLogTimeZone(String tz)
+    {
+        _logTimeZone=tz;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return The date format timezone to use within the log file.
+     */
+    public String getLogTimeZone()
+    {
+        return _logTimeZone;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return The number of days to retain rollovered log files.
+     */
+    public int getRetainDays()
+    {
+        return _retainDays;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @param retainDays The number of days to retain rollovered log files.
+     */
+    public void setRetainDays(int retainDays)
+    {
+        _retainDays = retainDays;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return True if NCSA extended format is to be used.
+     */
+    public boolean isExtended()
+    {
+        return _extended;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @param e True if NCSA extended format is to be used.
+     */
+    public void setExtended(boolean e)
+    {
+        _extended=e;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** 
+     * @return True if logs are appended to existing log files.
+     */
+    public boolean isAppend()
+    {
+        return _append;
+    }
+
+    /* ------------------------------------------------------------ */
+    /** 
+     * @param a True if logs are appended to existing log files.
+     */
+    public void setAppend(boolean a)
+    {
+        _append=a;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @deprecated ignored
+     */
+    public void setBuffered(boolean b)
+    {}
+    
+    /* ------------------------------------------------------------ */
+    /** Set which paths to ignore.
+     *
+     * @param ignorePaths Array of path specifications to ignore
+     */
+    public void setIgnorePaths(String[] ignorePaths)
+    {
+        // Contributed by  Martin Vilcans (martin@jadestone.se)
+        _ignorePaths = ignorePaths;
+    }
+
+    /* ------------------------------------------------------------ */
+    public String[] getIgnorePaths()
+    {
+        return _ignorePaths;
+    }
+
+    /* ------------------------------------------------------------ */
+    /**
+     * @return Returns the logCookies.
+     */
+    public boolean getLogCookies()
+    {
+        return _logCookies;
+    }
+    /* ------------------------------------------------------------ */
+    /**
+     * @param logCookies The logCookies to set.
+     */
+    public void setLogCookies(boolean logCookies)
+    {
+        _logCookies = logCookies;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @return Returns true if logging latency
+     */
+    public boolean getLogLatency()
+    {
+        return _logLatency;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+     * @param logLatency If true, latency is logged at the end of the log line
+     */
+    public void setLogLatency(boolean logLatency)
+    {
+        _logLatency = logLatency;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /**
+    * Prefer to log the proxied-for IP address (if present in
+    * the request header) over the native requester IP address.
+    * Useful in reverse-proxy situations when you'd rather see
+    * the IP address of the host before the most recent proxy
+    * server, as opposed to your own proxy server(s) every time.
+    *
+    * jlrobins@socialserve.com, March 2004.
+    **/
+    public void setPreferProxiedForAddress(boolean value)
+    {
+       _preferProxiedForAddress = value;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void start()
+        throws Exception
+    {
+        _logDateCache=new DateCache(_logDateFormat,_logLocale);
+        _logDateCache.setTimeZoneID(_logTimeZone);
+        
+        if (_filename != null)
+        {
+            _fileOut=new RolloverFileOutputStream(_filename,_append,_retainDays);
+            _closeOut=true;
+        }
+        else
+            _fileOut=System.err;
+
+        _out=_fileOut;
+
+        if (_ignorePaths!=null && _ignorePaths.length>0)
+        {
+            _ignorePathMap=new PathMap();
+            for (int i=0;i<_ignorePaths.length;i++)
+                _ignorePathMap.put(_ignorePaths[i],_ignorePaths[i]);
+        }
+        else
+            _ignorePathMap=null;
+
+        _writer=new OutputStreamWriter(_out);
+    }
+
+    /* ------------------------------------------------------------ */
+    public boolean isStarted()
+    {
+        return _fileOut!=null;
+    }
+    
+    /* ------------------------------------------------------------ */
+    public void stop()
+    {
+        try{if (_writer!=null)_writer.flush();} catch (IOException e){LogSupport.ignore(log,e);}
+        if (_out!=null && _closeOut)
+            try{_out.close();}catch(IOException e){LogSupport.ignore(log,e);}
+        _out=null;
+        _fileOut=null;
+        _closeOut=false;
+        _logDateCache=null;
+        _writer=null;
+    }
+    
+    /* ------------------------------------------------------------ */
+    /** Log a request.
+     * @param request The request
+     * @param response The response to this request.
+     * @param responseLength The bytes written to the response.
+     */
+    public void log(HttpRequest request,
+                    HttpResponse response,
+                    int responseLength)
+    {
+        try{
+            // ignore ignorables
+            if (_ignorePathMap != null &&
+                _ignorePathMap.getMatch(request.getPath()) != null)
+                return;
+
+            // log the rest
+            if (_fileOut==null)
+                return;
+
+            StringBuffer buf = new StringBuffer(160);
+            
+            String addr = null;
+            if(_preferProxiedForAddress)
+            {
+                // If header is not present, addr will remain null ...
+                addr = request.getField(HttpFields.__XForwardedFor);
+            }
+            if(addr == null)
+                addr = request.getRemoteAddr();
+            buf.append(addr);
+            
+            buf.append(" - ");
+            String user = request.getAuthUser();
+            buf.append((user==null)?"-":user);
+            buf.append(" [");
+            buf.append(_logDateCache.format(request.getTimeStamp()));
+            buf.append("] \"");
+            buf.append(request.getMethod());
+            buf.append(' ');
+            buf.append(request.getURI());
+            buf.append(' ');
+            buf.append(request.getVersion());
+            buf.append("\" ");
+            int status=response.getStatus();    
+            buf.append((char)('0'+((status/100)%10)));
+            buf.append((char)('0'+((status/10)%10)));
+            buf.append((char)('0'+(status%10)));
+            if (responseLength>=0)
+            {
+                buf.append(' ');
+                if (responseLength>99999)
+                    buf.append(Integer.toString(responseLength));
+                else
+                {
+                    if (responseLength>9999) 
+                        buf.append((char)('0'+((responseLength/10000)%10)));
+                    if (responseLength>999) 
+                        buf.append((char)('0'+((responseLength/1000)%10)));
+                    if (responseLength>99) 
+                        buf.append((char)('0'+((responseLength/100)%10)));
+                    if (responseLength>9) 
+                        buf.append((char)('0'+((responseLength/10)%10)));
+                    buf.append((char)('0'+(responseLength%10)));
+                }
+                buf.append(' ');
+            }
+            else
+                buf.append(" - ");
+
+            String log =buf.toString();
+            synchronized(_writer)
+            {
+                _writer.write(log);
+                if (_extended)
+                {
+                    logExtended(request,response,_writer);
+                    if (!_logCookies)
+                        _writer.write(" -");
+                }
+                
+                if (_logCookies)
+                {
+                    Cookie[] cookies = request.getCookies();
+                    if (cookies==null || cookies.length==0)
+                        _writer.write(" -");
+                    else
+                    {
+                        _writer.write(" \"");
+                        for (int i=0;i<cookies.length;i++)
+                        {
+                            if (i!=0)
+                                _writer.write(';');
+                            _writer.write(cookies[i].getName());
+                            _writer.write('=');
+                            _writer.write(cookies[i].getValue());
+                        }
+                        _writer.write("\"");
+                    }
+                }
+                
+                if (_logLatency)
+                    _writer.write(" "+(System.currentTimeMillis()-request.getTimeStamp()));
+                
+                _writer.write(StringUtil.__LINE_SEPARATOR);
+                _writer.flush();
+            }
+        }
+        catch(IOException e)
+        {
+            log.warn(LogSupport.EXCEPTION,e);
+        }
+    }
+
+    /* ------------------------------------------------------------ */
+    /** Log Extended fields.
+     * This method can be extended by a derived class to add extened fields to
+     * each log entry.  It is called by the log method after all standard
+     * fields have been added, but before the line terminator.
+     * Derived implementations should write extra fields to the Writer
+     * provided.
+     * The default implementation writes the referer and user agent.
+     * @param request The request to log.
+     * @param response The response to log.
+     * @param log The writer to write the extra fields to.
+     * @exception IOException Problem writing log
+     */
+    protected void logExtended(HttpRequest request,
+                               HttpResponse response,
+                               Writer log)
+        throws IOException
+    {
+        String referer = request.getField(HttpFields.__Referer);
+        if(referer==null)
+            log.write("\"-\" ");
+        else
+        {
+            log.write('"');
+            log.write(referer);
+            log.write("\" ");
+        }
+        
+        String agent = request.getField(HttpFields.__UserAgent);
+        if(agent==null)
+            log.write("\"-\"");
+        else
+        {
+            log.write('"');
+            log.write(agent);
+            log.write('"');
+        }
+        
+
+    }
+}
+
diff --git a/installer/resources/jetty.xml b/installer/resources/jetty.xml
index b14335f4f5..038647d1cc 100644
--- a/installer/resources/jetty.xml
+++ b/installer/resources/jetty.xml
@@ -152,7 +152,7 @@
   <!-- Configure the Request Log                                       -->
   <!-- =============================================================== -->
   <Set name="RequestLog">
-    <New class="org.mortbay.http.NCSARequestLog">
+    <New class="org.mortbay.http.I2PRequestLog">
       <Arg>./eepsite/logs/yyyy_mm_dd.request.log</Arg>
       <Set name="retainDays">90</Set>
       <Set name="append">true</Set>
-- 
GitLab