use of org.springframework.extensions.webscripts.WebScriptResponse in project alfresco-remote-api by Alfresco.
the class HttpRangeProcessor method processSingleRange.
/**
* Process a single range request.
*
* @param res HttpServletResponse
* @param reader ContentReader to retrieve content
* @param range Range header value
* @param mimetype Content mimetype
*
* @return true if processed range, false otherwise
*/
private boolean processSingleRange(Object res, ContentReader reader, String range, String mimetype) throws IOException {
// Handle either HttpServletResponse or WebScriptResponse
HttpServletResponse httpServletResponse = null;
WebScriptResponse webScriptResponse = null;
if (res instanceof HttpServletResponse) {
httpServletResponse = (HttpServletResponse) res;
} else if (res instanceof WebScriptResponse) {
webScriptResponse = (WebScriptResponse) res;
}
if (httpServletResponse == null && webScriptResponse == null) {
// Unknown response object type
return false;
}
// return the specific set of bytes as requested in the content-range header
/* Examples of byte-content-range-spec values, assuming that the entity contains total of 1234 bytes:
The first 500 bytes:
bytes 0-499/1234
The second 500 bytes:
bytes 500-999/1234
All except for the first 500 bytes:
bytes 500-1233/1234 */
/* 'Range' header example:
bytes=10485760-20971519 */
boolean processedRange = false;
Range r = null;
try {
r = Range.constructRange(range, mimetype, reader.getSize());
} catch (IllegalArgumentException err) {
if (getLogger().isDebugEnabled())
getLogger().debug("Failed to parse range header - returning 416 status code: " + err.getMessage());
if (httpServletResponse != null) {
httpServletResponse.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
httpServletResponse.setHeader(HEADER_CONTENT_RANGE, "\"*\"");
httpServletResponse.getOutputStream().close();
} else if (webScriptResponse != null) {
webScriptResponse.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
webScriptResponse.setHeader(HEADER_CONTENT_RANGE, "\"*\"");
webScriptResponse.getOutputStream().close();
}
return true;
}
// set Partial Content status and range headers
String contentRange = "bytes " + Long.toString(r.start) + "-" + Long.toString(r.end) + "/" + Long.toString(reader.getSize());
if (httpServletResponse != null) {
httpServletResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
httpServletResponse.setContentType(mimetype);
httpServletResponse.setHeader(HEADER_CONTENT_RANGE, contentRange);
httpServletResponse.setHeader(HEADER_CONTENT_LENGTH, Long.toString((r.end - r.start) + 1L));
} else if (webScriptResponse != null) {
webScriptResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
webScriptResponse.setContentType(mimetype);
webScriptResponse.setHeader(HEADER_CONTENT_RANGE, contentRange);
webScriptResponse.setHeader(HEADER_CONTENT_LENGTH, Long.toString((r.end - r.start) + 1L));
}
if (getLogger().isDebugEnabled())
getLogger().debug("Processing: Content-Range: " + contentRange);
InputStream is = null;
try {
// output the binary data for the range
OutputStream os = null;
if (httpServletResponse != null) {
os = httpServletResponse.getOutputStream();
} else if (webScriptResponse != null) {
os = webScriptResponse.getOutputStream();
}
is = reader.getContentInputStream();
streamRangeBytes(r, is, os, 0L);
os.close();
processedRange = true;
} catch (IOException err) {
if (getLogger().isDebugEnabled())
getLogger().debug("Unable to process single range due to IO Exception: " + err.getMessage());
throw err;
} finally {
if (is != null)
is.close();
}
return processedRange;
}
use of org.springframework.extensions.webscripts.WebScriptResponse in project alfresco-remote-api by Alfresco.
the class HttpRangeProcessor method processMultiRange.
/**
* Process multiple ranges.
*
* @param res HttpServletResponse
* @param range Range header value
* @param ref NodeRef to the content for streaming
* @param property Content Property for the content
* @param mimetype Mimetype of the content
* @param userAgent User Agent of the caller
*
* @return true if processed range, false otherwise
*/
private boolean processMultiRange(Object res, String range, NodeRef ref, QName property, String mimetype, String userAgent) throws IOException {
final Log logger = getLogger();
// Handle either HttpServletResponse or WebScriptResponse
HttpServletResponse httpServletResponse = null;
WebScriptResponse webScriptResponse = null;
if (res instanceof HttpServletResponse) {
httpServletResponse = (HttpServletResponse) res;
} else if (res instanceof WebScriptResponse) {
webScriptResponse = (WebScriptResponse) res;
}
if (httpServletResponse == null && webScriptResponse == null) {
// Unknown response object type
return false;
}
// return the sets of bytes as requested in the content-range header
// the response will be formatted as multipart/byteranges media type message
/* Examples of byte-ranges-specifier values (assuming an entity-body of length 10000):
- The first 500 bytes (byte offsets 0-499, inclusive): bytes=0-499
- The second 500 bytes (byte offsets 500-999, inclusive):
bytes=500-999
- The final 500 bytes (byte offsets 9500-9999, inclusive):
bytes=-500
- Or bytes=9500-
- The first and last bytes only (bytes 0 and 9999): bytes=0-0,-1
- Several legal but not canonical specifications of byte offsets 500-999, inclusive:
bytes=500-600,601-999
bytes=500-700,601-999 */
boolean processedRange = false;
// get the content reader
ContentReader reader = contentService.getReader(ref, property);
final List<Range> ranges = new ArrayList<Range>(8);
long entityLength = reader.getSize();
for (StringTokenizer t = new StringTokenizer(range, ", "); t.hasMoreTokens(); ) /**/
{
try {
ranges.add(Range.constructRange(t.nextToken(), mimetype, entityLength));
} catch (IllegalArgumentException err) {
if (getLogger().isDebugEnabled())
getLogger().debug("Failed to parse range header - returning 416 status code: " + err.getMessage());
if (httpServletResponse != null) {
httpServletResponse.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
httpServletResponse.setHeader(HEADER_CONTENT_RANGE, "\"*\"");
httpServletResponse.getOutputStream().close();
} else if (webScriptResponse != null) {
webScriptResponse.setStatus(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);
webScriptResponse.setHeader(HEADER_CONTENT_RANGE, "\"*\"");
webScriptResponse.getOutputStream().close();
}
return true;
}
}
if (ranges.size() != 0) {
// merge byte ranges if possible - IE handles this well, FireFox not so much
if (userAgent == null || userAgent.indexOf("MSIE ") != -1) {
Collections.sort(ranges);
for (int i = 0; i < ranges.size() - 1; i++) {
Range first = ranges.get(i);
Range second = ranges.get(i + 1);
if (first.end + 1 >= second.start) {
if (logger.isDebugEnabled())
logger.debug("Merging byte range: " + first + " with " + second);
if (first.end < second.end) {
// merge second range into first
first.end = second.end;
}
// else we simply discard the second range - it is contained within the first
// delete second range
ranges.remove(i + 1);
// reset loop index
i--;
}
}
}
// calculate response content length
long length = MULTIPART_BYTERANGES_BOUNDRY_END.length() + 2;
for (Range r : ranges) {
length += r.getLength();
}
// output headers as we have at least one range to process
OutputStream os = null;
if (httpServletResponse != null) {
httpServletResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
httpServletResponse.setHeader(HEADER_CONTENT_TYPE, MULTIPART_BYTERANGES_HEADER);
httpServletResponse.setHeader(HEADER_CONTENT_LENGTH, Long.toString(length));
os = httpServletResponse.getOutputStream();
} else if (webScriptResponse != null) {
webScriptResponse.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
webScriptResponse.setHeader(HEADER_CONTENT_TYPE, MULTIPART_BYTERANGES_HEADER);
webScriptResponse.setHeader(HEADER_CONTENT_LENGTH, Long.toString(length));
os = webScriptResponse.getOutputStream();
}
InputStream is = null;
try {
for (Range r : ranges) {
if (logger.isDebugEnabled())
logger.debug("Processing: " + r.getContentRange());
try {
// output the header bytes for the range
if (os instanceof ServletOutputStream)
r.outputHeader((ServletOutputStream) os);
// output the binary data for the range
// need a new reader for each new InputStream
is = contentService.getReader(ref, property).getContentInputStream();
streamRangeBytes(r, is, os, 0L);
is.close();
is = null;
// section marker and flush stream
if (os instanceof ServletOutputStream)
((ServletOutputStream) os).println();
os.flush();
} catch (IOException err) {
if (getLogger().isDebugEnabled())
getLogger().debug("Unable to process multiple range due to IO Exception: " + err.getMessage());
throw err;
}
}
} finally {
if (is != null) {
is.close();
}
}
// end marker
if (os instanceof ServletOutputStream)
((ServletOutputStream) os).println(MULTIPART_BYTERANGES_BOUNDRY_END);
os.close();
processedRange = true;
}
return processedRange;
}
use of org.springframework.extensions.webscripts.WebScriptResponse in project records-management by Alfresco.
the class BaseWebScriptUnitTest method executeWebScript.
/**
* Execute web script and return result as a string.
*
* @param parameters map of all parameter values
* @return {@link String} result of web script
*/
protected String executeWebScript(Map<String, String> parameters, String content) throws Exception {
AbstractWebScript webScript = getWebScript();
String template = getWebScriptTemplate();
// initialise webscript
webScript.init(getMockedContainer(template), getMockedDescription());
// execute webscript
WebScriptResponse mockedResponse = getMockedWebScriptResponse();
webScript.execute(getMockedWebScriptRequest(webScript, parameters, content), mockedResponse);
// return results
return mockedResponse.getWriter().toString();
}
use of org.springframework.extensions.webscripts.WebScriptResponse in project alfresco-remote-api by Alfresco.
the class ExecutionTests method testInvalidUrls.
@Test
public void testInvalidUrls() throws IOException {
AbstractResourceWebScript executor = getExecutor();
Map<String, String> templateVars = new HashMap();
templateVars.put("apiScope", "private");
templateVars.put("apiVersion", "1");
templateVars.put("apiName", "alfrescomock");
WebScriptResponse response = mockResponse();
templateVars.put(ResourceLocator.COLLECTION_RESOURCE, "blah:");
executor.execute(api, mockRequest(templateVars, new HashMap<String, List<String>>(1)), response);
// Can't find it so a 404
verify(response, times(1)).setStatus(HttpServletResponse.SC_NOT_FOUND);
}
use of org.springframework.extensions.webscripts.WebScriptResponse in project alfresco-remote-api by Alfresco.
the class ExecutionTests method testInvokeAbstract.
@Test
public void testInvokeAbstract() throws IOException {
AbstractResourceWebScript executor = getExecutor();
Map<String, String> templateVars = new HashMap();
templateVars.put("apiScope", "private");
templateVars.put("apiVersion", "1");
templateVars.put("apiName", "alfrescomock");
templateVars.put(ResourceLocator.COLLECTION_RESOURCE, "sheep");
executor.execute(ApiAssistant.determineApi(templateVars), mockRequest(templateVars, new HashMap<String, List<String>>(1)), mock(WebScriptResponse.class));
WebScriptResponse response = mockResponse();
templateVars.put(ResourceLocator.COLLECTION_RESOURCE, "bad");
executor.execute(api, mockRequest(templateVars, new HashMap<String, List<String>>(1)), response);
// throws a runtime exception so INTERNAL_SERVER_ERROR
verify(response, times(1)).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
response = mockResponse();
templateVars.put(ResourceLocator.ENTITY_ID, "badId");
executor.execute(api, mockRequest(templateVars, new HashMap<String, List<String>>(1)), response);
// throws a IntegrityException so 422
verify(response, times(1)).setStatus(422);
}
Aggregations