package org.basex.http; import static org.basex.core.users.UserText.*; import static org.basex.util.Token.*; import static org.basex.util.http.HttpMethod.*; import static org.junit.Assert.*; import java.io.*; import java.net.*; import java.util.*; import org.basex.*; import org.basex.core.*; import org.basex.core.StaticOptions.AuthMethod; import org.basex.io.*; import org.basex.io.in.*; import org.basex.util.*; import org.basex.util.http.*; import org.basex.util.list.*; import org.junit.*; /** * This class contains common methods for the HTTP services. * * @author BaseX Team 2005-17, BSD License * @author Christian Gruen */ public abstract class HTTPTest extends SandboxTest { /** Database context. */ private static final Context CONTEXT = HTTPContext.context(); /** HTTP server. */ private static BaseXHTTP http; /** Root path. */ private static String rootUrl; // INITIALIZATION ===================================================================== /** * Initializes the test. * @param rt root path * @param local local flag * @throws Exception exception */ protected static void init(final String rt, final boolean local) throws Exception { init(rt, local, false); } /** * Initializes the test. * @param url root path * @param local local flag * @param auth enforce authentication * @throws Exception exception */ protected static void init(final String url, final boolean local, final boolean auth) throws Exception { assertTrue(new IOFile(CONTEXT.soptions.get(StaticOptions.WEBPATH)).md()); rootUrl = url; final StringList sl = new StringList(); sl.add("-p" + DB_PORT, "-h" + HTTP_PORT, "-s" + STOP_PORT, "-z", "-q"); if(local) sl.add("-l"); if(!auth) sl.add("-U" + ADMIN); http = new BaseXHTTP(sl.toArray()); } /** * Finish test. * @throws Exception exception */ @AfterClass public static void stop() throws Exception { http.stop(); // cleanup: remove project specific system properties final StringList keys = new StringList(); final Properties props = System.getProperties(); for(final Object key : props.keySet()) { final String path = key.toString(); if(path.startsWith(Prop.DBPREFIX)) keys.add(path); } for(final String key : keys) props.remove(key); } // PROTECTED METHODS ================================================================== /** * Executes the specified GET request and returns the result. * @param query request * @return string result, or {@code null} for a failure. * @throws IOException I/O exception */ protected static String get(final String query) throws IOException { return request(query, GET); } /** * Executes the specified DELETE request. * @param query request * @return response code * @throws IOException I/O exception */ protected static String delete(final String query) throws IOException { return request(query, DELETE); } /** * Executes the specified HEAD request and returns the result. * @param query request * @return string result, or {@code null} for a failure. * @throws IOException I/O exception */ protected static String head(final String query) throws IOException { return request(query, HEAD); } /** * Executes the specified HTTP request and returns the result. * @param query request * @param method HTTP method * @return string result, or {@code null} for a failure. * @throws IOException I/O exception */ private static String request(final String query, final HttpMethod method)throws IOException { return request(query, method.name()); } /** * Executes the specified HTTP request and returns the result. * @param query request * @param method HTTP method * @return string result, or {@code null} for a failure. * @throws IOException I/O exception */ protected static String request(final String query, final String method) throws IOException { return request(rootUrl, query, method); } /** * Executes the specified HTTP request and returns the result. * @param root root URL * @param query request * @param method HTTP method * @return string result, or {@code null} for a failure. * @throws IOException I/O exception */ protected static String request(final String root, final String query, final String method) throws IOException { final IOUrl url = new IOUrl(root + query); final HttpURLConnection conn = (HttpURLConnection) url.connection(); try { conn.setRequestMethod(method); return read(new BufferInput(conn.getInputStream())); } catch(final IOException ex) { throw error(conn, ex); } finally { conn.disconnect(); } } /** * Executes the specified PUT request. * @param query path * @param request request * @param type media type * @return string result, or {@code null} for a failure. * @throws IOException I/O exception */ protected static String post(final String query, final String request, final MediaType type) throws IOException { // create connection final IOUrl url = new IOUrl(rootUrl + query); final HttpURLConnection conn = (HttpURLConnection) url.connection(); conn.setDoOutput(true); conn.setRequestMethod(POST.name()); conn.setRequestProperty(HttpText.CONTENT_TYPE, type.toString()); // basic authentication final String encoded = org.basex.util.Base64.encode(ADMIN + ':' + ADMIN); conn.setRequestProperty(HttpText.AUTHORIZATION, AuthMethod.BASIC + " " + encoded); // send query try(OutputStream out = conn.getOutputStream()) { out.write(token(request)); } try { return read(conn.getInputStream()); } catch(final IOException ex) { throw error(conn, ex); } finally { conn.disconnect(); } } /** * Returns an exception with improved error message. * @param conn connection reference * @param ex exception * @return exception * @throws IOException I/O exception */ protected static IOException error(final HttpURLConnection conn, final IOException ex) throws IOException { final String msg = read(conn.getErrorStream()); throw new BaseXException(msg.isEmpty() ? ex.getMessage() : msg); } /** * Returns a string result from the specified input stream. * @param is input stream * @return string * @throws IOException I/O exception */ protected static String read(final InputStream is) throws IOException { return is == null ? "" : string(new BufferInput(is).content()); } /** * Executes the specified PUT request. * @param u url * @param is input stream * @throws IOException I/O exception */ protected static void put(final String u, final InputStream is) throws IOException { put(u, is, null); } /** * Executes the specified PUT request. * @param u url * @param is input stream * @param type media type (optional, may be {@code null}) * @throws IOException I/O exception */ protected static void put(final String u, final InputStream is, final MediaType type) throws IOException { final IOUrl url = new IOUrl(rootUrl + u); final HttpURLConnection conn = (HttpURLConnection) url.connection(); conn.setDoOutput(true); conn.setRequestMethod(PUT.name()); if(type != null) conn.setRequestProperty(HttpText.CONTENT_TYPE, type.toString()); try(OutputStream bos = new BufferedOutputStream(conn.getOutputStream())) { if(is != null) { // send input stream if it not empty try(BufferedInputStream bis = new BufferedInputStream(is)) { for(int i; (i = bis.read()) != -1;) bos.write(i); } } } try { read(conn.getInputStream()); } catch(final IOException ex) { throw error(conn, ex); } finally { conn.disconnect(); } } }