forked from I2P_Developers/i2p.i2p
Console:
- Move multipart form support from susimail to jetty-i2p.jar so console can use it - Add multipart form support to formhandler.jsi and FormHandler.java Reseed: - Fix zip magic number - Finish manual reseed from local file package.html files for jetty-i2p.jar
This commit is contained in:
7
apps/jetty/java/src/net/i2p/jetty/package.html
Normal file
7
apps/jetty/java/src/net/i2p/jetty/package.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Classes for starting Jetty, logging requests, and debug logging to the I2P router log.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
206
apps/jetty/java/src/net/i2p/servlet/RequestWrapper.java
Normal file
206
apps/jetty/java/src/net/i2p/servlet/RequestWrapper.java
Normal file
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Created on Dec 8, 2004
|
||||
*
|
||||
* This file is part of susimail project, see http://susi.i2p/
|
||||
*
|
||||
* Copyright (C) 2004-2005 <susi23@mail.i2p>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* $Revision: 1.3 $
|
||||
*/
|
||||
package net.i2p.servlet;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
import org.mortbay.servlet.MultiPartRequest;
|
||||
|
||||
/**
|
||||
* Required major changes for Jetty 6
|
||||
* to support change from MultiPartRequest to MultiPartFilter.
|
||||
* See http://docs.codehaus.org/display/JETTY/File+Upload+in+jetty6
|
||||
* Unfortunately, Content-type not available until Jetty 8
|
||||
* See https://bugs.eclipse.org/bugs/show_bug.cgi?id=349110
|
||||
*
|
||||
* So we could either extend and fix MultiPartFilter, and rewrite everything here,
|
||||
* or copy MultiParRequest into our war and fix it so it compiles with Jetty 6.
|
||||
* We do the latter.
|
||||
*
|
||||
* The filter would have been added in web.xml,
|
||||
* see that file, where it's commented out.
|
||||
* Filter isn't supported until Tomcat 7 (Servlet 3.0)
|
||||
*
|
||||
* @author user
|
||||
* @since 0.9.19 moved from susimail so it may be used by routerconsole too
|
||||
*/
|
||||
public class RequestWrapper {
|
||||
|
||||
private final HttpServletRequest httpRequest;
|
||||
private final MultiPartRequest multiPartRequest;
|
||||
private final Hashtable<String, String> cache;
|
||||
private Hashtable<String, Integer> cachedParameterNames;
|
||||
|
||||
/**
|
||||
* @param httpRequest
|
||||
*/
|
||||
public RequestWrapper(HttpServletRequest httpRequest) {
|
||||
cache = new Hashtable<String, String>();
|
||||
this.httpRequest = httpRequest;
|
||||
String contentType = httpRequest.getContentType();
|
||||
MultiPartRequest mpr = null;
|
||||
if( contentType != null && contentType.toLowerCase(Locale.US).startsWith( "multipart/form-data" ) ) {
|
||||
try {
|
||||
mpr = new MultiPartRequest( httpRequest );
|
||||
} catch (IOException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
multiPartRequest = mpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param b
|
||||
*/
|
||||
public HttpSession getSession(boolean b) {
|
||||
return httpRequest.getSession( b );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param name Specific parameter key
|
||||
* @return parameter value
|
||||
*/
|
||||
public String getParameter(String name ) {
|
||||
return getParameter( name, null );
|
||||
}
|
||||
|
||||
public HttpSession getSession() {
|
||||
return httpRequest.getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return List of request parameter names
|
||||
*/
|
||||
@SuppressWarnings("unchecked") // TODO-Java6: Remove, type is correct
|
||||
public Enumeration<String> getParameterNames() {
|
||||
if( multiPartRequest != null ) {
|
||||
if( cachedParameterNames == null ) {
|
||||
cachedParameterNames = new Hashtable<String, Integer>();
|
||||
String[] partNames = multiPartRequest.getPartNames();
|
||||
for( int i = 0; i < partNames.length; i++ )
|
||||
cachedParameterNames.put( partNames[i], Integer.valueOf( i ) );
|
||||
}
|
||||
return cachedParameterNames.keys();
|
||||
}
|
||||
else
|
||||
return httpRequest.getParameterNames();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The total length of the content.
|
||||
*/
|
||||
public int getContentLength() {
|
||||
return httpRequest.getContentLength();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The content type of the request.
|
||||
*/
|
||||
public String getContentType() {
|
||||
return httpRequest.getContentType();
|
||||
}
|
||||
|
||||
public String getContentType( String partName )
|
||||
{
|
||||
String result = null;
|
||||
if( multiPartRequest != null ) {
|
||||
Hashtable<String, String> params = multiPartRequest.getParams( partName );
|
||||
for( Map.Entry<String, String> e : params.entrySet() ) {
|
||||
String key = e.getKey();
|
||||
if( key.toLowerCase(Locale.US).compareToIgnoreCase( "content-type") == 0 ) {
|
||||
String value = e.getValue();
|
||||
int i = value.indexOf( ";" );
|
||||
if( i != -1 )
|
||||
result = value.substring( 0, i );
|
||||
else
|
||||
result = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public Object getAttribute(String string) {
|
||||
return httpRequest.getAttribute( string );
|
||||
}
|
||||
|
||||
public String getParameter( String name, String defaultValue )
|
||||
{
|
||||
String result = defaultValue;
|
||||
if( multiPartRequest != null ) {
|
||||
String str = cache.get(name);
|
||||
if( str != null ) {
|
||||
result = str;
|
||||
}
|
||||
else {
|
||||
String[] partNames = multiPartRequest.getPartNames();
|
||||
for( int i = 0; i < partNames.length; i++ )
|
||||
if( partNames[i].compareToIgnoreCase( name ) == 0 ) {
|
||||
str = multiPartRequest.getString( partNames[i] );
|
||||
if( str != null ) {
|
||||
result = str;
|
||||
cache.put( name, result );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
String str = httpRequest.getParameter( name );
|
||||
if( str != null )
|
||||
result = str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public String getFilename(String partName )
|
||||
{
|
||||
String result = null;
|
||||
if( multiPartRequest != null ) {
|
||||
String str = multiPartRequest.getFilename( partName );
|
||||
if( str != null )
|
||||
result = str;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public InputStream getInputStream(String partName )
|
||||
{
|
||||
InputStream result = null;
|
||||
if( multiPartRequest != null ) {
|
||||
result = multiPartRequest.getInputStream( partName );
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
7
apps/jetty/java/src/net/i2p/servlet/filters/package.html
Normal file
7
apps/jetty/java/src/net/i2p/servlet/filters/package.html
Normal file
@@ -0,0 +1,7 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
XSS filter, since 0.9.14.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
11
apps/jetty/java/src/net/i2p/servlet/package.html
Normal file
11
apps/jetty/java/src/net/i2p/servlet/package.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
RequestWrapper was a susimail class,
|
||||
moved from susimail to jetty-i2p.jar when we needed them in the router console also.
|
||||
As of 0.9.19.
|
||||
Requires org.mortbay classes also in this jar.
|
||||
Will be maintained as a public API until we move to Tomcat 7 (servlet 3.0).
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
446
apps/jetty/java/src/org/mortbay/servlet/MultiPartRequest.java
Normal file
446
apps/jetty/java/src/org/mortbay/servlet/MultiPartRequest.java
Normal file
@@ -0,0 +1,446 @@
|
||||
// ========================================================================
|
||||
// $Id: MultiPartRequest.java,v 1.16 2005/12/02 20:13:52 gregwilkins Exp $
|
||||
// Copyright 1996-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.servlet;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.util.Hashtable;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
//import org.apache.commons.logging.Log;
|
||||
//import org.mortbay.log.LogFactory;
|
||||
//import org.eclipse.jetty.util.MultiMap;
|
||||
import org.mortbay.util.MultiMap;
|
||||
import org.mortbay.util.LineInput;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Multipart Form Data request.
|
||||
* <p>
|
||||
* This class decodes the multipart/form-data stream sent by
|
||||
* a HTML form that uses a file input item.
|
||||
*
|
||||
* <p><h4>Usage</h4>
|
||||
* Each part of the form data is named from the HTML form and
|
||||
* is available either via getString(name) or getInputStream(name).
|
||||
* Furthermore the MIME parameters and filename can be requested for
|
||||
* each part.
|
||||
* <pre>
|
||||
* </pre>
|
||||
*
|
||||
* Modded to compile with Jetty 6 for I2P
|
||||
*
|
||||
* @version $Id: MultiPartRequest.java,v 1.16 2005/12/02 20:13:52 gregwilkins Exp $
|
||||
* @author Greg Wilkins
|
||||
* @author Jim Crossley
|
||||
*/
|
||||
public class MultiPartRequest
|
||||
{
|
||||
//private static Log log = LogFactory.getLog(MultiPartRequest.class);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
HttpServletRequest _request;
|
||||
LineInput _in;
|
||||
String _boundary;
|
||||
String _encoding;
|
||||
byte[] _byteBoundary;
|
||||
MultiMap<String> _partMap = new MultiMap<String>(10);
|
||||
int _char=-2;
|
||||
boolean _lastPart=false;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param request The request containing a multipart/form-data
|
||||
* request
|
||||
* @exception IOException IOException
|
||||
*/
|
||||
public MultiPartRequest(HttpServletRequest request)
|
||||
throws IOException
|
||||
{
|
||||
_request=request;
|
||||
String content_type = request.getHeader("Content-Type");
|
||||
if (!content_type.startsWith("multipart/form-data"))
|
||||
throw new IOException("Not multipart/form-data request");
|
||||
|
||||
//if(log.isDebugEnabled())log.debug("Multipart content type = "+content_type);
|
||||
_encoding = request.getCharacterEncoding();
|
||||
if (_encoding != null)
|
||||
_in = new LineInput(request.getInputStream(), 2048, _encoding);
|
||||
else
|
||||
_in = new LineInput(request.getInputStream());
|
||||
|
||||
// Extract boundary string
|
||||
_boundary="--"+
|
||||
value(content_type.substring(content_type.indexOf("boundary=")));
|
||||
|
||||
//if(log.isDebugEnabled())log.debug("Boundary="+_boundary);
|
||||
_byteBoundary= (_boundary+"--").getBytes("UTF-8");
|
||||
|
||||
loadAllParts();
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the part names.
|
||||
* @return an array of part names
|
||||
*/
|
||||
public String[] getPartNames()
|
||||
{
|
||||
Set<String> s = _partMap.keySet();
|
||||
return s.toArray(new String[s.size()]);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Check if a named part is present
|
||||
* @param name The part
|
||||
* @return true if it was included
|
||||
*/
|
||||
public boolean contains(String name)
|
||||
{
|
||||
Part part = (Part)_partMap.get(name);
|
||||
return (part!=null);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the data of a part as a string.
|
||||
* @param name The part name
|
||||
* @return The part data
|
||||
*/
|
||||
public String getString(String name)
|
||||
{
|
||||
List<Object> part = _partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
if (_encoding != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new String(((Part)part.get(0))._data, _encoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException uee)
|
||||
{
|
||||
//if (log.isDebugEnabled())log.debug("Invalid character set: " + uee);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
return new String(((Part)part.get(0))._data);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/**
|
||||
* @param name The part name
|
||||
* @return The parts data
|
||||
*/
|
||||
public String[] getStrings(String name)
|
||||
{
|
||||
List<Object> parts = _partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
String[] strings = new String[parts.size()];
|
||||
|
||||
if (_encoding == null)
|
||||
{
|
||||
for (int i=0; i<strings.length; i++)
|
||||
strings[i] = new String(((Part)parts.get(i))._data);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
for (int i=0; i<strings.length; i++)
|
||||
strings[i] = new String(((Part)parts.get(i))._data, _encoding);
|
||||
}
|
||||
catch (UnsupportedEncodingException uee)
|
||||
{
|
||||
//if (log.isDebugEnabled())log.debug("Invalid character set: " + uee);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return strings;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the data of a part as a stream.
|
||||
* @param name The part name
|
||||
* @return Stream providing the part data
|
||||
*/
|
||||
public InputStream getInputStream(String name)
|
||||
{
|
||||
List<Object> part = _partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
return new ByteArrayInputStream(((Part)part.get(0))._data);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public InputStream[] getInputStreams(String name)
|
||||
{
|
||||
List<Object> parts = _partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
InputStream[] streams = new InputStream[parts.size()];
|
||||
for (int i=0; i<streams.length; i++) {
|
||||
streams[i] = new ByteArrayInputStream(((Part)parts.get(i))._data);
|
||||
}
|
||||
return streams;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the MIME parameters associated with a part.
|
||||
* @param name The part name
|
||||
* @return Hashtable of parameters
|
||||
*/
|
||||
public Hashtable<String, String> getParams(String name)
|
||||
{
|
||||
List<Object> part = _partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
return ((Part)part.get(0))._headers;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public Hashtable[] getMultipleParams(String name)
|
||||
{
|
||||
List<Object> parts = _partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
Hashtable[] params = new Hashtable[parts.size()];
|
||||
for (int i=0; i<params.length; i++) {
|
||||
params[i] = ((Part)parts.get(i))._headers;
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get any file name associated with a part.
|
||||
* @param name The part name
|
||||
* @return The filename
|
||||
*/
|
||||
public String getFilename(String name)
|
||||
{
|
||||
List<Object> part = _partMap.getValues(name);
|
||||
if (part==null)
|
||||
return null;
|
||||
return ((Part)part.get(0))._filename;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public String[] getFilenames(String name)
|
||||
{
|
||||
List<Object> parts = _partMap.getValues(name);
|
||||
if (parts==null)
|
||||
return null;
|
||||
String[] filenames = new String[parts.size()];
|
||||
for (int i=0; i<filenames.length; i++) {
|
||||
filenames[i] = ((Part)parts.get(i))._filename;
|
||||
}
|
||||
return filenames;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void loadAllParts()
|
||||
throws IOException
|
||||
{
|
||||
// Get first boundary
|
||||
String line = _in.readLine();
|
||||
if (line == null || !line.equals(_boundary))
|
||||
{
|
||||
//log.warn(line);
|
||||
throw new IOException("Missing initial multi part boundary");
|
||||
}
|
||||
|
||||
// Read each part
|
||||
while (!_lastPart)
|
||||
{
|
||||
// Read Part headers
|
||||
Part part = new Part();
|
||||
|
||||
String content_disposition=null;
|
||||
while ((line=_in.readLine())!=null)
|
||||
{
|
||||
// If blank line, end of part headers
|
||||
if (line.length()==0)
|
||||
break;
|
||||
|
||||
//if(log.isDebugEnabled())log.debug("LINE="+line);
|
||||
|
||||
// place part header key and value in map
|
||||
int c = line.indexOf(':',0);
|
||||
if (c>0)
|
||||
{
|
||||
String key = line.substring(0,c).trim().toLowerCase();
|
||||
String value = line.substring(c+1,line.length()).trim();
|
||||
String ev = part._headers.get(key);
|
||||
part._headers.put(key,(ev!=null)?(ev+';'+value):value);
|
||||
//if(log.isDebugEnabled())log.debug(key+": "+value);
|
||||
if (key.equals("content-disposition"))
|
||||
content_disposition=value;
|
||||
}
|
||||
}
|
||||
|
||||
// Extract content-disposition
|
||||
boolean form_data=false;
|
||||
if (content_disposition==null)
|
||||
{
|
||||
throw new IOException("Missing content-disposition");
|
||||
}
|
||||
|
||||
StringTokenizer tok =
|
||||
new StringTokenizer(content_disposition,";");
|
||||
while (tok.hasMoreTokens())
|
||||
{
|
||||
String t = tok.nextToken().trim();
|
||||
String tl = t.toLowerCase();
|
||||
if (t.startsWith("form-data"))
|
||||
form_data=true;
|
||||
else if (tl.startsWith("name="))
|
||||
part._name=value(t);
|
||||
else if (tl.startsWith("filename="))
|
||||
part._filename=value(t);
|
||||
}
|
||||
|
||||
// Check disposition
|
||||
if (!form_data)
|
||||
{
|
||||
//log.warn("Non form-data part in multipart/form-data");
|
||||
continue;
|
||||
}
|
||||
if (part._name==null || part._name.length()==0)
|
||||
{
|
||||
//log.warn("Part with no name in multipart/form-data");
|
||||
continue;
|
||||
}
|
||||
//if(log.isDebugEnabled())log.debug("name="+part._name);
|
||||
//if(log.isDebugEnabled())log.debug("filename="+part._filename);
|
||||
_partMap.add(part._name,part);
|
||||
part._data=readBytes();
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private byte[] readBytes()
|
||||
throws IOException
|
||||
{
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
|
||||
int c;
|
||||
boolean cr=false;
|
||||
boolean lf=false;
|
||||
|
||||
// loop for all lines`
|
||||
while (true)
|
||||
{
|
||||
int b=0;
|
||||
while ((c=(_char!=-2)?_char:_in.read())!=-1)
|
||||
{
|
||||
_char=-2;
|
||||
|
||||
// look for CR and/or LF
|
||||
if (c==13 || c==10)
|
||||
{
|
||||
if (c==13) _char=_in.read();
|
||||
break;
|
||||
}
|
||||
|
||||
// look for boundary
|
||||
if (b>=0 && b<_byteBoundary.length && c==_byteBoundary[b])
|
||||
b++;
|
||||
else
|
||||
{
|
||||
// this is not a boundary
|
||||
if (cr) baos.write(13);
|
||||
if (lf) baos.write(10);
|
||||
cr=lf=false;
|
||||
|
||||
if (b>0)
|
||||
baos.write(_byteBoundary,0,b);
|
||||
b=-1;
|
||||
|
||||
baos.write(c);
|
||||
}
|
||||
}
|
||||
|
||||
// check partial boundary
|
||||
if ((b>0 && b<_byteBoundary.length-2) ||
|
||||
(b==_byteBoundary.length-1))
|
||||
{
|
||||
if (cr) baos.write(13);
|
||||
if (lf) baos.write(10);
|
||||
cr=lf=false;
|
||||
baos.write(_byteBoundary,0,b);
|
||||
b=-1;
|
||||
}
|
||||
|
||||
// boundary match
|
||||
if (b>0 || c==-1)
|
||||
{
|
||||
if (b==_byteBoundary.length)
|
||||
_lastPart=true;
|
||||
if (_char==10) _char=-2;
|
||||
break;
|
||||
}
|
||||
|
||||
// handle CR LF
|
||||
if (cr) baos.write(13);
|
||||
if (lf) baos.write(10);
|
||||
cr=(c==13);
|
||||
lf=(c==10 || _char==10);
|
||||
if (_char==10) _char=-2;
|
||||
}
|
||||
//if(log.isTraceEnabled())log.trace(baos.toString());
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private String value(String nameEqualsValue)
|
||||
{
|
||||
String value =
|
||||
nameEqualsValue.substring(nameEqualsValue.indexOf('=')+1).trim();
|
||||
|
||||
int i=value.indexOf(';');
|
||||
if (i>0)
|
||||
value=value.substring(0,i);
|
||||
if (value.startsWith("\""))
|
||||
{
|
||||
value=value.substring(1,value.indexOf('"',1));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
i=value.indexOf(' ');
|
||||
if (i>0)
|
||||
value=value.substring(0,i);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static class Part
|
||||
{
|
||||
String _name;
|
||||
String _filename;
|
||||
Hashtable<String, String> _headers= new Hashtable<String, String>(10);
|
||||
byte[] _data;
|
||||
}
|
||||
};
|
11
apps/jetty/java/src/org/mortbay/servlet/package.html
Normal file
11
apps/jetty/java/src/org/mortbay/servlet/package.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Old Jetty 5 classes for multipart form requests, moved to susimail and modded when we moved to Jetty 6,
|
||||
then moved from susimail to jetty-i2p.jar when we needed them in the router console also.
|
||||
As of 0.9.19.
|
||||
Not a public API, not for direct use.
|
||||
These are requirements for net.i2p.servlet.RequestWrapper.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
113
apps/jetty/java/src/org/mortbay/util/ByteArrayPool.java
Normal file
113
apps/jetty/java/src/org/mortbay/util/ByteArrayPool.java
Normal file
@@ -0,0 +1,113 @@
|
||||
// ========================================================================
|
||||
// $Id: ByteArrayPool.java,v 1.9 2004/05/09 20:32:49 gregwilkins Exp $
|
||||
// Copyright 2002-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.util;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Byte Array Pool
|
||||
* Simple pool for recycling byte arrays of a fixed size.
|
||||
*
|
||||
* @version $Id: ByteArrayPool.java,v 1.9 2004/05/09 20:32:49 gregwilkins Exp $
|
||||
* @author Greg Wilkins (gregw)
|
||||
*/
|
||||
public class ByteArrayPool
|
||||
{
|
||||
public static final int __POOL_SIZE=
|
||||
Integer.getInteger("org.mortbay.util.ByteArrayPool.pool_size",8).intValue();
|
||||
|
||||
public static final ThreadLocal __pools=new BAThreadLocal();
|
||||
public static final AtomicInteger __slot = new AtomicInteger();
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get a byte array from the pool of known size.
|
||||
* @param size Size of the byte array.
|
||||
* @return Byte array of known size.
|
||||
*/
|
||||
public static byte[] getByteArray(int size)
|
||||
{
|
||||
byte[][] pool = (byte[][])__pools.get();
|
||||
boolean full=true;
|
||||
for (int i=pool.length;i-->0;)
|
||||
{
|
||||
if (pool[i]!=null && pool[i].length==size)
|
||||
{
|
||||
byte[]b = pool[i];
|
||||
pool[i]=null;
|
||||
return b;
|
||||
}
|
||||
else
|
||||
full=false;
|
||||
}
|
||||
|
||||
if (full)
|
||||
for (int i=pool.length;i-->0;)
|
||||
pool[i]=null;
|
||||
|
||||
return new byte[size];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static byte[] getByteArrayAtLeast(int minSize)
|
||||
{
|
||||
byte[][] pool = (byte[][])__pools.get();
|
||||
for (int i=pool.length;i-->0;)
|
||||
{
|
||||
if (pool[i]!=null && pool[i].length>=minSize)
|
||||
{
|
||||
byte[]b = pool[i];
|
||||
pool[i]=null;
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
return new byte[minSize];
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public static void returnByteArray(final byte[] b)
|
||||
{
|
||||
if (b==null)
|
||||
return;
|
||||
|
||||
byte[][] pool = (byte[][])__pools.get();
|
||||
for (int i=pool.length;i-->0;)
|
||||
{
|
||||
if (pool[i]==null)
|
||||
{
|
||||
pool[i]=b;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// slot.
|
||||
int s = __slot.getAndIncrement();
|
||||
if (s<0)s=-s;
|
||||
pool[s%pool.length]=b;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/* ------------------------------------------------------------ */
|
||||
private static final class BAThreadLocal extends ThreadLocal
|
||||
{
|
||||
protected Object initialValue()
|
||||
{
|
||||
return new byte[__POOL_SIZE][];
|
||||
}
|
||||
}
|
||||
}
|
719
apps/jetty/java/src/org/mortbay/util/LineInput.java
Normal file
719
apps/jetty/java/src/org/mortbay/util/LineInput.java
Normal file
@@ -0,0 +1,719 @@
|
||||
// ========================================================================
|
||||
// $Id: LineInput.java,v 1.17 2005/10/05 11:32:40 gregwilkins Exp $
|
||||
// Copyright 1996-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.util;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
//import org.apache.commons.logging.Log;
|
||||
//import org.mortbay.log.LogFactory;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Fast LineInput InputStream.
|
||||
* This buffered InputStream provides methods for reading lines
|
||||
* of bytes. The lines can be converted to String or character
|
||||
* arrays either using the default encoding or a user supplied
|
||||
* encoding.
|
||||
*
|
||||
* Buffering and data copying are highly optimized, making this
|
||||
* an ideal class for protocols that mix character encoding lines
|
||||
* with arbitrary byte data (eg HTTP).
|
||||
*
|
||||
* The buffer size is also the maximum line length in bytes and/or
|
||||
* characters. If the byte length of a line is less than the max,
|
||||
* but the character length is greater, than then trailing characters
|
||||
* are lost.
|
||||
*
|
||||
* Line termination is forgiving and accepts CR, LF, CRLF or EOF.
|
||||
* Line input uses the mark/reset mechanism, so any marks set
|
||||
* prior to a readLine call are lost.
|
||||
*
|
||||
* @version $Id: LineInput.java,v 1.17 2005/10/05 11:32:40 gregwilkins Exp $
|
||||
* @author Greg Wilkins (gregw)
|
||||
*/
|
||||
public class LineInput extends FilterInputStream
|
||||
{
|
||||
//private static Log log = LogFactory.getLog(LineInput.class);
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private byte _buf[];
|
||||
private ByteBuffer _byteBuffer;
|
||||
private InputStreamReader _reader;
|
||||
private int _mark=-1; // reset marker
|
||||
private int _pos; // Start marker
|
||||
private int _avail; // Available back marker, may be byte limited
|
||||
private int _contents; // Absolute back marker of buffer
|
||||
private int _byteLimit=-1;
|
||||
private boolean _newByteLimit;
|
||||
private LineBuffer _lineBuffer;
|
||||
private String _encoding;
|
||||
private boolean _eof=false;
|
||||
private boolean _lastCr=false;
|
||||
private boolean _seenCrLf=false;
|
||||
|
||||
private final static int LF=10;
|
||||
private final static int CR=13;
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* Default buffer and maximum line size is 2048.
|
||||
* @param in The underlying input stream.
|
||||
*/
|
||||
public LineInput(InputStream in)
|
||||
{
|
||||
this(in,0);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param in The underlying input stream.
|
||||
* @param bufferSize The buffer size and maximum line length.
|
||||
*/
|
||||
public LineInput(InputStream in, int bufferSize)
|
||||
{
|
||||
super(in);
|
||||
_mark=-1;
|
||||
if (bufferSize==0)
|
||||
bufferSize=8192;
|
||||
_buf=ByteArrayPool.getByteArray(bufferSize);
|
||||
_byteBuffer=new ByteBuffer(_buf);
|
||||
_lineBuffer=new LineBuffer(bufferSize);
|
||||
|
||||
try
|
||||
{
|
||||
_reader=new InputStreamReader(_byteBuffer,"UTF-8");
|
||||
}
|
||||
catch (UnsupportedEncodingException e)
|
||||
{
|
||||
_reader=new InputStreamReader(_byteBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Constructor.
|
||||
* @param in The underlying input stream.
|
||||
* @param bufferSize The buffer size and maximum line length.
|
||||
* @param encoding the character encoding to use for readLine methods.
|
||||
* @exception UnsupportedEncodingException
|
||||
*/
|
||||
public LineInput(InputStream in, int bufferSize, String encoding)
|
||||
throws UnsupportedEncodingException
|
||||
{
|
||||
super(in);
|
||||
_mark=-1;
|
||||
if (bufferSize==0)
|
||||
bufferSize=2048;
|
||||
_buf=ByteArrayPool.getByteArray(bufferSize);
|
||||
_byteBuffer=new ByteBuffer(_buf);
|
||||
_lineBuffer=new LineBuffer(bufferSize);
|
||||
_reader=new InputStreamReader(_byteBuffer,encoding);
|
||||
_encoding=encoding;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public InputStream getInputStream()
|
||||
{
|
||||
return in;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Set the byte limit.
|
||||
* If set, only this number of bytes are read before EOF.
|
||||
* @param bytes Limit number of bytes, or -1 for no limit.
|
||||
*/
|
||||
public void setByteLimit(int bytes)
|
||||
{
|
||||
_byteLimit=bytes;
|
||||
|
||||
if (bytes>=0)
|
||||
{
|
||||
_newByteLimit=true;
|
||||
_byteLimit-=_contents-_pos;
|
||||
if (_byteLimit<0)
|
||||
{
|
||||
_avail+=_byteLimit;
|
||||
_byteLimit=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_newByteLimit=false;
|
||||
_avail=_contents;
|
||||
_eof=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Get the byte limit.
|
||||
* @return Number of bytes until EOF is returned or -1 for no limit.
|
||||
*/
|
||||
public int getByteLimit()
|
||||
{
|
||||
if (_byteLimit<0)
|
||||
return _byteLimit;
|
||||
|
||||
return _byteLimit+_avail-_pos;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Read a line ended by CR, LF or CRLF.
|
||||
* The default or supplied encoding is used to convert bytes to
|
||||
* characters.
|
||||
* @return The line as a String or null for EOF.
|
||||
* @exception IOException
|
||||
*/
|
||||
public synchronized String readLine()
|
||||
throws IOException
|
||||
{
|
||||
int len=fillLine(_buf.length);
|
||||
|
||||
if (len<0)
|
||||
return null;
|
||||
|
||||
String s=null;
|
||||
if (_encoding==null)
|
||||
s=new String(_buf,_mark,len);
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
s=new String(_buf,_mark,len,_encoding);
|
||||
}
|
||||
catch(UnsupportedEncodingException e)
|
||||
{
|
||||
//log.warn(LogSupport.EXCEPTION,e);
|
||||
}
|
||||
}
|
||||
_mark=-1;
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Read a line ended by CR, LF or CRLF.
|
||||
* The default or supplied encoding is used to convert bytes to
|
||||
* characters.
|
||||
* @param c Character buffer to place the line into.
|
||||
* @param off Offset into the buffer.
|
||||
* @param len Maximum length of line.
|
||||
* @return The length of the line or -1 for EOF.
|
||||
* @exception IOException
|
||||
*/
|
||||
public int readLine(char[] c,int off,int len)
|
||||
throws IOException
|
||||
{
|
||||
int blen=fillLine(len);
|
||||
|
||||
if (blen<0)
|
||||
return -1;
|
||||
if (blen==0)
|
||||
return 0;
|
||||
|
||||
_byteBuffer.setStream(_mark,blen);
|
||||
|
||||
int read=0;
|
||||
while(read<len && _reader.ready())
|
||||
{
|
||||
int r = _reader.read(c,off+read,len-read);
|
||||
if (r<=0)
|
||||
break;
|
||||
read+=r;
|
||||
}
|
||||
|
||||
_mark=-1;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Read a line ended by CR, LF or CRLF.
|
||||
* @param b Byte array to place the line into.
|
||||
* @param off Offset into the buffer.
|
||||
* @param len Maximum length of line.
|
||||
* @return The length of the line or -1 for EOF.
|
||||
* @exception IOException
|
||||
*/
|
||||
public int readLine(byte[] b,int off,int len)
|
||||
throws IOException
|
||||
{
|
||||
len=fillLine(len);
|
||||
|
||||
if (len<0)
|
||||
return -1;
|
||||
if (len==0)
|
||||
return 0;
|
||||
|
||||
System.arraycopy(_buf,_mark, b, off, len);
|
||||
_mark=-1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Read a Line ended by CR, LF or CRLF.
|
||||
* Read a line into a shared LineBuffer instance. The LineBuffer is
|
||||
* resused between calls and should not be held by the caller.
|
||||
* The default or supplied encoding is used to convert bytes to
|
||||
* characters.
|
||||
* @return LineBuffer instance or null for EOF.
|
||||
* @exception IOException
|
||||
*/
|
||||
public LineBuffer readLineBuffer()
|
||||
throws IOException
|
||||
{
|
||||
return readLineBuffer(_buf.length);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Read a Line ended by CR, LF or CRLF.
|
||||
* Read a line into a shared LineBuffer instance. The LineBuffer is
|
||||
* resused between calls and should not be held by the caller.
|
||||
* The default or supplied encoding is used to convert bytes to
|
||||
* characters.
|
||||
* @param len Maximum length of a line, or 0 for default
|
||||
* @return LineBuffer instance or null for EOF.
|
||||
* @exception IOException
|
||||
*/
|
||||
public LineBuffer readLineBuffer(int len)
|
||||
throws IOException
|
||||
{
|
||||
len=fillLine(len>0?len:_buf.length);
|
||||
|
||||
if (len<0)
|
||||
return null;
|
||||
|
||||
if (len==0)
|
||||
{
|
||||
_lineBuffer.size=0;
|
||||
return _lineBuffer;
|
||||
}
|
||||
|
||||
_byteBuffer.setStream(_mark,len);
|
||||
|
||||
_lineBuffer.size=0;
|
||||
int read=0;
|
||||
while(read<len && _reader.ready())
|
||||
{
|
||||
int r = _reader.read(_lineBuffer.buffer,
|
||||
read,
|
||||
len-read);
|
||||
if (r<=0)
|
||||
break;
|
||||
read+=r;
|
||||
}
|
||||
_lineBuffer.size=read;
|
||||
_mark=-1;
|
||||
|
||||
return _lineBuffer;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized int read() throws IOException
|
||||
{
|
||||
int b;
|
||||
if (_pos >=_avail)
|
||||
fill();
|
||||
if (_pos >=_avail)
|
||||
b=-1;
|
||||
else
|
||||
b=_buf[_pos++]&255;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized int read(byte b[], int off, int len) throws IOException
|
||||
{
|
||||
int avail=_avail-_pos;
|
||||
if (avail <=0)
|
||||
{
|
||||
fill();
|
||||
avail=_avail-_pos;
|
||||
}
|
||||
|
||||
if (avail <=0)
|
||||
len=-1;
|
||||
else
|
||||
{
|
||||
len=(avail < len) ? avail : len;
|
||||
System.arraycopy(_buf,_pos,b,off,len);
|
||||
_pos +=len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public long skip(long n) throws IOException
|
||||
{
|
||||
int avail=_avail-_pos;
|
||||
if (avail <=0)
|
||||
{
|
||||
fill();
|
||||
avail=_avail-_pos;
|
||||
}
|
||||
|
||||
if (avail <=0)
|
||||
n=0;
|
||||
else
|
||||
{
|
||||
n=(avail < n) ? avail : n;
|
||||
_pos +=n;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized int available()
|
||||
throws IOException
|
||||
{
|
||||
int in_stream=in.available();
|
||||
if (_byteLimit>=0 && in_stream>_byteLimit)
|
||||
in_stream=_byteLimit;
|
||||
|
||||
return _avail - _pos + in_stream;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized void mark(int limit)
|
||||
throws IllegalArgumentException
|
||||
{
|
||||
if (limit>_buf.length)
|
||||
{
|
||||
byte[] new_buf=new byte[limit];
|
||||
System.arraycopy(_buf,_pos,new_buf,_pos,_avail-_pos);
|
||||
_buf=new_buf;
|
||||
if (_byteBuffer!=null)
|
||||
_byteBuffer.setBuffer(_buf);
|
||||
}
|
||||
_mark=_pos;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public synchronized void reset()
|
||||
throws IOException
|
||||
{
|
||||
if (_mark < 0)
|
||||
throw new IOException("Resetting to invalid mark");
|
||||
_pos=_mark;
|
||||
_mark=-1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public boolean markSupported()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private void fill()
|
||||
throws IOException
|
||||
{
|
||||
// if the mark is in the middle of the buffer
|
||||
if (_mark > 0)
|
||||
{
|
||||
// moved saved bytes to start of buffer
|
||||
int saved=_contents - _mark;
|
||||
System.arraycopy(_buf, _mark, _buf, 0, saved);
|
||||
_pos-=_mark;
|
||||
_avail-=_mark;
|
||||
_contents=saved;
|
||||
_mark=0;
|
||||
}
|
||||
else if (_mark<0 && _pos>0)
|
||||
{
|
||||
// move remaining bytes to start of buffer
|
||||
int saved=_contents-_pos;
|
||||
System.arraycopy(_buf,_pos, _buf, 0, saved);
|
||||
_avail-=_pos;
|
||||
_contents=saved;
|
||||
_pos=0;
|
||||
}
|
||||
else if (_mark==0 && _pos>0 && _contents==_buf.length)
|
||||
{
|
||||
// Discard the mark as we need the space.
|
||||
_mark=-1;
|
||||
fill();
|
||||
return;
|
||||
}
|
||||
|
||||
// Get ready to top up the buffer
|
||||
int n=0;
|
||||
_eof=false;
|
||||
|
||||
// Handle byte limited EOF
|
||||
if (_byteLimit==0)
|
||||
_eof=true;
|
||||
// else loop until something is read.
|
||||
else while (!_eof && n==0 && _buf.length>_contents)
|
||||
{
|
||||
// try to read as much as will fit.
|
||||
int space=_buf.length-_contents;
|
||||
|
||||
n=in.read(_buf,_contents,space);
|
||||
|
||||
if (n<=0)
|
||||
{
|
||||
// If no bytes - we could be NBIO, so we want to avoid
|
||||
// a busy loop.
|
||||
if (n==0)
|
||||
{
|
||||
// Yield to give a chance for some bytes to turn up
|
||||
Thread.yield();
|
||||
|
||||
// Do a byte read as that is blocking
|
||||
int b = in.read();
|
||||
if (b>=0)
|
||||
{
|
||||
n=1;
|
||||
_buf[_contents++]=(byte)b;
|
||||
}
|
||||
else
|
||||
_eof=true;
|
||||
}
|
||||
else
|
||||
_eof=true;
|
||||
}
|
||||
else
|
||||
_contents+=n;
|
||||
_avail=_contents;
|
||||
|
||||
// If we have a byte limit
|
||||
if (_byteLimit>0)
|
||||
{
|
||||
// adjust the bytes available
|
||||
if (_contents-_pos >=_byteLimit)
|
||||
_avail=_byteLimit+_pos;
|
||||
|
||||
if (n>_byteLimit)
|
||||
_byteLimit=0;
|
||||
else if (n>=0)
|
||||
_byteLimit-=n;
|
||||
else if (n==-1)
|
||||
throw new IOException("Premature EOF");
|
||||
}
|
||||
}
|
||||
|
||||
// If we have some characters and the last read was a CR and
|
||||
// the first char is a LF, skip it
|
||||
if (_avail-_pos>0 && _lastCr && _buf[_pos]==LF)
|
||||
{
|
||||
_seenCrLf=true;
|
||||
_pos++;
|
||||
if (_mark>=0)
|
||||
_mark++;
|
||||
_lastCr=false;
|
||||
|
||||
// If the byte limit has just been imposed, dont count
|
||||
// LF as content.
|
||||
if(_byteLimit>=0 && _newByteLimit)
|
||||
{
|
||||
if (_avail<_contents)
|
||||
_avail++;
|
||||
else
|
||||
_byteLimit++;
|
||||
}
|
||||
// If we ate all that ws filled, fill some more
|
||||
if (_pos==_avail)
|
||||
fill();
|
||||
}
|
||||
_newByteLimit=false;
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private int fillLine(int maxLen)
|
||||
throws IOException
|
||||
{
|
||||
_mark=_pos;
|
||||
|
||||
if (_pos>=_avail)
|
||||
fill();
|
||||
if (_pos>=_avail)
|
||||
return -1;
|
||||
|
||||
byte b;
|
||||
boolean cr=_lastCr;
|
||||
boolean lf=false;
|
||||
_lastCr=false;
|
||||
int len=0;
|
||||
|
||||
LineLoop:
|
||||
while (_pos<=_avail)
|
||||
{
|
||||
// if we have gone past the end of the buffer
|
||||
while (_pos==_avail)
|
||||
{
|
||||
// If EOF or no more space in the buffer,
|
||||
// return a line.
|
||||
if (_eof || (_mark==0 && _contents==_buf.length))
|
||||
{
|
||||
_lastCr=!_eof && _buf[_avail-1]==CR;
|
||||
|
||||
cr=true;
|
||||
lf=true;
|
||||
break LineLoop;
|
||||
}
|
||||
|
||||
// If we have a CR and no more characters are available
|
||||
if (cr && in.available()==0 && !_seenCrLf)
|
||||
{
|
||||
_lastCr=true;
|
||||
cr=true;
|
||||
lf=true;
|
||||
break LineLoop;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Else just wait for more...
|
||||
_pos=_mark;
|
||||
fill();
|
||||
_pos=len;
|
||||
cr=false;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the byte
|
||||
b=_buf[_pos++];
|
||||
|
||||
switch(b)
|
||||
{
|
||||
case LF:
|
||||
if (cr) _seenCrLf=true;
|
||||
lf=true;
|
||||
break LineLoop;
|
||||
|
||||
case CR:
|
||||
if (cr)
|
||||
{
|
||||
// Double CR
|
||||
if (_pos>1)
|
||||
{
|
||||
_pos--;
|
||||
break LineLoop;
|
||||
}
|
||||
}
|
||||
cr=true;
|
||||
break;
|
||||
|
||||
default:
|
||||
if(cr)
|
||||
{
|
||||
if (_pos==1)
|
||||
cr=false;
|
||||
else
|
||||
{
|
||||
_pos--;
|
||||
break LineLoop;
|
||||
}
|
||||
}
|
||||
|
||||
len++;
|
||||
if (len==maxLen)
|
||||
{
|
||||
// look for EOL
|
||||
if (_mark!=0 && _pos+2>=_avail && _avail<_buf.length)
|
||||
fill();
|
||||
|
||||
if (_pos<_avail && _buf[_pos]==CR)
|
||||
{
|
||||
cr=true;
|
||||
_pos++;
|
||||
}
|
||||
if (_pos<_avail && _buf[_pos]==LF)
|
||||
{
|
||||
lf=true;
|
||||
_pos++;
|
||||
}
|
||||
|
||||
if (!cr && !lf)
|
||||
{
|
||||
// fake EOL
|
||||
lf=true;
|
||||
cr=true;
|
||||
}
|
||||
break LineLoop;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cr && !lf && len==0)
|
||||
len=-1;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
private static class ByteBuffer extends ByteArrayInputStream
|
||||
{
|
||||
ByteBuffer(byte[] buffer)
|
||||
{
|
||||
super(buffer);
|
||||
}
|
||||
|
||||
void setBuffer(byte[] buffer)
|
||||
{
|
||||
buf=buffer;
|
||||
}
|
||||
|
||||
void setStream(int offset,int length)
|
||||
{
|
||||
pos=offset;
|
||||
count=offset+length;
|
||||
mark=-1;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
/** Reusable LineBuffer.
|
||||
* Externalized LineBuffer for fast line parsing.
|
||||
*/
|
||||
public static class LineBuffer
|
||||
{
|
||||
public char[] buffer;
|
||||
public int size;
|
||||
public LineBuffer(int maxLineLength)
|
||||
{buffer=new char[maxLineLength];}
|
||||
|
||||
public String toString(){return new String(buffer,0,size);}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------ */
|
||||
public void destroy()
|
||||
{
|
||||
ByteArrayPool.returnByteArray(_buf);
|
||||
_byteBuffer=null;
|
||||
_reader=null;
|
||||
_lineBuffer=null;
|
||||
_encoding=null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
63
apps/jetty/java/src/org/mortbay/util/MultiMap.java
Normal file
63
apps/jetty/java/src/org/mortbay/util/MultiMap.java
Normal file
@@ -0,0 +1,63 @@
|
||||
package org.mortbay.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A multi valued Map.
|
||||
* Simple I2P replacement for org.eclipse.jetty.util.MultiMap
|
||||
* so we don't depend on Jetty utils.
|
||||
*
|
||||
* Contains only the methods required by MultiPartRequest.
|
||||
* Does not implement Map. Unsynchronized.
|
||||
*
|
||||
* @since 0.9.12
|
||||
*/
|
||||
public class MultiMap<T>
|
||||
{
|
||||
private final HashMap<T, LinkedList<Object>> data;
|
||||
|
||||
public MultiMap(int capacity)
|
||||
{
|
||||
data = new HashMap<T, LinkedList<Object>>(capacity);
|
||||
}
|
||||
|
||||
public Set<T> keySet()
|
||||
{
|
||||
return data.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the first item or null.
|
||||
* The Jetty version appears to return the item if only one,
|
||||
* or the entire list if more than one.
|
||||
* Only used by MultiPartRequest.contains() which is unused.
|
||||
* contains() would fail with a ClassCastException if we returned a list here,
|
||||
* which is a bug in MultiPartRequest?
|
||||
*/
|
||||
public Object get(T key)
|
||||
{
|
||||
List<Object> tmp = getValues(key);
|
||||
|
||||
return tmp != null ? tmp.get( 0 ) : null;
|
||||
}
|
||||
|
||||
public List<Object> getValues(T key)
|
||||
{
|
||||
return data.get( key );
|
||||
}
|
||||
|
||||
public void add(T key, Object value )
|
||||
{
|
||||
LinkedList<Object> list = data.get( key );
|
||||
|
||||
if( list == null ) {
|
||||
list = new LinkedList<Object>();
|
||||
data.put( key, list );
|
||||
}
|
||||
|
||||
list.add( value );
|
||||
}
|
||||
}
|
11
apps/jetty/java/src/org/mortbay/util/package.html
Normal file
11
apps/jetty/java/src/org/mortbay/util/package.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<html>
|
||||
<body>
|
||||
<p>
|
||||
Old Jetty 5 classes for multipart form requests, moved to susimail and modded when we moved to Jetty 6,
|
||||
then moved from susimail to jetty-i2p.jar when we needed them in the router console also.
|
||||
As of 0.9.19.
|
||||
Not a public API, not for direct use.
|
||||
These are requirements for net.i2p.servlet.RequestWrapper.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
Reference in New Issue
Block a user