use of org.exist.http.Descriptor in project exist by eXist-db.
the class XQueryServlet method process.
/**
* Processes incoming HTTP requests for XQuery.
*
* @param request the http request
* @param response the http response
*
* @throws ServletException if the servlet raises an exception
* @throws IOException if an I/O error occurs
*/
protected void process(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// first, adjust the path
String path = request.getPathTranslated();
if (path == null) {
path = request.getRequestURI().substring(request.getContextPath().length());
final int p = path.lastIndexOf(';');
if (p != Constants.STRING_NOT_FOUND) {
path = path.substring(0, p);
}
path = getServletContext().getRealPath(path);
}
// second, perform descriptor actions
final Descriptor descriptor = Descriptor.getDescriptorSingleton();
if (descriptor != null && !descriptor.requestsFiltered()) {
// logs the request if specified in the descriptor
descriptor.doLogRequestInReplayLog(request);
// map's the path if a mapping is specified in the descriptor
path = descriptor.mapPath(path);
}
// if (request.getCharacterEncoding() == null)
// try {
// request.setCharacterEncoding(formEncoding);
// } catch (IllegalStateException e) {
// }
final ServletOutputStream sout = response.getOutputStream();
final PrintWriter output = new PrintWriter(new OutputStreamWriter(sout, getFormEncoding()));
// response.setContentType(contentType + "; charset=" + formEncoding);
response.addHeader("pragma", "no-cache");
response.addHeader("Cache-Control", "no-cache");
String requestPath = request.getRequestURI();
final int p = requestPath.lastIndexOf('/');
if (p != Constants.STRING_NOT_FOUND) {
requestPath = requestPath.substring(0, p);
}
String moduleLoadPath;
final Object loadPathAttrib = request.getAttribute(ATTR_MODULE_LOAD_PATH);
if (loadPathAttrib != null) {
moduleLoadPath = getValue(loadPathAttrib);
} else {
moduleLoadPath = getServletContext().getRealPath(requestPath.substring(request.getContextPath().length()));
}
Subject user = getDefaultUser();
// to determine the user, first check the request attribute "xquery.user", then
// the current session attribute "user"
final Object userAttrib = request.getAttribute(ATTR_XQUERY_USER);
final HttpSession session = request.getSession(false);
if (userAttrib != null || (session != null && request.isRequestedSessionIdValid())) {
final Object passwdAttrib = request.getAttribute(ATTR_XQUERY_PASSWORD);
String username;
String password;
if (userAttrib != null) {
username = getValue(userAttrib);
password = getValue(passwdAttrib);
} else {
username = getSessionAttribute(session, "user");
password = getSessionAttribute(session, "password");
}
// TODO authentication should use super.authenticate(...) !!!
try {
if (username != null && password != null) {
Subject newUser = getPool().getSecurityManager().authenticate(username, password);
if (newUser != null && newUser.isAuthenticated()) {
user = newUser;
}
}
} catch (final AuthenticationException e) {
getLog().error("User can not be authenticated ({}).", username);
}
}
if (user == getDefaultUser()) {
Subject requestUser = HttpAccount.getUserFromServletRequest(request);
if (requestUser != null) {
user = requestUser;
} else {
requestUser = getAuthenticator().authenticate(request, response, false);
if (requestUser != null) {
user = requestUser;
}
}
}
Source source = null;
final Object sourceAttrib = request.getAttribute(ATTR_XQUERY_SOURCE);
final Object urlAttrib = request.getAttribute(ATTR_XQUERY_URL);
if (sourceAttrib != null) {
String s;
if (sourceAttrib instanceof Item)
try {
s = ((Item) sourceAttrib).getStringValue();
} catch (final XPathException e) {
throw new ServletException("Failed to read XQuery source string from " + "request attribute '" + ATTR_XQUERY_SOURCE + "': " + e.getMessage(), e);
}
else {
s = sourceAttrib.toString();
}
source = new StringSource(s);
} else if (urlAttrib != null) {
try (final DBBroker broker = getPool().get(Optional.ofNullable(user))) {
source = SourceFactory.getSource(broker, moduleLoadPath, urlAttrib.toString(), true);
if (source == null) {
final String msg = "Could not read source: context=" + moduleLoadPath + ", location=" + urlAttrib.toString();
getLog().error(msg);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
sendError(output, "Error", msg);
}
} catch (final Exception e) {
getLog().error(e.getMessage(), e);
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
sendError(output, "Error", e.getMessage());
}
} else {
final Path f = Paths.get(path);
if (!Files.isReadable(f)) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
sendError(output, "Cannot read source file", path);
return;
}
source = new FileSource(f, Charset.forName(encoding), true);
}
if (source == null) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
sendError(output, "Source not found", path);
}
boolean reportErrors = false;
final String errorOpt = (String) request.getAttribute(ATTR_XQUERY_REPORT_ERRORS);
if (errorOpt != null) {
reportErrors = errorOpt.equalsIgnoreCase("YES");
}
// allow source viewing for GET?
if ("GET".equals(request.getMethod().toUpperCase())) {
String option;
boolean allowSource = false;
if ((option = request.getParameter("_source")) != null)
allowSource = "yes".equals(option);
// Should we display the source of the XQuery or execute it
if (allowSource && descriptor != null) {
// System.out.println("path="+path);
if (descriptor.allowSource(path)) {
if (source instanceof DBSource) {
try {
((DBSource) source).validate(user, Permission.READ);
} catch (final PermissionDeniedException e) {
if (getDefaultUser().equals(user)) {
getAuthenticator().sendChallenge(request, response);
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Permission to view XQuery source for: " + path + " denied. (no read access)");
}
return;
}
}
// Show the source of the XQuery
// writeResourceAs(resource, broker, stylesheet, encoding, "text/plain", outputProperties, response);
response.setContentType("text/plain; charset=" + getFormEncoding());
output.write(source.getContent());
output.flush();
return;
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "Permission to view XQuery source for: " + path + " denied. Must be explicitly defined in descriptor.xml");
return;
}
}
}
// -------------------------------
// URI baseUri;
// try {
// baseUri = new URI(request.getScheme(),
// null/*user info?*/, request.getLocalPart(), request.getLocalPort(),
// request.getRequestURI(), null, null);
// } catch(URISyntaxException e) {
// baseUri = null;
// }
final String requestAttr = (String) request.getAttribute(ATTR_XQUERY_ATTRIBUTE);
try (final DBBroker broker = getPool().get(Optional.ofNullable(user))) {
final XQuery xquery = broker.getBrokerPool().getXQueryService();
CompiledXQuery query = getPool().getXQueryPool().borrowCompiledXQuery(broker, source);
XQueryContext context;
if (query == null) {
context = new XQueryContext(getPool());
context.setModuleLoadPath(moduleLoadPath);
try {
query = xquery.compile(context, source);
} catch (final XPathException ex) {
throw new EXistException("Cannot compile xquery: " + ex.getMessage(), ex);
} catch (final IOException ex) {
throw new EXistException("I/O exception while compiling xquery: " + ex.getMessage(), ex);
}
} else {
context = query.getContext();
context.setModuleLoadPath(moduleLoadPath);
context.prepareForReuse();
}
final Properties outputProperties = new Properties();
outputProperties.put("base-uri", collectionURI.toString());
final HttpRequestWrapper reqw = new HttpRequestWrapper(request, getFormEncoding(), getContainerEncoding());
final ResponseWrapper respw = new HttpResponseWrapper(response);
context.setHttpContext(new XQueryContext.HttpContext(reqw, respw, session != null ? new HttpSessionWrapper(session) : null));
final String timeoutOpt = (String) request.getAttribute(ATTR_TIMEOUT);
if (timeoutOpt != null) {
try {
final long timeout = Long.parseLong(timeoutOpt);
context.getWatchDog().setTimeout(timeout);
} catch (final NumberFormatException e) {
throw new EXistException("Bad timeout option: " + timeoutOpt);
}
}
final String maxNodesOpt = (String) request.getAttribute(ATTR_MAX_NODES);
if (maxNodesOpt != null) {
try {
final int maxNodes = Integer.parseInt(maxNodesOpt);
context.getWatchDog().setMaxNodes(maxNodes);
} catch (final NumberFormatException e) {
throw new EXistException("Bad max-nodes option: " + maxNodesOpt);
}
}
DebuggeeFactory.checkForDebugRequest(request, context);
Sequence resultSequence;
try {
resultSequence = xquery.execute(broker, query, null, outputProperties);
} finally {
context.runCleanupTasks();
getPool().getXQueryPool().returnCompiledXQuery(source, query);
}
final String mediaType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
if (mediaType != null) {
if (!response.isCommitted()) {
if (MimeTable.getInstance().isTextContent(mediaType)) {
response.setContentType(mediaType + "; charset=" + getFormEncoding());
response.setCharacterEncoding(getFormEncoding());
} else
response.setContentType(mediaType);
}
} else {
String contentType = this.contentType;
try {
contentType = getServletContext().getMimeType(path);
if (contentType == null) {
contentType = this.contentType;
}
} catch (final Throwable e) {
contentType = this.contentType;
} finally {
if (MimeTable.getInstance().isTextContent(contentType)) {
contentType += "; charset=" + getFormEncoding();
}
response.setContentType(contentType);
}
}
if (requestAttr != null && (XmldbURI.API_LOCAL.equals(collectionURI.getApiName()))) {
request.setAttribute(requestAttr, resultSequence);
} else {
XQuerySerializer serializer = new XQuerySerializer(broker, outputProperties, output);
serializer.serialize(resultSequence);
}
} catch (final PermissionDeniedException e) {
if (getDefaultUser().equals(user)) {
getAuthenticator().sendChallenge(request, response);
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, "No permission to execute XQuery for: " + path + " denied.");
}
return;
} catch (final XPathException e) {
final Logger logger = getLog();
if (logger.isDebugEnabled()) {
logger.debug(e.getMessage(), e);
}
if (reportErrors) {
writeError(output, e);
} else {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
sendError(output, "Error", e.getMessage());
}
} catch (final Throwable e) {
getLog().error(e.getMessage(), e);
if (reportErrors) {
writeError(output, e);
} else {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
sendError(output, "Error", e.getMessage());
}
}
output.flush();
output.close();
}
use of org.exist.http.Descriptor in project exist by eXist-db.
the class EXistServlet method doPatch.
protected void doPatch(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException {
// first, adjust the path
String path = adjustPath(request);
// second, perform descriptor actions
final Descriptor descriptor = Descriptor.getDescriptorSingleton();
if (descriptor != null) {
// TODO: figure out a way to log PATCH requests with
// HttpServletRequestWrapper and
// Descriptor.doLogRequestInReplayLog()
// map's the path if a mapping is specified in the descriptor
path = descriptor.mapPath(path);
}
// third, authenticate the user
final Subject user = authenticate(request, response);
if (user == null) {
// You now get a HTTP Authentication challenge if there is no user
return;
}
// fourth, process the request
try (final DBBroker broker = getPool().get(Optional.of(user));
final Txn transaction = getPool().getTransactionManager().beginTransaction()) {
final XmldbURI dbpath = XmldbURI.createInternal(path);
try (final Collection collection = broker.getCollection(dbpath)) {
if (collection != null) {
transaction.abort();
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "A PATCH request is not allowed against a plain collection path.");
return;
}
}
try {
srvREST.doPatch(broker, transaction, dbpath, request, response);
transaction.commit();
} catch (final Throwable t) {
transaction.abort();
throw t;
}
} catch (final MethodNotAllowedException e) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, e.getMessage());
} catch (final BadRequestException e) {
if (response.isCommitted()) {
throw new ServletException(e.getMessage(), e);
}
response.sendError(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
} catch (final PermissionDeniedException e) {
// Else return a FORBIDDEN Error
if (user.equals(getDefaultUser())) {
getAuthenticator().sendChallenge(request, response);
} else {
response.sendError(HttpServletResponse.SC_FORBIDDEN, e.getMessage());
}
} catch (final EXistException e) {
if (response.isCommitted()) {
throw new ServletException(e.getMessage(), e);
}
response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
} catch (final Throwable e) {
LOG.error(e);
throw new ServletException("An unknown error occurred: " + e.getMessage(), e);
}
}
use of org.exist.http.Descriptor in project exist by eXist-db.
the class XQueryServlet method doPost.
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
HttpServletRequest request = null;
try {
// For POST request, If we are logging the requests we must wrap HttpServletRequest in HttpServletRequestWrapper
// otherwise we cannot access the POST parameters from the content body of the request!!! - deliriumsky
final Descriptor descriptor = Descriptor.getDescriptorSingleton();
if (descriptor != null) {
if (descriptor.allowRequestLogging()) {
request = new HttpServletRequestWrapper(() -> (String) getPool().getConfiguration().getProperty(Configuration.BINARY_CACHE_CLASS_PROPERTY), req, getFormEncoding());
} else {
request = req;
}
} else {
request = req;
}
process(request, response);
} finally {
if (request != null && request instanceof HttpServletRequestWrapper) {
((HttpServletRequestWrapper) request).close();
}
}
}
use of org.exist.http.Descriptor in project exist by eXist-db.
the class XQueryServlet method doPut.
// -------------------------------
// doPut and doDelete added by Andrzej Taramina (andrzej@chaeron.com)
// Date: Sept/05/2007
//
// These methods were added so that you can issue an HTTP PUT or DELETE request and have it serviced by an XQuery.
// NOTE: The XQuery referenced in the target URL of the request will be executed and the PUT/DELETE request will be passed to it
//
// -------------------------------
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse response) throws ServletException, IOException {
HttpServletRequest request = null;
try {
// For POST request, If we are logging the requests we must wrap HttpServletRequest in HttpServletRequestWrapper
// otherwise we cannot access the POST parameters from the content body of the request!!! - deliriumsky
final Descriptor descriptor = Descriptor.getDescriptorSingleton();
if (descriptor != null) {
if (descriptor.allowRequestLogging()) {
request = new HttpServletRequestWrapper(() -> (String) getPool().getConfiguration().getProperty(Configuration.BINARY_CACHE_CLASS_PROPERTY), req, getFormEncoding());
} else {
request = req;
}
} else {
request = req;
}
process(request, response);
} finally {
if (request != null && request instanceof HttpServletRequestWrapper) {
((HttpServletRequestWrapper) request).close();
}
}
}
use of org.exist.http.Descriptor in project exist by eXist-db.
the class XQueryURLRewrite method service.
@Override
protected void service(final HttpServletRequest request, final HttpServletResponse response) throws IOException, ServletException {
if (rewriteConfig == null) {
configure();
rewriteConfig = new RewriteConfig(this);
}
final long start = System.currentTimeMillis();
if (LOG.isTraceEnabled()) {
LOG.trace(request.getRequestURI());
}
final Descriptor descriptor = Descriptor.getDescriptorSingleton();
if (descriptor != null && descriptor.requestsFiltered()) {
final String attr = (String) request.getAttribute("XQueryURLRewrite.forwarded");
if (attr == null) {
// logs the request if specified in the descriptor
descriptor.doLogRequestInReplayLog(request);
request.setAttribute("XQueryURLRewrite.forwarded", "true");
}
}
Subject user = defaultUser;
Subject requestUser = HttpAccount.getUserFromServletRequest(request);
if (requestUser != null) {
user = requestUser;
} else {
// Secondly try basic authentication
final String auth = request.getHeader("Authorization");
if (auth != null) {
requestUser = authenticator.authenticate(request, response, sendChallenge);
if (requestUser != null) {
user = requestUser;
}
}
}
try {
configure();
// checkCache(user);
final RequestWrapper modifiedRequest = new RequestWrapper(request);
final URLRewrite staticRewrite = rewriteConfig.lookup(modifiedRequest);
if (staticRewrite != null && !staticRewrite.isControllerForward()) {
modifiedRequest.setPaths(staticRewrite.resolve(modifiedRequest), staticRewrite.getPrefix());
if (LOG.isTraceEnabled()) {
LOG.trace("Forwarding to target: {}", staticRewrite.getTarget());
}
staticRewrite.doRewrite(modifiedRequest, response);
} else {
if (LOG.isTraceEnabled()) {
LOG.trace("Processing request URI: {}", request.getRequestURI());
}
if (staticRewrite != null) {
// fix the request URI
staticRewrite.updateRequest(modifiedRequest);
}
// check if the request URI is already in the url cache
ModelAndView modelView = getFromCache(request.getHeader("Host") + request.getRequestURI(), user);
if (LOG.isDebugEnabled()) {
LOG.debug("Checked cache for URI: {} original: {}", modifiedRequest.getRequestURI(), request.getRequestURI());
}
// no: create a new model and view configuration
if (modelView == null) {
modelView = new ModelAndView();
// Execute the query
try (final DBBroker broker = pool.get(Optional.ofNullable(user))) {
modifiedRequest.setAttribute(RQ_ATTR_REQUEST_URI, request.getRequestURI());
final Properties outputProperties = new Properties();
outputProperties.setProperty(OutputKeys.INDENT, "yes");
outputProperties.setProperty(OutputKeys.ENCODING, "UTF-8");
outputProperties.setProperty(OutputKeys.MEDIA_TYPE, MimeType.XML_TYPE.getName());
final Sequence result = runQuery(broker, modifiedRequest, response, modelView, staticRewrite, outputProperties);
logResult(broker, result);
if (response.isCommitted()) {
return;
}
// process the query result
if (result.getItemCount() == 1) {
final Item resource = result.itemAt(0);
if (!Type.subTypeOf(resource.getType(), Type.NODE)) {
throw new ServletException("XQueryURLRewrite: urlrewrite query should return an element!");
}
Node node = ((NodeValue) resource).getNode();
if (node.getNodeType() == Node.DOCUMENT_NODE) {
node = ((Document) node).getDocumentElement();
}
if (node.getNodeType() != Node.ELEMENT_NODE) {
// throw new ServletException("Redirect XQuery should return an XML element!");
response(broker, response, outputProperties, result);
return;
}
Element elem = (Element) node;
final String ns = elem.getNamespaceURI();
if (!Namespaces.EXIST_NS.equals(ns)) {
response(broker, response, outputProperties, result);
return;
}
final String nsUri = elem.getNamespaceURI();
if (Namespaces.EXIST_NS.equals(nsUri) && "dispatch".equals(elem.getLocalName())) {
node = elem.getFirstChild();
while (node != null) {
final String nodeNs = node.getNamespaceURI();
if (node.getNodeType() == Node.ELEMENT_NODE && Namespaces.EXIST_NS.equals(nodeNs)) {
final Element action = (Element) node;
if ("view".equals(action.getLocalName())) {
parseViews(modifiedRequest, action, modelView);
} else if ("error-handler".equals(action.getLocalName())) {
parseErrorHandlers(modifiedRequest, action, modelView);
} else if ("cache-control".equals(action.getLocalName())) {
final String option = action.getAttribute("cache");
modelView.setUseCache("yes".equals(option));
} else {
final URLRewrite urw = parseAction(modifiedRequest, action);
if (urw != null) {
modelView.setModel(urw);
}
}
}
node = node.getNextSibling();
}
if (modelView.getModel() == null) {
modelView.setModel(new PassThrough(config, elem, modifiedRequest));
}
} else if (nsUri != null && Namespaces.EXIST_NS.equals(elem.getNamespaceURI()) && "ignore".equals(elem.getLocalName())) {
modelView.setModel(new PassThrough(config, elem, modifiedRequest));
final NodeList nl = elem.getElementsByTagNameNS(Namespaces.EXIST_NS, "cache-control");
if (nl.getLength() > 0) {
elem = (Element) nl.item(0);
final String option = elem.getAttribute("cache");
modelView.setUseCache("yes".equals(option));
}
} else {
response(broker, response, outputProperties, result);
return;
}
} else if (result.getItemCount() > 1) {
response(broker, response, outputProperties, result);
return;
}
if (modelView.useCache()) {
LOG.debug("Caching request to {}", request.getRequestURI());
urlCache.put(modifiedRequest.getHeader("Host") + request.getRequestURI(), modelView);
}
}
// store the original request URI to org.exist.forward.request-uri
modifiedRequest.setAttribute(RQ_ATTR_REQUEST_URI, request.getRequestURI());
modifiedRequest.setAttribute(RQ_ATTR_SERVLET_PATH, request.getServletPath());
}
if (LOG.isTraceEnabled()) {
LOG.trace("URLRewrite took {}ms.", System.currentTimeMillis() - start);
}
final HttpServletResponse wrappedResponse = new CachingResponseWrapper(response, modelView.hasViews() || modelView.hasErrorHandlers());
if (modelView.getModel() == null) {
modelView.setModel(new PassThrough(config, modifiedRequest));
}
if (staticRewrite != null) {
if (modelView.getModel().doResolve()) {
staticRewrite.rewriteRequest(modifiedRequest);
} else {
modelView.getModel().setAbsolutePath(modifiedRequest);
}
}
modifiedRequest.allowCaching(!modelView.hasViews());
doRewrite(modelView.getModel(), modifiedRequest, wrappedResponse);
final int status = wrappedResponse.getStatus();
if (status == HttpServletResponse.SC_NOT_MODIFIED) {
response.flushBuffer();
} else if (status < HttpServletResponse.SC_BAD_REQUEST) {
if (modelView.hasViews()) {
applyViews(modelView, modelView.views, response, modifiedRequest, wrappedResponse);
} else {
((CachingResponseWrapper) wrappedResponse).flush();
}
} else {
// HTTP response code indicates an error
if (modelView.hasErrorHandlers()) {
final byte[] data = ((CachingResponseWrapper) wrappedResponse).getData();
if (data != null) {
modifiedRequest.setAttribute(RQ_ATTR_ERROR, new String(data, UTF_8));
}
applyViews(modelView, modelView.errorHandlers, response, modifiedRequest, wrappedResponse);
} else {
flushError(response, wrappedResponse);
}
}
}
} catch (final Throwable e) {
LOG.error("Error while processing {}: {}", request.getRequestURI(), e.getMessage(), e);
throw new ServletException("An error occurred while processing request to " + request.getRequestURI() + ": " + e.getMessage(), e);
}
}
Aggregations