(connNo);
+ for (int i = 0; i < connNo; i++) {
+ responseData2.add(new ResponseSequence());
+ }
+
+ final String[] method = new String[1];
+
+ HttpRequestHandler requestHandler = new HttpRequestHandler() {
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+
+ String s = request.getRequestLine().getUri();
+ URI uri;
+ try {
+ uri = new URI(s);
+ } catch (URISyntaxException ex) {
+ throw new HttpException("Invalid request URI: " + s);
+ }
+ int index = Integer.parseInt(uri.getQuery());
+
+ byte[] data = requestData.getBytes(index);
+ NByteArrayEntity entity = new NByteArrayEntity(data);
+ response.setEntity(entity);
+ }
+
+ };
+
+ HttpRequestExecutionHandler requestExecutionHandler = new HttpRequestExecutionHandler() {
+
+ public void initalizeContext(final HttpContext context, final Object attachment) {
+ context.setAttribute("LIST", (ResponseSequence) attachment);
+ context.setAttribute("REQ-COUNT", new Integer(0));
+ context.setAttribute("RES-COUNT", new Integer(0));
+ }
+
+ public void finalizeContext(final HttpContext context) {
+ }
+
+ public HttpRequest submitRequest(final HttpContext context) {
+ int i = ((Integer) context.getAttribute("REQ-COUNT")).intValue();
+ BasicHttpRequest request = null;
+ if (i < reqNo) {
+ request = new BasicHttpRequest(method[0], "/?" + i);
+ context.setAttribute("REQ-COUNT", new Integer(i + 1));
+ }
+ return request;
+ }
+
+ public void handleResponse(final HttpResponse response, final HttpContext context) {
+ NHttpConnection conn = (NHttpConnection) context.getAttribute(
+ ExecutionContext.HTTP_CONNECTION);
+
+ ResponseSequence list = (ResponseSequence) context.getAttribute("LIST");
+ int i = ((Integer) context.getAttribute("RES-COUNT")).intValue();
+ i++;
+ context.setAttribute("RES-COUNT", new Integer(i));
+
+ list.addResponse(response);
+ requestCount.decrement();
+
+ if (i < reqNo) {
+ conn.requestInput();
+ }
+ }
+
+ };
+
+ NHttpServiceHandler serviceHandler = createHttpServiceHandler(
+ requestHandler,
+ null);
+
+ NHttpClientHandler clientHandler = createHttpClientHandler(
+ requestExecutionHandler);
+
+ this.server.start(serviceHandler);
+ this.client.start(clientHandler);
+
+ ListenerEndpoint endpoint = this.server.getListenerEndpoint();
+ endpoint.waitFor();
+ InetSocketAddress serverAddress = (InetSocketAddress) endpoint.getAddress();
+
+ method[0] = "GET";
+
+ for (int i = 0; i < responseData1.size(); i++) {
+ this.client.openConnection(
+ new InetSocketAddress("localhost", serverAddress.getPort()),
+ responseData1.get(i));
+ }
+
+ requestCount.await(connNo * reqNo, 10000);
+ assertEquals(connNo * reqNo, requestCount.getValue());
+
+ method[0] = "HEAD";
+
+ for (int i = 0; i < responseData2.size(); i++) {
+ this.client.openConnection(
+ new InetSocketAddress("localhost", serverAddress.getPort()),
+ responseData2.get(i));
+ }
+
+
+ requestCount.await(10000);
+ assertEquals(0, requestCount.getValue());
+
+ this.client.shutdown();
+ this.server.shutdown();
+
+ for (int c = 0; c < connNo; c++) {
+ ResponseSequence getResponses = responseData1.get(c);
+ ResponseSequence headResponses = responseData2.get(c);
+ ByteSequence expectedPackets = requestData;
+ assertEquals(expectedPackets.size(), headResponses.size());
+ assertEquals(expectedPackets.size(), getResponses.size());
+ for (int p = 0; p < requestData.size(); p++) {
+ HttpResponse getResponse = getResponses.getResponse(p);
+ HttpResponse headResponse = headResponses.getResponse(p);
+ assertEquals(null, headResponse.getEntity());
+
+ Header[] getHeaders = getResponse.getAllHeaders();
+ Header[] headHeaders = headResponse.getAllHeaders();
+ assertEquals(getHeaders.length, headHeaders.length);
+ for (int j = 0; j < getHeaders.length; j++) {
+ if ("Date".equals(getHeaders[j].getName())) {
+ continue;
+ }
+ assertEquals(getHeaders[j].toString(), headHeaders[j].toString());
+ }
+ }
+ }
+ }
+
+ static class ByteContentListener implements ContentListener {
+ final SimpleInputBuffer input = new SimpleInputBuffer(2048, new HeapByteBufferAllocator());
+
+ @Override
+ public boolean consumeContent(ContentDecoder decoder, IOControl ioctrl)
+ throws IOException {
+ input.consumeContent(decoder);
+ return decoder.isCompleted();
+ }
+
+ @Override
+ public void finish() {
+ input.reset();
+ }
+
+ byte[] getContent() throws IOException {
+ byte[] b = new byte[input.length()];
+ input.read(b);
+ return b;
+ }
+ }
+
+}
Property changes on: module-nio/src/test/java/org/apache/http/nio/protocol/TestAsyncNHttpHandlers.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/test/java/org/apache/http/mockup/SimpleNHttpRequestHandlerResolver.java
===================================================================
--- module-nio/src/test/java/org/apache/http/mockup/SimpleNHttpRequestHandlerResolver.java (revision 0)
+++ module-nio/src/test/java/org/apache/http/mockup/SimpleNHttpRequestHandlerResolver.java (revision 0)
@@ -0,0 +1,18 @@
+package org.apache.http.mockup;
+
+import org.apache.http.nio.protocol.NHttpRequestHandler;
+import org.apache.http.nio.protocol.NHttpRequestHandlerResolver;
+
+public class SimpleNHttpRequestHandlerResolver implements NHttpRequestHandlerResolver {
+
+ private final NHttpRequestHandler handler;
+
+ public SimpleNHttpRequestHandlerResolver(final NHttpRequestHandler handler) {
+ this.handler = handler;
+ }
+
+ public NHttpRequestHandler lookup(final String requestURI) {
+ return this.handler;
+ }
+
+}
Property changes on: module-nio/src/test/java/org/apache/http/mockup/SimpleNHttpRequestHandlerResolver.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/ContentEncoderChannel.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/ContentEncoderChannel.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/ContentEncoderChannel.java (revision 0)
@@ -0,0 +1,33 @@
+package org.apache.http.nio;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.WritableByteChannel;
+
+import org.apache.http.nio.ContentEncoder;
+
+/**
+ * A {@link WritableByteChannel} that delegates to a {@link ContentEncoder}.
+ * Attempts to close this channel are ignored, and isOpen always returns true.
+ *
+ * @author Sam Berlin
+ */
+public class ContentEncoderChannel implements WritableByteChannel {
+
+ private final ContentEncoder contentEncoder;
+
+ public ContentEncoderChannel(ContentEncoder contentEncoder) {
+ this.contentEncoder = contentEncoder;
+ }
+
+ public int write(ByteBuffer src) throws IOException {
+ return contentEncoder.write(src);
+ }
+
+ public void close() {}
+
+ public boolean isOpen() {
+ return true;
+ }
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/ContentEncoderChannel.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpResponseTrigger.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/NHttpResponseTrigger.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/NHttpResponseTrigger.java (revision 0)
@@ -0,0 +1,15 @@
+package org.apache.http.nio.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponse;
+
+public interface NHttpResponseTrigger {
+ void submitResponse(HttpResponse response);
+
+ void recoverableException(HttpException exception);
+
+ void fatalException(IOException exception);
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpResponseTrigger.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpServiceHandler.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpServiceHandler.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpServiceHandler.java (revision 0)
@@ -0,0 +1,59 @@
+package org.apache.http.nio.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.nio.NHttpServerConnection;
+import org.apache.http.nio.NHttpServiceHandler;
+import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.nio.util.HeapByteBufferAllocator;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.HttpExpectationVerifier;
+import org.apache.http.protocol.HttpProcessor;
+
+public abstract class AbstractNHttpServiceHandler extends NHttpHandlerBase
+ implements NHttpServiceHandler {
+
+ protected final HttpResponseFactory responseFactory;
+
+ protected HttpExpectationVerifier expectationVerifier;
+
+ public AbstractNHttpServiceHandler(
+ final HttpProcessor httpProcessor,
+ final HttpResponseFactory responseFactory,
+ final ConnectionReuseStrategy connStrategy,
+ final ByteBufferAllocator allocator,
+ final HttpParams params) {
+ super(httpProcessor, connStrategy, allocator, params);
+ if (responseFactory == null) {
+ throw new IllegalArgumentException("Response factory may not be null");
+ }
+ this.responseFactory = responseFactory;
+ }
+
+ public AbstractNHttpServiceHandler(
+ final HttpProcessor httpProcessor,
+ final HttpResponseFactory responseFactory,
+ final ConnectionReuseStrategy connStrategy,
+ final HttpParams params) {
+ this(httpProcessor, responseFactory, connStrategy,
+ new HeapByteBufferAllocator(), params);
+ }
+
+ public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
+ this.expectationVerifier = expectationVerifier;
+ }
+
+ public void exception(final NHttpServerConnection conn, final IOException ex) {
+ shutdownConnection(conn, ex);
+
+ if (this.eventListener != null) {
+ this.eventListener.fatalIOException(ex, conn);
+ }
+ }
+
+ public void timeout(final NHttpServerConnection conn) {
+ handleTimeout(conn);
+ }
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/protocol/AbstractNHttpServiceHandler.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandler.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandler.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandler.java (revision 0)
@@ -0,0 +1,21 @@
+package org.apache.http.nio.protocol;
+
+import java.io.IOException;
+
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.nio.entity.ContentListener;
+import org.apache.http.protocol.HttpContext;
+
+public interface NHttpRequestHandler {
+
+ ContentListener entityRequest(HttpEntityEnclosingRequest request,
+ HttpContext context) throws HttpException, IOException;
+
+ void handle(HttpRequest request, HttpResponse response,
+ NHttpResponseTrigger trigger, HttpContext context)
+ throws HttpException, IOException;
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandler.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpServiceHandlerBase.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/NHttpServiceHandlerBase.java (revision 628407)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/NHttpServiceHandlerBase.java (working copy)
@@ -31,26 +31,16 @@
package org.apache.http.nio.protocol;
-import java.io.IOException;
-
import org.apache.http.ConnectionReuseStrategy;
import org.apache.http.HttpResponseFactory;
-import org.apache.http.nio.NHttpServerConnection;
-import org.apache.http.nio.NHttpServiceHandler;
import org.apache.http.nio.util.ByteBufferAllocator;
-import org.apache.http.nio.util.HeapByteBufferAllocator;
import org.apache.http.params.HttpParams;
-import org.apache.http.protocol.HttpExpectationVerifier;
import org.apache.http.protocol.HttpProcessor;
import org.apache.http.protocol.HttpRequestHandlerResolver;
-public abstract class NHttpServiceHandlerBase extends NHttpHandlerBase
- implements NHttpServiceHandler {
+public abstract class NHttpServiceHandlerBase extends AbstractNHttpServiceHandler {
- protected final HttpResponseFactory responseFactory;
-
protected HttpRequestHandlerResolver handlerResolver;
- protected HttpExpectationVerifier expectationVerifier;
public NHttpServiceHandlerBase(
final HttpProcessor httpProcessor,
@@ -58,11 +48,7 @@
final ConnectionReuseStrategy connStrategy,
final ByteBufferAllocator allocator,
final HttpParams params) {
- super(httpProcessor, connStrategy, allocator, params);
- if (responseFactory == null) {
- throw new IllegalArgumentException("Response factory may not be null");
- }
- this.responseFactory = responseFactory;
+ super(httpProcessor, responseFactory, connStrategy, allocator, params);
}
public NHttpServiceHandlerBase(
@@ -70,28 +56,11 @@
final HttpResponseFactory responseFactory,
final ConnectionReuseStrategy connStrategy,
final HttpParams params) {
- this(httpProcessor, responseFactory, connStrategy,
- new HeapByteBufferAllocator(), params);
+ super(httpProcessor, responseFactory, connStrategy, params);
}
public void setHandlerResolver(final HttpRequestHandlerResolver handlerResolver) {
this.handlerResolver = handlerResolver;
}
-
- public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
- this.expectationVerifier = expectationVerifier;
- }
-
- public void exception(final NHttpServerConnection conn, final IOException ex) {
- shutdownConnection(conn, ex);
-
- if (this.eventListener != null) {
- this.eventListener.fatalIOException(ex, conn);
- }
- }
-
- public void timeout(final NHttpServerConnection conn) {
- handleTimeout(conn);
- }
}
Index: module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpServiceHandler.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpServiceHandler.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpServiceHandler.java (revision 0)
@@ -0,0 +1,576 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/protocol/BufferingHttpServiceHandler.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 17:09:22 -0500 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.nio.protocol;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpConnection;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.MethodNotSupportedException;
+import org.apache.http.ProtocolException;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.UnsupportedHttpVersionException;
+import org.apache.http.impl.nio.DefaultNHttpServerConnection;
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.NHttpServerConnection;
+import org.apache.http.nio.NHttpServiceHandler;
+import org.apache.http.nio.entity.BasicConsumingNHttpEntity;
+import org.apache.http.nio.entity.ConsumingNHttpEntity;
+import org.apache.http.nio.entity.ContentListener;
+import org.apache.http.nio.entity.NBlockingProducingNHttpEntity;
+import org.apache.http.nio.entity.NByteArrayEntity;
+import org.apache.http.nio.entity.ProducingNHttpEntity;
+import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.nio.util.HeapByteBufferAllocator;
+import org.apache.http.params.DefaultedHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpProcessor;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.util.EncodingUtils;
+
+
+/**
+ * HTTP service handler implementation that works with
+ * {@link ConsumingNHttpEntity} and {@link ProducingNHttpEntity}. The contents
+ * of HTTP headers are stored in memory, HTTP entities are streamed directly
+ * from the NHttpEntity to the underlying channel (and vice versa).
+ *
+ * When using this {@link NHttpServiceHandler}, it is important to ensure that
+ * entities supplied for writing implement ProducingNHttpEntity. Doing
+ * so will allow the entity to be written out asynchronously. If entities
+ * supplied for writing do not implement ProducingNHttpEntity, a delegate is
+ * added that buffers the entire contents in memory. Additionally, the buffering
+ * might take place in the I/O thread, which could cause I/O to block
+ * temporarily. For best results, ensure that all entities set on
+ * {@link HttpResponse HttpResponses} from
+ * {@link HttpRequestHandler HttpRequestHandlers} implement
+ * ProducingNHttpEntity.
+ *
+ * If incoming requests have entities, HttpRequestHandlers must not call
+ * {@link HttpEntity#getContent()}. Doing so will throw an
+ * {@link UnsupportedOperationException}. Instead, handlers must expect that
+ * incoming entities implement ConsumingNHttpEntity and install a
+ * {@link ContentListener} on those entities. The ContentListener will be
+ * notified when new data is available for reading. After all data has been
+ * read, the response will automatically be sent.
+ *
+ * To support legacy HttpRequestHandlers that do use getContent(), you can wrap
+ * the handler within a {@link NBlockingHttpRequestHandler}. Doing so will
+ * allow the handler to be processed on a new thread, in a blocking manner.
+ *
+ *
+ * @author Oleg Kalnichevski
+ * @author Sam Berlin
+ * @author Steffen Pingel
+ *
+ */
+public class AsyncNHttpServiceHandler extends AbstractNHttpServiceHandler
+ implements NHttpServiceHandler {
+
+ protected NHttpRequestHandlerResolver handlerResolver;
+
+ public AsyncNHttpServiceHandler(final HttpProcessor httpProcessor,
+ final HttpResponseFactory responseFactory,
+ final ConnectionReuseStrategy connStrategy,
+ final ByteBufferAllocator allocator, final HttpParams params) {
+ super(httpProcessor, responseFactory, connStrategy, allocator, params);
+ }
+
+ public AsyncNHttpServiceHandler(final HttpProcessor httpProcessor,
+ final HttpResponseFactory responseFactory,
+ final ConnectionReuseStrategy connStrategy, final HttpParams params) {
+ this(httpProcessor, responseFactory, connStrategy,
+ new HeapByteBufferAllocator(), params);
+ }
+
+ public void setHandlerResolver(final NHttpRequestHandlerResolver handlerResolver) {
+ this.handlerResolver = handlerResolver;
+ }
+
+
+ public void connected(final NHttpServerConnection conn) {
+ HttpContext context = conn.getContext();
+
+ ServerConnState connState = new ServerConnState();
+ context.setAttribute(CONN_STATE, connState);
+ context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
+
+ if (this.eventListener != null) {
+ this.eventListener.connectionOpen(conn);
+ }
+ }
+
+ public void requestReceived(final NHttpServerConnection conn) {
+ HttpContext context = conn.getContext();
+
+ HttpRequest request = conn.getHttpRequest();
+ request.setParams(new DefaultedHttpParams(request.getParams(), this.params));
+
+ ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
+ if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
+ // Downgrade protocol version if greater than HTTP/1.1
+ ver = HttpVersion.HTTP_1_1;
+ }
+
+ HttpResponse response;
+
+ try {
+
+ if (request instanceof HttpEntityEnclosingRequest) {
+ if (((HttpEntityEnclosingRequest) request).expectContinue()) {
+ response = this.responseFactory.newHttpResponse(
+ ver, HttpStatus.SC_CONTINUE, context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+
+ if (this.expectationVerifier != null) {
+ try {
+ this.expectationVerifier.verify(request, response, context);
+ } catch (HttpException ex) {
+ ex.printStackTrace();
+ response = this.responseFactory.newHttpResponse(
+ HttpVersion.HTTP_1_0,
+ HttpStatus.SC_INTERNAL_SERVER_ERROR,
+ context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+ handleException(ex, response);
+ }
+ }
+
+ if (response.getStatusLine().getStatusCode() < 200) {
+ // Send 1xx response indicating the server expections
+ // have been met
+ conn.submitResponse(response);
+ } else {
+ conn.resetInput();
+ sendResponse(conn, request, response);
+ }
+ }
+ // Request content is expected.
+ // Wait until the request content is fully received
+ } else {
+ // No request content is expected.
+ // Process request right away
+ conn.suspendInput();
+ processRequest(conn, request);
+ }
+
+ } catch (IOException ex) {
+ shutdownConnection(conn, ex);
+ if (this.eventListener != null) {
+ this.eventListener.fatalIOException(ex, conn);
+ }
+ } catch (HttpException ex) {
+ closeConnection(conn, ex);
+ if (this.eventListener != null) {
+ this.eventListener.fatalProtocolException(ex, conn);
+ }
+ }
+
+ }
+
+ public void closed(final NHttpServerConnection conn) {
+ ServerConnState connState = (ServerConnState) ((NHttpServerConnection)conn).getContext().getAttribute(CONN_STATE);
+ connState.finish();
+
+ if (this.eventListener != null) {
+ this.eventListener.connectionClosed(conn);
+ }
+ }
+
+ public void exception(final NHttpServerConnection conn, final HttpException httpex) {
+ if (conn.isResponseSubmitted()) {
+ closeConnection(conn, httpex); // TODO: Is this correct?
+ if (eventListener != null) {
+ eventListener.fatalProtocolException(httpex, conn);
+ }
+ return;
+ }
+
+ HttpContext context = conn.getContext();
+ try {
+ HttpResponse response = this.responseFactory.newHttpResponse(
+ HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+ handleException(httpex, response);
+ response.setEntity(null);
+ sendResponse(conn, null, response);
+
+ } catch (IOException ex) {
+ shutdownConnection(conn, ex);
+ if (this.eventListener != null) {
+ this.eventListener.fatalIOException(ex, conn);
+ }
+ } catch (HttpException ex) {
+ closeConnection(conn, ex);
+ if (this.eventListener != null) {
+ this.eventListener.fatalProtocolException(ex, conn);
+ }
+ }
+ }
+
+ public void inputReady(final NHttpServerConnection conn, final ContentDecoder decoder) {
+ HttpEntityEnclosingRequest request = (HttpEntityEnclosingRequest)conn.getHttpRequest();
+ HttpEntity entity = request.getEntity();
+ HttpContext context = conn.getContext();
+ ServerConnState connState = (ServerConnState) ((NHttpServerConnection)conn).getContext().getAttribute(CONN_STATE);
+
+ try {
+ // If we haven't set the entity for asynchronous input yet...
+ if(!(entity instanceof ConsumingNHttpEntity)) {
+ NHttpRequestHandler handler = getRequestHandler(request);
+ ContentListener listener = null;
+ if(handler != null)
+ listener = handler.entityRequest(request, context);
+ if(listener == null)
+ listener = new SkipContentListener(allocator);
+ connState.addContentListener(listener);
+ // TODO: Can entityReq.getEntity() ever be null here? What to do if it is?
+ entity = new BasicConsumingNHttpEntity(listener, entity);
+ request.setEntity(entity);
+ }
+
+
+ BasicConsumingNHttpEntity consumingEntity = (BasicConsumingNHttpEntity)entity;
+ boolean flowthrough = consumingEntity.getContentListener().consumeContent(decoder, conn);
+
+ if (flowthrough || decoder.isCompleted()) {
+ if(decoder.isCompleted()) {
+ conn.suspendInput();
+ }
+
+ if(!consumingEntity.isHandled()) {
+ consumingEntity.setHandled(true);
+ processRequest(conn, request);
+ }
+ }
+
+ } catch (IOException ex) {
+ shutdownConnection(conn, ex);
+ if (this.eventListener != null) {
+ this.eventListener.fatalIOException(ex, conn);
+ }
+ } catch (HttpException ex) {
+ closeConnection(conn, ex);
+ if (this.eventListener != null) {
+ this.eventListener.fatalProtocolException(ex, conn);
+ }
+ }
+ }
+
+ public void responseReady(final NHttpServerConnection conn) {
+ if (conn.isOpen()) {
+ conn.requestInput();
+ // make sure any buffered requests are processed
+ if (((DefaultNHttpServerConnection)conn).hasBufferedInput()) {
+ ((DefaultNHttpServerConnection)conn).consumeInput(this);
+ }
+ }
+ }
+
+ public void outputReady(final NHttpServerConnection conn, final ContentEncoder encoder) {
+ HttpContext context = conn.getContext();
+ HttpResponse response = conn.getHttpResponse();
+ ServerConnState connState = (ServerConnState) ((NHttpServerConnection)conn).getContext().getAttribute(CONN_STATE);
+
+ try {
+ ProducingNHttpEntity entity = (ProducingNHttpEntity)response.getEntity();
+ entity.produceContent(encoder, conn);
+
+ if (encoder.isCompleted()) {
+ connState.removeProducingEntity(entity);
+ if (!this.connStrategy.keepAlive(response, context)) {
+ conn.close();
+ }
+ }
+
+ } catch (IOException ex) {
+ shutdownConnection(conn, ex);
+ if (this.eventListener != null) {
+ this.eventListener.fatalIOException(ex, conn);
+ }
+ }
+ }
+
+ @Override
+ protected void closeConnection(final HttpConnection conn, final Throwable cause) {
+ ServerConnState connState = (ServerConnState) ((NHttpServerConnection)conn).getContext().getAttribute(CONN_STATE);
+ connState.finish();
+
+ super.closeConnection(conn, cause);
+ }
+
+ @Override
+ protected void shutdownConnection(HttpConnection conn, Throwable cause) {
+ ServerConnState connState = (ServerConnState) ((NHttpServerConnection)conn).getContext().getAttribute(CONN_STATE);
+ connState.finish();
+
+ super.shutdownConnection(conn, cause);
+ }
+
+ private void handleException(final HttpException ex, final HttpResponse response) {
+ int code = HttpStatus.SC_INTERNAL_SERVER_ERROR;
+ if (ex instanceof MethodNotSupportedException) {
+ code = HttpStatus.SC_NOT_IMPLEMENTED;
+ } else if (ex instanceof UnsupportedHttpVersionException) {
+ code = HttpStatus.SC_HTTP_VERSION_NOT_SUPPORTED;
+ } else if (ex instanceof ProtocolException) {
+ code = HttpStatus.SC_BAD_REQUEST;
+ }
+ response.setStatusCode(code);
+
+ byte[] msg = EncodingUtils.getAsciiBytes(ex.getMessage());
+ NByteArrayEntity entity = new NByteArrayEntity(msg);
+ entity.setContentType("text/plain; charset=US-ASCII");
+ response.setEntity(entity);
+ }
+
+ private void processRequest(
+ final NHttpServerConnection conn,
+ final HttpRequest request) throws IOException, HttpException {
+
+ HttpContext context = conn.getContext();
+ ProtocolVersion ver = request.getRequestLine().getProtocolVersion();
+
+ if (!ver.lessEquals(HttpVersion.HTTP_1_1)) {
+ // Downgrade protocol version if greater than HTTP/1.1
+ ver = HttpVersion.HTTP_1_1;
+ }
+
+ HttpResponse response = this.responseFactory.newHttpResponse(
+ ver,
+ HttpStatus.SC_OK,
+ conn.getContext());
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+
+ try {
+ this.httpProcessor.process(request, context);
+
+ NHttpRequestHandler handler = getRequestHandler(request);
+ if (handler != null) {
+ handler.handle(request, response, new ResponseTrigger(conn, request), context);
+ } else {
+ response.setStatusCode(HttpStatus.SC_NOT_IMPLEMENTED);
+ }
+ } catch (HttpException ex) {
+ response = this.responseFactory.newHttpResponse(HttpVersion.HTTP_1_0,
+ HttpStatus.SC_INTERNAL_SERVER_ERROR, context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+ handleException(ex, response);
+ }
+ }
+
+ private void sendResponse(final NHttpServerConnection conn,
+ HttpRequest request, HttpResponse response) throws IOException,
+ HttpException {
+ HttpContext context = conn.getContext();
+ ServerConnState connState = (ServerConnState) ((NHttpServerConnection)conn).getContext().getAttribute(CONN_STATE);
+
+ // Now that a response is ready, we can cleanup the listener for the request.
+ if(request instanceof HttpEntityEnclosingRequest) {
+ HttpEntityEnclosingRequest entityReq = (HttpEntityEnclosingRequest)request;
+ HttpEntity entity = entityReq.getEntity();
+ if(entity instanceof ConsumingNHttpEntity) {
+ ConsumingNHttpEntity consumingEntity = (ConsumingNHttpEntity)entity;
+ connState.removeContentListener(consumingEntity.getContentListener());
+ }
+ }
+
+ // Some processers need the request that generated this response.
+ context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
+ this.httpProcessor.process(response, context);
+ context.setAttribute(ExecutionContext.HTTP_REQUEST, null);
+
+ if (response.getEntity() != null && !canResponseHaveBody(request, response)) {
+ response.setEntity(null);
+ }
+
+ HttpEntity entity = response.getEntity();
+ if (entity != null) {
+ ProducingNHttpEntity producingEntity;
+ if(!(entity instanceof ProducingNHttpEntity)) {
+ producingEntity = new NBlockingProducingNHttpEntity(entity, allocator);
+ response.setEntity(producingEntity);
+ } else {
+ producingEntity = (ProducingNHttpEntity)entity;
+ }
+ connState.addProducingEntity(producingEntity);
+ } else {
+ if (!this.connStrategy.keepAlive(response, context)) {
+ conn.close();
+ }
+ }
+
+ conn.submitResponse(response);
+ }
+
+ private NHttpRequestHandler getRequestHandler(HttpRequest request) {
+ NHttpRequestHandler handler = null;
+ if (this.handlerResolver != null) {
+ String requestURI = request.getRequestLine().getUri();
+ handler = this.handlerResolver.lookup(requestURI);
+ }
+
+ return handler;
+ }
+
+ static class ServerConnState {
+ private List pendingListeners = new ArrayList();
+ private List pendingResponses = new ArrayList();
+
+ void finish() {
+ for(ContentListener listener : pendingListeners)
+ listener.finish();
+ for(ProducingNHttpEntity entity : pendingResponses)
+ entity.finish();
+
+ pendingListeners.clear();
+ pendingResponses.clear();
+ }
+
+ public void addProducingEntity(ProducingNHttpEntity producingEntity) {
+ pendingResponses.add(producingEntity);
+ }
+
+ public void removeProducingEntity(ProducingNHttpEntity entity) {
+ entity.finish();
+ pendingResponses.remove(entity);
+ }
+
+ public void removeContentListener(ContentListener contentListener) {
+ contentListener.finish();
+ pendingListeners.remove(contentListener);
+ }
+
+ public void addContentListener(ContentListener listener) {
+ pendingListeners.add(listener);
+ }
+ }
+
+ static class SkipContentListener implements ContentListener {
+ private final ByteBuffer buffer;
+ public SkipContentListener(ByteBufferAllocator allocator) {
+ this.buffer = allocator.allocate(2048);
+ }
+
+ @Override
+ public boolean consumeContent(ContentDecoder decoder, IOControl ioctrl)
+ throws IOException {
+ int totalRead = 0;
+ int lastRead;
+ do {
+ buffer.clear();
+ lastRead = decoder.read(buffer);
+ if(lastRead > 0)
+ totalRead += lastRead;
+ } while(lastRead > 0);
+ return decoder.isCompleted();
+ }
+
+ @Override
+ public void finish() {}
+ }
+
+ /**
+ * A response listener to help handle legacy HttpRequestHandlers that
+ * perform the handle in a new thread.
+ */
+ class ResponseTrigger implements NHttpResponseTrigger {
+ private final NHttpServerConnection conn;
+ private final HttpRequest request;
+
+ public ResponseTrigger(NHttpServerConnection conn, HttpRequest request) {
+ this.conn = conn;
+ this.request = request;
+ }
+
+ @Override
+ public void fatalException(IOException exception) {
+ AsyncNHttpServiceHandler handler = AsyncNHttpServiceHandler.this;
+ handler.shutdownConnection(conn, exception);
+ if (handler.eventListener != null) {
+ handler.eventListener.fatalIOException(exception, conn);
+ }
+ }
+
+ @Override
+ public void recoverableException(HttpException exception) {
+ AsyncNHttpServiceHandler handler = AsyncNHttpServiceHandler.this;
+ HttpContext context = conn.getContext();
+ HttpResponse response = handler.responseFactory.newHttpResponse(
+ HttpVersion.HTTP_1_0, HttpStatus.SC_INTERNAL_SERVER_ERROR,
+ context);
+ response.setParams(new DefaultedHttpParams(response.getParams(),
+ handler.params));
+ handler.handleException(exception, response);
+ submitResponse(response);
+ }
+
+ @Override
+ public void submitResponse(HttpResponse response) {
+ AsyncNHttpServiceHandler handler = AsyncNHttpServiceHandler.this;
+ try {
+ handler.sendResponse(conn, request, response);
+ } catch (IOException ex) {
+ handler.shutdownConnection(conn, ex);
+ if (handler.eventListener != null) {
+ handler.eventListener.fatalIOException(ex, conn);
+ }
+ } catch (HttpException ex) {
+ handler.closeConnection(conn, ex);
+ if (handler.eventListener != null) {
+ handler.eventListener.fatalProtocolException(ex, conn);
+ }
+ }
+ }
+ }
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/protocol/AsyncNHttpServiceHandler.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/protocol/NBlockingHttpRequestHandler.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/NBlockingHttpRequestHandler.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/NBlockingHttpRequestHandler.java (revision 0)
@@ -0,0 +1,240 @@
+package org.apache.http.nio.protocol;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+
+import org.apache.http.Header;
+import org.apache.http.HeaderIterator;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolVersion;
+import org.apache.http.RequestLine;
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.entity.ConsumingNHttpEntity;
+import org.apache.http.nio.entity.ContentBufferEntity;
+import org.apache.http.nio.entity.ContentListener;
+import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.nio.util.ContentInputBuffer;
+import org.apache.http.nio.util.HeapByteBufferAllocator;
+import org.apache.http.nio.util.SharedInputBuffer;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+
+/**
+ * A {@link HttpRequestHandler} that is intended for use with
+ * {@link AsyncNHttpServiceHandler} and pre-existing HttpRequestHandlers that
+ * use {@link HttpEntity#getContent()}. Normally, calling getContent() on an
+ * entity from AsyncNHttpServiceHandler would throw an
+ * {@link UnsupportedOperationException}. This class will intercept the entity
+ * and allow getContent() to be called. However, a portion of the entity may be
+ * buffered in memory if classes do not quickly consume the content.
+ *
+ * Use this class sparingly. For best results, rewrite the handler to work with
+ * {@link ConsumingNHttpEntity}, and avoid using this class entirely.
+ *
+ * @author Sam Berlin
+ */
+public class NBlockingHttpRequestHandler implements NHttpRequestHandler {
+
+ private final HttpRequestHandler delegate;
+ private final Executor executor;
+ private final ByteBufferAllocator allocator;
+
+ public NBlockingHttpRequestHandler(HttpRequestHandler delegate,
+ Executor executor) {
+ this(delegate, executor, new HeapByteBufferAllocator());
+ }
+
+ public NBlockingHttpRequestHandler(HttpRequestHandler delegate,
+ Executor executor, ByteBufferAllocator allocator) {
+ this.delegate = delegate;
+ this.executor = executor;
+ this.allocator = allocator;
+ }
+
+ @Override
+ public ContentListener entityRequest(HttpEntityEnclosingRequest request,
+ HttpContext context) {
+ IOControl ioctrl = (IOControl)context.getAttribute(ExecutionContext.HTTP_CONNECTION);
+ return new ContentReader(allocator, ioctrl);
+ }
+
+ @Override
+ public void handle(final HttpRequest request, final HttpResponse response,
+ final NHttpResponseTrigger trigger, final HttpContext context) {
+ // TODO: It's possible that if the request wasn't an entity-enclosing request,
+ // this could process outside of the executor. However, that opens up the
+ // possibility that client code might block (for some unknown reason, such
+ // as looking up an outside resource) before setting a response.
+ executor.execute(new Runnable() {
+ public void run() {
+ HttpRequest newRequest = request;
+ // Wrap the request in a new request that returns a blocking entity,
+ // if necessary.
+ if(newRequest instanceof HttpEntityEnclosingRequest) {
+ HttpEntityEnclosingRequest entityReq = (HttpEntityEnclosingRequest)request;
+ ConsumingNHttpEntity consumingEntity = (ConsumingNHttpEntity)entityReq.getEntity();
+ ContentReader reader = (ContentReader)consumingEntity.getContentListener();
+ HttpEntity blockingEntity = new ContentBufferEntity(consumingEntity, reader.getInputBuffer());
+ newRequest = new EntityRequest(entityReq, blockingEntity);
+ }
+ try {
+ delegate.handle(newRequest, response, context);
+ trigger.submitResponse(response);
+ } catch (HttpException e) {
+ trigger.recoverableException(e);
+ } catch (IOException e) {
+ trigger.fatalException(e);
+ }
+ }
+ });
+ }
+
+ static class ContentReader implements ContentListener {
+ private final SharedInputBuffer inputBuffer;
+
+ public ContentReader(ByteBufferAllocator allocator, IOControl ioctrl) {
+ inputBuffer = new SharedInputBuffer(2048, ioctrl, allocator);
+ }
+
+ @Override
+ public boolean consumeContent(ContentDecoder decoder, IOControl ioctrl)
+ throws IOException {
+ inputBuffer.consumeContent(decoder);
+ return true;
+ }
+
+ @Override
+ public void finish() {
+ inputBuffer.shutdown();
+ }
+
+ public ContentInputBuffer getInputBuffer() {
+ return inputBuffer;
+ }
+ }
+
+ static class EntityRequest implements HttpEntityEnclosingRequest {
+ private final HttpEntityEnclosingRequest request;
+ private final HttpEntity entity;
+
+ public EntityRequest(HttpEntityEnclosingRequest request,
+ HttpEntity entity) {
+ this.request = request;
+ this.entity = entity;
+ }
+
+ @Override
+ public boolean expectContinue() {
+ return request.expectContinue();
+ }
+
+ @Override
+ public HttpEntity getEntity() {
+ return entity;
+ }
+
+ @Override
+ public void setEntity(HttpEntity entity) {
+ throw new UnsupportedOperationException("cannot set entity");
+ }
+
+ @Override
+ public RequestLine getRequestLine() {
+ return request.getRequestLine();
+ }
+
+ @Override
+ public void addHeader(Header header) {
+ throw new UnsupportedOperationException("cannot add header");
+ }
+
+ @Override
+ public void addHeader(String name, String value) {
+ throw new UnsupportedOperationException("cannot add header");
+ }
+
+ @Override
+ public boolean containsHeader(String name) {
+ return request.containsHeader(name);
+ }
+
+ @Override
+ public Header[] getAllHeaders() {
+ return request.getAllHeaders();
+ }
+
+ @Override
+ public Header getFirstHeader(String name) {
+ return request.getFirstHeader(name);
+ }
+
+ @Override
+ public Header[] getHeaders(String name) {
+ return request.getHeaders(name);
+ }
+
+ @Override
+ public Header getLastHeader(String name) {
+ return request.getLastHeader(name);
+ }
+
+ @Override
+ public HttpParams getParams() {
+ return request.getParams();
+ }
+
+ @Override
+ public ProtocolVersion getProtocolVersion() {
+ return request.getProtocolVersion();
+ }
+
+ @Override
+ public HeaderIterator headerIterator() {
+ return request.headerIterator();
+ }
+
+ @Override
+ public HeaderIterator headerIterator(String name) {
+ return request.headerIterator(name);
+ }
+
+ @Override
+ public void removeHeader(Header header) {
+ throw new UnsupportedOperationException("cannot remove header");
+
+ }
+
+ @Override
+ public void removeHeaders(String name) {
+ throw new UnsupportedOperationException("cannot remove header");
+ }
+
+ @Override
+ public void setHeader(Header header) {
+ throw new UnsupportedOperationException("cannot set header");
+ }
+
+ @Override
+ public void setHeader(String name, String value) {
+ throw new UnsupportedOperationException("cannot set header");
+ }
+
+ @Override
+ public void setHeaders(Header[] headers) {
+ throw new UnsupportedOperationException("cannot set header");
+ }
+
+ @Override
+ public void setParams(HttpParams params) {
+ throw new UnsupportedOperationException("cannot set params");
+ }
+
+ }
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/protocol/NBlockingHttpRequestHandler.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerResolver.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerResolver.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerResolver.java (revision 0)
@@ -0,0 +1,46 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestHandlerResolver.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 17:09:22 -0500 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.nio.protocol;
+
+/**
+ * Interface to be implemented by objects that can resolve
+ * {@link NHttpRequestHandler} instances by request URI.
+ *
+ * @author Oleg Kalnichevski
+ *
+ * @version $Revision: 613298 $
+ */
+public interface NHttpRequestHandlerResolver {
+
+ NHttpRequestHandler lookup(String requestURI);
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerResolver.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerRegistry.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerRegistry.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerRegistry.java (revision 0)
@@ -0,0 +1,76 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/protocol/HttpRequestHandlerRegistry.java $
+ * $Revision: 613298 $
+ * $Date: 2008-01-18 17:09:22 -0500 (Fri, 18 Jan 2008) $
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.nio.protocol;
+
+import java.util.Map;
+
+import org.apache.http.protocol.UriPatternMatcher;
+
+/**
+ * Maintains a map of HTTP request handlers keyed by a request URI pattern.
+ * {@link NHttpRequestHandler} instances can be looked up by request URI
+ * using the {@link NHttpRequestHandlerResolver} interface.
+ * Patterns may have three formats:
+ *
+ * *
+ * *<uri>
+ * <uri>*
+ *
+ *
+ * @author Oleg Kalnichevski
+ *
+ * @version $Revision: 613298 $
+ */
+public class NHttpRequestHandlerRegistry implements NHttpRequestHandlerResolver {
+
+ private final UriPatternMatcher matcher;
+
+ public NHttpRequestHandlerRegistry() {
+ this.matcher = new UriPatternMatcher();
+ }
+
+ public void register(final String pattern, final NHttpRequestHandler handler) {
+ matcher.register(pattern, handler);
+ }
+
+ public void unregister(final String pattern) {
+ matcher.unregister(pattern);
+ }
+
+ public void setHandlers(final Map map) {
+ matcher.setHandlers(map);
+ }
+
+ public NHttpRequestHandler lookup(String requestURI) {
+ return (NHttpRequestHandler)matcher.lookup(requestURI);
+ }
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/protocol/NHttpRequestHandlerRegistry.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/ContentDecoderChannel.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/ContentDecoderChannel.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/ContentDecoderChannel.java (revision 0)
@@ -0,0 +1,36 @@
+package org.apache.http.nio;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+
+/**
+ * A {@link ReadableByteChannel} that delegates to a {@link ContentDecoder}.
+ * Attempts to close this channel are ignored, and isOpen always returns true.
+ *
+ * @author Sam Berlin
+ */
+public class ContentDecoderChannel implements ReadableByteChannel {
+
+ private final ContentDecoder decoder;
+
+ public ContentDecoderChannel(ContentDecoder decoder) {
+ this.decoder = decoder;
+ }
+
+ @Override
+ public int read(ByteBuffer dst) throws IOException {
+ return decoder.read(dst);
+ }
+
+ @Override
+ public void close() {}
+
+ @Override
+ public boolean isOpen() {
+ return true;
+ }
+
+
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/ContentDecoderChannel.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/ContentBufferEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/ContentBufferEntity.java (revision 628407)
+++ module-nio/src/main/java/org/apache/http/nio/entity/ContentBufferEntity.java (working copy)
@@ -36,6 +36,7 @@
import org.apache.http.entity.BasicHttpEntity;
import org.apache.http.nio.util.ContentInputBuffer;
+@Deprecated
public class ContentBufferEntity extends BasicHttpEntity {
/** The wrapped entity. */
Index: module-nio/src/main/java/org/apache/http/nio/entity/ByteArrayNIOEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/ByteArrayNIOEntity.java (revision 628407)
+++ module-nio/src/main/java/org/apache/http/nio/entity/ByteArrayNIOEntity.java (working copy)
@@ -1,7 +1,7 @@
/*
- * $HeadURL:$
- * $Revision:$
- * $Date:$
+ * $HeadURL$
+ * $Revision$
+ * $Date$
*
* ====================================================================
* Licensed to the Apache Software Foundation (ASF) under one
@@ -45,10 +45,11 @@
*
* @author Oleg Kalnichevski
*
- * @version $Revision:$
+ * @version $Revision$
*
* @since 4.0
*/
+@Deprecated
public class ByteArrayNIOEntity extends ByteArrayEntity implements HttpNIOEntity {
public ByteArrayNIOEntity(final byte[] b) {
Index: module-nio/src/main/java/org/apache/http/nio/entity/ProducingNHttpEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/ProducingNHttpEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/ProducingNHttpEntity.java (revision 0)
@@ -0,0 +1,25 @@
+package org.apache.http.nio.entity;
+
+import java.io.IOException;
+
+import org.apache.http.HttpEntity;
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.IOControl;
+
+/**
+ * An {@link NHttpEntity} that writes content to a {@link ContentEncoder}.
+ *
+ * @author Sam Berlin
+ */
+public interface ProducingNHttpEntity extends HttpEntity {
+
+ /**
+ * Notification that content should be written to the encoder.
+ * When all content is finished, this MUST call {@link ContentEncoder#complete()}.
+ * Failure to do so could result in the entity never being written.
+ */
+ void produceContent(ContentEncoder encoder, IOControl ioctrl) throws IOException;
+
+ void finish();
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/ProducingNHttpEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/ContentInputStream.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/ContentInputStream.java (revision 628407)
+++ module-nio/src/main/java/org/apache/http/nio/entity/ContentInputStream.java (working copy)
@@ -36,6 +36,7 @@
import org.apache.http.nio.util.ContentInputBuffer;
+@Deprecated
public class ContentInputStream extends InputStream {
private final ContentInputBuffer buffer;
Index: module-nio/src/main/java/org/apache/http/nio/entity/ContentOutputStream.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/ContentOutputStream.java (revision 628407)
+++ module-nio/src/main/java/org/apache/http/nio/entity/ContentOutputStream.java (working copy)
@@ -36,6 +36,7 @@
import org.apache.http.nio.util.ContentOutputBuffer;
+@Deprecated
public class ContentOutputStream extends OutputStream {
private final ContentOutputBuffer buffer;
Index: module-nio/src/main/java/org/apache/http/nio/entity/ConsumingNHttpEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/ConsumingNHttpEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/ConsumingNHttpEntity.java (revision 0)
@@ -0,0 +1,23 @@
+package org.apache.http.nio.entity;
+
+import org.apache.http.HttpEntity;
+
+
+
+/**
+ * A non-blocking entity that allows content to be consumed from a decoder.
+ *
+ * If external code wants to be notified when more content is available, it
+ * should install a ContentListener on the entity via
+ * {@link #setContentListener(org.apache.http.nio.entity.ConsumingNHttpEntity.ContentListener)}.
+ * When content becomes available, implementations must notify the listener.
+ *
+ * All blocking methods throw an {@link UnsupportedOperationException}.
+ *
+ * @author Sam Berlin
+ */
+public interface ConsumingNHttpEntity extends HttpEntity {
+
+ ContentListener getContentListener();
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/ConsumingNHttpEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/NByteArrayEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/NByteArrayEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/NByteArrayEntity.java (revision 0)
@@ -0,0 +1,87 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/entity/ByteArrayNIOEntity.java $
+ * $Revision: 602520 $
+ * $Date: 2007-12-08 12:42:26 -0500 (Sat, 08 Dec 2007) $
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.nio.entity;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.protocol.AsyncNHttpServiceHandler;
+
+/**
+ * An entity whose content is retrieved from a byte array.
+ * This entity is intended for use only as an {@link NHttpEntity}.
+ * Blocking methods are not supported.
+ *
+ * @author Sam Berlin
+ *
+ * @version $Revision: 602520 $
+ *
+ * @see AsyncNHttpServiceHandler
+ * @since 4.0
+ */
+public class NByteArrayEntity extends AbstractNHttpEntity implements ProducingNHttpEntity {
+
+ protected final ByteBuffer buffer;
+
+ public NByteArrayEntity(final byte[] b) {
+ this.buffer = ByteBuffer.wrap(b);
+ }
+
+ @Override
+ public void finish() {
+ buffer.rewind();
+ }
+
+ @Override
+ public void produceContent(ContentEncoder encoder, IOControl ioctrl)
+ throws IOException {
+ encoder.write(buffer);
+ if(!buffer.hasRemaining())
+ encoder.complete();
+ }
+
+ @Override
+ public long getContentLength() {
+ return buffer.limit();
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ return true;
+ }
+
+
+
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/NByteArrayEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/AbstractNHttpEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/AbstractNHttpEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/AbstractNHttpEntity.java (revision 0)
@@ -0,0 +1,37 @@
+package org.apache.http.nio.entity;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.apache.http.entity.AbstractHttpEntity;
+
+/**
+ * An abstract implementation of {@link NHttpEntity} that stubs out all blocking
+ * methods, throwing an {@link UnsupportedOperationException}.
+ */
+public abstract class AbstractNHttpEntity extends AbstractHttpEntity {
+
+ @Override
+ public final InputStream getContent() throws IOException, IllegalStateException {
+ throw new UnsupportedOperationException("Does not support blocking methods");
+ }
+
+ @Override
+ public final boolean isStreaming() {
+ throw new UnsupportedOperationException("Does not support blocking methods");
+ }
+
+ @Override
+ public final void writeTo(OutputStream arg0) throws IOException {
+ throw new UnsupportedOperationException("Does not support blocking methods");
+ }
+
+ @Override
+ public final void consumeContent() throws IOException, UnsupportedOperationException {
+ throw new UnsupportedOperationException("Does not support blocking methods");
+ }
+
+
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/AbstractNHttpEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/BasicConsumingNHttpEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/BasicConsumingNHttpEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/BasicConsumingNHttpEntity.java (revision 0)
@@ -0,0 +1,57 @@
+package org.apache.http.nio.entity;
+
+import org.apache.http.HttpEntity;
+
+/**
+ * A default implementation of {@link ConsumingNHttpEntity}.
+ * Blocking output methods will throw {@link UnsupportedOperationException}.
+ *
+ * @author Sam Berlin
+ */
+public class BasicConsumingNHttpEntity extends AbstractNHttpEntity implements ConsumingNHttpEntity {
+
+ private final ContentListener contentListener;
+ private long contentLength;
+ private boolean handled;
+
+ public BasicConsumingNHttpEntity(ContentListener contentListener, HttpEntity httpEntity) {
+ this.contentListener = contentListener;
+ setChunked(httpEntity.isChunked());
+ setContentEncoding(httpEntity.getContentEncoding());
+ setContentLength(httpEntity.getContentLength());
+ setContentType(httpEntity.getContentType());
+ }
+
+ public void setHandled(boolean handled) {
+ this.handled = handled;
+ }
+
+ public boolean isHandled() {
+ return handled;
+ }
+
+ /**
+ * Specifies the length of the content.
+ *
+ * @param len the number of bytes in the content, or
+ * a negative number to indicate an unknown length
+ */
+ public void setContentLength(long len) {
+ this.contentLength = len;
+ }
+
+ @Override
+ public ContentListener getContentListener() {
+ return contentListener;
+ }
+
+ @Override
+ public long getContentLength() {
+ return contentLength;
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ return false;
+ }
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/BasicConsumingNHttpEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/ContentListener.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/ContentListener.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/ContentListener.java (revision 0)
@@ -0,0 +1,23 @@
+package org.apache.http.nio.entity;
+
+import java.io.IOException;
+
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.IOControl;
+
+/**
+ * A listener for available data on a non-blocking {@link ConsumingNHttpEntity}.
+ */
+public interface ContentListener {
+
+ /**
+ * Notification that content is available to be read from the decoder.
+ * Implementations should return true when flow can continue in processing
+ * a series of requests & responses. In general, an implementation should
+ * return true if {@link ContentDecoder#isCompleted()} is true.
+ */
+ boolean consumeContent(ContentDecoder decoder, IOControl ioctrl) throws IOException;
+
+ /** Notification that any resources allocated for reading can be released. */
+ void finish();
+}
\ No newline at end of file
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/ContentListener.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/NStringEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/NStringEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/NStringEntity.java (revision 0)
@@ -0,0 +1,98 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/entity/StringNIOEntity.java $
+ * $Revision: 602520 $
+ * $Date: 2007-12-08 12:42:26 -0500 (Sat, 08 Dec 2007) $
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.nio.entity;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.nio.ByteBuffer;
+
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.protocol.AsyncNHttpServiceHandler;
+import org.apache.http.protocol.HTTP;
+
+/**
+ * An entity whose content is retrieved from a string.
+ * This entity is intended for use only as an {@link NHttpEntity}.
+ * Blocking methods are not supported.
+ *
+ * @author Sam Berlin
+ *
+ * @version $Revision: 602520 $
+ *
+ * @see AsyncNHttpServiceHandler
+ * @since 4.0
+ */
+public class NStringEntity extends AbstractNHttpEntity implements ProducingNHttpEntity {
+
+ protected final ByteBuffer buffer;
+
+ public NStringEntity(final String s, String charset)
+ throws UnsupportedEncodingException {
+ if (s == null) {
+ throw new IllegalArgumentException("Source string may not be null");
+ }
+ if (charset == null) {
+ charset = HTTP.DEFAULT_CONTENT_CHARSET;
+ }
+ this.buffer = ByteBuffer.wrap(s.getBytes(charset));
+ setContentType(HTTP.PLAIN_TEXT_TYPE + HTTP.CHARSET_PARAM + charset);
+ }
+
+ public NStringEntity(final String s) throws UnsupportedEncodingException {
+ this(s, null);
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ @Override
+ public long getContentLength() {
+ return this.buffer.limit();
+ }
+
+ @Override
+ public void finish() {
+ buffer.rewind();
+ }
+
+ @Override
+ public void produceContent(ContentEncoder encoder, IOControl ioctrl)
+ throws IOException {
+ encoder.write(buffer);
+ if(!buffer.hasRemaining())
+ encoder.complete();
+ }
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/NStringEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/HttpNIOEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/HttpNIOEntity.java (revision 628407)
+++ module-nio/src/main/java/org/apache/http/nio/entity/HttpNIOEntity.java (working copy)
@@ -36,6 +36,7 @@
import org.apache.http.HttpEntity;
+@Deprecated
public interface HttpNIOEntity extends HttpEntity {
ReadableByteChannel getChannel() throws IOException;
Index: module-nio/src/main/java/org/apache/http/nio/entity/NFileEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/NFileEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/NFileEntity.java (revision 0)
@@ -0,0 +1,113 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-nio/src/main/java/org/apache/http/nio/entity/FileNIOEntity.java $
+ * $Revision: 602520 $
+ * $Date: 2007-12-08 12:42:26 -0500 (Sat, 08 Dec 2007) $
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+
+package org.apache.http.nio.entity;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.ContentEncoderChannel;
+import org.apache.http.nio.FileContentEncoder;
+import org.apache.http.nio.IOControl;
+
+/**
+ * An entity whose content is retrieved from from a file.
+ * This entity is intended for use only as an {@link NHttpEntity}.
+ * Blocking methods are not supported.
+ *
+ * @author Sam Berlin
+ *
+ * @version $Revision: 602520 $
+ *
+ * @since 4.0
+ */
+public class NFileEntity extends AbstractNHttpEntity implements ProducingNHttpEntity {
+
+ private final File file;
+ private FileChannel fileChannel;
+ private long idx = -1;
+ private boolean useFileChannels;
+
+ public NFileEntity(final File file, final String contentType, boolean useFileChannels) {
+ if (file == null) {
+ throw new IllegalArgumentException("File may not be null");
+ }
+ this.file = file;
+ this.useFileChannels = useFileChannels;
+ setContentType(contentType);
+ }
+
+ @Override
+ public void finish() {
+ try {
+ if(fileChannel != null)
+ fileChannel.close();
+ } catch(IOException ignored) {}
+ fileChannel = null;
+ }
+
+ @Override
+ public long getContentLength() {
+ return file.length();
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ return true;
+ }
+
+ @Override
+ public void produceContent(ContentEncoder encoder, IOControl ioctrl)
+ throws IOException {
+ if(fileChannel == null) {
+ FileInputStream in = new FileInputStream(file);
+ fileChannel = in.getChannel();
+ idx = 0;
+ }
+
+ long transferred;
+ if(useFileChannels && encoder instanceof FileContentEncoder) {
+ transferred = ((FileContentEncoder)encoder).transfer(fileChannel, idx, 100);
+ } else {
+ transferred = fileChannel.transferTo(idx, Long.MAX_VALUE, new ContentEncoderChannel(encoder));
+ }
+
+ if(transferred > 0)
+ idx += transferred;
+
+ if(idx >= fileChannel.size())
+ encoder.complete();
+ }
+
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/NFileEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/entity/NBlockingProducingNHttpEntity.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/entity/NBlockingProducingNHttpEntity.java (revision 0)
+++ module-nio/src/main/java/org/apache/http/nio/entity/NBlockingProducingNHttpEntity.java (revision 0)
@@ -0,0 +1,77 @@
+package org.apache.http.nio.entity;
+
+import java.io.IOException;
+
+import org.apache.http.Header;
+import org.apache.http.HttpEntity;
+import org.apache.http.nio.ContentEncoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.protocol.AsyncNHttpServiceHandler;
+import org.apache.http.nio.util.ByteBufferAllocator;
+import org.apache.http.nio.util.SimpleOutputBuffer;
+
+/**
+ * A {@link ProducingNHttpEntity} that delegates to a blocking
+ * {@link HttpEntity}. This is useful when the only entity available is a
+ * blocking one, but you want to make it work in a non-blocking manner.
+ *
+ * The entire output is buffered in memory.
+ *
+ * @see AsyncNHttpServiceHandler
+ *
+ * @author Sam Berlin
+ */
+public class NBlockingProducingNHttpEntity extends AbstractNHttpEntity implements
+ ProducingNHttpEntity {
+
+ private final HttpEntity entity;
+ private final ByteBufferAllocator allocator;
+ private SimpleOutputBuffer outputBuffer;
+
+ public NBlockingProducingNHttpEntity(HttpEntity entity, ByteBufferAllocator allocator) {
+ this.entity = entity;
+ this.allocator = allocator;
+ }
+
+ @Override
+ public void finish() {
+ }
+
+
+ @Override
+ public void produceContent(ContentEncoder encoder, IOControl ioctrl) throws IOException {
+ if(outputBuffer == null) {
+ outputBuffer = new SimpleOutputBuffer(2048, allocator);
+ entity.writeTo(new ContentOutputStream(outputBuffer));
+ }
+
+ outputBuffer.produceContent(encoder);
+ if(!outputBuffer.hasData())
+ encoder.complete();
+ }
+
+ @Override
+ public long getContentLength() {
+ return entity.getContentLength();
+ }
+
+ @Override
+ public boolean isRepeatable() {
+ return entity.isRepeatable();
+ }
+
+ @Override
+ public Header getContentEncoding() {
+ return entity.getContentEncoding();
+ }
+
+ @Override
+ public Header getContentType() {
+ return entity.getContentType();
+ }
+
+ @Override
+ public boolean isChunked() {
+ return entity.isChunked();
+ }
+}
Property changes on: module-nio/src/main/java/org/apache/http/nio/entity/NBlockingProducingNHttpEntity.java
___________________________________________________________________
Name: svn:executable
+ *
Index: module-nio/src/main/java/org/apache/http/nio/util/ContentInputBuffer.java
===================================================================
--- module-nio/src/main/java/org/apache/http/nio/util/ContentInputBuffer.java (revision 628407)
+++ module-nio/src/main/java/org/apache/http/nio/util/ContentInputBuffer.java (working copy)
@@ -35,6 +35,7 @@
import org.apache.http.nio.ContentDecoder;
+@Deprecated
public interface ContentInputBuffer {
int consumeContent(ContentDecoder decoder) throws IOException;
Index: module-nio/src/examples/org/apache/http/examples/nio/AsyncNHttpFileServer.java
===================================================================
--- module-nio/src/examples/org/apache/http/examples/nio/AsyncNHttpFileServer.java (revision 0)
+++ module-nio/src/examples/org/apache/http/examples/nio/AsyncNHttpFileServer.java (revision 0)
@@ -0,0 +1,250 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-nio/src/examples/org/apache/http/examples/nio/NHttpFileServer.java $
+ * $Revision: 610763 $
+ * $Date: 2008-01-10 07:01:13 -0500 (Thu, 10 Jan 2008) $
+ *
+ * ====================================================================
+ * 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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * .
+ *
+ */
+package org.apache.http.examples.nio;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetSocketAddress;
+import java.net.URLDecoder;
+import java.nio.channels.FileChannel;
+
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.DefaultHttpResponseFactory;
+import org.apache.http.impl.nio.DefaultServerIOEventDispatch;
+import org.apache.http.impl.nio.reactor.DefaultListeningIOReactor;
+import org.apache.http.nio.ContentDecoder;
+import org.apache.http.nio.ContentDecoderChannel;
+import org.apache.http.nio.FileContentDecoder;
+import org.apache.http.nio.IOControl;
+import org.apache.http.nio.NHttpConnection;
+import org.apache.http.nio.NHttpServiceHandler;
+import org.apache.http.nio.entity.ConsumingNHttpEntity;
+import org.apache.http.nio.entity.ContentListener;
+import org.apache.http.nio.entity.NFileEntity;
+import org.apache.http.nio.entity.NStringEntity;
+import org.apache.http.nio.protocol.AsyncNHttpServiceHandler;
+import org.apache.http.nio.protocol.EventListener;
+import org.apache.http.nio.protocol.NHttpRequestHandler;
+import org.apache.http.nio.protocol.NHttpRequestHandlerRegistry;
+import org.apache.http.nio.protocol.NHttpResponseTrigger;
+import org.apache.http.nio.reactor.IOEventDispatch;
+import org.apache.http.nio.reactor.ListeningIOReactor;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.HttpRequestHandlerRegistry;
+import org.apache.http.protocol.ResponseConnControl;
+import org.apache.http.protocol.ResponseContent;
+import org.apache.http.protocol.ResponseDate;
+import org.apache.http.protocol.ResponseServer;
+
+/**
+ * A version of {@link NHttpFileServer} that uses {@link AsyncNHttpServiceHandler}
+ * instead of implementing its own {@link NHttpServiceHandler}. This makes the example
+ * very analogous to {@link NHttpServer}, except it is fully asynchronous and does
+ * not buffer the contents of the file in memory.
+ */
+public class AsyncNHttpFileServer {
+
+ public static void main(String[] args) throws Exception {
+ if (args.length < 1) {
+ System.err.println("Please specify document root directory");
+ System.exit(1);
+ }
+ boolean useFileChannels = true;
+ if (args.length >= 2) {
+ String s = args[1];
+ if (s.equalsIgnoreCase("disableFileChannels")) {
+ useFileChannels = false;
+ }
+ }
+
+ HttpParams params = new BasicHttpParams();
+ params
+ .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
+ .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
+ .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
+ .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
+ .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "HttpComponents/1.1");
+
+ BasicHttpProcessor httpproc = new BasicHttpProcessor();
+ httpproc.addInterceptor(new ResponseDate());
+ httpproc.addInterceptor(new ResponseServer());
+ httpproc.addInterceptor(new ResponseContent());
+ httpproc.addInterceptor(new ResponseConnControl());
+
+ AsyncNHttpServiceHandler handler = new AsyncNHttpServiceHandler(
+ httpproc,
+ new DefaultHttpResponseFactory(),
+ new DefaultConnectionReuseStrategy(),
+ params);
+
+ // Set up request handlers
+ NHttpRequestHandlerRegistry reqistry = new NHttpRequestHandlerRegistry();
+ reqistry.register("*", new HttpFileHandler(args[0], useFileChannels));
+
+ handler.setHandlerResolver(reqistry);
+
+ // Provide an event logger
+ handler.setEventListener(new EventLogger());
+
+ IOEventDispatch ioEventDispatch = new DefaultServerIOEventDispatch(handler, params);
+ ListeningIOReactor ioReactor = new DefaultListeningIOReactor(2, params);
+ try {
+ ioReactor.listen(new InetSocketAddress(8080));
+ ioReactor.execute(ioEventDispatch);
+ } catch (InterruptedIOException ex) {
+ System.err.println("Interrupted");
+ } catch (IOException e) {
+ System.err.println("I/O error: " + e.getMessage());
+ }
+ System.out.println("Shutdown");
+ }
+
+ static class HttpFileHandler implements NHttpRequestHandler {
+
+ private final String docRoot;
+ private final boolean useFileChannels;
+
+ public HttpFileHandler(final String docRoot, boolean useFileChannels) {
+ this.docRoot = docRoot;
+ this.useFileChannels = useFileChannels;
+ }
+
+ @Override
+ public ContentListener entityRequest(
+ HttpEntityEnclosingRequest request, HttpContext context)
+ throws HttpException, IOException {
+ return new FileWriteListener(useFileChannels);
+ }
+
+ @Override
+ public void handle(HttpRequest request, HttpResponse response,
+ NHttpResponseTrigger trigger, HttpContext context)
+ throws HttpException, IOException {
+ String target = request.getRequestLine().getUri();
+ final File file = new File(this.docRoot, URLDecoder.decode(target, "UTF-8"));
+ if (!file.exists()) {
+ response.setStatusCode(HttpStatus.SC_NOT_FOUND);
+ NStringEntity entity = new NStringEntity("
File" +
+ file.getPath() + " not found
", "UTF-8");
+ entity.setContentType("text/html; charset=UTF-8");
+ response.setEntity(entity);
+ } else if (!file.canRead() || file.isDirectory()) {
+ response.setStatusCode(HttpStatus.SC_FORBIDDEN);
+ NStringEntity entity = new NStringEntity("Access denied
", "UTF-8");
+ entity.setContentType("text/html; charset=UTF-8");
+ response.setEntity(entity);
+ } else {
+ response.setStatusCode(HttpStatus.SC_OK);
+ NFileEntity entity = new NFileEntity(file, "text/html", useFileChannels);
+ response.setEntity(entity);
+ }
+
+ trigger.submitResponse(response);
+ }
+ }
+
+ static class FileWriteListener implements ContentListener {
+ private final File file;
+ private final FileInputStream inputFile;
+ private final FileChannel fileChannel;
+ private final boolean useFileChannels;
+ private long idx = 0;
+
+ public FileWriteListener(boolean useFileChannels) throws IOException {
+ this.file = File.createTempFile("tmp", ".tmp", null);
+ this.inputFile = new FileInputStream(file);
+ this.fileChannel = inputFile.getChannel();
+ this.useFileChannels = useFileChannels;
+ }
+
+ @Override
+ public boolean consumeContent(ContentDecoder decoder, IOControl ioctrl)
+ throws IOException {
+ long transferred;
+ if(useFileChannels && decoder instanceof FileContentDecoder) {
+ transferred = ((FileContentDecoder)decoder).transfer(fileChannel, idx, Long.MAX_VALUE);
+ } else {
+ transferred = fileChannel.transferFrom(new ContentDecoderChannel(decoder), idx, Long.MAX_VALUE);
+ }
+
+ if(transferred > 0)
+ idx += transferred;
+ return decoder.isCompleted();
+ }
+
+ @Override
+ public void finish() {
+ try {
+ inputFile.close();
+ } catch(IOException ignored) {}
+ try {
+ fileChannel.close();
+ } catch(IOException ignored) {}
+ }
+ }
+
+ static class EventLogger implements EventListener {
+
+ public void connectionOpen(final NHttpConnection conn) {
+ System.out.println("Connection open: " + conn);
+ }
+
+ public void connectionTimeout(final NHttpConnection conn) {
+ System.out.println("Connection timed out: " + conn);
+ }
+
+ public void connectionClosed(final NHttpConnection conn) {
+ System.out.println("Connection closed: " + conn);
+ }
+
+ public void fatalIOException(final IOException ex, final NHttpConnection conn) {
+ System.err.println("I/O error: " + ex.getMessage());
+ }
+
+ public void fatalProtocolException(final HttpException ex, final NHttpConnection conn) {
+ System.err.println("HTTP error: " + ex.getMessage());
+ }
+
+ }
+}
Property changes on: module-nio/src/examples/org/apache/http/examples/nio/AsyncNHttpFileServer.java
___________________________________________________________________
Name: svn:executable
+ *