package org.basex.http;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.Map.Entry;
import org.basex.core.*;
import org.basex.io.*;
import org.basex.io.in.*;
import org.basex.query.*;
import org.basex.query.value.*;
import org.basex.query.value.item.*;
import org.basex.util.*;
import org.basex.util.http.*;
/**
* Bundles parameters of an HTTP request.
*
* @author BaseX Team 2005-17, BSD License
* @author Christian Gruen
*/
public final class HTTPParams {
/** HTTP Connection. */
private final HTTPConnection conn;
/** Parameter map. */
private Map<String, String[]> map;
/** Query parameters. */
private Map<String, Value> query;
/** Form parameters. */
private Map<String, Value> form;
/** Content body. */
private IOContent content;
/**
* Returns an immutable map with all query parameters.
* @param conn HTTP connection
*/
HTTPParams(final HTTPConnection conn) {
this.conn = conn;
}
/**
* Returns the query parameters as map.
* @return map
* @throws IOException I/O exception
*/
public Map<String, String[]> map() throws IOException {
try {
if(map == null) map = conn.req.getParameterMap();
return map;
} catch(final IllegalStateException ex) {
// may be caused by too large input (#884)
throw new IOException(ex);
}
}
/**
* Binds form parameters.
* @param options main options
* @return parameters
* @throws IOException I/O exception
* @throws QueryException query exception
*/
public Map<String, Value> form(final MainOptions options) throws QueryException, IOException {
if(form == null) {
form = new HashMap<>();
final MediaType mt = conn.contentType();
if(mt.is(MediaType.MULTIPART_FORM_DATA)) {
// convert multipart parameters encoded in a form
addMultipart(mt, options);
} else if(mt.is(MediaType.APPLICATION_X_WWW_FORM_URLENCODED)) {
// convert URL-encoded parameters
addURLEncoded();
}
}
return form;
}
/**
* Returns query parameters.
* @return query parameters
* @throws IOException I/O exception
*/
public Map<String, Value> query() throws IOException {
if(query == null) {
query = new HashMap<>();
for(final Entry<String, String[]> entry : map().entrySet()) {
final String key = entry.getKey();
final String[] values = entry.getValue();
final ValueBuilder vb = new ValueBuilder();
for(final String v : values) vb.add(new Atm(v));
query.put(key, vb.value());
}
}
return query;
}
/**
* Returns the cached body.
* @return value
* @throws IOException I/O exception
*/
public IOContent body() throws IOException {
if(content == null) {
content = new IOContent(new BufferInput(conn.req.getInputStream()).content());
}
return content;
}
// PRIVATE FUNCTIONS ============================================================================
/**
* Adds multipart form-data from the passed on request body.
* @param type media type
* @param options main options
* @throws QueryException query exception
* @throws IOException I/O exception
*/
private void addMultipart(final MediaType type, final MainOptions options)
throws QueryException, IOException {
try(InputStream is = body().inputStream()) {
final HttpPayload hp = new HttpPayload(is, true, null, options);
for(final Entry<String, Value> entry : hp.multiForm(type).entrySet()) {
form.put(entry.getKey(), entry.getValue());
}
}
}
/**
* Adds URL-encoded parameters from the passed on request body.
* @throws IOException I/O exception
*/
private void addURLEncoded() throws IOException {
for(final String nv : Strings.split(body().toString(), '&')) {
final String[] parts = Strings.split(nv, '=', 2);
if(parts.length == 2) {
final Atm i = new Atm(URLDecoder.decode(parts[1], Strings.UTF8));
final String k = parts[0];
final Value v = form.get(k);
form.put(k, v == null ? i : new ValueBuilder().add(v).add(i).value());
}
}
}
}