mirror of https://github.com/apache/lucene.git
SOLR-142: Added RawResponseWriter and ShowFileRequestHandler. This returns config files directly. If the AdminHandlers is configured, this will be added automatically.
git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@608150 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
641e7f3c4a
commit
3a726d0b6d
|
@ -176,6 +176,10 @@ New Features
|
|||
This will register: Luke/SystemInfo/PluginInfo/ThreadDump/PropertiesRequestHandler.
|
||||
(ryan)
|
||||
|
||||
35. SOLR-142: Added RawResponseWriter and ShowFileRequestHandler. This returns config
|
||||
files directly. If the AdminHandlers is configured, this will be added automatically.
|
||||
(ryan)
|
||||
|
||||
Changes in runtime behavior
|
||||
|
||||
Optimizations
|
||||
|
|
|
@ -502,7 +502,15 @@
|
|||
<requestHandler name="/admin/plugins" class="org.apache.solr.handler.admin.PluginInfoHandler" />
|
||||
<requestHandler name="/admin/threads" class="org.apache.solr.handler.admin.ThreadDumpHandler" />
|
||||
<requestHandler name="/admin/properties" class="org.apache.solr.handler.admin.PropertiesRequestHandler" />
|
||||
<requestHandler name="/admin/file" class="org.apache.solr.handler.admin.ShowFileRequestHandler" >
|
||||
|
||||
If you wish to hide files under ${solr.home}/conf, explicitly register the ShowFileRequestHandler using:
|
||||
<requestHandler name="/admin/file" class="org.apache.solr.handler.admin.ShowFileRequestHandler" >
|
||||
<lst name="invariants">
|
||||
<str name="hidden">synonyms.txt</str>
|
||||
<str name="hidden">anotherfile.txt</str>
|
||||
</lst>
|
||||
</requestHandler>
|
||||
-->
|
||||
<requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />
|
||||
|
||||
|
|
|
@ -54,6 +54,7 @@ import org.apache.solr.highlight.SolrHighlighter;
|
|||
import org.apache.solr.request.JSONResponseWriter;
|
||||
import org.apache.solr.request.PythonResponseWriter;
|
||||
import org.apache.solr.request.QueryResponseWriter;
|
||||
import org.apache.solr.request.RawResponseWriter;
|
||||
import org.apache.solr.request.RubyResponseWriter;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.request.SolrQueryResponse;
|
||||
|
@ -968,7 +969,9 @@ public final class SolrCore {
|
|||
if (responseWriters.get("ruby")==null) {
|
||||
responseWriters.put("ruby", new RubyResponseWriter());
|
||||
}
|
||||
|
||||
if (responseWriters.get("raw")==null) {
|
||||
responseWriters.put("raw", new RawResponseWriter());
|
||||
}
|
||||
}
|
||||
|
||||
/** Finds a writer by name, or returns the default writer if not found. */
|
||||
|
|
|
@ -84,7 +84,8 @@ public class AdminHandlers implements SolrCoreAware, SolrRequestHandler
|
|||
new StandardHandler( "system", new SystemInfoHandler() ),
|
||||
new StandardHandler( "plugins", new PluginInfoHandler() ),
|
||||
new StandardHandler( "threads", new ThreadDumpHandler() ),
|
||||
new StandardHandler( "properties", new PropertiesRequestHandler() )
|
||||
new StandardHandler( "properties", new PropertiesRequestHandler() ),
|
||||
new StandardHandler( "file", new ShowFileRequestHandler() )
|
||||
};
|
||||
|
||||
for( StandardHandler handler : list ) {
|
||||
|
|
|
@ -0,0 +1,255 @@
|
|||
/**
|
||||
* 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.handler.admin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.solr.common.SolrException;
|
||||
import org.apache.solr.common.SolrException.ErrorCode;
|
||||
import org.apache.solr.common.params.CommonParams;
|
||||
import org.apache.solr.common.params.ModifiableSolrParams;
|
||||
import org.apache.solr.common.util.ContentStream;
|
||||
import org.apache.solr.common.util.NamedList;
|
||||
import org.apache.solr.common.util.SimpleOrderedMap;
|
||||
import org.apache.solr.core.SolrCore;
|
||||
import org.apache.solr.core.SolrResourceLoader;
|
||||
import org.apache.solr.handler.RequestHandlerBase;
|
||||
import org.apache.solr.handler.RequestHandlerUtils;
|
||||
import org.apache.solr.request.RawResponseWriter;
|
||||
import org.apache.solr.request.SolrQueryRequest;
|
||||
import org.apache.solr.request.SolrQueryResponse;
|
||||
|
||||
/**
|
||||
* This handler uses the RawResponseWriter to give client access to
|
||||
* files inside ${solr.home}/conf
|
||||
*
|
||||
* If you want to selectively restrict access some configuration files, you can list
|
||||
* these files in the {@link #HIDDEN} invariants. For example to hide
|
||||
* synonyms.txt and anotherfile.txt, you would register:
|
||||
*
|
||||
* <pre>
|
||||
* <requestHandler name="/admin/file" class="org.apache.solr.handler.admin.ShowFileRequestHandler" >
|
||||
* <lst name="defaults">
|
||||
* <str name="echoParams">explicit</str>
|
||||
* </lst>
|
||||
* <lst name="invariants">
|
||||
* <str name="hidden">synonyms.txt</str>
|
||||
* <str name="hidden">anotherfile.txt</str>
|
||||
* </lst>
|
||||
* </requestHandler>
|
||||
* </pre>
|
||||
*
|
||||
* The ShowFileRequestHandler uses the {@link RawResponseWriter} (wt=raw) to return
|
||||
* file contents. If you need to use a different writer, you will need to change
|
||||
* the registered invarient param for wt.
|
||||
*
|
||||
* If you want to override the contentType header returned for a given file, you can
|
||||
* set it directly using: {@link #USE_CONTENT_TYPE}. For example, to get a plain text
|
||||
* version of schema.xml, try:
|
||||
* <pre>
|
||||
* http://localhost:8983/solr/admin/file?file=schema.xml&contentType=text/plain
|
||||
* </pre>
|
||||
*
|
||||
* @version $Id$
|
||||
* @since solr 1.3
|
||||
*/
|
||||
public class ShowFileRequestHandler extends RequestHandlerBase
|
||||
{
|
||||
public static final String HIDDEN = "hidden";
|
||||
public static final String USE_CONTENT_TYPE = "contentType";
|
||||
|
||||
protected Set<String> hiddenFiles;
|
||||
|
||||
private static ShowFileRequestHandler instance;
|
||||
public ShowFileRequestHandler()
|
||||
{
|
||||
super();
|
||||
instance = this; // used so that getFileContents can access hiddenFiles
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(NamedList args) {
|
||||
super.init( args );
|
||||
|
||||
// by default, use wt=raw
|
||||
ModifiableSolrParams params = new ModifiableSolrParams( invariants );
|
||||
if( params.get( CommonParams.WT ) == null ) {
|
||||
params.set( CommonParams.WT, "raw" );
|
||||
}
|
||||
this.invariants = params;
|
||||
|
||||
// Build a list of hidden files
|
||||
hiddenFiles = new HashSet<String>();
|
||||
if( invariants != null ) {
|
||||
String[] hidden = invariants.getParams( HIDDEN );
|
||||
if( hidden != null ) {
|
||||
for( String s : hidden ) {
|
||||
hiddenFiles.add( s.toUpperCase() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleRequestBody(SolrQueryRequest req, SolrQueryResponse rsp) throws IOException
|
||||
{
|
||||
File adminFile = null;
|
||||
|
||||
final SolrResourceLoader loader = req.getCore().getResourceLoader();
|
||||
File configdir = new File( loader.getConfigDir() );
|
||||
String fname = req.getParams().get("file", null);
|
||||
if( fname == null ) {
|
||||
adminFile = configdir;
|
||||
}
|
||||
else {
|
||||
fname = fname.replace( '\\', '/' ); // normalize slashes
|
||||
if( hiddenFiles.contains( fname.toUpperCase() ) ) {
|
||||
throw new SolrException( ErrorCode.FORBIDDEN, "Can not access: "+fname );
|
||||
}
|
||||
if( fname.indexOf( ".." ) >= 0 ) {
|
||||
throw new SolrException( ErrorCode.FORBIDDEN, "Invalid path: "+fname );
|
||||
}
|
||||
adminFile = new File( configdir, fname );
|
||||
}
|
||||
|
||||
// Make sure the file exists, is readable and is not a hidden file
|
||||
if( !adminFile.exists() ) {
|
||||
throw new SolrException( ErrorCode.BAD_REQUEST, "Can not find: "+adminFile.getName()
|
||||
+ " ["+adminFile.getAbsolutePath()+"]" );
|
||||
}
|
||||
if( !adminFile.canRead() || adminFile.isHidden() ) {
|
||||
throw new SolrException( ErrorCode.BAD_REQUEST, "Can not show: "+adminFile.getName()
|
||||
+ " ["+adminFile.getAbsolutePath()+"]" );
|
||||
}
|
||||
|
||||
// Add a warning
|
||||
RequestHandlerUtils.addExperimentalFormatWarning(rsp);
|
||||
|
||||
// Show a directory listing
|
||||
if( adminFile.isDirectory() ) {
|
||||
|
||||
int basePath = configdir.getAbsolutePath().length() + 1;
|
||||
NamedList<SimpleOrderedMap<Object>> files = new SimpleOrderedMap<SimpleOrderedMap<Object>>();
|
||||
for( File f : adminFile.listFiles() ) {
|
||||
String path = f.getAbsolutePath().substring( basePath );
|
||||
path = path.replace( '\\', '/' ); // normalize slashes
|
||||
if( hiddenFiles.contains( path.toUpperCase() ) ) {
|
||||
continue; // don't show 'hidden' files
|
||||
}
|
||||
if( f.isHidden() || f.getName().startsWith( "." ) ) {
|
||||
continue; // skip hidden system files...
|
||||
}
|
||||
|
||||
SimpleOrderedMap<Object> fileInfo = new SimpleOrderedMap<Object>();
|
||||
files.add( path, fileInfo );
|
||||
if( f.isDirectory() ) {
|
||||
fileInfo.add( "directory", true );
|
||||
}
|
||||
else {
|
||||
// TODO? content type
|
||||
fileInfo.add( "size", f.length() );
|
||||
}
|
||||
fileInfo.add( "modified", new Date( f.lastModified() ) );
|
||||
}
|
||||
rsp.add( "files", files );
|
||||
}
|
||||
else {
|
||||
// Check if they want the file as text
|
||||
final String contentType = req.getParams().get( USE_CONTENT_TYPE );
|
||||
|
||||
final File file = adminFile;
|
||||
//final URLConnection conn = adminFile.toURI().toURL().openConnection();
|
||||
|
||||
ContentStream stream = new ContentStream() {
|
||||
public String getName() { return file.getName(); }
|
||||
public Long getSize() { return file.length(); }
|
||||
public String getSourceInfo() { return null; }
|
||||
|
||||
public String getContentType() {
|
||||
if( contentType != null ) {
|
||||
return contentType;
|
||||
}
|
||||
return null; //conn.getContentType();
|
||||
}
|
||||
|
||||
public InputStream getStream() throws IOException {
|
||||
return loader.openResource( file.getPath() ); //conn.getInputStream();
|
||||
}
|
||||
|
||||
public Reader getReader() throws IOException {
|
||||
return new FileReader( file );
|
||||
}
|
||||
};
|
||||
|
||||
rsp.add( RawResponseWriter.CONTENT, stream );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a utility function that lets you get the contents of an admin file
|
||||
*
|
||||
* It is only used so that we can get rid of "/admin/get-file.jsp" and include
|
||||
* "admin-extra.html" in "/admin/index.html" using jsp scriptlets
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getFileContents( String path )
|
||||
{
|
||||
if( instance != null && instance.hiddenFiles != null ) {
|
||||
if( instance.hiddenFiles.contains( path ) ) {
|
||||
return ""; // ignore it...
|
||||
}
|
||||
}
|
||||
try {
|
||||
SolrCore core = SolrCore.getSolrCore();
|
||||
InputStream input = core.getResourceLoader().openResource(path);
|
||||
return IOUtils.toString( input );
|
||||
}
|
||||
catch( Exception ex ) {} // ignore it
|
||||
return "";
|
||||
}
|
||||
|
||||
//////////////////////// SolrInfoMBeans methods //////////////////////
|
||||
|
||||
@Override
|
||||
public String getDescription() {
|
||||
return "Admin Get File -- view config files directly";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return "$Revision$";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceId() {
|
||||
return "$Id$";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSource() {
|
||||
return "$URL$";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* 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.request;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.solr.common.util.ContentStream;
|
||||
import org.apache.solr.common.util.NamedList;
|
||||
|
||||
/**
|
||||
* Writes a ContentStream directly to the output.
|
||||
*
|
||||
* <p>
|
||||
* This writer is a special case that extends and alters the
|
||||
* QueryResponseWriter contract. If SolrQueryResponse contains a
|
||||
* ContentStream added with the key {@link #CONTENT}
|
||||
* then this writer will output that stream exactly as is (with it's
|
||||
* Content-Type). if no such ContentStream has been added, then a
|
||||
* "base" QueryResponseWriter will be used to write the response
|
||||
* according to the usual contract. The name of the "base" writer can
|
||||
* be specified as an initialization param for this writer, or it
|
||||
* defaults to the "standard" writer.
|
||||
* </p>
|
||||
*
|
||||
* @version $Id$
|
||||
* @since solr 1.3
|
||||
*/
|
||||
public class RawResponseWriter implements QueryResponseWriter
|
||||
{
|
||||
/**
|
||||
* The key that should be used to add a ContentStream to the
|
||||
* SolrQueryResponse if you intend to use this Writer.
|
||||
*/
|
||||
public static final String CONTENT = "content";
|
||||
private String _baseWriter = null;
|
||||
|
||||
public void init(NamedList n) {
|
||||
if( n != null ) {
|
||||
Object base = n.get( "base" );
|
||||
if( base != null ) {
|
||||
_baseWriter = base.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Even if this is null, it should be ok
|
||||
protected QueryResponseWriter getBaseWriter( SolrQueryRequest request )
|
||||
{
|
||||
return request.getCore().getQueryResponseWriter( _baseWriter );
|
||||
}
|
||||
|
||||
public String getContentType(SolrQueryRequest request, SolrQueryResponse response) {
|
||||
Object obj = response.getValues().get( CONTENT );
|
||||
if( obj != null && (obj instanceof ContentStream ) ) {
|
||||
// copy the contents to the writer...
|
||||
ContentStream content = (ContentStream)obj;
|
||||
return content.getContentType();
|
||||
}
|
||||
return getBaseWriter( request ).getContentType( request, response );
|
||||
}
|
||||
|
||||
public void write(Writer writer, SolrQueryRequest request, SolrQueryResponse response) throws IOException
|
||||
{
|
||||
Object obj = response.getValues().get( CONTENT );
|
||||
if( obj != null && (obj instanceof ContentStream ) ) {
|
||||
// copy the contents to the writer...
|
||||
ContentStream content = (ContentStream)obj;
|
||||
IOUtils.copy( content.getStream(), writer );
|
||||
}
|
||||
else {
|
||||
getBaseWriter( request ).write( writer, request, response );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,6 +23,13 @@
|
|||
java.io.Reader,
|
||||
java.util.StringTokenizer"%>
|
||||
<%
|
||||
//
|
||||
// NOTE -- this file is Deprecated - should use the ShowFileRequestHandler instead
|
||||
//
|
||||
|
||||
System.out.println( "WARNING -- using deprecated jsp file: " + request.getServletPath() );
|
||||
|
||||
|
||||
Object ocore = request.getAttribute("org.apache.solr.SolrCore");
|
||||
SolrCore core = ocore instanceof SolrCore? (SolrCore) ocore : SolrCore.getSolrCore();
|
||||
String fname = request.getParameter("file");
|
||||
|
|
|
@ -34,8 +34,8 @@
|
|||
<h3>Solr</h3>
|
||||
</td>
|
||||
<td>
|
||||
[<a href="get-file.jsp?file=<%=core.getSchemaFile()%>">Schema</a>]
|
||||
[<a href="get-file.jsp?file=<%=core.getConfigFile()%>">Config</a>]
|
||||
[<a href="file/?file=<%=core.getSchemaFile()%>">Schema</a>]
|
||||
[<a href="file/?file=<%=core.getConfigFile()%>">Config</a>]
|
||||
[<a href="analysis.jsp?highlight=on">Analysis</a>]
|
||||
<br>
|
||||
[<a href="stats.jsp">Statistics</a>]
|
||||
|
@ -80,7 +80,10 @@ if (cores.size() > 1) {%><tr><td><strong>Cores:</strong><br></td><td><%
|
|||
</tr>
|
||||
|
||||
|
||||
<jsp:include page="get-file.jsp?file=admin-extra.html&optional=y" flush="true"/>
|
||||
<%
|
||||
// a quick hack to get rid of get-file.jsp -- note this still spits out invalid HTML
|
||||
out.write( org.apache.solr.handler.admin.ShowFileRequestHandler.getFileContents( "admin-extra.html" ) );
|
||||
%>
|
||||
|
||||
</table><P>
|
||||
|
||||
|
|
Loading…
Reference in New Issue