/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.solr.servlet;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.util.EntityUtils;
import org.apache.http.Header;
import org.apache.http.HeaderIterator;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpResponse;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.cloud.Aliases;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.cloud.SolrZkClient;
import org.apache.solr.common.cloud.ZkCoreNodeProps;
import org.apache.solr.common.cloud.ZkNodeProps;
import org.apache.solr.common.cloud.ZkStateReader;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.ContentStreamBase;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.ConfigSolr;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrConfig;
import org.apache.solr.core.SolrCore;
import org.apache.solr.core.SolrResourceLoader;
import org.apache.solr.client.solrj.impl.HttpClientUtil;
import org.apache.solr.handler.ContentStreamHandlerBase;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryRequestBase;
import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.request.SolrRequestInfo;
import org.apache.solr.response.BinaryQueryResponseWriter;
import org.apache.solr.response.QueryResponseWriter;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.servlet.cache.HttpCacheHeaderUtil;
import org.apache.solr.servlet.cache.Method;
import org.apache.solr.update.processor.DistributingUpdateProcessorFactory;
import org.apache.solr.util.FastWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
/**
* This filter looks at the incoming URL maps them to handlers defined in solrconfig.xml
*
* @since solr 1.2
*/
public class SolrDispatchFilter implements Filter
{
private static final String CONNECTION_HEADER = "Connection";
private static final String TRANSFER_ENCODING_HEADER = "Transfer-Encoding";
private static final String CONTENT_LENGTH_HEADER = "Content-Length";
final Logger log;
protected volatile CoreContainer cores;
protected String pathPrefix = null; // strip this from the beginning of a path
protected String abortErrorMessage = null;
protected final HttpClient httpClient = HttpClientUtil.createClient(new ModifiableSolrParams());
private static final Charset UTF8 = Charset.forName("UTF-8");
public SolrDispatchFilter() {
try {
log = LoggerFactory.getLogger(SolrDispatchFilter.class);
} catch (NoClassDefFoundError e) {
throw new SolrException(
ErrorCode.SERVER_ERROR,
"Could not find necessary SLF4j logging jars. If using Jetty, the SLF4j logging jars need to go in "
+"the jetty lib/ext directory. For other containers, the corresponding directory should be used. "
+"For more information, see: http://wiki.apache.org/solr/SolrLogging",
e);
}
}
@Override
public void init(FilterConfig config) throws ServletException
{
log.info("SolrDispatchFilter.init()");
try {
// web.xml configuration
this.pathPrefix = config.getInitParameter( "path-prefix" );
this.cores = createCoreContainer();
log.info("user.dir=" + System.getProperty("user.dir"));
}
catch( Throwable t ) {
// catch this so our filter still works
log.error( "Could not start Solr. Check solr/home property and the logs");
SolrCore.log( t );
if (t instanceof Error) {
throw (Error) t;
}
}
log.info("SolrDispatchFilter.init() done");
}
private ConfigSolr loadConfigSolr(SolrResourceLoader loader) {
String solrxmlLocation = System.getProperty("solr.solrxml.location", "solrhome");
if (solrxmlLocation == null || "solrhome".equalsIgnoreCase(solrxmlLocation))
return ConfigSolr.fromSolrHome(loader, loader.getInstanceDir());
if ("zookeeper".equalsIgnoreCase(solrxmlLocation)) {
String zkHost = System.getProperty("zkHost");
log.info("Trying to read solr.xml from " + zkHost);
if (StringUtils.isEmpty(zkHost))
throw new SolrException(ErrorCode.SERVER_ERROR,
"Could not load solr.xml from zookeeper: zkHost system property not set");
SolrZkClient zkClient = new SolrZkClient(zkHost, 30000);
try {
if (!zkClient.exists("/solr.xml", true))
throw new SolrException(ErrorCode.SERVER_ERROR, "Could not load solr.xml from zookeeper: node not found");
byte[] data = zkClient.getData("/solr.xml", null, null, true);
return ConfigSolr.fromInputStream(loader, new ByteArrayInputStream(data));
} catch (Exception e) {
throw new SolrException(ErrorCode.SERVER_ERROR, "Could not load solr.xml from zookeeper", e);
} finally {
zkClient.close();
}
}
throw new SolrException(ErrorCode.SERVER_ERROR,
"Bad solr.solrxml.location set: " + solrxmlLocation + " - should be 'solrhome' or 'zookeeper'");
}
/**
* Override this to change CoreContainer initialization
* @return a CoreContainer to hold this server's cores
*/
protected CoreContainer createCoreContainer() {
SolrResourceLoader loader = new SolrResourceLoader(SolrResourceLoader.locateSolrHome());
ConfigSolr config = loadConfigSolr(loader);
CoreContainer cores = new CoreContainer(loader, config);
cores.load();
return cores;
}
public CoreContainer getCores() {
return cores;
}
@Override
public void destroy() {
if (cores != null) {
cores.shutdown();
cores = null;
}
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
doFilter(request, response, chain, false);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain, boolean retry) throws IOException, ServletException {
if( abortErrorMessage != null ) {
((HttpServletResponse)response).sendError( 500, abortErrorMessage );
return;
}
if (this.cores == null) {
((HttpServletResponse)response).sendError( 503, "Server is shutting down or failed to initialize" );
return;
}
CoreContainer cores = this.cores;
SolrCore core = null;
SolrQueryRequest solrReq = null;
Aliases aliases = null;
if( request instanceof HttpServletRequest) {
HttpServletRequest req = (HttpServletRequest)request;
HttpServletResponse resp = (HttpServletResponse)response;
SolrRequestHandler handler = null;
String corename = "";
String origCorename = null;
try {
// put the core container in request attribute
req.setAttribute("org.apache.solr.CoreContainer", cores);
String path = req.getServletPath();
if( req.getPathInfo() != null ) {
// this lets you handle /update/commit when /update is a servlet
path += req.getPathInfo();
}
if( pathPrefix != null && path.startsWith( pathPrefix ) ) {
path = path.substring( pathPrefix.length() );
}
// check for management path
String alternate = cores.getManagementPath();
if (alternate != null && path.startsWith(alternate)) {
path = path.substring(0, alternate.length());
}
// unused feature ?
int idx = path.indexOf( ':' );
if( idx > 0 ) {
// save the portion after the ':' for a 'handler' path parameter
path = path.substring( 0, idx );
}
// Check for the core admin page
if( path.equals( cores.getAdminPath() ) ) {
handler = cores.getMultiCoreHandler();
solrReq = SolrRequestParsers.DEFAULT.parse(null,path, req);
handleAdminRequest(req, response, handler, solrReq);
return;
}
boolean usingAliases = false;
List<String> collectionsList = null;
// Check for the core admin collections url
if( path.equals( "/admin/collections" ) ) {
handler = cores.getCollectionsHandler();
solrReq = SolrRequestParsers.DEFAULT.parse(null,path, req);
handleAdminRequest(req, response, handler, solrReq);
return;
}
// Check for the core admin info url
if( path.startsWith( "/admin/info" ) ) {
handler = cores.getInfoHandler();
solrReq = SolrRequestParsers.DEFAULT.parse(null,path, req);
handleAdminRequest(req, response, handler, solrReq);
return;
}
else {
//otherwise, we should find a core from the path
idx = path.indexOf( "/", 1 );
if( idx > 1 ) {
// try to get the corename as a request parameter first
corename = path.substring( 1, idx );
// look at aliases
if (cores.isZooKeeperAware()) {
origCorename = corename;
ZkStateReader reader = cores.getZkController().getZkStateReader();
aliases = reader.getAliases();
if (aliases != null && aliases.collectionAliasSize() > 0) {
usingAliases = true;
String alias = aliases.getCollectionAlias(corename);
if (alias != null) {
collectionsList = StrUtils.splitSmart(alias, ",", true);
corename = collectionsList.get(0);
}
}
}
core = cores.getCore(corename);
if (core != null) {
path = path.substring( idx );
}
}
if (core == null) {
if (!cores.isZooKeeperAware() ) {
core = cores.getCore("");
}
}
}
if (core == null && cores.isZooKeeperAware()) {
// we couldn't find the core - lets make sure a collection was not specified instead
core = getCoreByCollection(cores, corename, path);
if (core != null) {
// we found a core, update the path
path = path.substring( idx );
}
// if we couldn't find it locally, look on other nodes
if (core == null && idx > 0) {
String coreUrl = getRemotCoreUrl(cores, corename, origCorename);
// don't proxy for internal update requests
SolrParams queryParams = SolrRequestParsers.parseQueryString(req.getQueryString());
if (coreUrl != null
&& queryParams
.get(DistributingUpdateProcessorFactory.DISTRIB_UPDATE_PARAM) == null) {
path = path.substring(idx);
remoteQuery(coreUrl + path, req, solrReq, resp);
return;
} else {
if (!retry) {
// we couldn't find a core to work with, try reloading aliases
// TODO: it would be nice if admin ui elements skipped this...
ZkStateReader reader = cores.getZkController()
.getZkStateReader();
reader.updateAliases();
doFilter(request, response, chain, true);
return;
}
}
}
// try the default core
if (core == null) {
core = cores.getCore("");
}
}
// With a valid core...
if( core != null ) {
final SolrConfig config = core.getSolrConfig();
// get or create/cache the parser for the core
SolrRequestParsers parser = config.getRequestParsers();
// Handle /schema/* and /config/* paths via Restlet
if( path.equals("/schema") || path.startsWith("/schema/")
|| path.equals("/config") || path.startsWith("/config/")) {
solrReq = parser.parse(core, path, req);
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, new SolrQueryResponse()));
if( path.equals(req.getServletPath()) ) {
// avoid endless loop - pass through to Restlet via webapp
chain.doFilter(request, response);
} else {
// forward rewritten URI (without path prefix and core/collection name) to Restlet
req.getRequestDispatcher(path).forward(request, response);
}
return;
}
// Determine the handler from the url path if not set
// (we might already have selected the cores handler)
if( handler == null && path.length() > 1 ) { // don't match "" or "/" as valid path
handler = core.getRequestHandler( path );
// no handler yet but allowed to handle select; let's check
if( handler == null && parser.isHandleSelect() ) {
if( "/select".equals( path ) || "/select/".equals( path ) ) {
solrReq = parser.parse( core, path, req );
String qt = solrReq.getParams().get( CommonParams.QT );
handler = core.getRequestHandler( qt );
if( handler == null ) {
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "unknown handler: "+qt);
}
if( qt != null && qt.startsWith("/") && (handler instanceof ContentStreamHandlerBase)) {
//For security reasons it's a bad idea to allow a leading '/', ex: /select?qt=/update see SOLR-3161
//There was no restriction from Solr 1.4 thru 3.5 and it's not supported for update handlers.
throw new SolrException( SolrException.ErrorCode.BAD_REQUEST, "Invalid Request Handler ('qt'). Do not use /select to access: "+qt);
}
}
}
}
// With a valid handler and a valid core...
if( handler != null ) {
// if not a /select, create the request
if( solrReq == null ) {
solrReq = parser.parse( core, path, req );
}
if (usingAliases) {
processAliases(solrReq, aliases, collectionsList);
}
final Method reqMethod = Method.getMethod(req.getMethod());
HttpCacheHeaderUtil.setCacheControlHeader(config, resp, reqMethod);
// unless we have been explicitly told not to, do cache validation
// if we fail cache validation, execute the query
if (config.getHttpCachingConfig().isNever304() ||
!HttpCacheHeaderUtil.doCacheHeaderValidation(solrReq, req, reqMethod, resp)) {
SolrQueryResponse solrRsp = new SolrQueryResponse();
/* even for HEAD requests, we need to execute the handler to
* ensure we don't get an error (and to make sure the correct
* QueryResponseWriter is selected and we get the correct
* Content-Type)
*/
SolrRequestInfo.setRequestInfo(new SolrRequestInfo(solrReq, solrRsp));
this.execute( req, handler, solrReq, solrRsp );
HttpCacheHeaderUtil.checkHttpCachingVeto(solrRsp, resp, reqMethod);
// add info to http headers
//TODO: See SOLR-232 and SOLR-267.
/*try {
NamedList solrRspHeader = solrRsp.getResponseHeader();
for (int i=0; i<solrRspHeader.size(); i++) {
((javax.servlet.http.HttpServletResponse) response).addHeader(("Solr-" + solrRspHeader.getName(i)), String.valueOf(solrRspHeader.getVal(i)));
}
} catch (ClassCastException cce) {
log.log(Level.WARNING, "exception adding response header log information", cce);
}*/
QueryResponseWriter responseWriter = core.getQueryResponseWriter(solrReq);
writeResponse(solrRsp, response, responseWriter, solrReq, reqMethod);
}
return; // we are done with a valid handler
}
}
log.debug("no handler or core retrieved for " + path + ", follow through...");
}
catch (Throwable ex) {
sendError( core, solrReq, request, (HttpServletResponse)response, ex );
if (ex instanceof Error) {
throw (Error) ex;
}
return;
} finally {
try {
if (solrReq != null) {
log.debug("Closing out SolrRequest: {}", solrReq);
solrReq.close();
}
} finally {
try {
if (core != null) {
core.close();
}
} finally {
SolrRequestInfo.clearRequestInfo();
}
}
}
}
// Otherwise let the webapp handle the request
chain.doFilter(request, response);
}
private void processAliases(SolrQueryRequest solrReq, Aliases aliases,
List<String> collectionsList) {
String collection = solrReq.getParams().get("collection");
if (collection != null) {
collectionsList = StrUtils.splitSmart(collection, ",", true);
}
if (collectionsList != null) {
Set<String> newCollectionsList = new HashSet<>(
collectionsList.size());
for (String col : collectionsList) {
String al = aliases.getCollectionAlias(col);
if (al != null) {
List<String> aliasList = StrUtils.splitSmart(al, ",", true);
newCollectionsList.addAll(aliasList);
} else {
newCollectionsList.add(col);
}
}
if (newCollectionsList.size() > 0) {
StringBuilder collectionString = new StringBuilder();
Iterator<String> it = newCollectionsList.iterator();
int sz = newCollectionsList.size();
for (int i = 0; i < sz; i++) {
collectionString.append(it.next());
if (i < newCollectionsList.size() - 1) {
collectionString.append(",");
}
}
ModifiableSolrParams params = new ModifiableSolrParams(
solrReq.getParams());
params.set("collection", collectionString.toString());
solrReq.setParams(params);
}
}
}
private void remoteQuery(String coreUrl, HttpServletRequest req,
SolrQueryRequest solrReq, HttpServletResponse resp) throws IOException {
HttpRequestBase method = null;
HttpEntity httpEntity = null;
boolean success = false;
try {
String urlstr = coreUrl;
String queryString = req.getQueryString();
urlstr += queryString == null ? "" : "?" + queryString;
URL url = new URL(urlstr);
boolean isPostOrPutRequest = "POST".equals(req.getMethod()) || "PUT".equals(req.getMethod());
if ("GET".equals(req.getMethod())) {
method = new HttpGet(urlstr);
}
else if ("HEAD".equals(req.getMethod())) {
method = new HttpHead(urlstr);
}
else if (isPostOrPutRequest) {
HttpEntityEnclosingRequestBase entityRequest =
"POST".equals(req.getMethod()) ? new HttpPost(urlstr) : new HttpPut(urlstr);
HttpEntity entity = new InputStreamEntity(req.getInputStream(), req.getContentLength());
entityRequest.setEntity(entity);
method = entityRequest;
}
else if ("DELETE".equals(req.getMethod())) {
method = new HttpDelete(urlstr);
}
else {
throw new SolrException(SolrException.ErrorCode.SERVER_ERROR,
"Unexpected method type: " + req.getMethod());
}
for (Enumeration<String> e = req.getHeaderNames(); e.hasMoreElements();) {
String headerName = e.nextElement();
method.addHeader(headerName, req.getHeader(headerName));
}
// These headers not supported for HttpEntityEnclosingRequests
if (method instanceof HttpEntityEnclosingRequest) {
method.removeHeaders(TRANSFER_ENCODING_HEADER);
method.removeHeaders(CONTENT_LENGTH_HEADER);
}
final HttpResponse response = httpClient.execute(method);
int httpStatus = response.getStatusLine().getStatusCode();
httpEntity = response.getEntity();
resp.setStatus(httpStatus);
for (HeaderIterator responseHeaders = response.headerIterator(); responseHeaders.hasNext();) {
Header header = responseHeaders.nextHeader();
// We pull out these two headers below because they can cause chunked
// encoding issues with Tomcat
if (header != null && !header.getName().equals(TRANSFER_ENCODING_HEADER)
&& !header.getName().equals(CONNECTION_HEADER)) {
resp.addHeader(header.getName(), header.getValue());
}
}
if (httpEntity != null) {
if (httpEntity.getContentEncoding() != null) resp.setCharacterEncoding(httpEntity.getContentEncoding().getValue());
if (httpEntity.getContentType() != null) resp.setContentType(httpEntity.getContentType().getValue());
InputStream is = httpEntity.getContent();
OutputStream os = resp.getOutputStream();
try {
IOUtils.copyLarge(is, os);
os.flush();
} finally {
IOUtils.closeQuietly(os); // TODO: I thought we weren't supposed to explicitly close servlet streams
IOUtils.closeQuietly(is);
}
}
success = true;
} catch (IOException e) {
sendError(null, solrReq, req, resp, new SolrException(
SolrException.ErrorCode.SERVER_ERROR,
"Error trying to proxy request for url: " + coreUrl, e));
} finally {
EntityUtils.consumeQuietly(httpEntity);
if (method != null && !success) {
method.abort();
}
}
}
private String getRemotCoreUrl(CoreContainer cores, String collectionName, String origCorename) {
ClusterState clusterState = cores.getZkController().getClusterState();
Collection<Slice> slices = clusterState.getActiveSlices(collectionName);
boolean byCoreName = false;
if (slices == null) {
slices = new ArrayList<>();
// look by core name
byCoreName = true;
slices = getSlicesForCollections(clusterState, slices, true);
if (slices == null || slices.size() == 0) {
slices = getSlicesForCollections(clusterState, slices, false);
}
}
if (slices == null || slices.size() == 0) {
return null;
}
String coreUrl = getCoreUrl(cores, collectionName, origCorename, clusterState,
slices, byCoreName, true);
if (coreUrl == null) {
coreUrl = getCoreUrl(cores, collectionName, origCorename, clusterState,
slices, byCoreName, false);
}
return coreUrl;
}
private String getCoreUrl(CoreContainer cores, String collectionName,
String origCorename, ClusterState clusterState, Collection<Slice> slices,
boolean byCoreName, boolean activeReplicas) {
String coreUrl;
Set<String> liveNodes = clusterState.getLiveNodes();
Iterator<Slice> it = slices.iterator();
while (it.hasNext()) {
Slice slice = it.next();
Map<String,Replica> sliceShards = slice.getReplicasMap();
for (ZkNodeProps nodeProps : sliceShards.values()) {
ZkCoreNodeProps coreNodeProps = new ZkCoreNodeProps(nodeProps);
if (!activeReplicas || (liveNodes.contains(coreNodeProps.getNodeName())
&& coreNodeProps.getState().equals(ZkStateReader.ACTIVE))) {
if (byCoreName && !collectionName.equals(coreNodeProps.getCoreName())) {
// if it's by core name, make sure they match
continue;
}
if (coreNodeProps.getBaseUrl().equals(cores.getZkController().getBaseUrl())) {
// don't count a local core
continue;
}
if (origCorename != null) {
coreUrl = coreNodeProps.getBaseUrl() + "/" + origCorename;
} else {
coreUrl = coreNodeProps.getCoreUrl();
if (coreUrl.endsWith("/")) {
coreUrl = coreUrl.substring(0, coreUrl.length() - 1);
}
}
return coreUrl;
}
}
}
return null;
}
private Collection<Slice> getSlicesForCollections(ClusterState clusterState,
Collection<Slice> slices, boolean activeSlices) {
Set<String> collections = clusterState.getCollections();
for (String collection : collections) {
if (activeSlices) {
slices.addAll(clusterState.getActiveSlices(collection));
} else {
slices.addAll(clusterState.getSlices(collection));
}
}
return slices;
}
private SolrCore getCoreByCollection(CoreContainer cores, String corename, String path) {
String collection = corename;
ZkStateReader zkStateReader = cores.getZkController().getZkStateReader();
ClusterState clusterState = zkStateReader.getClusterState();
Map<String,Slice> slices = clusterState.getActiveSlicesMap(collection);
if (slices == null) {
return null;
}
// look for a core on this node
Set<Entry<String,Slice>> entries = slices.entrySet();
SolrCore core = null;
done:
for (Entry<String,Slice> entry : entries) {
// first see if we have the leader
ZkNodeProps leaderProps = clusterState.getLeader(collection, entry.getKey());
if (leaderProps != null) {
core = checkProps(cores, path, leaderProps);
}
if (core != null) {
break done;
}
// check everyone then
Map<String,Replica> shards = entry.getValue().getReplicasMap();
Set<Entry<String,Replica>> shardEntries = shards.entrySet();
for (Entry<String,Replica> shardEntry : shardEntries) {
Replica zkProps = shardEntry.getValue();
core = checkProps(cores, path, zkProps);
if (core != null) {
break done;
}
}
}
return core;
}
private SolrCore checkProps(CoreContainer cores, String path,
ZkNodeProps zkProps) {
String corename;
SolrCore core = null;
if (cores.getZkController().getNodeName().equals(zkProps.getStr(ZkStateReader.NODE_NAME_PROP))) {
corename = zkProps.getStr(ZkStateReader.CORE_NAME_PROP);
core = cores.getCore(corename);
}
return core;
}
private void handleAdminRequest(HttpServletRequest req, ServletResponse response, SolrRequestHandler handler,
SolrQueryRequest solrReq) throws IOException {
SolrQueryResponse solrResp = new SolrQueryResponse();
SolrCore.preDecorateResponse(solrReq, solrResp);
handler.handleRequest(solrReq, solrResp);
SolrCore.postDecorateResponse(handler, solrReq, solrResp);
if (log.isInfoEnabled() && solrResp.getToLog().size() > 0) {
log.info(solrResp.getToLogAsString("[admin] "));
}
QueryResponseWriter respWriter = SolrCore.DEFAULT_RESPONSE_WRITERS.get(solrReq.getParams().get(CommonParams.WT));
if (respWriter == null) respWriter = SolrCore.DEFAULT_RESPONSE_WRITERS.get("standard");
writeResponse(solrResp, response, respWriter, solrReq, Method.getMethod(req.getMethod()));
}
private void writeResponse(SolrQueryResponse solrRsp, ServletResponse response,
QueryResponseWriter responseWriter, SolrQueryRequest solrReq, Method reqMethod)
throws IOException {
// Now write it out
final String ct = responseWriter.getContentType(solrReq, solrRsp);
// don't call setContentType on null
if (null != ct) response.setContentType(ct);
if (solrRsp.getException() != null) {
NamedList info = new SimpleOrderedMap();
int code = ResponseUtils.getErrorInfo(solrRsp.getException(), info, log);
solrRsp.add("error", info);
((HttpServletResponse) response).setStatus(code);
}
if (Method.HEAD != reqMethod) {
if (responseWriter instanceof BinaryQueryResponseWriter) {
BinaryQueryResponseWriter binWriter = (BinaryQueryResponseWriter) responseWriter;
binWriter.write(response.getOutputStream(), solrReq, solrRsp);
} else {
String charset = ContentStreamBase.getCharsetFromContentType(ct);
Writer out = (charset == null || charset.equalsIgnoreCase("UTF-8"))
? new OutputStreamWriter(response.getOutputStream(), UTF8)
: new OutputStreamWriter(response.getOutputStream(), charset);
out = new FastWriter(out);
responseWriter.write(out, solrReq, solrRsp);
out.flush();
}
}
//else http HEAD request, nothing to write out, waited this long just to get ContentType
}
protected void execute( HttpServletRequest req, SolrRequestHandler handler, SolrQueryRequest sreq, SolrQueryResponse rsp) {
// a custom filter could add more stuff to the request before passing it on.
// for example: sreq.getContext().put( "HttpServletRequest", req );
// used for logging query stats in SolrCore.execute()
sreq.getContext().put( "webapp", req.getContextPath() );
sreq.getCore().execute( handler, sreq, rsp );
}
protected void sendError(SolrCore core,
SolrQueryRequest req,
ServletRequest request,
HttpServletResponse response,
Throwable ex) throws IOException {
Exception exp = null;
SolrCore localCore = null;
try {
SolrQueryResponse solrResp = new SolrQueryResponse();
if(ex instanceof Exception) {
solrResp.setException((Exception)ex);
}
else {
solrResp.setException(new RuntimeException(ex));
}
if(core==null) {
localCore = cores.getCore(""); // default core
} else {
localCore = core;
}
if(req==null) {
final SolrParams solrParams;
if (request instanceof HttpServletRequest) {
// use GET parameters if available:
solrParams = SolrRequestParsers.parseQueryString(((HttpServletRequest) request).getQueryString());
} else {
// we have no params at all, use empty ones:
solrParams = new MapSolrParams(Collections.<String,String>emptyMap());
}
req = new SolrQueryRequestBase(core, solrParams) {};
}
QueryResponseWriter writer = core.getQueryResponseWriter(req);
writeResponse(solrResp, response, writer, req, Method.GET);
}
catch (Exception e) { // This error really does not matter
exp = e;
} finally {
try {
if (exp != null) {
SimpleOrderedMap info = new SimpleOrderedMap();
int code = ResponseUtils.getErrorInfo(ex, info, log);
response.sendError(code, info.toString());
}
} finally {
if (core == null && localCore != null) {
localCore.close();
}
}
}
}
//---------------------------------------------------------------------
//---------------------------------------------------------------------
/**
* Set the prefix for all paths. This is useful if you want to apply the
* filter to something other then /*, perhaps because you are merging this
* filter into a larger web application.
*
* For example, if web.xml specifies:
* <pre class="prettyprint">
* {@code
* <filter-mapping>
* <filter-name>SolrRequestFilter</filter-name>
* <url-pattern>/xxx/*</url-pattern>
* </filter-mapping>}
* </pre>
*
* Make sure to set the PathPrefix to "/xxx" either with this function
* or in web.xml.
*
* <pre class="prettyprint">
* {@code
* <init-param>
* <param-name>path-prefix</param-name>
* <param-value>/xxx</param-value>
* </init-param>}
* </pre>
*/
public void setPathPrefix(String pathPrefix) {
this.pathPrefix = pathPrefix;
}
public String getPathPrefix() {
return pathPrefix;
}
}