// Copyright (C) 2003-2009 by Object Mentor, Inc. All rights reserved. // Released under the terms of the CPL Common Public License version 1.0. package fitnesse.http; import java.io.Closeable; import java.io.IOException; import java.io.Writer; import java.nio.ByteBuffer; public class ChunkedResponse extends Response implements Closeable { private ResponseSender sender; private int bytesSent = 0; private boolean dontChunk = false; private ChunkedDataProvider chunckedDataProvider; public ChunkedResponse(String format, ChunkedDataProvider chunckedDataProvider) { super(format); this.chunckedDataProvider = chunckedDataProvider; if (isTextFormat()) dontChunk = true; } @Override public void sendTo(ResponseSender sender) throws IOException { this.sender = sender; sender.send(makeHttpHeaders().getBytes()); chunckedDataProvider.startSending(); } @Override protected void addContentHeaders() { super.addContentHeaders(); if (!dontChunk) addHeader("Transfer-Encoding", "chunked"); } public static String asHex(int value) { return Integer.toHexString(value); } public void add(String text) throws IOException { if (text != null) add(getEncodedBytes(text)); } public void add(byte[] bytes) throws IOException { if (bytes == null || bytes.length == 0) return; if (dontChunk) { sender.send(bytes); } else { String sizeLine = asHex(bytes.length) + CRLF; ByteBuffer chunk = ByteBuffer.allocate(sizeLine.length() + bytes.length + 2); chunk.put(sizeLine.getBytes()).put(bytes).put(CRLF.getBytes()); sender.send(chunk.array()); } bytesSent += bytes.length; } public void addTrailingHeader(String key, String value) throws IOException { if (!dontChunk) { String header = key + ": " + value + CRLF; sender.send(header.getBytes()); } } public void closeChunks() throws IOException { if (!dontChunk) { sender.send(("0" + CRLF).getBytes()); } } public void closeTrailer() throws IOException { if (!dontChunk) { sender.send(CRLF.getBytes()); } } @Override public void close() throws IOException { closeChunks(); closeTrailer(); sender.close(); } @Override public int getContentSize() { return bytesSent; } public void turnOffChunking() { dontChunk = true; } public boolean isChunkingTurnedOff() { return dontChunk; } public Writer getWriter() { return new Writer() { @Override public void close() throws IOException { //sender.close(); } @Override public void flush() throws IOException { // sender.flush(); -- flush is done on write } @Override public void write(String str) throws IOException { add(str); } @Override public void write(char[] cbuf, int off, int len) throws IOException { write(new String(cbuf, off, len)); } }; } }