Merge remote-tracking branch 'origin/jetty-9.2.x'

Conflicts:
	jetty-util/src/main/java/org/eclipse/jetty/util/IO.java
	jetty-util/src/test/java/org/eclipse/jetty/util/resource/ResourceTest.java
This commit is contained in:
Greg Wilkins 2015-07-23 11:34:59 +10:00
commit e1faa5c1e9
4 changed files with 109 additions and 3 deletions

View File

@ -25,6 +25,7 @@ import static org.junit.Assert.fail;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
@ -33,13 +34,17 @@ import java.net.SocketException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel; import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel; import java.nio.channels.SocketChannel;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.nio.file.StandardOpenOption;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import org.eclipse.jetty.io.ClientConnectionFactory.Helper;
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
import org.eclipse.jetty.toolchain.test.OS; import org.eclipse.jetty.toolchain.test.OS;
import org.eclipse.jetty.util.BufferUtil; import org.eclipse.jetty.util.BufferUtil;
import org.eclipse.jetty.util.IO; import org.eclipse.jetty.util.IO;
@ -452,4 +457,35 @@ public class IOTest
Assert.assertEquals(ByteBuffer.wrap(data), read); Assert.assertEquals(ByteBuffer.wrap(data), read);
} }
@Test
public void testGatherWrite() throws Exception
{
File dir = MavenTestingUtils.getTargetTestingDir();
if (!dir.exists())
dir.mkdir();
File file = File.createTempFile("test",".txt",dir);
file.deleteOnExit();
FileChannel out = FileChannel.open(file.toPath(),
StandardOpenOption.CREATE,
StandardOpenOption.READ,
StandardOpenOption.WRITE,
StandardOpenOption.DELETE_ON_CLOSE);
ByteBuffer[] buffers = new ByteBuffer[4096];
long expected=0;
for (int i=0;i<buffers.length;i++)
{
buffers[i]=BufferUtil.toBuffer(i);
expected+=buffers[i].remaining();
}
long wrote = IO.write(out,buffers,0,buffers.length);
assertEquals(expected,wrote);
for (int i=0;i<buffers.length;i++)
assertEquals(0,buffers[i].remaining());
}
} }

View File

@ -33,6 +33,7 @@ import java.nio.file.attribute.FileAttribute;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.component.Destroyable; import org.eclipse.jetty.util.component.Destroyable;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.log.Logger;
@ -249,8 +250,9 @@ public abstract class AfterContentTransformer implements AsyncMiddleManServlet.C
int size = sourceBuffers.size(); int size = sourceBuffers.size();
if (size > 0) if (size > 0)
{ {
inputFile.write(sourceBuffers.toArray(new ByteBuffer[size])); ByteBuffer[] buffers = sourceBuffers.toArray(new ByteBuffer[size]);
sourceBuffers.clear(); sourceBuffers.clear();
IO.write(inputFile,buffers,0,buffers.length);
} }
} }
inputFile.write(input); inputFile.write(input);
@ -421,6 +423,7 @@ public abstract class AfterContentTransformer implements AsyncMiddleManServlet.C
return stream; return stream;
} }
private void overflow(ByteBuffer output) throws IOException private void overflow(ByteBuffer output) throws IOException
{ {
if (outputFile == null) if (outputFile == null)
@ -434,8 +437,10 @@ public abstract class AfterContentTransformer implements AsyncMiddleManServlet.C
int size = sinkBuffers.size(); int size = sinkBuffers.size();
if (size > 0) if (size > 0)
{ {
outputFile.write(sinkBuffers.toArray(new ByteBuffer[size])); ByteBuffer[] buffers = sinkBuffers.toArray(new ByteBuffer[size]);
sinkBuffers.clear(); sinkBuffers.clear();
IO.write(outputFile,buffers,0,buffers.length);
} }
} }
outputFile.write(output); outputFile.write(output);

View File

@ -30,6 +30,9 @@ import java.io.PrintWriter;
import java.io.Reader; import java.io.Reader;
import java.io.StringWriter; import java.io.StringWriter;
import java.io.Writer; import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.GatheringByteChannel;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Log;
@ -415,9 +418,55 @@ public class IO
copy(in,bout); copy(in,bout);
return bout.toByteArray(); return bout.toByteArray();
} }
/* ------------------------------------------------------------ */ /* ------------------------------------------------------------ */
/** /**
* A gathering write utility wrapper.
* <p>This method wraps a gather write with a loop that handles the limitations of some operating systems that
* have a limit on the number of buffers written. The method loops on the write until either all the content
* is written or no progress is made.
* @param out The GatheringgByteChannel to write to
* @param buffers The buffers to write
* @param offset The offset into the buffers array
* @param length The length in buffers to write
* @return The total bytes written
* @throws IOException
*/
public static long write(GatheringByteChannel out, ByteBuffer[] buffers, int offset, int length) throws IOException
{
long total=0;
write: while (length>0)
{
// Write as much as we can
long wrote=out.write(buffers,offset,length);
// If we can't write any more, give up
if (wrote==0)
break;
// count the total
total+=wrote;
// Look for unwritten content
for (int i=offset;i<buffers.length;i++)
{
if (buffers[i].hasRemaining())
{
// loop with new offset and length;
length=length-(i-offset);
offset=i;
continue write;
}
}
length=0;
}
return total;
}
/* ------------------------------------------------------------ */
/**
* @return An outputstream to nowhere * @return An outputstream to nowhere
*/ */
public static OutputStream getNullStream() public static OutputStream getNullStream()
@ -503,6 +552,7 @@ public class IO
} }
private static NullWrite __nullWriter = new NullWrite(); private static NullWrite __nullWriter = new NullWrite();
private static PrintWriter __nullPrintWriter = new PrintWriter(__nullWriter); private static PrintWriter __nullPrintWriter = new PrintWriter(__nullWriter);
} }

View File

@ -187,6 +187,21 @@ public class ResourceTest
return bdata; return bdata;
} }
} }
/* ------------------------------------------------------------ */
@Test
public void testEncodeAddPath ()
throws Exception
{
Resource r;
r = Resource.newResource(__userURL+"TestData/").addPath("foo%/b r");
Assert.assertThat(r.getURI().toString(),Matchers.endsWith("/foo%25/b%20r"));
r = Resource.newResource("jar:"+__userURL+"TestData/test.zip!/subdir/").addPath("foo%/b r");
Assert.assertThat(r.getURI().toString(),Matchers.endsWith("/foo%25/b%20r"));
}
@Parameters(name="{0}") @Parameters(name="{0}")