You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by dp...@apache.org on 2011/09/13 18:20:42 UTC
svn commit: r1170230 - in
/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk:
client/Client.java client/HttpExecutor.java client/Request.java
util/ChunkedInputStream.java util/ChunkedOutputStream.java
Author: dpfister
Date: Tue Sep 13 16:20:42 2011
New Revision: 1170230
URL: http://svn.apache.org/viewvc?rev=1170230&view=rev
Log:
HTTP interface to microkernel
- simplify chunked transmittal
Added:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedOutputStream.java (with props)
Modified:
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Client.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/HttpExecutor.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Request.java
jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedInputStream.java
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Client.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Client.java?rev=1170230&r1=1170229&r2=1170230&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Client.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Client.java Tue Sep 13 16:20:42 2011
@@ -202,7 +202,7 @@ public class Client implements MicroKern
request.addParameter("blob_id", blobId);
request.addParameter("pos", pos);
request.addParameter("length", length);
- return request.getBytes(buff, off, length);
+ return request.read(buff, off, length);
} catch (IOException e) {
throw toMicroKernelException(e);
} finally {
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/HttpExecutor.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/HttpExecutor.java?rev=1170230&r1=1170229&r2=1170230&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/HttpExecutor.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/HttpExecutor.java Tue Sep 13 16:20:42 2011
@@ -30,6 +30,7 @@ import java.util.Map;
import org.apache.jackrabbit.mk.util.BoundedInputStream;
import org.apache.jackrabbit.mk.util.ChunkedInputStream;
+import org.apache.jackrabbit.mk.util.ChunkedOutputStream;
import org.apache.jackrabbit.mk.util.IOUtils;
/**
@@ -37,13 +38,14 @@ import org.apache.jackrabbit.mk.util.IOU
*/
class HttpExecutor implements Closeable {
+ // TODO should actually NEVER match some part of binary content
+ private static final String BOUNDARY = "------ClientFormBoundaryHB5WJrSAPZjfwtqt--";
+
private final Socket socket;
private InputStream socketIn;
private OutputStream socketOut;
-
- private final byte[] chunkLen = new byte[4];
/**
* Create a new instance of this class.
@@ -80,18 +82,24 @@ class HttpExecutor implements Closeable
writeLine("Transfer-Encoding: chunked");
writeLine("");
+ OutputStream bodyOut = new ChunkedOutputStream(socketOut);
+
if (in != null) {
- // TODO sendInputStream(in);
+ bodyOut.write(BOUNDARY.getBytes());
+ bodyOut.write("\r\n\r\n".getBytes());
+ IOUtils.copy(in, bodyOut);
+ bodyOut.write("\r\n".getBytes());
+ bodyOut.write(BOUNDARY.getBytes());
} else {
for (Map.Entry<String,String> param : params.entrySet()) {
String s = String.format("%s=%s&",
URLEncoder.encode(param.getKey(), "8859_1"),
URLEncoder.encode(param.getValue(), "8859_1"));
- writeChunk(s.getBytes());
+ bodyOut.write(s.getBytes());
}
}
- writeChunk(new byte[0]);
+ bodyOut.close();
socketOut.flush();
// read response
@@ -177,29 +185,6 @@ class HttpExecutor implements Closeable
}
/**
- * Write a chunk of bytes in the request body.
- *
- * @param b bytes
- * @throws IOException if an I/O error occurs
- */
- private void writeChunk(byte[] b) throws IOException {
- int off = 0;
-
- do {
- int len = Math.min(b.length - off, 65534);
-
- toHexString(len, chunkLen);
- socketOut.write(chunkLen);
- socketOut.write("\r\n".getBytes());
- socketOut.write(b, off, len);
- socketOut.write("\r\n".getBytes());
-
- off += len;
-
- } while (off < b.length);
- }
-
- /**
* Read a single line, terminated by a CR LF combination from an input.
*
* @return line
@@ -223,24 +208,4 @@ class HttpExecutor implements Closeable
}
}
}
-
- /**
- * Convert an integer into a byte array, consisting of its hexadecimal
- * representation.
- *
- * @param n integer
- * @param b byte array
- */
- private static void toHexString(int n, byte[] b) {
- for (int i = b.length - 1; i >= 0; i--) {
- int c = n & 0x0f;
- if (c >= 0 && c <= 9) {
- c += '0';
- } else {
- c += 'A' - 10;
- }
- b[i] = (byte) c;
- n >>= 4;
- }
- }
}
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Request.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Request.java?rev=1170230&r1=1170229&r2=1170230&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Request.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/client/Request.java Tue Sep 13 16:20:42 2011
@@ -101,7 +101,7 @@ class Request implements Closeable {
return Long.parseLong(getString());
}
- public int getBytes(byte[] b, int off, int len) throws IOException {
+ public int read(byte[] b, int off, int len) throws IOException {
execute();
int count = 0;
Modified: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedInputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedInputStream.java?rev=1170230&r1=1170229&r2=1170230&view=diff
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedInputStream.java (original)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedInputStream.java Tue Sep 13 16:20:42 2011
@@ -190,8 +190,14 @@ public class ChunkedInputStream extends
* @see java.io.FilterInputStream#close()
*/
public void close() throws IOException {
- while (!lastChunk) {
- readChunk();
+ if (in != null) {
+ try {
+ while (!lastChunk) {
+ readChunk();
+ }
+ } finally {
+ in = null;
+ }
}
}
}
Added: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedOutputStream.java
URL: http://svn.apache.org/viewvc/jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedOutputStream.java?rev=1170230&view=auto
==============================================================================
--- jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedOutputStream.java (added)
+++ jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedOutputStream.java Tue Sep 13 16:20:42 2011
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.apache.jackrabbit.mk.util;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Output stream that encodes and writes HTTP chunks.
+ */
+public class ChunkedOutputStream extends FilterOutputStream {
+
+ /**
+ * Maximum chunk size.
+ */
+ private static final int MAX_CHUNK_SIZE = 65535;
+
+ /**
+ * CR + LF combination.
+ */
+ private static final byte[] CRLF = "\r\n".getBytes();
+
+ /**
+ * Last chunk.
+ */
+ private static final byte[] LAST_CHUNK = "0000\r\n\r\n".getBytes();
+
+ /**
+ * Chunk prefix (length encoded as hexadecimal string).
+ */
+ private final byte[] prefix = new byte[4];
+
+ /**
+ * Chunk data.
+ */
+ private final byte[] data;
+
+ /**
+ * Current offset.
+ */
+ private int offset;
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param out underlying output stream.
+ * @param size internal buffer size
+ * @throws IllegalArgumentException if <code>size</code> is smaller than 1
+ * or bigger than <code>65535</code>
+ */
+ public ChunkedOutputStream(OutputStream out, int size) {
+ super(out);
+
+ if (size < 1 || size > MAX_CHUNK_SIZE) {
+ String msg = "Chunk size smaller than 1 or bigger than " + MAX_CHUNK_SIZE;
+ throw new IllegalArgumentException(msg);
+ }
+ this.data = new byte[size];
+ }
+
+ /**
+ * Create a new instance of this class.
+ *
+ * @param out underlying output stream.
+ */
+ public ChunkedOutputStream(OutputStream out) {
+ this(out, MAX_CHUNK_SIZE);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.FilterOutputStream#write(int)
+ */
+ public void write(int b) throws IOException {
+ if (offset == data.length) {
+ writeChunk();
+ }
+ data[offset++] = (byte) (b & 0xff);
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.FilterOutputStream#write(byte[], int, int)
+ */
+ public void write(byte[] b, int off, int len) throws IOException {
+ int written = 0;
+ while (written < len) {
+ if (offset == data.length) {
+ writeChunk();
+ }
+ int available = Math.min(len - written, data.length - offset);
+ System.arraycopy(b, off + written, data, offset, available);
+ written += available;
+ offset += available;
+ }
+ }
+
+ /**
+ * Writes the contents of the internal buffer as chunk to the underlying
+ * output stream.
+ *
+ * @throws IOException if an error occurs
+ */
+ private void writeChunk() throws IOException {
+ toHexString(offset, prefix);
+ out.write(prefix);
+ out.write(CRLF);
+ out.write(data, 0, offset);
+ out.write(CRLF);
+ offset = 0;
+ }
+
+ /**
+ * Convert an integer into a byte array, consisting of its hexadecimal
+ * representation.
+ *
+ * @param n integer
+ * @param b byte array
+ */
+ private static void toHexString(int n, byte[] b) {
+ for (int i = b.length - 1; i >= 0; i--) {
+ int c = n & 0x0f;
+ if (c >= 0 && c <= 9) {
+ c += '0';
+ } else {
+ c += 'A' - 10;
+ }
+ b[i] = (byte) c;
+ n >>= 4;
+ }
+ }
+
+ /**
+ * Flush the contents of the internal buffer to the underlying output
+ * stream as a chunk if it is non-zero. Never do that for a zero-size
+ * chunk as this would indicate EOF.
+ *
+ * @see java.io.FilterOutputStream#flush()
+ */
+ public void flush() throws IOException {
+ if (offset > 0) {
+ writeChunk();
+ }
+ super.flush();
+ }
+
+ /**
+ * Close this output stream. Flush the contents of the internal buffer
+ * and writes the last chunk to the underlying output stream. Does
+ * <b>not</b> close the underlying output stream.
+ *
+ * @see java.io.FilterOutputStream#close()
+ */
+ public void close() throws IOException {
+ if (out == null) {
+ return;
+ }
+ try {
+ if (offset > 0) {
+ writeChunk();
+ }
+ out.write(LAST_CHUNK);
+ } finally {
+ out = null;
+ }
+ }
+}
Propchange: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedOutputStream.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: jackrabbit/sandbox/microkernel/src/main/java/org/apache/jackrabbit/mk/util/ChunkedOutputStream.java
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision Rev Url