package net.bringert.niowww;
import java.io.*;
import java.nio.*;
import java.nio.channels.*;
/**
* A simple class for sending HTTP responses.
*
* @author Bjorn Bringert (bjorn@bringert.net)
*/
public class HttpResponse extends Handler {
/**
* RFC-2616 end-of-line marker
*/
private static final String CRLF_STR = "\r\n";
/**
* The response code.
*/
private int code = 200;
/**
* The response message.
*/
private String message = "OK";
/**
* The response header.
*/
private StringBuffer header = new StringBuffer();
/**
* The content source.
*/
private Content content;
/**
* Creates a new HttpResponse.
*/
public HttpResponse (NioWebServer server) {
super(server);
}
/**
* Adds a name value pair to the header.
*/
public void addHeader (String name, long value) {
addHeader(name, String.valueOf(value));
}
/**
* Adds a name value pair to the header.
*/
public void addHeader (String name, String value) {
header.append(name).append(": ").append(value).append(CRLF_STR);
}
/**
* Writes the header to the channel.
*/
public void writeHeader (WritableByteChannel channel) throws IOException {
// FIX - assumes header fits in output buffer
channel.write(server.getCodings().encode(CharBuffer.wrap(
"HTTP/1.1 " + code + " " + message
+ CRLF_STR + header + CRLF_STR)));
}
/**
* Sends an error header and a a simple error document to the client.
*/
public void writeError (int code, String message,
boolean sendContent,
WritableByteChannel channel) throws IOException {
this.code = code;
this.message = message;
String body = "
"+code+" "+message
+""+code+" "+message
+"
\n";
if (sendContent) {
ByteBuffer buf = server.getCodings().encode(CharBuffer.wrap(body));
setContent(new BufferContent(buf, "test/html"));
} else {
setContent(null);
}
writeHeader(channel);
}
/**
* Sets the content producer for this response.
*/
public void setContent (Content content) {
this.content = content;
if (content != null) {
addHeader("Content-Length", content.getSize());
String type = content.getContentType();
if (type != null)
addHeader("Content-Type", type);
}
}
public int getInterestOps () {
return SelectionKey.OP_WRITE;
}
/**
* Checks the request and initializes the response.
*/
public void initResponse (HttpRequest request, SocketChannel channel)
throws IOException {
addHeader("Server", server.getServerName());
addHeader("Connection", "close");
try {
request.parse();
server.getFileSender().handleFileRequest(request, this);
writeHeader(channel);
} catch (ServerException ex) {
writeError(ex.getCode(), ex.getMessage(), request.allowsContent(),
channel);
} catch (IOException ex) {
writeError(500, "Internal server error", request.allowsContent(),
channel);
ex.printStackTrace();
}
server.log(request.getMethod() + " "
+ request.getRequestURI() + " -> "
+ code + " " + message);
server.register(channel, this);
}
/**
* Serve a complete request.
*/
public void handle (SelectableChannel channel) throws IOException {
boolean completed = true;
try {
if (content != null)
completed = content.writeTo((SocketChannel)channel);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
if (completed)
channel.close();
}
}
}