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:
Ryan McKinley 2008-01-02 17:15:30 +00:00
parent 641e7f3c4a
commit 3a726d0b6d
8 changed files with 377 additions and 5 deletions

View File

@ -175,6 +175,10 @@ New Features
<requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" /> <requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />
This will register: Luke/SystemInfo/PluginInfo/ThreadDump/PropertiesRequestHandler. This will register: Luke/SystemInfo/PluginInfo/ThreadDump/PropertiesRequestHandler.
(ryan) (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 Changes in runtime behavior

View File

@ -502,7 +502,15 @@
<requestHandler name="/admin/plugins" class="org.apache.solr.handler.admin.PluginInfoHandler" /> <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/threads" class="org.apache.solr.handler.admin.ThreadDumpHandler" />
<requestHandler name="/admin/properties" class="org.apache.solr.handler.admin.PropertiesRequestHandler" /> <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" /> <requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />

View File

@ -54,6 +54,7 @@ import org.apache.solr.highlight.SolrHighlighter;
import org.apache.solr.request.JSONResponseWriter; import org.apache.solr.request.JSONResponseWriter;
import org.apache.solr.request.PythonResponseWriter; import org.apache.solr.request.PythonResponseWriter;
import org.apache.solr.request.QueryResponseWriter; import org.apache.solr.request.QueryResponseWriter;
import org.apache.solr.request.RawResponseWriter;
import org.apache.solr.request.RubyResponseWriter; import org.apache.solr.request.RubyResponseWriter;
import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.request.SolrQueryResponse; import org.apache.solr.request.SolrQueryResponse;
@ -968,7 +969,9 @@ public final class SolrCore {
if (responseWriters.get("ruby")==null) { if (responseWriters.get("ruby")==null) {
responseWriters.put("ruby", new RubyResponseWriter()); 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. */ /** Finds a writer by name, or returns the default writer if not found. */

View File

@ -84,7 +84,8 @@ public class AdminHandlers implements SolrCoreAware, SolrRequestHandler
new StandardHandler( "system", new SystemInfoHandler() ), new StandardHandler( "system", new SystemInfoHandler() ),
new StandardHandler( "plugins", new PluginInfoHandler() ), new StandardHandler( "plugins", new PluginInfoHandler() ),
new StandardHandler( "threads", new ThreadDumpHandler() ), new StandardHandler( "threads", new ThreadDumpHandler() ),
new StandardHandler( "properties", new PropertiesRequestHandler() ) new StandardHandler( "properties", new PropertiesRequestHandler() ),
new StandardHandler( "file", new ShowFileRequestHandler() )
}; };
for( StandardHandler handler : list ) { for( StandardHandler handler : list ) {

View File

@ -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>
* &lt;requestHandler name="/admin/file" class="org.apache.solr.handler.admin.ShowFileRequestHandler" &gt;
* &lt;lst name="defaults"&gt;
* &lt;str name="echoParams"&gt;explicit&lt;/str&gt;
* &lt;/lst&gt;
* &lt;lst name="invariants"&gt;
* &lt;str name="hidden"&gt;synonyms.txt&lt;/str&gt;
* &lt;str name="hidden"&gt;anotherfile.txt&lt;/str&gt;
* &lt;/lst&gt;
* &lt;/requestHandler&gt;
* </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$";
}
}

View File

@ -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 );
}
}
}

View File

@ -23,6 +23,13 @@
java.io.Reader, java.io.Reader,
java.util.StringTokenizer"%> 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"); Object ocore = request.getAttribute("org.apache.solr.SolrCore");
SolrCore core = ocore instanceof SolrCore? (SolrCore) ocore : SolrCore.getSolrCore(); SolrCore core = ocore instanceof SolrCore? (SolrCore) ocore : SolrCore.getSolrCore();
String fname = request.getParameter("file"); String fname = request.getParameter("file");

View File

@ -34,8 +34,8 @@
<h3>Solr</h3> <h3>Solr</h3>
</td> </td>
<td> <td>
[<a href="get-file.jsp?file=<%=core.getSchemaFile()%>">Schema</a>] [<a href="file/?file=<%=core.getSchemaFile()%>">Schema</a>]
[<a href="get-file.jsp?file=<%=core.getConfigFile()%>">Config</a>] [<a href="file/?file=<%=core.getConfigFile()%>">Config</a>]
[<a href="analysis.jsp?highlight=on">Analysis</a>] [<a href="analysis.jsp?highlight=on">Analysis</a>]
<br> <br>
[<a href="stats.jsp">Statistics</a>] [<a href="stats.jsp">Statistics</a>]
@ -80,7 +80,10 @@ if (cores.size() > 1) {%><tr><td><strong>Cores:</strong><br></td><td><%
</tr> </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> </table><P>