summaryrefslogtreecommitdiffstats
path: root/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java')
-rw-r--r--gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java298
1 files changed, 0 insertions, 298 deletions
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java
deleted file mode 100644
index bfaf0c789e..0000000000
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/restapi/ParameterParser.java
+++ /dev/null
@@ -1,298 +0,0 @@
-// Copyright (C) 2012 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package com.google.gerrit.httpd.restapi;
-
-import static com.google.gerrit.httpd.restapi.RestApiServlet.ALLOWED_CORS_METHODS;
-import static com.google.gerrit.httpd.restapi.RestApiServlet.XD_AUTHORIZATION;
-import static com.google.gerrit.httpd.restapi.RestApiServlet.XD_CONTENT_TYPE;
-import static com.google.gerrit.httpd.restapi.RestApiServlet.XD_METHOD;
-import static com.google.gerrit.httpd.restapi.RestApiServlet.replyBinaryResult;
-import static com.google.gerrit.httpd.restapi.RestApiServlet.replyError;
-import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
-
-import com.google.auto.value.AutoValue;
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.base.Splitter;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableListMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.ListMultimap;
-import com.google.common.collect.MultimapBuilder;
-import com.google.gerrit.common.Nullable;
-import com.google.gerrit.extensions.registration.DynamicMap;
-import com.google.gerrit.extensions.restapi.BadRequestException;
-import com.google.gerrit.extensions.restapi.BinaryResult;
-import com.google.gerrit.extensions.restapi.Url;
-import com.google.gerrit.server.DynamicOptions;
-import com.google.gerrit.util.cli.CmdLineParser;
-import com.google.gson.JsonArray;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonPrimitive;
-import com.google.gwtexpui.server.CacheHeaders;
-import com.google.inject.Inject;
-import com.google.inject.Injector;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Set;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.kohsuke.args4j.CmdLineException;
-
-public class ParameterParser {
- private static final ImmutableSet<String> RESERVED_KEYS =
- ImmutableSet.of("pp", "prettyPrint", "strict", "callback", "alt", "fields");
-
- @AutoValue
- public abstract static class QueryParams {
- static final String I = QueryParams.class.getName();
-
- static QueryParams create(
- @Nullable String accessToken,
- @Nullable String xdMethod,
- @Nullable String xdContentType,
- ImmutableListMultimap<String, String> config,
- ImmutableListMultimap<String, String> params) {
- return new AutoValue_ParameterParser_QueryParams(
- accessToken, xdMethod, xdContentType, config, params);
- }
-
- @Nullable
- public abstract String accessToken();
-
- @Nullable
- abstract String xdMethod();
-
- @Nullable
- abstract String xdContentType();
-
- abstract ImmutableListMultimap<String, String> config();
-
- abstract ImmutableListMultimap<String, String> params();
-
- boolean hasXdOverride() {
- return xdMethod() != null || xdContentType() != null;
- }
- }
-
- public static QueryParams getQueryParams(HttpServletRequest req) throws BadRequestException {
- QueryParams qp = (QueryParams) req.getAttribute(QueryParams.I);
- if (qp != null) {
- return qp;
- }
-
- String accessToken = null;
- String xdMethod = null;
- String xdContentType = null;
- ListMultimap<String, String> config = MultimapBuilder.hashKeys(4).arrayListValues().build();
- ListMultimap<String, String> params = MultimapBuilder.hashKeys().arrayListValues().build();
-
- String queryString = req.getQueryString();
- if (!Strings.isNullOrEmpty(queryString)) {
- for (String kvPair : Splitter.on('&').split(queryString)) {
- Iterator<String> i = Splitter.on('=').limit(2).split(kvPair).iterator();
- String key = Url.decode(i.next());
- String val = i.hasNext() ? Url.decode(i.next()) : "";
-
- if (XD_AUTHORIZATION.equals(key)) {
- if (accessToken != null) {
- throw new BadRequestException("duplicate " + XD_AUTHORIZATION);
- }
- accessToken = val;
- } else if (XD_METHOD.equals(key)) {
- if (xdMethod != null) {
- throw new BadRequestException("duplicate " + XD_METHOD);
- } else if (!ALLOWED_CORS_METHODS.contains(val)) {
- throw new BadRequestException("invalid " + XD_METHOD);
- }
- xdMethod = val;
- } else if (XD_CONTENT_TYPE.equals(key)) {
- if (xdContentType != null) {
- throw new BadRequestException("duplicate " + XD_CONTENT_TYPE);
- }
- xdContentType = val;
- } else if (RESERVED_KEYS.contains(key)) {
- config.put(key, val);
- } else {
- params.put(key, val);
- }
- }
- }
-
- qp =
- QueryParams.create(
- accessToken,
- xdMethod,
- xdContentType,
- ImmutableListMultimap.copyOf(config),
- ImmutableListMultimap.copyOf(params));
- req.setAttribute(QueryParams.I, qp);
- return qp;
- }
-
- private final CmdLineParser.Factory parserFactory;
- private final Injector injector;
- private final DynamicMap<DynamicOptions.DynamicBean> dynamicBeans;
-
- @Inject
- ParameterParser(
- CmdLineParser.Factory pf,
- Injector injector,
- DynamicMap<DynamicOptions.DynamicBean> dynamicBeans) {
- this.parserFactory = pf;
- this.injector = injector;
- this.dynamicBeans = dynamicBeans;
- }
-
- <T> boolean parse(
- T param, ListMultimap<String, String> in, HttpServletRequest req, HttpServletResponse res)
- throws IOException {
- CmdLineParser clp = parserFactory.create(param);
- DynamicOptions pluginOptions = new DynamicOptions(param, injector, dynamicBeans);
- pluginOptions.parseDynamicBeans(clp);
- pluginOptions.setDynamicBeans();
- pluginOptions.onBeanParseStart();
- try {
- clp.parseOptionMap(in);
- } catch (CmdLineException | NumberFormatException e) {
- if (!clp.wasHelpRequestedByOption()) {
- replyError(req, res, SC_BAD_REQUEST, e.getMessage(), e);
- return false;
- }
- }
-
- if (clp.wasHelpRequestedByOption()) {
- StringWriter msg = new StringWriter();
- clp.printQueryStringUsage(req.getRequestURI(), msg);
- msg.write('\n');
- msg.write('\n');
- clp.printUsage(msg, null);
- msg.write('\n');
- CacheHeaders.setNotCacheable(res);
- replyBinaryResult(req, res, BinaryResult.create(msg.toString()).setContentType("text/plain"));
- return false;
- }
- pluginOptions.onBeanParseEnd();
-
- return true;
- }
-
- private static Set<String> query(HttpServletRequest req) {
- Set<String> params = new HashSet<>();
- if (!Strings.isNullOrEmpty(req.getQueryString())) {
- for (String kvPair : Splitter.on('&').split(req.getQueryString())) {
- params.add(Iterables.getFirst(Splitter.on('=').limit(2).split(kvPair), null));
- }
- }
- return params;
- }
-
- /**
- * Convert a standard URL encoded form input into a parsed JSON tree.
- *
- * <p>Given an input such as:
- *
- * <pre>
- * message=Does+not+compile.&labels.Verified=-1
- * </pre>
- *
- * which is easily created using the curl command line tool:
- *
- * <pre>
- * curl --data 'message=Does not compile.' --data labels.Verified=-1
- * </pre>
- *
- * converts to a JSON object structure that is normally expected:
- *
- * <pre>
- * {
- * "message": "Does not compile.",
- * "labels": {
- * "Verified": "-1"
- * }
- * }
- * </pre>
- *
- * This input can then be further processed into the Java input type expected by a view using
- * Gson. Here we rely on Gson to perform implicit conversion of a string {@code "-1"} to a number
- * type when the Java input type expects a number.
- *
- * <p>Conversion assumes any field name that does not contain {@code "."} will be a property of
- * the top level input object. Any field with a dot will use the first segment as the top level
- * property name naming an object, and the rest of the field name as a property in the nested
- * object.
- *
- * @param req request to parse form input from and create JSON tree.
- * @return the converted JSON object tree.
- * @throws BadRequestException the request cannot be cast, as there are conflicting definitions
- * for a nested object.
- */
- static JsonObject formToJson(HttpServletRequest req) throws BadRequestException {
- Map<String, String[]> map = req.getParameterMap();
- return formToJson(map, query(req));
- }
-
- @VisibleForTesting
- static JsonObject formToJson(Map<String, String[]> map, Set<String> query)
- throws BadRequestException {
- JsonObject inputObject = new JsonObject();
- for (Map.Entry<String, String[]> ent : map.entrySet()) {
- String key = ent.getKey();
- String[] values = ent.getValue();
-
- if (query.contains(key) || values.length == 0) {
- // Disallow processing query parameters as input body fields.
- // Implementations of views should avoid duplicate naming.
- continue;
- }
-
- JsonObject obj = inputObject;
- int dot = key.indexOf('.');
- if (0 <= dot) {
- String property = key.substring(0, dot);
- JsonElement e = inputObject.get(property);
- if (e == null) {
- obj = new JsonObject();
- inputObject.add(property, obj);
- } else if (e.isJsonObject()) {
- obj = e.getAsJsonObject();
- } else {
- throw new BadRequestException(String.format("key %s conflicts with %s", key, property));
- }
- key = key.substring(dot + 1);
- }
-
- if (obj.get(key) != null) {
- // This error should never happen. If all form values are handled
- // together in a single pass properties are set only once. Setting
- // again indicates something has gone very wrong.
- throw new BadRequestException("invalid form input, use JSON instead");
- } else if (values.length == 1) {
- obj.addProperty(key, values[0]);
- } else {
- JsonArray list = new JsonArray();
- for (String v : values) {
- list.add(new JsonPrimitive(v));
- }
- obj.add(key, list);
- }
- }
- return inputObject;
- }
-}