use of org.eclipse.jetty.io.WriterOutputStream in project bnd by bndtools.
the class ETaggingResourceHandler method handle.
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (baseRequest.isHandled())
return;
boolean skipContentBody = false;
if (!HttpMethods.GET.equals(request.getMethod())) {
if (!HttpMethods.HEAD.equals(request.getMethod())) {
// try another handler
super.handle(target, baseRequest, request, response);
return;
}
skipContentBody = true;
}
Resource resource = getResource(request);
if (resource == null || !resource.exists()) {
// no resource - try other handlers
super.handle(target, baseRequest, request, response);
return;
}
// We are going to serve something
baseRequest.setHandled(true);
if (resource.isDirectory()) {
response.sendError(HttpStatus.FORBIDDEN_403);
}
// set some headers
long last_modified = resource.lastModified();
if (last_modified > 0) {
long if_modified = request.getDateHeader(HttpHeaders.IF_MODIFIED_SINCE);
if (if_modified > 0 && last_modified / 1000 <= if_modified / 1000) {
response.setStatus(HttpStatus.NOT_MODIFIED_304);
return;
}
}
String etag = calculateETag(resource);
String incomingETag = request.getHeader(HttpHeaders.IF_NONE_MATCH);
if (incomingETag != null) {
if (incomingETag.equals(etag)) {
response.setStatus(HttpStatus.NOT_MODIFIED_304);
return;
}
}
response.setHeader(HttpHeaders.ETAG, etag);
Buffer mime = _mimeTypes.getMimeByExtension(resource.toString());
if (mime == null)
mime = _mimeTypes.getMimeByExtension(request.getPathInfo());
// set the headers
doResponseHeaders(response, resource, mime != null ? mime.toString() : null);
response.setDateHeader(HttpHeaders.LAST_MODIFIED, last_modified);
if (skipContentBody)
return;
// Send the content
OutputStream out = null;
try {
out = response.getOutputStream();
} catch (IllegalStateException e) {
out = new WriterOutputStream(response.getWriter());
}
resource.writeTo(out, 0, resource.length());
}
use of org.eclipse.jetty.io.WriterOutputStream in project jetty.project by eclipse.
the class ResourceService method sendData.
/* ------------------------------------------------------------ */
protected boolean sendData(HttpServletRequest request, HttpServletResponse response, boolean include, final HttpContent content, Enumeration<String> reqRanges) throws IOException {
final long content_length = content.getContentLengthValue();
// Get the output stream (or writer)
OutputStream out = null;
boolean written;
try {
out = response.getOutputStream();
// has something already written to the response?
written = out instanceof HttpOutput ? ((HttpOutput) out).isWritten() : true;
} catch (IllegalStateException e) {
out = new WriterOutputStream(response.getWriter());
// there may be data in writer buffer, so assume written
written = true;
}
if (LOG.isDebugEnabled())
LOG.debug(String.format("sendData content=%s out=%s async=%b", content, out, request.isAsyncSupported()));
if (reqRanges == null || !reqRanges.hasMoreElements() || content_length < 0) {
// if there were no ranges, send entire entity
if (include) {
// write without headers
content.getResource().writeTo(out, 0, content_length);
} else // else if we can't do a bypass write because of wrapping
if (written || !(out instanceof HttpOutput)) {
// write normally
putHeaders(response, content, written ? -1 : 0);
ByteBuffer buffer = content.getIndirectBuffer();
if (buffer != null)
BufferUtil.writeTo(buffer, out);
else
content.getResource().writeTo(out, 0, content_length);
} else // else do a bypass write
{
// write the headers
putHeaders(response, content, 0);
// write the content asynchronously if supported
if (request.isAsyncSupported() && content.getContentLengthValue() > response.getBufferSize()) {
final AsyncContext context = request.startAsync();
context.setTimeout(0);
((HttpOutput) out).sendContent(content, new Callback() {
@Override
public void succeeded() {
context.complete();
content.release();
}
@Override
public void failed(Throwable x) {
if (x instanceof IOException)
LOG.debug(x);
else
LOG.warn(x);
context.complete();
content.release();
}
@Override
public String toString() {
return String.format("ResourceService@%x$CB", ResourceService.this.hashCode());
}
});
return false;
}
// otherwise write content blocking
((HttpOutput) out).sendContent(content);
}
} else {
// Parse the satisfiable ranges
List<InclusiveByteRange> ranges = InclusiveByteRange.satisfiableRanges(reqRanges, content_length);
// if there are no satisfiable ranges, send 416 response
if (ranges == null || ranges.size() == 0) {
putHeaders(response, content, 0);
response.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
response.setHeader(HttpHeader.CONTENT_RANGE.asString(), InclusiveByteRange.to416HeaderRangeString(content_length));
content.getResource().writeTo(out, 0, content_length);
return true;
}
// since were here now), send that range with a 216 response
if (ranges.size() == 1) {
InclusiveByteRange singleSatisfiableRange = ranges.get(0);
long singleLength = singleSatisfiableRange.getSize(content_length);
putHeaders(response, content, singleLength);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
if (!response.containsHeader(HttpHeader.DATE.asString()))
response.addDateHeader(HttpHeader.DATE.asString(), System.currentTimeMillis());
response.setHeader(HttpHeader.CONTENT_RANGE.asString(), singleSatisfiableRange.toHeaderRangeString(content_length));
content.getResource().writeTo(out, singleSatisfiableRange.getFirst(content_length), singleLength);
return true;
}
// multiple non-overlapping valid ranges cause a multipart
// 216 response which does not require an overall
// content-length header
//
putHeaders(response, content, -1);
String mimetype = (content == null ? null : content.getContentTypeValue());
if (mimetype == null)
LOG.warn("Unknown mimetype for " + request.getRequestURI());
MultiPartOutputStream multi = new MultiPartOutputStream(out);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
if (!response.containsHeader(HttpHeader.DATE.asString()))
response.addDateHeader(HttpHeader.DATE.asString(), System.currentTimeMillis());
// If the request has a "Request-Range" header then we need to
// send an old style multipart/x-byteranges Content-Type. This
// keeps Netscape and acrobat happy. This is what Apache does.
String ctp;
if (request.getHeader(HttpHeader.REQUEST_RANGE.asString()) != null)
ctp = "multipart/x-byteranges; boundary=";
else
ctp = "multipart/byteranges; boundary=";
response.setContentType(ctp + multi.getBoundary());
InputStream in = content.getResource().getInputStream();
long pos = 0;
// calculate the content-length
int length = 0;
String[] header = new String[ranges.size()];
for (int i = 0; i < ranges.size(); i++) {
InclusiveByteRange ibr = ranges.get(i);
header[i] = ibr.toHeaderRangeString(content_length);
length += ((i > 0) ? 2 : 0) + 2 + multi.getBoundary().length() + 2 + (mimetype == null ? 0 : HttpHeader.CONTENT_TYPE.asString().length() + 2 + mimetype.length()) + 2 + HttpHeader.CONTENT_RANGE.asString().length() + 2 + header[i].length() + 2 + 2 + (ibr.getLast(content_length) - ibr.getFirst(content_length)) + 1;
}
length += 2 + 2 + multi.getBoundary().length() + 2 + 2;
response.setContentLength(length);
for (int i = 0; i < ranges.size(); i++) {
InclusiveByteRange ibr = ranges.get(i);
multi.startPart(mimetype, new String[] { HttpHeader.CONTENT_RANGE + ": " + header[i] });
long start = ibr.getFirst(content_length);
long size = ibr.getSize(content_length);
if (in != null) {
// Handle non cached resource
if (start < pos) {
in.close();
in = content.getResource().getInputStream();
pos = 0;
}
if (pos < start) {
in.skip(start - pos);
pos = start;
}
IO.copy(in, multi, size);
pos += size;
} else
// Handle cached resource
content.getResource().writeTo(multi, start, size);
}
if (in != null)
in.close();
multi.close();
}
return true;
}
Aggregations