package org.exist.xquery.functions.request; import java.io.ByteArrayInputStream; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.PartSource; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.exist.http.RESTTest; import org.exist.xmldb.EXistResource; import org.exist.xmldb.UserManagementService; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.xmldb.api.DatabaseManager; import org.xmldb.api.base.Collection; import org.xmldb.api.base.XMLDBException; import org.xmldb.api.modules.BinaryResource; /** * Tests expected behaviour of request:get-parameter() XQuery function * * @author Adam Retter <adam@exist-db.org> * @version 1.0 */ public class GetParameterTest extends RESTTest { private final static String XQUERY = "for $param-name in request:get-parameter-names() return for $param-value in request:get-parameter($param-name, ()) return fn:concat($param-name, '=', $param-value)"; private final static String XQUERY_FILENAME = "test-get-parameter.xql"; private final static String TEST_FILE_CONTENT = "hello world"; private final static String TEST_FILE_NAME = "helloworld.txt"; private static Collection root; @BeforeClass public static void beforeClass() throws XMLDBException { root = DatabaseManager.getCollection("xmldb:exist://localhost:" + existWebServer.getPort() + "/xmlrpc/db", "admin", ""); BinaryResource res = (BinaryResource)root.createResource(XQUERY_FILENAME, "BinaryResource"); ((EXistResource) res).setMimeType("application/xquery"); res.setContent(XQUERY); root.storeResource(res); UserManagementService ums = (UserManagementService)root.getService("UserManagementService", "1.0"); ums.chmod(res, 0777); } @AfterClass public static void afterClass() throws XMLDBException { BinaryResource res = (BinaryResource)root.getResource(XQUERY_FILENAME); root.removeResource(res); } @Test public void testGetNoParameter() throws XMLDBException { testGet(null); } @Test public void testPostNoParameter() throws XMLDBException { testPost(null); } @Test public void testGetEmptyParameter() { testGet(new NameValues[] { new NameValues("param1", new String[]{}) }); } @Test public void testPostEmptyParameter() { testPost(new NameValues[] { new NameValues("param1", new String[]{}) }); } @Test public void testGetSingleValueParameter() { testGet(new NameValues[] { new NameValues("param1", new String[] { "value1" }) }); } @Test public void testPostSingleValueParameter() { testPost(new NameValues[] { new NameValues("param1", new String[] { "value1" }) }); } @Test public void testGetMultiValueParameter() { testGet(new NameValues[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }) }); } @Test public void testPostMultiValueParameter() { testPost(new NameValues[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }) }); } @Test public void testPostMultiValueParameterWithQueryStringMultiValueParameter() { testPost( new NameValues[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }), }, new NameValues[]{ new NameValues("param2", new String[] { "valueA", "valueB", "valueC", "valueD" }), } ); } @Test public void testPostMultiValueParameterWithQueryStringMultiValueParameterMerge() { testPost( new NameValues[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }), }, new NameValues[]{ new NameValues("param1", new String[] { "valueA", "valueB", "valueC", "valueD" }), } ); } @Test public void testMultipartPostMultiValueParameterAndFile() { testMultipartPost( new Param[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }), new TextFileUpload(TEST_FILE_NAME, TEST_FILE_CONTENT) } ); } @Test public void testMultipartPostFileAndMultiValueParameter() { testMultipartPost( new Param[]{ new TextFileUpload(TEST_FILE_NAME, TEST_FILE_CONTENT), new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }) } ); } @Test public void testMultipartPostMultiValueParameterAndFileAndMultiValueParameter() { testMultipartPost( new Param[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }), new TextFileUpload(TEST_FILE_NAME, TEST_FILE_CONTENT), new NameValues("param2", new String[] { "valueA", "valueB", "valueC", "valueD" }) } ); } @Test public void testMultipartPostAndMultiValueParameterAndFileAndMultiValueParameterWithQueryStringMultiValueParameters() { testMultipartPost( new NameValues[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }) }, new Param[]{ new NameValues("param2", new String[] { "valueA", "valueB", "valueC", "valueD" }), new TextFileUpload(TEST_FILE_NAME, TEST_FILE_CONTENT), new NameValues("param3", new String[] { "valueZ", "valueY", "valueX", "valueW" }) } ); } @Test public void testMultipartPostAndMultiValueParameterAndFileAndMultiValueParameterWithQueryStringMultiValueParametersMerged() { testMultipartPost( new NameValues[]{ new NameValues("param1", new String[] { "value1", "value2", "value3", "value4" }) }, new Param[]{ new NameValues("param1", new String[] { "value5", "value6", "value7", "value8" }), new TextFileUpload(TEST_FILE_NAME, TEST_FILE_CONTENT), new NameValues("param2", new String[] { "valueA", "valueB", "valueC", "valueD" }) } ); } private void testGet(NameValues queryStringParams[]) { StringBuilder expectedResponse = new StringBuilder(); NameValuePair qsParams[] = convertNameValuesToNameValuePairs(queryStringParams, expectedResponse); GetMethod get = new GetMethod(getCollectionRootUri() + "/" + XQUERY_FILENAME); if(qsParams.length > 0) { get.setQueryString(qsParams); } testRequest(get, expectedResponse); } private void testPost(NameValues formParams[]) { StringBuilder expectedResponse = new StringBuilder(); NameValuePair fParams[] = convertNameValuesToNameValuePairs(formParams, expectedResponse); PostMethod post = new PostMethod(getCollectionRootUri() + "/" + XQUERY_FILENAME); if(fParams.length > 0) { post.setRequestBody(fParams); } testRequest(post, expectedResponse); } private void testPost(NameValues queryStringParams[], NameValues formParams[]) { StringBuilder expectedResponse = new StringBuilder(); NameValuePair qsParams[] = convertNameValuesToNameValuePairs(queryStringParams, expectedResponse); NameValuePair fParams[] = convertNameValuesToNameValuePairs(formParams, expectedResponse); PostMethod post = new PostMethod(getCollectionRootUri() + "/" + XQUERY_FILENAME); if(qsParams.length > 0) { post.setQueryString(qsParams); } if(fParams.length > 0) { post.setRequestBody(fParams); } testRequest(post, expectedResponse); } private void testMultipartPost(Param multipartParams[]) { List<Part> parts = new ArrayList<Part>(); StringBuilder expectedResponse = new StringBuilder(); for(Param multipartParam : multipartParams) { if(multipartParam instanceof NameValues) { for(NameValuePair nameValuePair : convertNameValueToNameValuePairs((NameValues)multipartParam, expectedResponse)) { parts.add(new StringPart(nameValuePair.getName(), nameValuePair.getValue())); } } else if(multipartParam instanceof TextFileUpload) { parts.add(convertFileUploadToFilePart((TextFileUpload)multipartParam, expectedResponse)); } } PostMethod post = new PostMethod(getCollectionRootUri() + "/" + XQUERY_FILENAME); post.setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[parts.size()]), post.getParams())); testRequest(post, expectedResponse); } private void testMultipartPost(NameValues queryStringParams[], Param multipartParams[]) { List<Part> parts = new ArrayList<Part>(); StringBuilder expectedResponse = new StringBuilder(); NameValuePair qsParams[] = convertNameValuesToNameValuePairs(queryStringParams, expectedResponse); for(Param multipartParam : multipartParams) { if(multipartParam instanceof NameValues) { for(NameValuePair nameValuePair : convertNameValueToNameValuePairs((NameValues)multipartParam, expectedResponse)) { parts.add(new StringPart(nameValuePair.getName(), nameValuePair.getValue())); } } else if(multipartParam instanceof TextFileUpload) { parts.add(convertFileUploadToFilePart((TextFileUpload)multipartParam, expectedResponse)); } } PostMethod post = new PostMethod(getCollectionRootUri() + "/" + XQUERY_FILENAME); if(qsParams.length > 0) { post.setQueryString(qsParams); } post.setRequestEntity(new MultipartRequestEntity(parts.toArray(new Part[parts.size()]), post.getParams())); testRequest(post, expectedResponse); } private void testRequest(HttpMethod method, StringBuilder expectedResponse) { try { int httpResult = client.executeMethod(method); byte buf[] = new byte[1024]; int read = -1; StringBuilder responseBody = new StringBuilder(); InputStream is = method.getResponseBodyAsStream(); while((read = is.read(buf)) > -1) { responseBody.append(new String(buf, 0, read)); } assertEquals(HttpStatus.SC_OK, httpResult); assertEquals(expectedResponse.toString(), responseBody.toString()); } catch(IOException ioe) { fail(ioe.getMessage()); } finally { method.releaseConnection(); } } private NameValuePair[] convertNameValuesToNameValuePairs(final NameValues nameValues[], final StringBuilder expectedResponse) { final List<NameValuePair> nameValuePairs = new ArrayList<>(); if(nameValues != null) { for(final NameValues param : nameValues) { nameValuePairs.addAll(convertNameValueToNameValuePairs(param, expectedResponse)); } } return nameValuePairs.toArray(new NameValuePair[nameValuePairs.size()]); } private List<NameValuePair> convertNameValueToNameValuePairs(final NameValues nameValues, final StringBuilder expectedResponse) { final List<NameValuePair> nameValuePairs = new ArrayList<>(); for(final String paramValue : nameValues.getData()) { nameValuePairs.add(new NameValuePair(nameValues.getName(), paramValue)); expectedResponse.append(nameValues.getName()); expectedResponse.append("="); expectedResponse.append(paramValue); } return nameValuePairs; } private FilePart convertFileUploadToFilePart(final TextFileUpload txtFileUpload, final StringBuilder expectedResponse) { final String filePartName = "fileUpload"; final FilePart filePart = new FilePart(filePartName, new PartSource() { private byte data[] = txtFileUpload.getData().getBytes(); @Override public long getLength() { return data.length; } @Override public String getFileName() { return txtFileUpload.getName(); } @Override public InputStream createInputStream() throws IOException { return new ByteArrayInputStream(data); } }); expectedResponse.append(filePartName); expectedResponse.append("="); expectedResponse.append(txtFileUpload.getData()); return filePart; } public class NameValues implements Param<String[]> { final String name; final String values[]; public NameValues(final String name, final String values[]) { this.name = name; this.values = values; } @Override public String getName() { return name; } @Override public String[] getData() { return values; } } public class TextFileUpload implements Param<String> { final String name; final String content; public TextFileUpload(final String name, final String content) { this.name = name; this.content = content; } @Override public String getData() { return content; } @Override public String getName() { return name; } } public interface Param<T> { String getName(); T getData(); } }