protected void doAction(final HttpServletRequest req, final HttpServletResponse resp, String action) {
        // Read the request.
        ApiRequest srequest;
        try {
            srequest = readRequest(req);
            srequest.setType(action);
        } catch (Exception e) {
            writeError(null, resp, e);
            return;
        }

        final CountDownLatch latch = new CountDownLatch(1);
        final ApiRequest finalRequest = srequest;

        // Now execute the request via the apiman engine
        IApiRequestExecutor executor = getEngine().executor(srequest, new IAsyncResultHandler<IEngineResult>() {
            @Override
            public void handle(IAsyncResult<IEngineResult> asyncResult) {
                if (asyncResult.isSuccess()) {
                    IEngineResult engineResult = asyncResult.getResult();
                    if (engineResult.isResponse()) {
                        try {
                            writeResponse(resp, engineResult.getApiResponse());
                            final ServletOutputStream outputStream = resp.getOutputStream();
                            engineResult.bodyHandler(new IAsyncHandler<IApimanBuffer>() {
                                @Override
                                public void handle(IApimanBuffer chunk) {
                                    try {
                                        if (chunk instanceof ByteBuffer) {
                                            byte [] buffer = (byte []) chunk.getNativeBuffer();
                                            outputStream.write(buffer, 0, chunk.length());
                                        } else {
                                            outputStream.write(chunk.getBytes());
                                        }
                                    } catch (IOException e) {
                                        // This will get caught by the API connector, which will abort the
                                        // connection to the back-end API.
                                        throw new RuntimeException(e);
                                    }
                                }
                            });
                            engineResult.endHandler(new IAsyncHandler<Void>() {
                                @Override
                                public void handle(Void result) {
                                    try {
                                        resp.flushBuffer();
                                    } catch (IOException e) {
                                        // This will get caught by the API connector, which will abort the
                                        // connection to the back-end API.
                                        throw new RuntimeException(e);
                                    } finally {
                                        latch.countDown();
                                    }
                                }
                            });
                        } catch (IOException e) {
                            // this would mean we couldn't get the output stream from the response, so we
                            // need to abort the engine result (which will let the back-end connection
                            // close down).
                            engineResult.abort(e);
                            latch.countDown();
                            throw new RuntimeException(e);
                        }
                    } else {
                        writeFailure(finalRequest, resp, engineResult.getPolicyFailure());
                        latch.countDown();
                    }
                } else {
                    writeError(finalRequest, resp, asyncResult.getError());
                    latch.countDown();
                }
            }
        });
        executor.streamHandler(new IAsyncHandler<ISignalWriteStream>() {
            @Override
            public void handle(ISignalWriteStream connectorStream) {
                try {
                    final InputStream is = req.getInputStream();
                    ByteBuffer buffer = new ByteBuffer(2048);
                    int numBytes = buffer.readFrom(is);
                    while (numBytes != -1) {
                        connectorStream.write(buffer);
                        numBytes = buffer.readFrom(is);
                    }
                    connectorStream.end();
                } catch (Throwable e) {
                    connectorStream.abort(e);
                }
            }
        });
        executor.execute();
        try { latch.await(); } catch (InterruptedException e) { }
    }
Generic handler for all types of http actions/verbs.
@param req
@param resp
@param action
gateway/platforms/servlet/src/main/java/io/apiman/gateway/platforms/servlet/GatewayServlet.java