package com.limegroup.gnutella.uploader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.StringWriter;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.limegroup.gnutella.http.ConstantHTTPHeaderValue;
import com.limegroup.gnutella.http.HTTPHeaderName;
import com.limegroup.gnutella.http.HTTPUtils;
import com.limegroup.gnutella.settings.UploadSettings;
import com.limegroup.gnutella.tigertree.HashTree;
import com.limegroup.gnutella.util.BandwidthThrottle;
import com.limegroup.gnutella.util.ThrottledOutputStream;
/**
* Sends the THEX tree as an HTTP message.
*
* The tree is in compliance with the THEX protocol at
* http://open-content.net/specs/draft-jchapweske-thex-02.html
*
* @author Gregorio Roper
*/
public class THEXUploadState extends UploadState {
private final HashTree TREE;
private final StalledUploadWatchdog WATCHDOG;
private static final Log LOG = LogFactory.getLog(THEXUploadState.class);
/**
* Throttle for the speed of THEX uploads, allow up to 0.5K/s
*/
private static final BandwidthThrottle THROTTLE =
new BandwidthThrottle(UploadSettings.THEX_UPLOAD_SPEED.getValue());
/**
* Constructs a new TigerTreeUploadState
*
* @param uploader
* the <tt>HTTPUploader</tt> that sends this message
*/
public THEXUploadState(HTTPUploader uploader, StalledUploadWatchdog dog) {
super(uploader);
LOG.debug("creating thex upload state");
TREE = FILE_DESC.getHashTree();
if(TREE == null)
throw new NullPointerException("null TREE in THEXUploadState");
WATCHDOG = dog;
}
/**
* Write HTTP headers
*
* @param os
* the <tt>OutputStream</tt> to write to.
* @throws IOException
* if there was a problem writing to the <tt>OutputStream</tt>.
*/
public void writeMessageHeaders(OutputStream network) throws IOException {
LOG.debug("writing thex headers");
StringWriter os = new StringWriter();
os.write("HTTP/1.1 200 OK\r\n");
HTTPUtils.writeHeader(
HTTPHeaderName.SERVER,
ConstantHTTPHeaderValue.SERVER_VALUE,
os);
// write the URN in case the caller wants it
HTTPUtils.writeHeader(
HTTPHeaderName.GNUTELLA_CONTENT_URN,
FILE_DESC.getSHA1Urn(),
os);
HTTPUtils.writeHeader(
HTTPHeaderName.CONTENT_LENGTH,
TREE.getOutputLength(),
os);
HTTPUtils.writeHeader(
HTTPHeaderName.CONTENT_TYPE,
TREE.getOutputType(),
os);
os.write("\r\n");
WATCHDOG.activate(network);
try {
network.write(os.toString().getBytes());
} finally {
WATCHDOG.deactivate();
}
}
/**
* Write HTTP message body
*
* @param os
* the <tt>OutputStream</tt> to write to.
* @throws IOException
* if there was a problem writing to the <tt>OutputStream</tt>.
*/
public void writeMessageBody(OutputStream os) throws IOException {
LOG.debug("writing message body");
THROTTLE.setRate(UploadSettings.THEX_UPLOAD_SPEED.getValue());
OutputStream slowStream = new ThrottledOutputStream(os, THROTTLE);
// the tree might be large, but the watchdogs allows two minutes,
// so this is okay, since if an entire tree wasn't written in two
// minutes, there is a problem.
WATCHDOG.activate(os);
try {
TREE.write(slowStream);
} finally {
WATCHDOG.deactivate();
}
}
/**
* @return <tt>true</tt> if the connection should be closed after writing
* the message.
*/
public boolean getCloseConnection() {
return false;
}
}