From 12c890bd56063339697954bf41e07b4464bc53dc Mon Sep 17 00:00:00 2001 From: Philippe Schweitzer Date: Fri, 29 Jun 2018 18:20:52 +0200 Subject: [PATCH 1/3] INIT --- .../common/thread/ConcurrentExecutor.java | 28 +- .../common/thread/ConcurrentScheduler.java | 26 + .../common/thread/ExecutorQueue.java | 226 +++-- .../common/thread/SchedulerQueue.java | 38 + .../org/simpleframework/http/Response.java | 9 +- .../simpleframework/http/ResponseWrapper.java | 8 + .../simpleframework/http/core/Container.java | 2 + .../http/core/ContainerController.java | 78 +- .../core/ContainerTransportProcessor.java | 42 + .../simpleframework/http/core/Controller.java | 11 +- .../http/core/ResponseEntity.java | 793 +++++++-------- .../http/core/ResponseMessage.java | 17 - .../http/message/MessageHeader.java | 913 +++++++++--------- .../http/parse/ContentTypeParser.java | 3 + .../http/socket/service/RouterContainer.java | 3 +- .../transport/TransportProcessor.java | 4 + 16 files changed, 1251 insertions(+), 950 deletions(-) diff --git a/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentExecutor.java b/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentExecutor.java index 9f99025..44070a5 100644 --- a/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentExecutor.java +++ b/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentExecutor.java @@ -19,7 +19,7 @@ package org.simpleframework.common.thread; import java.util.concurrent.Executor; - +import org.simpleframework.http.core.Controller; /** * The ConcurrentExecutor object is used to execute tasks * in a thread pool. This creates a thread pool with an unbounded list @@ -94,6 +94,18 @@ public void execute(Runnable task) { public void stop() { stop(60000); } + + /** + * This is used to stop the executor by interrupting all running + * tasks and shutting down the threads within the pool. This will + * return once it has been stopped, and no further tasks will be + * accepted by this pool for execution. + * + * @param stopStrategy the requests/threads stop strategy + */ + public void stop(Controller.STOP_STRATEGY stopStrategy) { + stop(stopStrategy, 60000); + } /** * This is used to stop the executor by interrupting all running @@ -105,5 +117,19 @@ public void stop() { */ public void stop(long wait) { queue.stop(wait); + } + + + /** + * This is used to stop the executor by interrupting all running + * tasks and shutting down the threads within the pool. This will + * return once it has been stopped, and no further tasks will be + * accepted by this pool for execution. + * + * @param stopStrategy the number of milliseconds to wait for it to stop + * @param wait the number of milliseconds to wait for it to stop + */ + public void stop(Controller.STOP_STRATEGY stopStrategy, long wait) { + queue.stop(stopStrategy, wait); } } diff --git a/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentScheduler.java b/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentScheduler.java index bb4a117..fc189d1 100644 --- a/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentScheduler.java +++ b/simple/simple-common/src/main/java/org/simpleframework/common/thread/ConcurrentScheduler.java @@ -19,6 +19,7 @@ package org.simpleframework.common.thread; import java.util.concurrent.TimeUnit; +import org.simpleframework.http.core.Controller; /** * The ConcurrentScheduler object is used to schedule tasks @@ -108,6 +109,18 @@ public void stop() { stop(60000); } + /** + * This is used to stop the scheduler by interrupting all running + * tasks and shutting down the threads within the pool. This will + * return immediately once it has been stopped, and not further + * tasks will be accepted by this pool for execution. + * + * @param stopStrategy the requests/threads stop strategy + */ + public void stop(Controller.STOP_STRATEGY stopStrategy) { + stop(stopStrategy, 60000); + } + /** * This is used to stop the scheduler by interrupting all running * tasks and shutting down the threads within the pool. This will @@ -118,5 +131,18 @@ public void stop() { */ public void stop(long wait) { queue.stop(wait); + } + + /** + * This is used to stop the scheduler by interrupting all running + * tasks and shutting down the threads within the pool. This will + * return once it has been stopped, and no further tasks will be + * accepted by this pool for execution. + * + * @param stopStrategy the number of milliseconds to wait for it to stop + * @param wait the number of milliseconds to wait for it to stop + */ + public void stop(Controller.STOP_STRATEGY stopStrategy, long wait) { + queue.stop(stopStrategy, wait); } } diff --git a/simple/simple-common/src/main/java/org/simpleframework/common/thread/ExecutorQueue.java b/simple/simple-common/src/main/java/org/simpleframework/common/thread/ExecutorQueue.java index 99e8fb2..3c4aaac 100644 --- a/simple/simple-common/src/main/java/org/simpleframework/common/thread/ExecutorQueue.java +++ b/simple/simple-common/src/main/java/org/simpleframework/common/thread/ExecutorQueue.java @@ -15,7 +15,6 @@ * implied. See the License for the specific language governing * permissions and limitations under the License. */ - package org.simpleframework.common.thread; import static java.util.concurrent.TimeUnit.MILLISECONDS; @@ -25,104 +24,141 @@ import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import org.simpleframework.http.core.Controller; /** - * The ExecutorQueue object is used to queue tasks in - * a thread pool. This creates a thread pool with no limit to the - * number of tasks that can be enqueued, which ensures that any - * system requesting a task to be executed will not block when - * handing it over, it also means the user must use caution. - * + * The ExecutorQueue object is used to queue tasks in a thread + * pool. This creates a thread pool with no limit to the number of tasks that + * can be enqueued, which ensures that any system requesting a task to be + * executed will not block when handing it over, it also means the user must use + * caution. + * * @author Niall Gallagher - * + * * @see org.simpleframework.common.thread.ConcurrentExecutor */ class ExecutorQueue { - - /** - * This is the task queue that contains tasks due to execute. - */ - private final BlockingQueue queue; - - /** - * This is the actual thread pool implementation used. - */ - private final ThreadPoolExecutor executor; - - /** - * This is used to create the pool worker threads. - */ - private final ThreadFactory factory; - - /** - * Constructor for the ExecutorQueue object. This is - * used to create a pool of threads that can be used to execute - * arbitrary Runnable tasks. If the threads are - * busy this will simply enqueue the tasks and return. - * - * @param type this is the type of runnable that this accepts - * @param rest this is the number of threads to use in the pool - * @param active this is the maximum size the pool can grow to - */ - public ExecutorQueue(Class type, int rest, int active) { - this(type, rest, active, 120, TimeUnit.SECONDS); - } - - /** - * Constructor for the ExecutorQueue object. This is - * used to create a pool of threads that can be used to execute - * arbitrary Runnable tasks. If the threads are - * busy this will simply enqueue the tasks and return. - * - * @param type this is the type of runnable that this accepts - * @param rest this is the number of threads to use in the pool - * @param active this is the maximum size the pool can grow to - * @param duration the duration active threads remain idle for - * @param unit this is the time unit used for the duration - */ - public ExecutorQueue(Class type, int rest, int active, long duration, TimeUnit unit) { - this.queue = new LinkedBlockingQueue(); - this.factory = new DaemonFactory(type); - this.executor = new ThreadPoolExecutor(rest, active, duration, unit, queue, factory); - } - - /** - * The execute method is used to queue the task for - * execution. If all threads are busy the provided task is queued - * and waits until all current and outstanding tasks are finished. - * - * @param task this is the task to be queued for execution - */ - public void execute(Runnable task) { - executor.execute(task); - } - - /** - * This is used to stop the executor by interrupting all running - * tasks and shutting down the threads within the pool. This will - * return once it has been stopped, and no further tasks will be - * accepted by this pool for execution. - */ - public void stop() { - stop(60000); - } - - /** - * This is used to stop the executor by interrupting all running - * tasks and shutting down the threads within the pool. This will - * return once it has been stopped, and no further tasks will be - * accepted by this pool for execution. - * - * @param wait the number of milliseconds to wait for it to stop - */ - public void stop(long wait) { - if(!executor.isTerminated()) { - try { - executor.shutdown(); - executor.awaitTermination(wait, MILLISECONDS); - } catch(Exception e) { - throw new IllegalStateException("Could not stop pool", e); - } - } - } + + /** + * This is the task queue that contains tasks due to execute. + */ + private final BlockingQueue queue; + + /** + * This is the actual thread pool implementation used. + */ + private final ThreadPoolExecutor executor; + + /** + * This is used to create the pool worker threads. + */ + private final ThreadFactory factory; + + /** + * Constructor for the ExecutorQueue object. This is used to + * create a pool of threads that can be used to execute arbitrary + * Runnable tasks. If the threads are busy this will simply + * enqueue the tasks and return. + * + * @param type this is the type of runnable that this accepts + * @param rest this is the number of threads to use in the pool + * @param active this is the maximum size the pool can grow to + */ + public ExecutorQueue(Class type, int rest, int active) { + this(type, rest, active, 120, TimeUnit.SECONDS); + } + + /** + * Constructor for the ExecutorQueue object. This is used to + * create a pool of threads that can be used to execute arbitrary + * Runnable tasks. If the threads are busy this will simply + * enqueue the tasks and return. + * + * @param type this is the type of runnable that this accepts + * @param rest this is the number of threads to use in the pool + * @param active this is the maximum size the pool can grow to + * @param duration the duration active threads remain idle for + * @param unit this is the time unit used for the duration + */ + public ExecutorQueue(Class type, int rest, int active, long duration, TimeUnit unit) { + this.queue = new LinkedBlockingQueue(); + this.factory = new DaemonFactory(type); + this.executor = new ThreadPoolExecutor(rest, active, duration, unit, queue, factory); + } + + /** + * The execute method is used to queue the task for execution. + * If all threads are busy the provided task is queued and waits until all + * current and outstanding tasks are finished. + * + * @param task this is the task to be queued for execution + */ + public void execute(Runnable task) { + executor.execute(task); + } + + /** + * This is used to stop the executor by interrupting all running tasks and + * shutting down the threads within the pool. This will return once it has + * been stopped, and no further tasks will be accepted by this pool for + * execution. + */ + public void stop() { + stop(60000); + } + + /** + * This is used to stop the executor by interrupting all running tasks and + * shutting down the threads within the pool. This will return once it has + * been stopped, and no further tasks will be accepted by this pool for + * execution. + * + * @param wait the number of milliseconds to wait for it to stop + */ + public void stop(long wait) { + if (!executor.isTerminated()) { + try { + executor.shutdown(); + executor.awaitTermination(wait, MILLISECONDS); + } catch (Exception e) { + throw new IllegalStateException("Could not stop pool", e); + } + } + } + + /** + * This is used to stop the executor by interrupting all running tasks and + * shutting down the threads within the pool. This will return once it has + * been stopped, and no further tasks will be accepted by this pool for + * execution. + * + * @param stopStrategy the STOP_STRATEGY to use + */ + public void stop(Controller.STOP_STRATEGY stopStrategy) { + stop(stopStrategy, 60000); + } + + /** + * This is used to stop the executor by interrupting all running tasks and + * shutting down the threads within the pool. This will return once it has + * been stopped, and no further tasks will be accepted by this pool for + * execution. + * + * @param stopStrategy the STOP_STRATEGY to use + * @param wait the number of milliseconds to wait for it to stop + */ + public void stop(Controller.STOP_STRATEGY stopStrategy, long wait) { + if (!executor.isTerminated()) { + try { + if (stopStrategy == Controller.STOP_STRATEGY.KILL) { + executor.shutdownNow(); + } else { + executor.shutdown(); + executor.awaitTermination(wait, MILLISECONDS); + } + } catch (Exception e) { + throw new IllegalStateException("Could not stop pool", e); + } + } + } } diff --git a/simple/simple-common/src/main/java/org/simpleframework/common/thread/SchedulerQueue.java b/simple/simple-common/src/main/java/org/simpleframework/common/thread/SchedulerQueue.java index 67385ed..a466208 100644 --- a/simple/simple-common/src/main/java/org/simpleframework/common/thread/SchedulerQueue.java +++ b/simple/simple-common/src/main/java/org/simpleframework/common/thread/SchedulerQueue.java @@ -23,6 +23,8 @@ import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ThreadFactory; import java.util.concurrent.TimeUnit; +import static java.util.concurrent.TimeUnit.MILLISECONDS; +import org.simpleframework.http.core.Controller; /** * The SchedulerQueue object is used to schedule tasks @@ -124,4 +126,40 @@ public void stop(long wait) { } } } + + /** + * This is used to stop the executor by interrupting all running + * tasks and shutting down the threads within the pool. This will + * return once it has been stopped, and no further tasks will be + * accepted by this pool for execution. + * + * @param stopStrategy the STOP_STRATEGY to use + */ + public void stop(Controller.STOP_STRATEGY stopStrategy) { + stop(stopStrategy, 60000); + } + + /** + * This is used to stop the executor by interrupting all running + * tasks and shutting down the threads within the pool. This will + * return once it has been stopped, and no further tasks will be + * accepted by this pool for execution. + * + * @param stopStrategy the STOP_STRATEGY to use + * @param wait the number of milliseconds to wait for it to stop + */ + public void stop(Controller.STOP_STRATEGY stopStrategy, long wait) { + if (!executor.isTerminated()) { + try { + if (stopStrategy == Controller.STOP_STRATEGY.KILL) { + executor.shutdownNow(); + } else { + executor.shutdown(); + executor.awaitTermination(wait, MILLISECONDS); + } + } catch (Exception e) { + throw new IllegalStateException("Could not stop pool", e); + } + } + } } diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/Response.java b/simple/simple-http/src/main/java/org/simpleframework/http/Response.java index e9e54da..c55754a 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/Response.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/Response.java @@ -22,6 +22,7 @@ import java.io.OutputStream; import java.io.PrintStream; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; /** * This is used to represent the HTTP response. This provides methods @@ -49,7 +50,13 @@ * @author Niall Gallagher */ public interface Response extends ResponseHeader { - + + /** + * This method sets the Charset of the response. * + * @param charset the new Charset to set to the response + */ + void setCharset(Charset charset); + /** * This should be used when the size of the message body is known. * This ensures that Persistent HTTP (PHTTP) connections can be diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/ResponseWrapper.java b/simple/simple-http/src/main/java/org/simpleframework/http/ResponseWrapper.java index 240384c..cc1f9e1 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/ResponseWrapper.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/ResponseWrapper.java @@ -22,6 +22,7 @@ import java.io.OutputStream; import java.io.PrintStream; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; import java.util.List; /** @@ -55,6 +56,13 @@ public class ResponseWrapper implements Response { */ protected Response response; + /** + * This method sets the Charset of the response. * + * @param charset the new Charset to set to the response + */ + public void setCharset(Charset charset){ + this.response.setCharset(charset); + } /** * Constructor for ResponseWrapper object. This allows * the original Response object to be wrapped so that diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/core/Container.java b/simple/simple-http/src/main/java/org/simpleframework/http/core/Container.java index 91a034c..b4b2521 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/core/Container.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/core/Container.java @@ -20,6 +20,7 @@ import org.simpleframework.http.Request; import org.simpleframework.http.Response; +import org.simpleframework.http.core.Controller.STOP_STRATEGY; /** * The Container object is used to process HTTP requests @@ -59,4 +60,5 @@ public interface Container { * @param resp the response used to deliver the server response */ void handle(Request req, Response resp); + } diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerController.java b/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerController.java index 16a6374..efb39c1 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerController.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerController.java @@ -40,7 +40,17 @@ * * @author Niall Gallagher */ -class ContainerController implements Controller { +public class ContainerController implements Controller { + + /** + * This is the default requests/threads stop strategy + */ + private STOP_STRATEGY stopStrategy = STOP_STRATEGY.WAIT; + + /** + * This is the default requests/threads stop strategy timeout + */ + private long stopTimeout = 60000; /** * This is the thread pool used for servicing the requests. @@ -66,6 +76,30 @@ class ContainerController implements Controller { * This is the reactor used to schedule the collectors. */ private final Reactor reactor; + + + /** + * Constructor for the ContainerController object. This + * is used to create a controller which will collect and dispatch + * requests using two thread pools. The first is used to collect + * the requests, the second is used to service those requests. + * + * @param container this is the container used to service requests + * @param allocator this is used to allocate any buffers needed + * @param count this is the number of threads per thread pool + * @param select this is the number of controller threads to use + * @param closeStrategy this is the manner of requests/threads closing + * @param closeTimeout this is the timeout of requests/threads closing + */ + public ContainerController(Container container, Allocator allocator, int count, int select, STOP_STRATEGY stopStrategy, long stopTimeout) throws IOException { + this.executor = new ConcurrentExecutor(RequestDispatcher.class, count); + this.collect = new ConcurrentExecutor(RequestReader.class, count); + this.reactor = new ExecutorReactor(collect, select); + this.allocator = allocator; + this.container = container; + this.stopStrategy = stopStrategy; + this.stopTimeout = stopTimeout; + } /** * Constructor for the ContainerController object. This @@ -152,10 +186,46 @@ public void ready(Collector collector) throws IOException { public void stop() throws IOException { try { reactor.stop(); - executor.stop(); - collect.stop(); + executor.stop(stopStrategy, stopTimeout); + collect.stop(stopStrategy, stopTimeout); } catch(Exception cause) { throw new TransportException("Error stopping", cause); } - } + } + + /** + * Returns the STOP_STRATEGY for the controller. + * + * @return the STOP_STRATEGY for the controller + */ + public STOP_STRATEGY getStopStrategy() { + return stopStrategy; + } + + /** + * Sets the STOP_STRATEGY. + * + * @param stopStrategy the STOP_STRATEGY to set + */ + public void setStopStrategy(STOP_STRATEGY stopStrategy) { + this.stopStrategy = stopStrategy; + } + + /** + * Returns the timeout after the controller stops. + * + * @return the timeout after the controller stops + */ + public long getStopTimeout() { + return stopTimeout; + } + + /** + * Sets the timeout after the controller stops. + * + * @param stopTimeout the timeout after the controller stops + */ + public void setStopTimeout(long stopTimeout) { + this.stopTimeout = stopTimeout; + } } diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerTransportProcessor.java b/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerTransportProcessor.java index dd6df1a..1b80515 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerTransportProcessor.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/core/ContainerTransportProcessor.java @@ -42,6 +42,39 @@ public class ContainerTransportProcessor implements TransportProcessor { */ private final Controller controller; + /** + * Constructor for the ContainerProcessor object. + * This is used to create a processor which will convert the + * provided transport objects to channels, which can then be + * processed by the controller and dispatched to the container. + * + * @param container the container to dispatch requests to + * @param allocator this is the allocator used to buffer data + * @param count this is the number of threads to be used + * @param stopStrategy this is the stop strategy + * @param stopTimeout this is the timeout for stopping + */ + public ContainerTransportProcessor(Container container, Allocator allocator, int count, Controller.STOP_STRATEGY stopStrategy, long stopTimeout) throws IOException { + this(container, allocator, count, 1, stopStrategy, stopTimeout); + } + + /** + * Constructor for the ContainerProcessor object. + * This is used to create a processor which will convert the + * provided transport objects to channels, which can then be + * processed by the controller and dispatched to the container. + * + * @param container the container to dispatch requests to + * @param allocator this is the allocator used to buffer data + * @param count this is the number of threads to be used + * @param select this is the number of controller threads to use + * @param stopStrategy this is the stop strategy + * @param stopTimeout this is the timeout for stopping + */ + public ContainerTransportProcessor(Container container, Allocator allocator, int count, int select, Controller.STOP_STRATEGY stopStrategy, long stopTimeout) throws IOException { + this.controller = new ContainerController(container, allocator, count, select, stopStrategy, stopTimeout); + } + /** * Constructor for the ContainerProcessor object. * This is used to create a processor which will convert the @@ -93,4 +126,13 @@ public void process(Transport transport) throws IOException { public void stop() throws IOException { controller.stop(); } + + /** + * Returns the ContainerControler. + * + * @return the ContainerControler + */ + public ContainerController getControler(){ + return (ContainerController) this.controller; + } } \ No newline at end of file diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/core/Controller.java b/simple/simple-http/src/main/java/org/simpleframework/http/core/Controller.java index 3e152bd..ad97e53 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/core/Controller.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/core/Controller.java @@ -46,7 +46,16 @@ * * @see org.simpleframework.http.core.Collector */ -interface Controller { +public interface Controller { + + /** + * This is the list of requests/threads stop strategies + * + * WAIT: will wait for a timeout amount + * KILL: will immediately interrupt the execution + * + */ + public static enum STOP_STRATEGY {WAIT,KILL}; /** * This is used to initiate the processing of the channel. Once diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseEntity.java b/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseEntity.java index ae7aed9..7da56fa 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseEntity.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseEntity.java @@ -15,7 +15,6 @@ * implied. See the License for the specific language governing * permissions and limitations under the License. */ - package org.simpleframework.http.core; import static org.simpleframework.http.Protocol.CONTENT_LENGTH; @@ -26,412 +25,420 @@ import java.io.OutputStream; import java.io.PrintStream; import java.nio.channels.WritableByteChannel; +import java.nio.charset.Charset; import java.util.Map; import org.simpleframework.http.ContentType; import org.simpleframework.http.Request; import org.simpleframework.http.Response; import org.simpleframework.http.message.Entity; +import org.simpleframework.http.parse.ContentTypeParser; import org.simpleframework.transport.Channel; import org.simpleframework.transport.ByteWriter; import org.simpleframework.transport.trace.Trace; /** - * This is used to represent the HTTP response. This provides methods - * that can be used to set various characteristics of the response. - * The OutputStream of the Response can be - * retrieved from this interface as can the I.P address of the client - * that will be receiving the Response. The attributes - * of the connection can be retrieved also. This provides a set of - * methods that can be used to set the attributes of the stream so - * the Response can be transported properly. The headers - * can be set and will be sent once a commit is made, or when there - * is content sent over the output stream. + * This is used to represent the HTTP response. This provides methods that can + * be used to set various characteristics of the response. The + * OutputStream of the Response can be retrieved from + * this interface as can the I.P address of the client that will be receiving + * the Response. The attributes of the connection can be retrieved + * also. This provides a set of methods that can be used to set the attributes + * of the stream so the Response can be transported properly. The + * headers can be set and will be sent once a commit is made, or when there is + * content sent over the output stream. *

- * This should never allow the message body be sent if it should not - * be sent with the headers as of RFC 2616 rules for the presence of - * a message body. A message body must not be included with a HEAD - * request or with a 304 or a 204 response. A proper implementation - * of this will prevent a message body being sent if the response - * is to a HEAD request of if there is a 304 or 204 response code. + * This should never allow the message body be sent if it should not be sent + * with the headers as of RFC 2616 rules for the presence of a message body. A + * message body must not be included with a HEAD request or with a 304 or a 204 + * response. A proper implementation of this will prevent a message body being + * sent if the response is to a HEAD request of if there is a 304 or 204 + * response code. *

- * It is important to note that the Response controls - * the processing of the HTTP pipeline. The next HTTP request is - * not processed until the response has committed. The response is - * committed once the commit method is invoked if there - * is NO content body. Committing with a content body is done only if - * correct content is given. The OutputStream acts as - * a client and commits the response once the specified content has - * been written to the issued OutputStream. + * It is important to note that the Response controls the + * processing of the HTTP pipeline. The next HTTP request is not processed until + * the response has committed. The response is committed once the + * commit method is invoked if there is NO content body. Committing + * with a content body is done only if correct content is given. The + * OutputStream acts as a client and commits the response once the + * specified content has been written to the issued OutputStream. * * @author Niall Gallagher - */ -class ResponseEntity extends ResponseMessage implements Response { - - /** - * This is the observer that is used to monitor the response. - */ - private BodyObserver observer; - - /** - * This is used to buffer the bytes that are sent to the client. - */ - private ResponseBuffer buffer; - - /** - * This is the conversation used to determine connection type. - */ - private Conversation support; - - /** - * This is the underlying channel for the connected pipeline. - */ - private Channel channel; - - /** - * This is the sender object used to deliver to response data. - */ - private ByteWriter sender; - - /** - * This is used to trace events that occur with the response - */ - private Trace trace; - - /** - * Constructor for the ResponseEntity object. This is - * used to create a response instance using the provided request, - * entity, and monitor object. To ensure that the response is - * compatible with client the Request is used. Also - * to ensure the next request can be processed the provided monitor - * is used to signal response events to the server kernel. - * - * @param observer this is the observer used to signal events - * @param request this is the request that was sent by the client - * @param entity this is the entity that contains the channel - */ - public ResponseEntity(BodyObserver observer, Request request, Entity entity) { - this.support = new Conversation(request, this); - this.buffer = new ResponseBuffer(observer, this, support, entity); - this.channel = entity.getChannel(); - this.sender = channel.getWriter(); - this.trace = channel.getTrace(); - this.observer = observer; - } - - /** - * This represents the time at which the response has fully written. - * Because the response is delivered asynchronously to the client - * this response time does not represent the time to last byte. - * It simply represents the time at which the response has been - * fully generated and written to the output buffer or queue. This - * returns zero if the response has not finished. - * - * @return this is the time taken to complete the response - */ - public long getResponseTime() { - return observer.getTime(); - } - - /** - * This is used as a shortcut for acquiring attributes for the - * response. This avoids acquiring the Attributes - * in order to retrieve the attribute directly from that object. - * The attributes contain data specific to the response. - * - * @param name this is the name of the attribute to acquire - * - * @return this returns the attribute for the specified name - */ - public Object getAttribute(Object name) { - return getAttributes().get(name); - } - - /** - * This can be used to retrieve certain attributes about - * this Response. The attributes contains certain - * properties about the Response. For example if - * this Response goes over a secure line then there may be any - * arbitrary attributes. - * - * @return the response attributes of that have been set - */ - public Map getAttributes() { - return channel.getAttributes(); - } - - /** - * This should be used when the size of the message body is known. For - * performance reasons this should be used so the length of the output - * is known. This ensures that Persistent HTTP (PHTTP) connections - * can be maintained for both HTTP/1.0 and HTTP/1.1 clients. If the - * length of the output is not known HTTP/1.0 clients will require a - * connection close, which reduces performance (see RFC 2616). - *

- * This removes any previous Content-Length headers from the message - * header. This will then set the appropriate Content-Length header with - * the correct length. If a the Connection header is set with the close - * token then the semantics of the connection are such that the server - * will close it once the OutputStream.close is used. - * - * @param length this is the length of the HTTP message body - */ - public void setContentLength(long length) { - setLong(CONTENT_LENGTH, length); - } - - /** - * This is used to set the content type for the response. Typically - * a response will contain a message body of some sort. This is used - * to conveniently set the type for that response. Setting the - * content type can also be done explicitly if desired. - * - * @param type this is the type that is to be set in the response - */ - public void setContentType(String type) { - setValue(CONTENT_TYPE, type); - } - - /** - * This determines the charset for PrintStream objects - * returned from the getPrintStream method. This will - * return a valid charset regardless of whether the Content-Type - * header has been set, set without a charset, or not set at all. - * If unspecified, the charset returned is ISO-8859-1, - * as suggested by RFC 2616, section 3.7.1. - * - * @return returns the charset used by this response object - */ - private String getCharset() { - ContentType type = getContentType(); - - if(type == null) { - return "ISO-8859-1"; - } - if(type.getCharset()==null){ - return "ISO-8859-1"; - } - return type.getCharset(); - } - - /** - * Used to write a message body with the Response. The - * semantics of this OutputStream will be determined - * by the HTTP version of the client, and whether or not the content - * length has been set, through the setContentLength - * method. If the length of the output is not known then the output - * is chunked for HTTP/1.1 clients and closed for HTTP/1.0 clients. - * - * @return an output stream object used to write the message body - */ - public OutputStream getOutputStream() throws IOException { - return buffer; - } - - /** - * Used to write a message body with the Response. The - * semantics of this OutputStream will be determined - * by the HTTP version of the client, and whether or not the content - * length has been set, through the setContentLength - * method. If the length of the output is not known then the output - * is chunked for HTTP/1.1 clients and closed for HTTP/1.0 clients. - *

- * This will ensure that there is buffering done so that the output - * can be reset using the reset method. This will - * enable the specified number of bytes to be written without - * committing the response. This specified size is the minimum size - * that the response buffer must be. - * - * @param size the minimum size that the response buffer must be - * - * @return an output stream object used to write the message body - */ - public OutputStream getOutputStream(int size) throws IOException { - if(size > 0) { - buffer.expand(size); - } - return buffer; - } - - /** - * This method is provided for convenience so that the HTTP content - * can be written using the print methods provided by - * the PrintStream. This will basically wrap the - * getOutputStream with a buffer size of zero. - *

- * The retrieved PrintStream uses the charset used to - * describe the content, with the Content-Type header. This will - * check the charset parameter of the contents MIME type. So if - * the Content-Type was text/plain; charset=UTF-8 the - * resulting PrintStream would encode the written data - * using the UTF-8 encoding scheme. Care must be taken to ensure - * that bytes written to the stream are correctly encoded. - * - * @return a print stream object used to write the message body - */ - public PrintStream getPrintStream() throws IOException { - return getPrintStream(0, getCharset()); - } - - /** - * This method is provided for convenience so that the HTTP content - * can be written using the print methods provided by - * the PrintStream. This will basically wrap the - * getOutputStream with a specified buffer size. - *

- * The retrieved PrintStream uses the charset used to - * describe the content, with the Content-Type header. This will - * check the charset parameter of the contents MIME type. So if - * the Content-Type was text/plain; charset=UTF-8 the - * resulting PrintStream would encode the written data - * using the UTF-8 encoding scheme. Care must be taken to ensure - * that bytes written to the stream are correctly encoded. - * - * @param size the minimum size that the response buffer must be - * - * @return a print stream object used to write the message body - */ - public PrintStream getPrintStream(int size) throws IOException { - return getPrintStream(size, getCharset()); - } - - /** - * This is used to wrap the getOutputStream object in - * a PrintStream, which will write content using a - * specified charset. The PrintStream created will not - * buffer the content, it will write directly to the underlying - * OutputStream where it is buffered (if there is a - * buffer size greater than zero specified). In future the buffer - * of the PrintStream may be usable. - * - * @param size the minimum size that the response buffer must be - * @param charset this is the charset used by the resulting stream - * - * @return a print stream that encodes in the given charset - */ - private PrintStream getPrintStream(int size, String charset) throws IOException { - if(size > 0) { - buffer.expand(size); - } - return new PrintStream(buffer, false, charset); - } - - /** - * Used to write a message body with the Response. The - * semantics of this WritableByteChannel are determined - * by the HTTP version of the client, and whether or not the content - * length has been set, through the setContentLength - * method. If the length of the output is not known then the output - * is chunked for HTTP/1.1 clients and closed for HTTP/1.0 clients. - * - * @return a writable byte channel used to write the message body - */ - public WritableByteChannel getByteChannel() throws IOException { - return buffer; - } - - /** - * Used to write a message body with the Response. The - * semantics of this WritableByteChannel are determined - * by the HTTP version of the client, and whether or not the content - * length has been set, through the setContentLength - * method. If the length of the output is not known then the output - * is chunked for HTTP/1.1 clients and closed for HTTP/1.0 clients. - *

- * This will ensure that there is buffering done so that the output - * can be reset using the reset method. This will - * enable the specified number of bytes to be written without - * committing the response. This specified size is the minimum size - * that the response buffer must be. - * - * @param size the minimum size that the response buffer must be - * - * @return a writable byte channel used to write the message body - */ - public WritableByteChannel getByteChannel(int size) throws IOException { - if(size > 0) { - buffer.expand(size); - } - return buffer; - } - - /** - * This is used to determine if the HTTP response message is a - * keep alive message or if the underlying socket was closed. Even - * if the client requests a connection keep alive and supports - * persistent connections, the response can still be closed by - * the server. This can be explicitly indicated by the presence - * of the Connection HTTP header, it can also be - * implicitly indicated by using version HTTP/1.0. - * - * @return this returns true if the connection was closed - */ - public boolean isKeepAlive() { - return support.isKeepAlive(); - } - - /** - * This can be used to determine whether the Response - * has been committed. This is true if the Response - * was committed, either due to an explicit invocation of the - * commit method or due to the writing of content. If - * the Response has committed the reset - * method will not work in resetting content already written. - * - * @return true if the response has been fully committed - */ - public boolean isCommitted() { - return observer.isCommitted(); - } - - /** - * This is used to write the headers that where given to the - * Response. Any further attempts to give headers - * to the Response will be futile as only the headers - * that were given at the time of the first commit will be used - * in the message header. - *

- * This also performs some final checks on the headers submitted. - * This is done to determine the optimal performance of the - * output. If no specific Connection header has been specified - * this will set the connection so that HTTP/1.0 closes by default. - * - * @exception IOException thrown if there was a problem writing - */ - public void commit() throws IOException { - if(!observer.isCommitted()) { - String header = toString(); - byte[] message = header.getBytes("UTF-8"); - - trace.trace(WRITE_HEADER, header); - sender.write(message); - observer.commit(sender); - } - } - - /** - * This can be used to determine whether the Response - * has been committed. This is true if the Response - * was committed, either due to an explicit invocation of the - * commit method or due to the writing of content. If - * the Response has committed the reset - * method will not work in resetting content already written. - * - * @throws IOException thrown if there is a problem resetting - */ - public void reset() throws IOException { - buffer.reset(); - } - - /** - * This is used to close the connection and commit the request. - * This provides the same semantics as closing the output stream - * and ensures that the HTTP response is committed. This will - * throw an exception if the response can not be committed. - * - * @throws IOException thrown if there is a problem writing + */ +class ResponseEntity extends ResponseMessage implements Response { + + /** + * This is the observer that is used to monitor the response. + */ + private BodyObserver observer; + + /** + * This is used to buffer the bytes that are sent to the client. + */ + private ResponseBuffer buffer; + + /** + * This is the conversation used to determine connection type. + */ + private Conversation support; + + /** + * This is the underlying channel for the connected pipeline. + */ + private Channel channel; + + /** + * This is the sender object used to deliver to response data. + */ + private ByteWriter sender; + + /** + * This is used to trace events that occur with the response + */ + private Trace trace; + + /** + * Constructor for the ResponseEntity object. This is used to + * create a response instance using the provided request, entity, and + * monitor object. To ensure that the response is compatible with client the + * Request is used. Also to ensure the next request can be + * processed the provided monitor is used to signal response events to the + * server kernel. + * + * @param observer this is the observer used to signal events + * @param request this is the request that was sent by the client + * @param entity this is the entity that contains the channel + */ + public ResponseEntity(BodyObserver observer, Request request, Entity entity) { + this.support = new Conversation(request, this); + this.buffer = new ResponseBuffer(observer, this, support, entity); + this.channel = entity.getChannel(); + this.sender = channel.getWriter(); + this.trace = channel.getTrace(); + this.observer = observer; + } + + /** + * This represents the time at which the response has fully written. Because + * the response is delivered asynchronously to the client this response time + * does not represent the time to last byte. It simply represents the time + * at which the response has been fully generated and written to the output + * buffer or queue. This returns zero if the response has not finished. + * + * @return this is the time taken to complete the response + */ + public long getResponseTime() { + return observer.getTime(); + } + + /** + * This is used as a shortcut for acquiring attributes for the response. + * This avoids acquiring the Attributes in order to retrieve + * the attribute directly from that object. The attributes contain data + * specific to the response. + * + * @param name this is the name of the attribute to acquire + * + * @return this returns the attribute for the specified name + */ + public Object getAttribute(Object name) { + return getAttributes().get(name); + } + + /** + * This can be used to retrieve certain attributes about this + * Response. The attributes contains certain properties about + * the Response. For example if this Response goes over a + * secure line then there may be any arbitrary attributes. + * + * @return the response attributes of that have been set + */ + public Map getAttributes() { + return channel.getAttributes(); + } + + /** + * This should be used when the size of the message body is known. For + * performance reasons this should be used so the length of the output is + * known. This ensures that Persistent HTTP (PHTTP) connections can be + * maintained for both HTTP/1.0 and HTTP/1.1 clients. If the length of the + * output is not known HTTP/1.0 clients will require a connection close, + * which reduces performance (see RFC 2616). + *

+ * This removes any previous Content-Length headers from the message header. + * This will then set the appropriate Content-Length header with the correct + * length. If a the Connection header is set with the close token then the + * semantics of the connection are such that the server will close it once + * the OutputStream.close is used. + * + * @param length this is the length of the HTTP message body + */ + public void setContentLength(long length) { + setLong(CONTENT_LENGTH, length); + } + + /** + * This is used to set the content type for the response. Typically a + * response will contain a message body of some sort. This is used to + * conveniently set the type for that response. Setting the content type can + * also be done explicitly if desired. + * + * @param type this is the type that is to be set in the response + */ + public void setContentType(String type) { + + type = buildContentType(type); + setValue(CONTENT_TYPE, type); + } + + /** + * This determines the charset for PrintStream objects returned + * from the getPrintStream method. This will return a valid + * charset regardless of whether the Content-Type header has been set, set + * without a charset, or not set at all. If unspecified, the charset + * returned is ISO-8859-1, as suggested by RFC 2616, section + * 3.7.1. + * + * @return returns the charset used by this response object + */ + private String getCharset() { + ContentType type = getContentType(); + + if (type == null) { + return "ISO-8859-1"; + } + if (type.getCharset() == null) { + return "ISO-8859-1"; + } + + return type.getCharset(); + } + + /** + * This method sets the Charset of the response. + * @param charset the new Charset to set to the response */ - public void close() throws IOException { - buffer.close(); - } + public void setCharset(Charset charset) { + ContentType type = getContentType(); + type.setCharset(charset.name().toLowerCase()); + setContentType(type.toString()); + } + + /** + * Used to write a message body with the Response. The + * semantics of this OutputStream will be determined by the + * HTTP version of the client, and whether or not the content length has + * been set, through the setContentLength method. If the length + * of the output is not known then the output is chunked for HTTP/1.1 + * clients and closed for HTTP/1.0 clients. + * + * @return an output stream object used to write the message body + */ + public OutputStream getOutputStream() throws IOException { + return buffer; + } + + /** + * Used to write a message body with the Response. The + * semantics of this OutputStream will be determined by the + * HTTP version of the client, and whether or not the content length has + * been set, through the setContentLength method. If the length + * of the output is not known then the output is chunked for HTTP/1.1 + * clients and closed for HTTP/1.0 clients. + *

+ * This will ensure that there is buffering done so that the output can be + * reset using the reset method. This will enable the specified + * number of bytes to be written without committing the response. This + * specified size is the minimum size that the response buffer must be. + * + * @param size the minimum size that the response buffer must be + * + * @return an output stream object used to write the message body + */ + public OutputStream getOutputStream(int size) throws IOException { + if (size > 0) { + buffer.expand(size); + } + return buffer; + } + + /** + * This method is provided for convenience so that the HTTP content can be + * written using the print methods provided by the + * PrintStream. This will basically wrap the + * getOutputStream with a buffer size of zero. + *

+ * The retrieved PrintStream uses the charset used to describe + * the content, with the Content-Type header. This will check the charset + * parameter of the contents MIME type. So if the Content-Type was + * text/plain; charset=UTF-8 the resulting + * PrintStream would encode the written data using the UTF-8 + * encoding scheme. Care must be taken to ensure that bytes written to the + * stream are correctly encoded. + * + * @return a print stream object used to write the message body + */ + public PrintStream getPrintStream() throws IOException { + return getPrintStream(0, getCharset()); + } + + /** + * This method is provided for convenience so that the HTTP content can be + * written using the print methods provided by the + * PrintStream. This will basically wrap the + * getOutputStream with a specified buffer size. + *

+ * The retrieved PrintStream uses the charset used to describe + * the content, with the Content-Type header. This will check the charset + * parameter of the contents MIME type. So if the Content-Type was + * text/plain; charset=UTF-8 the resulting + * PrintStream would encode the written data using the UTF-8 + * encoding scheme. Care must be taken to ensure that bytes written to the + * stream are correctly encoded. + * + * @param size the minimum size that the response buffer must be + * + * @return a print stream object used to write the message body + */ + public PrintStream getPrintStream(int size) throws IOException { + return getPrintStream(size, getCharset()); + } + + /** + * This is used to wrap the getOutputStream object in a + * PrintStream, which will write content using a specified + * charset. The PrintStream created will not buffer the + * content, it will write directly to the underlying + * OutputStream where it is buffered (if there is a buffer size + * greater than zero specified). In future the buffer of the + * PrintStream may be usable. + * + * @param size the minimum size that the response buffer must be + * @param charset this is the charset used by the resulting stream + * + * @return a print stream that encodes in the given charset + */ + private PrintStream getPrintStream(int size, String charset) throws IOException { + if (size > 0) { + buffer.expand(size); + } + + return new PrintStream(buffer, false, charset); + } + + /** + * Used to write a message body with the Response. The + * semantics of this WritableByteChannel are determined by the + * HTTP version of the client, and whether or not the content length has + * been set, through the setContentLength method. If the length + * of the output is not known then the output is chunked for HTTP/1.1 + * clients and closed for HTTP/1.0 clients. + * + * @return a writable byte channel used to write the message body + */ + public WritableByteChannel getByteChannel() throws IOException { + return buffer; + } + + /** + * Used to write a message body with the Response. The + * semantics of this WritableByteChannel are determined by the + * HTTP version of the client, and whether or not the content length has + * been set, through the setContentLength method. If the length + * of the output is not known then the output is chunked for HTTP/1.1 + * clients and closed for HTTP/1.0 clients. + *

+ * This will ensure that there is buffering done so that the output can be + * reset using the reset method. This will enable the specified + * number of bytes to be written without committing the response. This + * specified size is the minimum size that the response buffer must be. + * + * @param size the minimum size that the response buffer must be + * + * @return a writable byte channel used to write the message body + */ + public WritableByteChannel getByteChannel(int size) throws IOException { + if (size > 0) { + buffer.expand(size); + } + return buffer; + } + + /** + * This is used to determine if the HTTP response message is a keep alive + * message or if the underlying socket was closed. Even if the client + * requests a connection keep alive and supports persistent connections, the + * response can still be closed by the server. This can be explicitly + * indicated by the presence of the Connection HTTP header, it + * can also be implicitly indicated by using version HTTP/1.0. + * + * @return this returns true if the connection was closed + */ + public boolean isKeepAlive() { + return support.isKeepAlive(); + } + + /** + * This can be used to determine whether the Response has been + * committed. This is true if the Response was committed, + * either due to an explicit invocation of the commit method or + * due to the writing of content. If the Response has committed + * the reset method will not work in resetting content already + * written. + * + * @return true if the response has been fully committed + */ + public boolean isCommitted() { + return observer.isCommitted(); + } + + /** + * This is used to write the headers that where given to the + * Response. Any further attempts to give headers to the + * Response will be futile as only the headers that were given + * at the time of the first commit will be used in the message header. + *

+ * This also performs some final checks on the headers submitted. This is + * done to determine the optimal performance of the output. If no specific + * Connection header has been specified this will set the connection so that + * HTTP/1.0 closes by default. + * + * @exception IOException thrown if there was a problem writing + */ + public void commit() throws IOException { + if (!observer.isCommitted()) { + String header = toString(); + byte[] message = header.getBytes("UTF-8"); + + trace.trace(WRITE_HEADER, header); + sender.write(message); + observer.commit(sender); + } + } + + /** + * This can be used to determine whether the Response has been + * committed. This is true if the Response was committed, + * either due to an explicit invocation of the commit method or + * due to the writing of content. If the Response has committed + * the reset method will not work in resetting content already + * written. + * + * @throws IOException thrown if there is a problem resetting + */ + public void reset() throws IOException { + buffer.reset(); + } + + /** + * This is used to close the connection and commit the request. This + * provides the same semantics as closing the output stream and ensures that + * the HTTP response is committed. This will throw an exception if the + * response can not be committed. + * + * @throws IOException thrown if there is a problem writing + */ + public void close() throws IOException { + buffer.close(); + } } diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseMessage.java b/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseMessage.java index 4dcfb08..67b5878 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseMessage.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/core/ResponseMessage.java @@ -190,23 +190,6 @@ public void setMinor(int minor) { this.minor = minor; } - /** - * This is a convenience method that can be used to determine the - * content type of the message body. This will determine whether - * there is a Content-Type header, if there is then - * this will parse that header and represent it as a typed object - * which will expose the various parts of the HTTP header. - * - * @return this returns the content type value if it exists - */ - public ContentType getContentType() { - String value = getValue(CONTENT_TYPE); - - if(value == null) { - return null; - } - return new ContentTypeParser(value); - } /** * This is a convenience method that can be used to determine diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/message/MessageHeader.java b/simple/simple-http/src/main/java/org/simpleframework/http/message/MessageHeader.java index b809efe..93b5852 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/message/MessageHeader.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/message/MessageHeader.java @@ -15,463 +15,502 @@ * implied. See the License for the specific language governing * permissions and limitations under the License. */ - package org.simpleframework.http.message; import java.util.LinkedList; import java.util.List; import org.simpleframework.common.KeyMap; +import org.simpleframework.http.ContentType; import org.simpleframework.http.Cookie; +import static org.simpleframework.http.Protocol.CONTENT_TYPE; +import org.simpleframework.http.parse.ContentTypeParser; import org.simpleframework.http.parse.DateParser; import org.simpleframework.http.parse.ValueParser; /** - * The Message object is used to store an retrieve the - * headers for both a request and response. Headers are stored and - * retrieved in a case insensitive manner according to RFC 2616. - * The message also allows multiple header values to be added to a - * single header name, headers such as Cookie and Set-Cookie can be - * added multiple times with different values. - * + * The Message object is used to store an retrieve the headers for + * both a request and response. Headers are stored and retrieved in a case + * insensitive manner according to RFC 2616. The message also allows multiple + * header values to be added to a single header name, headers such as Cookie and + * Set-Cookie can be added multiple times with different values. + * * @author Niall Gallagher */ public class MessageHeader implements Message { + /** + * This is used to store the cookies added to the HTTP header. + */ + private final KeyMap cookies; + + /** + * This is used to store multiple header values for a name. + */ + private final KeyMap values; + + /** + * This is used to store the individual names for the header. + */ + private final KeyMap names; + + /** + * This is used to parse all date headers added to the message. + */ + private final DateParser parser; + + /** + * Constructor for the Message object. This is used to create a + * case insensitive means for storing HTTP header names and values. Dates + * can also be added to message as a long value and is converted to RFC 1123 + * compliant date string. + */ + public MessageHeader() { + this.cookies = new KeyMap(); + this.values = new KeyMap(); + this.names = new KeyMap(); + this.parser = new DateParser(); + } + + /** + * This is used to acquire the names of the of the headers that have been + * set in the response. This can be used to acquire all header values by + * name that have been set within the response. If no headers have been set + * this will return an empty list. + * + * @return a list of strings representing the set header names + */ + public List getNames() { + return names.getValues(); + } + + /** + * This can be used to set a HTTP message header to this object. The name + * and value of the HTTP message header will be used to create a HTTP + * message header object which can be retrieved using the + * getValue in combination with the get methods. This will + * perform a remove using the issued header name before the + * header value is set. + * + * @param name the name of the HTTP message header to be added + * @param value the value the HTTP message header will have + */ + /* + TODO: + keep charset in content-type if already set + */ + public void setValue(String name, String value) { + List list = getAll(name); + + if (value == null) { + String token = name.toLowerCase(); + + values.remove(token); + names.remove(token); + } else { + if (name.equalsIgnoreCase(CONTENT_TYPE)) { + value = buildContentType(value); + } + list.clear(); + list.add(value); + } + } + /** - * This is used to store the cookies added to the HTTP header. - */ - private final KeyMap cookies; - - /** - * This is used to store multiple header values for a name. - */ - private final KeyMap values; - - /** - * This is used to store the individual names for the header. - */ - private final KeyMap names; - - /** - * This is used to parse all date headers added to the message. - */ - private final DateParser parser; - - /** - * Constructor for the Message object. This is used - * to create a case insensitive means for storing HTTP header - * names and values. Dates can also be added to message as a - * long value and is converted to RFC 1123 compliant date string. - */ - public MessageHeader() { - this.cookies = new KeyMap(); - this.values = new KeyMap(); - this.names = new KeyMap(); - this.parser = new DateParser(); - } - - /** - * This is used to acquire the names of the of the headers that - * have been set in the response. This can be used to acquire all - * header values by name that have been set within the response. - * If no headers have been set this will return an empty list. - * - * @return a list of strings representing the set header names - */ - public List getNames() { - return names.getValues(); - } - - /** - * This can be used to set a HTTP message header to this object. - * The name and value of the HTTP message header will be used to - * create a HTTP message header object which can be retrieved using - * the getValue in combination with the get methods. - * This will perform a remove using the issued header - * name before the header value is set. + * This is a convenience method that can be used to determine the + * content type of the message body. This will determine whether + * there is a Content-Type header, if there is then + * this will parse that header and represent it as a typed object + * which will expose the various parts of the HTTP header. * - * @param name the name of the HTTP message header to be added - * @param value the value the HTTP message header will have - */ - public void setValue(String name, String value) { - List list = getAll(name); - - if(value == null) { - String token = name.toLowerCase(); - - values.remove(token); - names.remove(token); - } else { - list.clear(); - list.add(value); - } - } - - /** - * This can be used to set a HTTP message header to this object. - * The name and value of the HTTP message header will be used to - * create a HTTP message header object which can be retrieved using - * the getValue in combination with the get methods. - * This will perform a remove using the issued header - * name before the header value is set. - * - * @param name the name of the HTTP message header to be added - * @param value the value the HTTP message header will have - */ - public void setInteger(String name, int value) { - setValue(name, String.valueOf(value)); - } - - /** - * This can be used to set a HTTP message header to this object. - * The name and value of the HTTP message header will be used to - * create a HTTP message header object which can be retrieved using - * the getValue in combination with the get methods. - * This will perform a remove using the issued header - * name before the header value is set. - * - * @param name the name of the HTTP message header to be added - * @param value the value the HTTP message header will have + * @return this returns the content type value if it exists */ - public void setLong(String name, long value) { - setValue(name, String.valueOf(value)); - } - - /** - * This is used as a convenience method for adding a header that - * needs to be parsed into a HTTP date string. This will convert - * the date given into a date string defined in RFC 2616 sec 3.3.1. - * This will perform a remove using the issued header - * name before the header value is set. - * - * @param name the name of the HTTP message header to be added - * @param date the value constructed as an RFC 1123 date string - */ - public void setDate(String name, long date) { - setValue(name, parser.convert(date)); - } - - /** - * This can be used to add a HTTP message header to this object. - * The name and value of the HTTP message header will be used to - * create a HTTP message header object which can be retrieved using - * the getValue in combination with the get methods. - * - * @param name the name of the HTTP message header to be added - * @param value the value the HTTP message header will have - */ - public void addValue(String name, String value) { - List list = getAll(name); - - if(value != null) { - list.add(value); - } - } - - /** - * This can be used to add a HTTP message header to this object. - * The name and value of the HTTP message header will be used to - * create a HTTP message header object which can be retrieved using - * the getInteger in combination with the get methods. - * - * @param name the name of the HTTP message header to be added - * @param value the value the HTTP message header will have - */ - public void addInteger(String name, int value) { - addValue(name, String.valueOf(value)); - } - - /** - * This is used as a convenience method for adding a header that - * needs to be parsed into a HTTPdate string. This will convert - * the date given into a date string defined in RFC 2616 sec 3.3.1. - * - * @param name the name of the HTTP message header to be added - * @param date the value constructed as an RFC 1123 date string - */ - public void addDate(String name, long date) { - addValue(name, parser.convert(date)); - } - - /** - * This can be used to get the value of the first message header - * that has the specified name. This will return the full string - * representing the named header value. If the named header does - * not exist then this will return a null value. - * - * @param name the HTTP message header to get the value from - * - * @return this returns the value that the HTTP message header - */ - public String getValue(String name) { - return getValue(name, 0); - } - - /** - * This can be used to get the value of the first message header - * that has the specified name. This will return the full string - * representing the named header value. If the named header does - * not exist then this will return a null value. - * - * @param name the HTTP message header to get the value from - * @param index this is the index to get the value from - * - * @return this returns the value that the HTTP message header - */ - public String getValue(String name, int index) { - List list = getAll(name); - - if(list.size() > index) { - return list.get(index); - } - return null; - } - - /** - * This can be used to get the value of the first message header - * that has the specified name. This will return the integer - * representing the named header value. If the named header does - * not exist then this will return a value of minus one, -1. - * - * @param name the HTTP message header to get the value from - * - * @return this returns the value that the HTTP message header - */ - public int getInteger(String name) { - String value = getValue(name); - - if(value == null) { - return -1; - } - return Integer.parseInt(value); - } - - /** - * This can be used to get the value of the first message header - * that has the specified name. This will return the long - * representing the named header value. If the named header does - * not exist then this will return a value of minus one, -1. - * - * @param name the HTTP message header to get the value from - * - * @return this returns the value that the HTTP message header - */ - public long getLong(String name) { - String value = getValue(name); - - if(value == null) { - return -1L; - } - return Long.parseLong(value); - } - - /** - * This can be used to get the value of the first message header - * that has the specified name. This will return the long value - * representing the named header value. If the named header does - * not exist then this will return a value of minus one, -1. - * - * @param name the HTTP message header to get the value from - * - * @return this returns the value that the HTTP message header - */ - public long getDate(String name) { - String value = getValue(name); - - if(value == null) { - return -1; - } - return parser.convert(value); - } - - /** - * This returns the Cookie object stored under the - * specified name. This is used to retrieve cookies that have been - * set with the setCookie methods. If the cookie does - * not exist under the specified name this will return null. - * - * @param name this is the name of the cookie to be retrieved - * - * @return returns the Cookie by the given name - */ - public Cookie getCookie(String name) { - return cookies.get(name); - } - - /** - * This returns all Cookie objects stored under the - * specified name. This is used to retrieve cookies that have been - * set with the setCookie methods. If there are no - * cookies then this will return an empty list. - * - * @return returns all the Cookie in the response - */ - public List getCookies() { - return cookies.getValues(); - } - - /** - * The setCookie method is used to set a cookie value - * with the cookie name. This will add a cookie to the response - * stored under the name of the cookie, when this is committed it - * will be added as a Set-Cookie header to the resulting response. - * This is a convenience method that avoids cookie creation. - * - * @param name this is the cookie to be added to the response - * @param value this is the cookie value that is to be used - * - * @return returns the cookie that has been set in the response - */ - public Cookie setCookie(String name, String value) { - return setCookie(new Cookie(name, value, true)); - } - - /** - * The setCookie method is used to set a cookie value - * with the cookie name. This will add a cookie to the response - * stored under the name of the cookie, when this is committed it - * will be added as a Set-Cookie header to the resulting response. - * - * @param cookie this is the cookie to be added to the response - * - * @return returns the cookie that has been set in the response - */ - public Cookie setCookie(Cookie cookie) { - String name = cookie.getName(); - - if(name != null) { - cookies.put(name, cookie); - } - return cookie; - } - - /** - * This can be used to get the values of HTTP message headers - * that have the specified name. This is a convenience method that - * will present that values as tokens extracted from the header. - * This has obvious performance benefits as it avoids having to - * deal with substring and trim calls. - *

- * The tokens returned by this method are ordered according to - * there HTTP quality values, or "q" values, see RFC 2616 section - * 3.9. This also strips out the quality parameter from tokens - * returned. So "image/html; q=0.9" results in "image/html". If - * there are no "q" values present then order is by appearance. - *

- * The result from this is either the trimmed header value, that - * is, the header value with no leading or trailing whitespace - * or an array of trimmed tokens ordered with the most preferred - * in the lower indexes, so index 0 is has highest preference. - * - * @param name the name of the headers that are to be retrieved - * - * @return ordered list of tokens extracted from the header(s) - */ - public List getValues(String name) { - return getValues(getAll(name)); - } - - /** - * This can be used to get the values of HTTP message headers - * that have the specified name. This is a convenience method that - * will present that values as tokens extracted from the header. - * This has obvious performance benefits as it avoids having to - * deal with substring and trim calls. - *

- * The tokens returned by this method are ordered according to - * there HTTP quality values, or "q" values, see RFC 2616 section - * 3.9. This also strips out the quality parameter from tokens - * returned. So "image/html; q=0.9" results in "image/html". If - * there are no "q" values present then order is by appearance. - *

- * The result from this is either the trimmed header value, that - * is, the header value with no leading or trailing whitespace - * or an array of trimmed tokens ordered with the most preferred - * in the lower indexes, so index 0 is has highest preference. - * - * @param list this is the list of individual header values - * - * @return ordered list of tokens extracted from the header(s) - */ - public List getValues(List list) { - return new ValueParser(list).list(); - } - - /** - * This is used to acquire all the individual header values from - * the message. The header values provided by this are unparsed - * and represent the actual string values that have been added to - * the message keyed by a given header name. - * - * @param name the name of the header to get the values for - * - * @return this returns a list of the values for the header name - */ - public List getAll(String name) { - String token = name.toLowerCase(); - Series series = values.get(token); - - if(series == null) { - return getAll(name, token); - } - return series.getValues(); - } - - /** - * This is used to acquire all the individual header values from - * the message. The header values provided by this are unparsed - * and represent the actual string values that have been added to - * the message keyed by a given header name. - * - * @param name the name of the header to get the values for - * @param token this provides a lower case version of the header - * - * @return this returns a list of the values for the header name - */ - private List getAll(String name, String token) { - Series series = new Series(); - String value = names.get(token); - + public ContentType getContentType() { + String value = getValue(CONTENT_TYPE); + if(value == null) { - names.put(token, name); + return null; } - values.put(token, series); - - return series.getValues(); + return new ContentTypeParser(value); } - /** - * The Series object is used to represent a list of - * HTTP header value for a given name. It allows multiple values - * to exist for a given header, such as the Cookie header. Most - * entries will contain a single value. - */ - private class Series { - - /** - * Contains the header values that belong to the entry name. - */ - private List value; - - /** - * Constructor for the Entry object. The entry is - * created using the name of the HTTP header. Values can be - * added to the entry list in order to build up the header. - */ - public Series() { - this.value = new LinkedList(); - } - - /** - * This returns the list of header values associated with the - * header name. Each value is added as an individual header - * prefixed by the header name and a semicolon character. - * - * @return this returns the list of values for the header - */ - public List getValues() { - return value; - } - } + public String buildContentType(String type) { + if (!type.toLowerCase().contains("charset")) { + + if (getContentType() == null) { + ContentTypeParser parser = new ContentTypeParser(); + type += "; charset=" + parser.getCharset(); + } else { + type += "; charset=" + getContentType().getCharset(); + } + } + return type; + } + + /** + * This can be used to set a HTTP message header to this object. The name + * and value of the HTTP message header will be used to create a HTTP + * message header object which can be retrieved using the + * getValue in combination with the get methods. This will + * perform a remove using the issued header name before the + * header value is set. + * + * @param name the name of the HTTP message header to be added + * @param value the value the HTTP message header will have + */ + public void setInteger(String name, int value) { + setValue(name, String.valueOf(value)); + } + + /** + * This can be used to set a HTTP message header to this object. The name + * and value of the HTTP message header will be used to create a HTTP + * message header object which can be retrieved using the + * getValue in combination with the get methods. This will + * perform a remove using the issued header name before the + * header value is set. + * + * @param name the name of the HTTP message header to be added + * @param value the value the HTTP message header will have + */ + public void setLong(String name, long value) { + setValue(name, String.valueOf(value)); + } + + /** + * This is used as a convenience method for adding a header that needs to be + * parsed into a HTTP date string. This will convert the date given into a + * date string defined in RFC 2616 sec 3.3.1. This will perform a + * remove using the issued header name before the header value + * is set. + * + * @param name the name of the HTTP message header to be added + * @param date the value constructed as an RFC 1123 date string + */ + public void setDate(String name, long date) { + setValue(name, parser.convert(date)); + } + + /** + * This can be used to add a HTTP message header to this object. The name + * and value of the HTTP message header will be used to create a HTTP + * message header object which can be retrieved using the + * getValue in combination with the get methods. + * + * @param name the name of the HTTP message header to be added + * @param value the value the HTTP message header will have + */ + public void addValue(String name, String value) { + List list = getAll(name); + + if (value != null) { + list.add(value); + } + } + + /** + * This can be used to add a HTTP message header to this object. The name + * and value of the HTTP message header will be used to create a HTTP + * message header object which can be retrieved using the + * getInteger in combination with the get methods. + * + * @param name the name of the HTTP message header to be added + * @param value the value the HTTP message header will have + */ + public void addInteger(String name, int value) { + addValue(name, String.valueOf(value)); + } + + /** + * This is used as a convenience method for adding a header that needs to be + * parsed into a HTTPdate string. This will convert the date given into a + * date string defined in RFC 2616 sec 3.3.1. + * + * @param name the name of the HTTP message header to be added + * @param date the value constructed as an RFC 1123 date string + */ + public void addDate(String name, long date) { + addValue(name, parser.convert(date)); + } + + /** + * This can be used to get the value of the first message header that has + * the specified name. This will return the full string representing the + * named header value. If the named header does not exist then this will + * return a null value. + * + * @param name the HTTP message header to get the value from + * + * @return this returns the value that the HTTP message header + */ + public String getValue(String name) { + return getValue(name, 0); + } + + /** + * This can be used to get the value of the first message header that has + * the specified name. This will return the full string representing the + * named header value. If the named header does not exist then this will + * return a null value. + * + * @param name the HTTP message header to get the value from + * @param index this is the index to get the value from + * + * @return this returns the value that the HTTP message header + */ + public String getValue(String name, int index) { + List list = getAll(name); + + if (list.size() > index) { + return list.get(index); + } + return null; + } + + /** + * This can be used to get the value of the first message header that has + * the specified name. This will return the integer representing the named + * header value. If the named header does not exist then this will return a + * value of minus one, -1. + * + * @param name the HTTP message header to get the value from + * + * @return this returns the value that the HTTP message header + */ + public int getInteger(String name) { + String value = getValue(name); + + if (value == null) { + return -1; + } + return Integer.parseInt(value); + } + + /** + * This can be used to get the value of the first message header that has + * the specified name. This will return the long representing the named + * header value. If the named header does not exist then this will return a + * value of minus one, -1. + * + * @param name the HTTP message header to get the value from + * + * @return this returns the value that the HTTP message header + */ + public long getLong(String name) { + String value = getValue(name); + + if (value == null) { + return -1L; + } + return Long.parseLong(value); + } + + /** + * This can be used to get the value of the first message header that has + * the specified name. This will return the long value representing the + * named header value. If the named header does not exist then this will + * return a value of minus one, -1. + * + * @param name the HTTP message header to get the value from + * + * @return this returns the value that the HTTP message header + */ + public long getDate(String name) { + String value = getValue(name); + + if (value == null) { + return -1; + } + return parser.convert(value); + } + + /** + * This returns the Cookie object stored under the specified + * name. This is used to retrieve cookies that have been set with the + * setCookie methods. If the cookie does not exist under the + * specified name this will return null. + * + * @param name this is the name of the cookie to be retrieved + * + * @return returns the Cookie by the given name + */ + public Cookie getCookie(String name) { + return cookies.get(name); + } + + /** + * This returns all Cookie objects stored under the specified + * name. This is used to retrieve cookies that have been set with the + * setCookie methods. If there are no cookies then this will + * return an empty list. + * + * @return returns all the Cookie in the response + */ + public List getCookies() { + return cookies.getValues(); + } + + /** + * The setCookie method is used to set a cookie value with the + * cookie name. This will add a cookie to the response stored under the name + * of the cookie, when this is committed it will be added as a Set-Cookie + * header to the resulting response. This is a convenience method that + * avoids cookie creation. + * + * @param name this is the cookie to be added to the response + * @param value this is the cookie value that is to be used + * + * @return returns the cookie that has been set in the response + */ + public Cookie setCookie(String name, String value) { + return setCookie(new Cookie(name, value, true)); + } + + /** + * The setCookie method is used to set a cookie value with the + * cookie name. This will add a cookie to the response stored under the name + * of the cookie, when this is committed it will be added as a Set-Cookie + * header to the resulting response. + * + * @param cookie this is the cookie to be added to the response + * + * @return returns the cookie that has been set in the response + */ + public Cookie setCookie(Cookie cookie) { + String name = cookie.getName(); + + if (name != null) { + cookies.put(name, cookie); + } + return cookie; + } + + /** + * This can be used to get the values of HTTP message headers that have the + * specified name. This is a convenience method that will present that + * values as tokens extracted from the header. This has obvious performance + * benefits as it avoids having to deal with substring and + * trim calls. + *

+ * The tokens returned by this method are ordered according to there HTTP + * quality values, or "q" values, see RFC 2616 section 3.9. This also strips + * out the quality parameter from tokens returned. So "image/html; q=0.9" + * results in "image/html". If there are no "q" values present then order is + * by appearance. + *

+ * The result from this is either the trimmed header value, that is, the + * header value with no leading or trailing whitespace or an array of + * trimmed tokens ordered with the most preferred in the lower indexes, so + * index 0 is has highest preference. + * + * @param name the name of the headers that are to be retrieved + * + * @return ordered list of tokens extracted from the header(s) + */ + public List getValues(String name) { + return getValues(getAll(name)); + } + + /** + * This can be used to get the values of HTTP message headers that have the + * specified name. This is a convenience method that will present that + * values as tokens extracted from the header. This has obvious performance + * benefits as it avoids having to deal with substring and + * trim calls. + *

+ * The tokens returned by this method are ordered according to there HTTP + * quality values, or "q" values, see RFC 2616 section 3.9. This also strips + * out the quality parameter from tokens returned. So "image/html; q=0.9" + * results in "image/html". If there are no "q" values present then order is + * by appearance. + *

+ * The result from this is either the trimmed header value, that is, the + * header value with no leading or trailing whitespace or an array of + * trimmed tokens ordered with the most preferred in the lower indexes, so + * index 0 is has highest preference. + * + * @param list this is the list of individual header values + * + * @return ordered list of tokens extracted from the header(s) + */ + public List getValues(List list) { + return new ValueParser(list).list(); + } + + /** + * This is used to acquire all the individual header values from the + * message. The header values provided by this are unparsed and represent + * the actual string values that have been added to the message keyed by a + * given header name. + * + * @param name the name of the header to get the values for + * + * @return this returns a list of the values for the header name + */ + public List getAll(String name) { + String token = name.toLowerCase(); + Series series = values.get(token); + + if (series == null) { + return getAll(name, token); + } + return series.getValues(); + } + + /** + * This is used to acquire all the individual header values from the + * message. The header values provided by this are unparsed and represent + * the actual string values that have been added to the message keyed by a + * given header name. + * + * @param name the name of the header to get the values for + * @param token this provides a lower case version of the header + * + * @return this returns a list of the values for the header name + */ + private List getAll(String name, String token) { + Series series = new Series(); + String value = names.get(token); + + if (value == null) { + names.put(token, name); + } + values.put(token, series); + + return series.getValues(); + } + + /** + * The Series object is used to represent a list of HTTP header + * value for a given name. It allows multiple values to exist for a given + * header, such as the Cookie header. Most entries will contain a single + * value. + */ + private class Series { + + /** + * Contains the header values that belong to the entry name. + */ + private List value; + + /** + * Constructor for the Entry object. The entry is created + * using the name of the HTTP header. Values can be added to the entry + * list in order to build up the header. + */ + public Series() { + this.value = new LinkedList(); + } + + /** + * This returns the list of header values associated with the header + * name. Each value is added as an individual header prefixed by the + * header name and a semicolon character. + * + * @return this returns the list of values for the header + */ + public List getValues() { + return value; + } + } } diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/parse/ContentTypeParser.java b/simple/simple-http/src/main/java/org/simpleframework/http/parse/ContentTypeParser.java index f42c073..f2f966b 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/parse/ContentTypeParser.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/parse/ContentTypeParser.java @@ -89,6 +89,9 @@ public ContentTypeParser(){ this.type = new ParseBuffer(); this.name = new ParseBuffer(); this.map = new KeyMap(); + + setCharset("utf-8"); + } /** diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/socket/service/RouterContainer.java b/simple/simple-http/src/main/java/org/simpleframework/http/socket/service/RouterContainer.java index 3b018a9..14e4a88 100644 --- a/simple/simple-http/src/main/java/org/simpleframework/http/socket/service/RouterContainer.java +++ b/simple/simple-http/src/main/java/org/simpleframework/http/socket/service/RouterContainer.java @@ -23,6 +23,7 @@ import org.simpleframework.http.Request; import org.simpleframework.http.Response; import org.simpleframework.http.core.Container; +import org.simpleframework.http.core.Controller; /** * The RouterContainer is used to route requests that @@ -105,5 +106,5 @@ public void handle(Request req, Response resp) { } else { container.handle(req, resp); } - } + } } diff --git a/simple/simple-transport/src/main/java/org/simpleframework/transport/TransportProcessor.java b/simple/simple-transport/src/main/java/org/simpleframework/transport/TransportProcessor.java index 13f505b..e63f71f 100644 --- a/simple/simple-transport/src/main/java/org/simpleframework/transport/TransportProcessor.java +++ b/simple/simple-transport/src/main/java/org/simpleframework/transport/TransportProcessor.java @@ -19,6 +19,8 @@ package org.simpleframework.transport; import java.io.IOException; +import org.simpleframework.http.core.ContainerController; +import org.simpleframework.http.core.Controller; /** * This is the TransportProcessor used to process the @@ -60,4 +62,6 @@ public interface TransportProcessor { * of unused memory and the closing of file and socket resources. */ void stop() throws IOException; + + public ContainerController getControler(); } From 3a8acf428951c7ef7f066de721656da9e3fdb506 Mon Sep 17 00:00:00 2001 From: Philippe Schweitzer Date: Wed, 3 Oct 2018 10:58:39 +0200 Subject: [PATCH 2/3] gradle integration --- build.gradle | 73 +++++++++++++++++++++++++++++++++++++++++++++++++ settings.gradle | 1 + 2 files changed, 74 insertions(+) create mode 100644 build.gradle create mode 100644 settings.gradle diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..3cf1f5e --- /dev/null +++ b/build.gradle @@ -0,0 +1,73 @@ +apply plugin: 'java' + +version = "6.0.1-2" + +sourceCompatibility = '1.8' +[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' + +// NetBeans will automatically add "run" and "debug" tasks relying on the +// "mainClass" property. You may however define the property prior executing +// tasks by passing a "-PmainClass=" argument. +// +// Note however, that you may define your own "run" and "debug" task if you +// prefer. In this case NetBeans will not add these tasks but you may rely on +// your own implementation. +if (!hasProperty('mainClass')) { + //ext.mainClass = 'org.cheetah.webserver.CheetahWebserver' +} +sourceSets.main.java { srcDirs = ["simple/simple-common/src/main/java", "simple/simple-http/src/main/java", "simple/simple-transport/src/main/java"]} + +repositories { + //mavenCentral() + // You may define additional repositories, or even remove "mavenCentral()". + // Read more about repositories here: + // http://www.gradle.org/docs/current/userguide/dependency_management.html#sec:repositories +} + +dependencies { + // TODO: Add dependencies here ... + // You can read more about how to add dependency here: + // http://www.gradle.org/docs/current/userguide/dependency_management.html#sec:how_to_declare_your_dependencies + testCompile group: 'junit', name: 'junit', version: '4.10' + + //compile fileTree(dir: 'lib', include: '*.jar') + //runtime fileTree(dir: 'lib', include: '*.jar') +} + +task wrapper(type: Wrapper) { + gradleVersion = "3.5" +} + + +/* +task packageTests(type: Jar) { + baseName = 'CheetahWebserverTest' + manifest { + attributes( + "Created-By": 'Philippe Schweitzer', + "Class-Path": 'lib/' + configurations.compile.collect { it.getName() }.join(' lib/') + ' lib/CheetahWebserver.jar', + "Main-Class": 'org.cheetah.webserver.CheetahWebserverTest' + ) + } + from sourceSets.test.output +} + +jar { + baseName = 'CheetahWebserver' + manifest { + attributes( + "Created-By": 'Philippe Schweitzer', + "Class-Path": 'lib/' + configurations.compile.collect { it.getName() }.join(' lib/'), + "Main-Class": 'org.cheetah.webserver.CheetahWebserver' + ) + } +} + +build { + dependsOn packageTests +} + +test { + dependsOn packageTests +} +*/ diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..7c7816a --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'Simpleframework' From 608b03365312e7cba408dcc23fb945212f83586d Mon Sep 17 00:00:00 2001 From: Philippe Schweitzer Date: Thu, 4 Oct 2018 10:14:17 +0200 Subject: [PATCH 3/3] From 'pschweitz' INIT commit: Add of stop strategy, either to wait (60sec by default), or to kill all threads at shutdown Add ability to choose the response charset, rather than taking the OS' one --- .gitignore | 33 ++++++++++++++++++++++++++++++++- build.gradle | 2 +- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 4de0c80..70efe33 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,32 @@ -simple-core/target/apidocs/org/simpleframework/http/Address.html \ No newline at end of file + +# Vim +*.sw[op] + +# Gradle +.gradle +build + +# IDEA +.idea +!.idea/codeStyleSettings.xml +*.iml +*.iws + +# Eclipse +.project +.classpath +.settings/ +bin + +# Maven +*.log +log/ +target/ + +# Output +log +logs +out + +# Mac +.DS_Store \ No newline at end of file diff --git a/build.gradle b/build.gradle index 3cf1f5e..b680942 100644 --- a/build.gradle +++ b/build.gradle @@ -35,7 +35,7 @@ dependencies { } task wrapper(type: Wrapper) { - gradleVersion = "3.5" + gradleVersion = "4.9" }