NanoHttpd/nanohttpd — pull request #88 by alexsilva (2013-12-20 12:46:52+00:00)
Title: Adding interface to implement the content received by a remote data source cache - OnDataSend.

I am creating a proxy server that content received from internent cache and the need arose to save to a file.
What I did was create an interface that shares the data sent to a callback and enables you to create this cache.

Exemplifying how would the proxy server:

```
@Override
public Response serve(String uri, Method method, Map header, Map parms, Map files) {
String targetUrl = Encoder.decode(parms.get(QUERY_URL));
if (DEBUG) Log.d(TAG, String.format("Loading (%s)", targetUrl));

String fileName = Encoder.decode(parms.get(QUERY_FILE));
if (DEBUG) Log.d(TAG, String.format("FILE (%s)", fileName));

Response response = new Response();
Stream stream = new Stream(0);

if (!hasItemInCache(fileName)){
try {
stream = doDownload(targetUrl, fileName, response, header);
} catch (Exception e){
if (DEBUG) e.printStackTrace();
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT,
String.valueOf(e.getMessage()));
}
} else {
SimpleDiskCache.InputStreamEntry cacheItem = getCacheItem(fileName);
stream.setInputStream(cacheItem.getInputStream());

Map cacheData = cacheItem.getMetadata();
MetaData meta = (MetaData) cacheData.get(CACHE_KEY);

long fileSize = meta.getFileSize();
stream.setCode(200); // OK
try {
if (stream.is.available() < (fileSize-10)){
try {
stream = doDownload(targetUrl, fileName, response, header);
} catch (Exception e){
if (DEBUG) e.printStackTrace();
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT,
String.valueOf(e.getMessage()));
} finally {
Util.close(stream.is);
cacheItem.close();
}
} else {
stream.setCached(true);
}
} catch (IOException e){
if (DEBUG) e.printStackTrace();
}
}
Response.Status status = Response.Status.lookup(stream.code);
response.setStatus(status);

response.setData(new BufferedInputStream(stream.is));
response.setMimeType(header.get(Header.CONTENT_TYPE));
response.setChunkedTransfer(true);

if (DEBUG) Log.d(TAG, String.format("File(%s) cached:%s", fileName, stream.cached));

// Interface implemented and assigned to the request (allows access to data sent).
final Stream _stream = stream;
response.setOnDataSend(new OnDataSend(){
@Override
public void onSend(byte[] buffer, int length) {
if (_stream.os != null && !_stream.cached){
try {
_stream.os.write(buffer, 0, length);
} catch (IOException e) {
if (DEBUG) e.printStackTrace();
}
}
@Override
public void onStopSend() {
try {
_stream.os.close();
} catch (IOException e) {
if (DEBUG) e.printStackTrace();
}
}
}
});
if (DEBUG) Log.d(TAG, String.format("Code[%d] Status[%s]", stream.code, status));
return response;
}
```

Without this interface is virtually impossible to create any cached content.