/* ------------------------------------------------------------ */ public Result generateResponse( MetaData.Response info, boolean head, ByteBuffer header, ByteBuffer chunk, ByteBuffer content, boolean last) throws IOException { switch (_state) { case START: { if (info == null) return Result.NEED_INFO; // Handle 0.9 if (info.getVersion() == HttpVersion.HTTP_0_9) { _persistent = false; _endOfContent = EndOfContent.EOF_CONTENT; if (BufferUtil.hasContent(content)) _contentPrepared += content.remaining(); _state = last ? State.COMPLETING : State.COMMITTED; return Result.FLUSH; } // Do we need a response header if (header == null) return Result.NEED_HEADER; // If we have not been told our persistence, set the default if (_persistent == null) _persistent = (info.getVersion().ordinal() > HttpVersion.HTTP_1_0.ordinal()); // prepare the header int pos = BufferUtil.flipToFill(header); try { // generate ResponseLine generateResponseLine(info, header); // Handle 1xx and no content responses int status = info.getStatus(); if (status >= 100 && status < 200) { _noContent = true; if (status != HttpStatus.SWITCHING_PROTOCOLS_101) { header.put(HttpTokens.CRLF); _state = State.COMPLETING_1XX; return Result.FLUSH; } } else if (status == HttpStatus.NO_CONTENT_204 || status == HttpStatus.NOT_MODIFIED_304) { _noContent = true; } generateHeaders(info, header, content, last); // handle the content. int len = BufferUtil.length(content); if (len > 0) { _contentPrepared += len; if (isChunking() && !head) prepareChunk(header, len); } _state = last ? State.COMPLETING : State.COMMITTED; } catch (Exception e) { String message = (e instanceof BufferOverflowException) ? "Response header too large" : e.getMessage(); throw new IOException(message, e); } finally { BufferUtil.flipToFlush(header, pos); } return Result.FLUSH; } case COMMITTED: { int len = BufferUtil.length(content); // handle the content. if (len > 0) { if (isChunking()) { if (chunk == null) return Result.NEED_CHUNK; BufferUtil.clearToFill(chunk); prepareChunk(chunk, len); BufferUtil.flipToFlush(chunk, 0); } _contentPrepared += len; } if (last) { _state = State.COMPLETING; return len > 0 ? Result.FLUSH : Result.CONTINUE; } return len > 0 ? Result.FLUSH : Result.DONE; } case COMPLETING_1XX: { reset(); return Result.DONE; } case COMPLETING: { if (BufferUtil.hasContent(content)) { if (LOG.isDebugEnabled()) LOG.debug("discarding content in COMPLETING"); BufferUtil.clear(content); } if (isChunking()) { // Do we need a chunk buffer? if (chunk == null) return Result.NEED_CHUNK; // Write the last chunk BufferUtil.clearToFill(chunk); prepareChunk(chunk, 0); BufferUtil.flipToFlush(chunk, 0); _endOfContent = EndOfContent.UNKNOWN_CONTENT; return Result.FLUSH; } _state = State.END; return Boolean.TRUE.equals(_persistent) ? Result.DONE : Result.SHUTDOWN_OUT; } case END: if (BufferUtil.hasContent(content)) { if (LOG.isDebugEnabled()) LOG.debug("discarding content in COMPLETING"); BufferUtil.clear(content); } return Result.DONE; default: throw new IllegalStateException(); } }
@Override protected void reset() { generator.reset(); super.reset(); }