package org.basex.http.rest;
import static org.basex.http.rest.RESTText.*;
import java.io.*;
import java.util.*;
import javax.xml.parsers.*;
import javax.xml.transform.dom.*;
import org.basex.core.*;
import org.basex.http.*;
import org.basex.io.*;
import org.basex.io.in.*;
import org.basex.io.serial.*;
import org.basex.query.*;
import org.basex.query.util.*;
import org.basex.query.value.item.*;
import org.basex.query.value.node.*;
import org.basex.util.*;
/**
* REST-based evaluation of POST operations.
*
* @author BaseX Team 2005-17, BSD License
* @author Christian Gruen
*/
final class RESTPost {
/** Private constructor. */
private RESTPost() { }
/**
* Creates and returns a REST command.
* @param session REST session
* @return code
* @throws IOException I/O exception
*/
public static RESTCmd get(final RESTSession session) throws IOException {
final HTTPConnection conn = session.conn;
String enc = conn.req.getCharacterEncoding();
if(enc == null) enc = Strings.UTF8;
// perform queries
final byte[] input = new NewlineInput(conn.req.getInputStream()).encoding(enc).content();
validate(input);
final Context ctx = conn.context;
final DBNode doc;
try {
doc = new DBNode(new IOContent(input));
} catch(final IOException ex) {
throw HTTPCode.BAD_REQUEST_X.get(ex);
}
try {
// handle serialization parameters
final SerializerOptions sopts = conn.sopts();
try(QueryProcessor qp = new QueryProcessor("*/*:parameter", ctx).context(doc)) {
for(final Item param : qp.value()) {
final String name = value("@name", param, ctx);
final String value = value("@value", param, ctx);
if(sopts.option(name) != null) {
sopts.assign(name, value);
} else {
throw HTTPCode.UNKNOWN_PARAM_X.get(name);
}
}
}
// handle database options
try(QueryProcessor qp = new QueryProcessor("*/*:option", ctx).context(doc)) {
for(final Item it : qp.value()) {
final String name = value("@name", it, ctx).toUpperCase(Locale.ENGLISH);
final String value = value("@value", it, ctx);
ctx.options.assign(name, value);
}
}
// handle variables
final Map<String, String[]> vars = new HashMap<>();
try(QueryProcessor qp = new QueryProcessor("*/*:variable", ctx).context(doc)) {
for(final Item it : qp.value()) {
final String name = value("@name", it, ctx);
final String value = value("@value", it, ctx);
final String type = value("@type", it, ctx);
vars.put(name, new String[] { value, type });
}
}
// handle input
String val = null;
try(QueryProcessor qp = new QueryProcessor("*/*:context/(*, text()[normalize-space()])",
ctx).context(doc)) {
for(final Item it : qp.value()) {
if(val != null) throw HTTPCode.MULTIPLE_CONTEXT_X.get();
// create main memory instance of the specified node
val = DataBuilder.stripNS((ANode) it, REST_URI, ctx).serialize().toString();
}
}
// handle request
final String request = value("local-name(*)", doc, ctx);
final String text = value("*/*:text/text()", doc, ctx);
if(request.equals(COMMAND)) return RESTCommand.get(session, text);
if(request.equals(RUN)) return RESTRun.get(session, text, vars, val);
return RESTQuery.get(session, text, vars, val);
} catch(final QueryException ex) {
throw HTTPCode.BAD_REQUEST_X.get(ex);
}
}
/**
* Returns the atomized item for the specified query.
* @param query query
* @param value context value
* @param ctx database context
* @return atomized item
* @throws QueryException query exception
*/
private static String value(final String query, final Item value, final Context ctx)
throws QueryException {
try(QueryProcessor qp = new QueryProcessor(query, ctx).context(value)) {
final Item it = qp.iter().next();
return it == null ? null : Token.string(it.string(null));
}
}
/**
* Validates the specified XML input against the POST schema.
* @param input input document
* @throws HTTPException exception
*/
private static void validate(final byte[] input) throws HTTPException {
try {
final DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
final DocumentBuilder db = dbf.newDocumentBuilder();
RESTSchema.newValidator().validate(new DOMSource(db.parse(new ArrayInput(input))));
} catch(final Exception ex) {
Util.debug("Error while validating \"" + Token.string(input) + '"');
// validation fails
throw HTTPCode.BAD_REQUEST_X.get(ex);
}
}
}