@Override
  protected void handleRequest(
      final RestRequest request, final RestChannel channel, final Client client) throws Exception {
    BytesRestResponse response = null;
    final XContentBuilder builder = channel.newBuilder();
    try {
      builder.startObject();
      final User user = ((User) request.getFromContext("_shield_user"));
      if (user != null) {
        builder.field("principal", user.principal());
        builder.field("roles", user.roles());
      } else {
        builder.nullField("principal");
      }

      builder.field("remote_address", request.getFromContext("_rest_remote_address"));
      builder.endObject();
      response = new BytesRestResponse(RestStatus.OK, builder);
    } catch (final Exception e1) {
      builder.startObject();
      builder.field("error", e1.toString());
      builder.endObject();
      response = new BytesRestResponse(RestStatus.INTERNAL_SERVER_ERROR, builder);
    }

    channel.sendResponse(response);
  }
 @Override
 public void handleRequest(
     final RestRequest request, final RestChannel channel, final NodeClient client)
     throws Exception {
   boolean helpWanted = request.paramAsBoolean("help", false);
   if (helpWanted) {
     Table table = getTableWithHeader(request);
     int[] width = buildHelpWidths(table, request);
     BytesStreamOutput bytesOutput = channel.bytesOutput();
     UTF8StreamWriter out = new UTF8StreamWriter().setOutput(bytesOutput);
     for (Table.Cell cell : table.getHeaders()) {
       // need to do left-align always, so create new cells
       pad(new Table.Cell(cell.value), width[0], request, out);
       out.append(" | ");
       pad(
           new Table.Cell(cell.attr.containsKey("alias") ? cell.attr.get("alias") : ""),
           width[1],
           request,
           out);
       out.append(" | ");
       pad(
           new Table.Cell(cell.attr.containsKey("desc") ? cell.attr.get("desc") : "not available"),
           width[2],
           request,
           out);
       out.append("\n");
     }
     out.close();
     channel.sendResponse(
         new BytesRestResponse(
             RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, bytesOutput.bytes()));
   } else {
     doRequest(request, channel, client);
   }
 }
 @Override
 public void handleRequest(RestRequest request, RestChannel channel, Client client) {
   if ("password".equals(request.header("Secret"))) {
     RestResponse response = new BytesRestResponse(RestStatus.OK, "Access granted");
     response.addHeader("Secret", "granted");
     channel.sendResponse(response);
   } else {
     RestResponse response = new BytesRestResponse(RestStatus.UNAUTHORIZED, "Access denied");
     response.addHeader("Secret", "required");
     channel.sendResponse(response);
   }
 }
  @Override
  public void sendResponse(final RestResponse response) {

    final User user = this.request.getFromContext("searchguard_authenticated_user");
    final Session _session =
        sessionStore.getSession(SecurityUtil.getSearchGuardSessionIdFromCookie(request));

    if (user != null) {
      if (_session == null) {
        final Session session = sessionStore.createSession(user);
        log.trace("Create session and set cookie for {}", user.getName());
        final CookieEncoder encoder = new CookieEncoder(true);
        final Cookie cookie = new DefaultCookie("es_searchguard_session", session.getId());

        // TODO FUTURE check cookie domain/path
        // cookie.setDomain(arg0);
        // cookie.setPath(arg0);

        cookie.setDiscard(true);
        cookie.setSecure(((NettyHttpRequest) request).request() instanceof DefaultHttpsRequest);
        cookie.setMaxAge(60 * 60); // 1h
        cookie.setHttpOnly(true);
        encoder.addCookie(cookie);
        response.addHeader("Set-Cookie", encoder.encode());
      } else {

        // Set-Cookie: token=deleted; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT
        log.trace("There is already a session");
        // TODO FUTURE check cookie seesion validity, expire, ...

      }
    }

    channel.sendResponse(response);
  }
  @Override
  public void handleRequest(RestRequest request, RestChannel channel) {
    if (logger.isDebugEnabled()) logger.debug("REST DropboxAction called");

    try {
      XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
      builder
          .startObject()
          .startArray("usage")
          .startObject()
          .field(new XContentBuilderString("method"), "GET")
          .field(new XContentBuilderString("endpoint"), "/_dropbox/")
          .field(new XContentBuilderString("comment"), "This help")
          .endObject()
          .startObject()
          .field(new XContentBuilderString("method"), "GET")
          .field(new XContentBuilderString("endpoint"), "/_dropbox/oauth/{appkey}/{appsecret}")
          .field(
              new XContentBuilderString("comment"),
              "Return the OAuth token, secret and url you should redirect your user to")
          .endObject()
          .startObject()
          .field(new XContentBuilderString("method"), "GET")
          .field(
              new XContentBuilderString("endpoint"),
              "/_dropbox/oauth/{appkey}/{appsecret}/{oauth_token}/{oauth_secret}")
          .field(new XContentBuilderString("comment"), "Return the OAuth token/secret for user")
          .endObject()
          .endArray()
          .endObject();
      channel.sendResponse(new XContentRestResponse(request, RestStatus.OK, builder));
    } catch (IOException e) {
      onFailure(channel, request, e);
    }
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    MultiSearchRequest multiSearchRequest = new MultiSearchRequest();
    multiSearchRequest.listenerThreaded(false);

    String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
    String[] types = Strings.splitStringByCommaToArray(request.param("type"));
    IndicesOptions indicesOptions =
        IndicesOptions.fromRequest(request, multiSearchRequest.indicesOptions());

    try {
      multiSearchRequest.add(
          request.content(),
          request.contentUnsafe(),
          indices,
          types,
          request.param("search_type"),
          request.param("routing"),
          indicesOptions,
          allowExplicitIndex);
    } catch (Exception e) {
      try {
        XContentBuilder builder = restContentBuilder(request);
        channel.sendResponse(
            new XContentRestResponse(
                request,
                BAD_REQUEST,
                builder.startObject().field("error", e.getMessage()).endObject()));
      } catch (IOException e1) {
        logger.error("Failed to send failure response", e1);
      }
      return;
    }

    client.multiSearch(
        multiSearchRequest,
        new ActionListener<MultiSearchResponse>() {
          @Override
          public void onResponse(MultiSearchResponse response) {
            try {
              XContentBuilder builder = restContentBuilder(request);
              builder.startObject();
              response.toXContent(builder, request);
              builder.endObject();
              channel.sendResponse(new XContentRestResponse(request, OK, builder));
            } catch (Throwable e) {
              onFailure(e);
            }
          }

          @Override
          public void onFailure(Throwable e) {
            try {
              channel.sendResponse(new XContentThrowableRestResponse(request, e));
            } catch (IOException e1) {
              logger.error("Failed to send failure response", e1);
            }
          }
        });
  }
 public SessionAwareNettyHttpChannel(
     final RestChannel channel,
     final SessionStore sessionStore,
     final boolean detailedErrorsEnabled) {
   super(channel.request(), detailedErrorsEnabled);
   this.channel = channel;
   this.sessionStore = sessionStore;
 }
 @Override
 public void onFailure(Throwable e) {
   try {
     restChannel.sendResponse(new XContentThrowableRestResponse(restRequest, e));
   } catch (IOException e1) {
     logger.error("Failed to send failure response", e1);
   }
 }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    String text = request.param("text");
    if (text == null && request.hasContent()) {
      text = request.content().toUtf8();
    }
    if (text == null) {
      try {
        channel.sendResponse(
            new XContentThrowableRestResponse(
                request, new ElasticsearchIllegalArgumentException("text is missing")));
      } catch (IOException e1) {
        logger.warn("Failed to send response", e1);
      }
      return;
    }

    AnalyzeRequest analyzeRequest = new AnalyzeRequest(request.param("index"), text);
    analyzeRequest.listenerThreaded(false);
    analyzeRequest.preferLocal(
        request.paramAsBoolean("prefer_local", analyzeRequest.preferLocalShard()));
    analyzeRequest.analyzer(request.param("analyzer"));
    analyzeRequest.field(request.param("field"));
    analyzeRequest.tokenizer(request.param("tokenizer"));
    analyzeRequest.tokenFilters(
        request.paramAsStringArray(
            "token_filters", request.paramAsStringArray("filters", analyzeRequest.tokenFilters())));
    analyzeRequest.charFilters(
        request.paramAsStringArray("char_filters", analyzeRequest.charFilters()));
    client
        .admin()
        .indices()
        .analyze(
            analyzeRequest,
            new ActionListener<AnalyzeResponse>() {
              @Override
              public void onResponse(AnalyzeResponse response) {
                try {
                  XContentBuilder builder = restContentBuilder(request, null);
                  builder.startObject();
                  response.toXContent(builder, request);
                  builder.endObject();
                  channel.sendResponse(new XContentRestResponse(request, OK, builder));
                } catch (Throwable e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                try {
                  channel.sendResponse(new XContentThrowableRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }
 public static RestResponse buildResponse(Table table, RestChannel channel) throws Exception {
   RestRequest request = channel.request();
   XContentType xContentType =
       XContentType.fromMediaTypeOrFormat(request.param("format", request.header("Accept")));
   if (xContentType != null) {
     return buildXContentBuilder(table, channel);
   }
   return buildTextPlainResponse(table, channel);
 }
  public static RestResponse buildXContentBuilder(Table table, RestChannel channel)
      throws Exception {
    RestRequest request = channel.request();
    XContentBuilder builder = channel.newBuilder();
    List<DisplayHeader> displayHeaders = buildDisplayHeaders(table, request);

    builder.startArray();
    for (int row = 0; row < table.getRows().size(); row++) {
      builder.startObject();
      for (DisplayHeader header : displayHeaders) {
        builder.field(
            header.display, renderValue(request, table.getAsMap().get(header.name).get(row).value));
      }
      builder.endObject();
    }
    builder.endArray();
    return new BytesRestResponse(RestStatus.OK, builder);
  }
  public static RestResponse buildTextPlainResponse(Table table, RestChannel channel)
      throws IOException {
    RestRequest request = channel.request();
    boolean verbose = request.paramAsBoolean("v", false);

    List<DisplayHeader> headers = buildDisplayHeaders(table, request);
    int[] width = buildWidths(table, request, verbose, headers);

    BytesStreamOutput bytesOut = channel.bytesOutput();
    UTF8StreamWriter out = new UTF8StreamWriter().setOutput(bytesOut);
    int lastHeader = headers.size() - 1;
    if (verbose) {
      for (int col = 0; col < headers.size(); col++) {
        DisplayHeader header = headers.get(col);
        boolean isLastColumn = col == lastHeader;
        pad(
            new Table.Cell(header.display, table.findHeaderByName(header.name)),
            width[col],
            request,
            out,
            isLastColumn);
        if (!isLastColumn) {
          out.append(" ");
        }
      }
      out.append("\n");
    }
    for (int row = 0; row < table.getRows().size(); row++) {
      for (int col = 0; col < headers.size(); col++) {
        DisplayHeader header = headers.get(col);
        boolean isLastColumn = col == lastHeader;
        pad(table.getAsMap().get(header.name).get(row), width[col], request, out, isLastColumn);
        if (!isLastColumn) {
          out.append(" ");
        }
      }
      out.append("\n");
    }
    out.close();
    return new BytesRestResponse(
        RestStatus.OK, BytesRestResponse.TEXT_CONTENT_TYPE, bytesOut.bytes());
  }
  @SuppressWarnings({"unchecked"})
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    PutIndexTemplateRequest putRequest = new PutIndexTemplateRequest(request.param("name"));

    try {
      putRequest.create(request.paramAsBoolean("create", false));
      putRequest.cause(request.param("cause", ""));
      putRequest.timeout(request.paramAsTime("timeout", timeValueSeconds(10)));
      putRequest.source(
          request.contentByteArray(), request.contentByteArrayOffset(), request.contentLength());
    } catch (Exception e) {
      try {
        channel.sendResponse(new XContentThrowableRestResponse(request, e));
      } catch (IOException e1) {
        logger.warn("Failed to send response", e1);
      }
      return;
    }

    putRequest.template(request.param("template", putRequest.template()));
    putRequest.order(request.paramAsInt("order", putRequest.order()));

    client
        .admin()
        .indices()
        .putTemplate(
            putRequest,
            new ActionListener<PutIndexTemplateResponse>() {
              @Override
              public void onResponse(PutIndexTemplateResponse response) {
                try {
                  XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
                  builder
                      .startObject()
                      .field(Fields.OK, true)
                      .field(Fields.ACKNOWLEDGED, response.acknowledged())
                      .endObject();
                  channel.sendResponse(new XContentRestResponse(request, OK, builder));
                } catch (IOException e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                try {
                  channel.sendResponse(new XContentThrowableRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    final ClusterUpdateSettingsRequest clusterUpdateSettingsRequest =
        Requests.clusterUpdateSettingsRequest();
    clusterUpdateSettingsRequest.listenerThreaded(false);
    try {
      Map<String, Object> source =
          XContentFactory.xContent(request.content()).createParser(request.content()).mapAndClose();
      if (source.containsKey("transient")) {
        clusterUpdateSettingsRequest.transientSettings((Map) source.get("transient"));
      }
      if (source.containsKey("persistent")) {
        clusterUpdateSettingsRequest.persistentSettings((Map) source.get("persistent"));
      }
    } catch (Exception e) {
      try {
        channel.sendResponse(new XContentThrowableRestResponse(request, e));
      } catch (IOException e1) {
        logger.warn("Failed to send response", e1);
      }
      return;
    }

    client
        .admin()
        .cluster()
        .updateSettings(
            clusterUpdateSettingsRequest,
            new ActionListener<ClusterUpdateSettingsResponse>() {
              @Override
              public void onResponse(ClusterUpdateSettingsResponse response) {
                try {
                  channel.sendResponse(new StringRestResponse(RestStatus.OK));
                } catch (Throwable e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                if (logger.isDebugEnabled()) {
                  logger.debug("failed to handle cluster state", e);
                }
                try {
                  channel.sendResponse(new XContentThrowableRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }
 @Override
 public void onResponse(Response response) {
   try {
     NodeResponse nodeInfo = response.getSuccessNodeResponse();
     if (nodeInfo == null) {
       restChannel.sendResponse(
           new XContentRestResponse(
               restRequest,
               RestStatus.NOT_FOUND,
               buildMessageDocument(
                   restRequest, "No JiraRiver found for name: " + actionRequest.getRiverName())));
     } else {
       handleJiraRiverResponse(nodeInfo);
     }
   } catch (Exception e) {
     onFailure(e);
   }
 }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    UpdateRequest updateRequest =
        new UpdateRequest(request.param("index"), request.param("type"), request.param("id"));
    updateRequest.listenerThreaded(false);
    updateRequest.routing(request.param("routing"));
    updateRequest.parent(
        request.param(
            "parent")); // order is important, set it after routing, so it will set the routing
    updateRequest.timeout(request.paramAsTime("timeout", updateRequest.timeout()));
    updateRequest.refresh(request.paramAsBoolean("refresh", updateRequest.refresh()));
    String replicationType = request.param("replication");
    if (replicationType != null) {
      updateRequest.replicationType(ReplicationType.fromString(replicationType));
    }
    String consistencyLevel = request.param("consistency");
    if (consistencyLevel != null) {
      updateRequest.consistencyLevel(WriteConsistencyLevel.fromString(consistencyLevel));
    }
    updateRequest.percolate(request.param("percolate", null));
    updateRequest.script(request.param("script"));
    updateRequest.scriptLang(request.param("lang"));
    for (Map.Entry<String, String> entry : request.params().entrySet()) {
      if (entry.getKey().startsWith("sp_")) {
        updateRequest.addScriptParam(entry.getKey().substring(3), entry.getValue());
      }
    }
    String sField = request.param("fields");
    if (sField != null) {
      String[] sFields = Strings.splitStringByCommaToArray(sField);
      if (sFields != null) {
        updateRequest.fields(sFields);
      }
    }
    updateRequest.retryOnConflict(
        request.paramAsInt("retry_on_conflict", updateRequest.retryOnConflict()));

    // see if we have it in the body
    if (request.hasContent()) {
      try {
        updateRequest.source(
            request.contentByteArray(), request.contentByteArrayOffset(), request.contentLength());
        IndexRequest upsertRequest = updateRequest.upsertRequest();
        if (upsertRequest != null) {
          upsertRequest.routing(request.param("routing"));
          upsertRequest.parent(
              request.param(
                  "parent")); // order is important, set it after routing, so it will set the
          // routing
          upsertRequest.timestamp(request.param("timestamp"));
          if (request.hasParam("ttl")) {
            upsertRequest.ttl(request.paramAsTime("ttl", null).millis());
          }
          upsertRequest.version(RestActions.parseVersion(request));
          upsertRequest.versionType(
              VersionType.fromString(request.param("version_type"), upsertRequest.versionType()));
        }
        IndexRequest doc = updateRequest.doc();
        if (doc != null) {
          doc.routing(request.param("routing"));
          doc.parent(
              request.param(
                  "parent")); // order is important, set it after routing, so it will set the
          // routing
          doc.timestamp(request.param("timestamp"));
          if (request.hasParam("ttl")) {
            doc.ttl(request.paramAsTime("ttl", null).millis());
          }
          doc.version(RestActions.parseVersion(request));
          doc.versionType(VersionType.fromString(request.param("version_type"), doc.versionType()));
        }
      } catch (Exception e) {
        try {
          channel.sendResponse(new XContentThrowableRestResponse(request, e));
        } catch (IOException e1) {
          logger.warn("Failed to send response", e1);
        }
        return;
      }
    }

    client.update(
        updateRequest,
        new ActionListener<UpdateResponse>() {
          @Override
          public void onResponse(UpdateResponse response) {
            try {
              XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
              builder
                  .startObject()
                  .field(Fields.OK, true)
                  .field(Fields._INDEX, response.index())
                  .field(Fields._TYPE, response.type())
                  .field(Fields._ID, response.id())
                  .field(Fields._VERSION, response.version());

              if (response.getResult() != null) {
                builder.startObject(Fields.GET);
                response.getResult().toXContentEmbedded(builder, request);
                builder.endObject();
              }

              if (response.matches() != null) {
                builder.startArray(Fields.MATCHES);
                for (String match : response.matches()) {
                  builder.value(match);
                }
                builder.endArray();
              }
              builder.endObject();
              RestStatus status = OK;
              if (response.version() == 1) {
                status = CREATED;
              }
              channel.sendResponse(new XContentRestResponse(request, status, builder));
            } catch (Exception e) {
              onFailure(e);
            }
          }

          @Override
          public void onFailure(Throwable e) {
            try {
              channel.sendResponse(new XContentThrowableRestResponse(request, e));
            } catch (IOException e1) {
              logger.error("Failed to send failure response", e1);
            }
          }
        });
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    IndicesAliasesRequest indicesAliasesRequest = new IndicesAliasesRequest();
    indicesAliasesRequest.listenerThreaded(false);
    indicesAliasesRequest.masterNodeTimeout(
        request.paramAsTime("master_timeout", indicesAliasesRequest.masterNodeTimeout()));
    XContentParser parser = null;
    try {
      // {
      //     actions : [
      //         { add : { index : "test1", alias : "alias1", filter : {"user" : "kimchy"} } }
      //         { remove : { index : "test1", alias : "alias1" } }
      //     ]
      // }
      indicesAliasesRequest.timeout(
          request.paramAsTime("timeout", indicesAliasesRequest.timeout()));
      parser = XContentFactory.xContent(request.content()).createParser(request.content());
      XContentParser.Token token = parser.nextToken();
      if (token == null) {
        throw new ElasticsearchIllegalArgumentException("No action is specified");
      }
      while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
        if (token == XContentParser.Token.START_ARRAY) {
          while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            if (token == XContentParser.Token.FIELD_NAME) {
              String action = parser.currentName();
              AliasAction.Type type;
              if ("add".equals(action)) {
                type = AliasAction.Type.ADD;
              } else if ("remove".equals(action)) {
                type = AliasAction.Type.REMOVE;
              } else {
                throw new ElasticsearchIllegalArgumentException(
                    "Alias action [" + action + "] not supported");
              }
              String index = null;
              String alias = null;
              Map<String, Object> filter = null;
              String routing = null;
              boolean routingSet = false;
              String indexRouting = null;
              boolean indexRoutingSet = false;
              String searchRouting = null;
              boolean searchRoutingSet = false;
              String currentFieldName = null;
              while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
                if (token == XContentParser.Token.FIELD_NAME) {
                  currentFieldName = parser.currentName();
                } else if (token == XContentParser.Token.VALUE_STRING) {
                  if ("index".equals(currentFieldName)) {
                    index = parser.text();
                  } else if ("alias".equals(currentFieldName)) {
                    alias = parser.text();
                  } else if ("routing".equals(currentFieldName)) {
                    routing = parser.textOrNull();
                    routingSet = true;
                  } else if ("indexRouting".equals(currentFieldName)
                      || "index-routing".equals(currentFieldName)
                      || "index_routing".equals(currentFieldName)) {
                    indexRouting = parser.textOrNull();
                    indexRoutingSet = true;
                  } else if ("searchRouting".equals(currentFieldName)
                      || "search-routing".equals(currentFieldName)
                      || "search_routing".equals(currentFieldName)) {
                    searchRouting = parser.textOrNull();
                    searchRoutingSet = true;
                  }
                } else if (token == XContentParser.Token.START_OBJECT) {
                  if ("filter".equals(currentFieldName)) {
                    filter = parser.mapOrdered();
                  }
                }
              }

              if (type == AliasAction.Type.ADD) {
                AliasAction aliasAction = newAddAliasAction(index, alias).filter(filter);
                if (routingSet) {
                  aliasAction.routing(routing);
                }
                if (indexRoutingSet) {
                  aliasAction.indexRouting(indexRouting);
                }
                if (searchRoutingSet) {
                  aliasAction.searchRouting(searchRouting);
                }
                indicesAliasesRequest.addAliasAction(aliasAction);
              } else if (type == AliasAction.Type.REMOVE) {
                indicesAliasesRequest.removeAlias(index, alias);
              }
            }
          }
        }
      }
    } catch (Exception e) {
      try {
        channel.sendResponse(new XContentThrowableRestResponse(request, e));
      } catch (IOException e1) {
        logger.warn("Failed to send response", e1);
      }
      return;
    } finally {
      parser.close();
    }
    client
        .admin()
        .indices()
        .aliases(
            indicesAliasesRequest,
            new AcknowledgedRestResponseActionListener<IndicesAliasesResponse>(
                request, channel, logger));
  }
  @Override
  public void handleRequest(final RestRequest request, final RestChannel channel) {
    OptimizeRequest optimizeRequest =
        new OptimizeRequest(RestActions.splitIndices(request.param("index")));
    optimizeRequest.listenerThreaded(false);
    if (request.hasParam("ignore_indices")) {
      optimizeRequest.ignoreIndices(IgnoreIndices.fromString(request.param("ignore_indices")));
    }
    try {
      optimizeRequest.waitForMerge(
          request.paramAsBoolean("wait_for_merge", optimizeRequest.waitForMerge()));
      optimizeRequest.maxNumSegments(
          request.paramAsInt("max_num_segments", optimizeRequest.maxNumSegments()));
      optimizeRequest.onlyExpungeDeletes(
          request.paramAsBoolean("only_expunge_deletes", optimizeRequest.onlyExpungeDeletes()));
      optimizeRequest.flush(request.paramAsBoolean("flush", optimizeRequest.flush()));
      optimizeRequest.refresh(request.paramAsBoolean("refresh", optimizeRequest.refresh()));

      BroadcastOperationThreading operationThreading =
          BroadcastOperationThreading.fromString(
              request.param("operation_threading"), BroadcastOperationThreading.SINGLE_THREAD);
      if (operationThreading == BroadcastOperationThreading.NO_THREADS) {
        // since we don't spawn, don't allow no_threads, but change it to a single thread
        operationThreading = BroadcastOperationThreading.THREAD_PER_SHARD;
      }
      optimizeRequest.operationThreading(operationThreading);
    } catch (Exception e) {
      try {
        XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
        channel.sendResponse(
            new XContentRestResponse(
                request,
                BAD_REQUEST,
                builder.startObject().field("error", e.getMessage()).endObject()));
      } catch (IOException e1) {
        logger.error("Failed to send failure response", e1);
      }
      return;
    }
    client
        .admin()
        .indices()
        .optimize(
            optimizeRequest,
            new ActionListener<OptimizeResponse>() {
              @Override
              public void onResponse(OptimizeResponse response) {
                try {
                  XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
                  builder.startObject();
                  builder.field("ok", true);

                  buildBroadcastShardsHeader(builder, response);

                  builder.endObject();
                  channel.sendResponse(new XContentRestResponse(request, OK, builder));
                } catch (Throwable e) {
                  onFailure(e);
                }
              }

              @Override
              public void onFailure(Throwable e) {
                try {
                  channel.sendResponse(new XContentThrowableRestResponse(request, e));
                } catch (IOException e1) {
                  logger.error("Failed to send failure response", e1);
                }
              }
            });
  }