mirror of https://github.com/apache/lucene.git
SOLR-8933: Solr should not close container streams.
This commit is contained in:
parent
69675126c6
commit
95c5d92f10
|
@ -148,6 +148,7 @@ public class ReplicationService {
|
||||||
throw new ServletException("unrecognized shard ID " + pathElements[SHARD_IDX]);
|
throw new ServletException("unrecognized shard ID " + pathElements[SHARD_IDX]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SOLR-8933 Don't close this stream.
|
||||||
ServletOutputStream resOut = resp.getOutputStream();
|
ServletOutputStream resOut = resp.getOutputStream();
|
||||||
try {
|
try {
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
|
|
@ -194,6 +194,8 @@ Other Changes
|
||||||
|
|
||||||
* SOLR-8929: Add an idea module for solr/server to enable launching start.jar (Scott Blum, Steve Rowe)
|
* SOLR-8929: Add an idea module for solr/server to enable launching start.jar (Scott Blum, Steve Rowe)
|
||||||
|
|
||||||
|
* SOLR-8933: Solr should not close container streams. (Mike Drob, Uwe Schindler, Mark Miller)
|
||||||
|
|
||||||
* SOLR-9037: Replace multiple "/replication" strings with one static constant. (Christine Poerschke)
|
* SOLR-9037: Replace multiple "/replication" strings with one static constant. (Christine Poerschke)
|
||||||
|
|
||||||
* SOLR-9047: zkcli should allow alternative locations for log4j configuration (Gregory Chanan)
|
* SOLR-9047: zkcli should allow alternative locations for log4j configuration (Gregory Chanan)
|
||||||
|
|
|
@ -17,9 +17,9 @@
|
||||||
package org.apache.solr.servlet;
|
package org.apache.solr.servlet;
|
||||||
|
|
||||||
import javax.servlet.ServletInputStream;
|
import javax.servlet.ServletInputStream;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import java.io.EOFException;
|
import java.io.EOFException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
@ -41,7 +41,10 @@ import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.io.input.CloseShieldInputStream;
|
||||||
|
import org.apache.commons.io.output.CloseShieldOutputStream;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.Header;
|
import org.apache.http.Header;
|
||||||
import org.apache.http.HeaderIterator;
|
import org.apache.http.HeaderIterator;
|
||||||
|
@ -533,7 +536,8 @@ public class HttpSolrCall {
|
||||||
} else if (isPostOrPutRequest) {
|
} else if (isPostOrPutRequest) {
|
||||||
HttpEntityEnclosingRequestBase entityRequest =
|
HttpEntityEnclosingRequestBase entityRequest =
|
||||||
"POST".equals(req.getMethod()) ? new HttpPost(urlstr) : new HttpPut(urlstr);
|
"POST".equals(req.getMethod()) ? new HttpPost(urlstr) : new HttpPut(urlstr);
|
||||||
HttpEntity entity = new InputStreamEntity(req.getInputStream(), req.getContentLength());
|
InputStream in = new CloseShieldInputStream(req.getInputStream()); // Prevent close of container streams
|
||||||
|
HttpEntity entity = new InputStreamEntity(in, req.getContentLength());
|
||||||
entityRequest.setEntity(entity);
|
entityRequest.setEntity(entity);
|
||||||
method = entityRequest;
|
method = entityRequest;
|
||||||
} else if ("DELETE".equals(req.getMethod())) {
|
} else if ("DELETE".equals(req.getMethod())) {
|
||||||
|
@ -722,7 +726,8 @@ public class HttpSolrCall {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Method.HEAD != reqMethod) {
|
if (Method.HEAD != reqMethod) {
|
||||||
QueryResponseWriterUtil.writeQueryResponse(response.getOutputStream(), responseWriter, solrReq, solrRsp, ct);
|
OutputStream out = new CloseShieldOutputStream(response.getOutputStream()); // Prevent close of container streams, see SOLR-8933
|
||||||
|
QueryResponseWriterUtil.writeQueryResponse(out, responseWriter, solrReq, solrRsp, ct);
|
||||||
}
|
}
|
||||||
//else http HEAD request, nothing to write out, waited this long just to get ContentType
|
//else http HEAD request, nothing to write out, waited this long just to get ContentType
|
||||||
} catch (EOFException e) {
|
} catch (EOFException e) {
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.solr.servlet;
|
package org.apache.solr.servlet;
|
||||||
|
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
|
import org.apache.commons.io.output.CloseShieldOutputStream;
|
||||||
import org.apache.commons.lang.StringEscapeUtils;
|
import org.apache.commons.lang.StringEscapeUtils;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.solr.common.params.CommonParams;
|
import org.apache.solr.common.params.CommonParams;
|
||||||
|
@ -25,6 +26,7 @@ import org.apache.solr.core.SolrCore;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
|
@ -49,11 +51,14 @@ public final class LoadAdminUiServlet extends BaseSolrServlet {
|
||||||
String admin = request.getRequestURI().substring(request.getContextPath().length());
|
String admin = request.getRequestURI().substring(request.getContextPath().length());
|
||||||
CoreContainer cores = (CoreContainer) request.getAttribute("org.apache.solr.CoreContainer");
|
CoreContainer cores = (CoreContainer) request.getAttribute("org.apache.solr.CoreContainer");
|
||||||
InputStream in = getServletContext().getResourceAsStream(admin);
|
InputStream in = getServletContext().getResourceAsStream(admin);
|
||||||
|
Writer out = null;
|
||||||
if(in != null && cores != null) {
|
if(in != null && cores != null) {
|
||||||
try {
|
try {
|
||||||
response.setCharacterEncoding("UTF-8");
|
response.setCharacterEncoding("UTF-8");
|
||||||
response.setContentType("text/html");
|
response.setContentType("text/html");
|
||||||
Writer out = new OutputStreamWriter(response.getOutputStream(), StandardCharsets.UTF_8);
|
|
||||||
|
// Protect container owned streams from being closed by us, see SOLR-8933
|
||||||
|
out = new OutputStreamWriter(new CloseShieldOutputStream(response.getOutputStream()), StandardCharsets.UTF_8);
|
||||||
|
|
||||||
String html = IOUtils.toString(in, "UTF-8");
|
String html = IOUtils.toString(in, "UTF-8");
|
||||||
Package pack = SolrCore.class.getPackage();
|
Package pack = SolrCore.class.getPackage();
|
||||||
|
@ -70,9 +75,9 @@ public final class LoadAdminUiServlet extends BaseSolrServlet {
|
||||||
};
|
};
|
||||||
|
|
||||||
out.write( StringUtils.replaceEach(html, search, replace) );
|
out.write( StringUtils.replaceEach(html, search, replace) );
|
||||||
out.flush();
|
|
||||||
} finally {
|
} finally {
|
||||||
IOUtils.closeQuietly(in);
|
IOUtils.closeQuietly(in);
|
||||||
|
IOUtils.closeQuietly(out);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
response.sendError(404);
|
response.sendError(404);
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* 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 java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ReadListener;
|
||||||
|
import javax.servlet.ServletInputStream;
|
||||||
|
|
||||||
|
import org.apache.solr.common.util.SuppressForbidden;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a convenient extension of the {@link ServletInputStream} class that can be subclassed by developers wishing
|
||||||
|
* to adapt the behavior of a Stream. One such example may be to override {@link #close()} to instead be a no-op as in
|
||||||
|
* SOLR-8933.
|
||||||
|
*
|
||||||
|
* This class implements the Wrapper or Decorator pattern. Methods default to calling through to the wrapped stream.
|
||||||
|
*/
|
||||||
|
@SuppressForbidden(reason = "delegate methods")
|
||||||
|
public class ServletInputStreamWrapper extends ServletInputStream {
|
||||||
|
final ServletInputStream stream;
|
||||||
|
|
||||||
|
public ServletInputStreamWrapper(ServletInputStream stream) throws IOException {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return stream.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return stream.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int available() throws IOException {
|
||||||
|
return stream.available();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isFinished() {
|
||||||
|
return stream.isFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReady() {
|
||||||
|
return stream.isReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read() throws IOException {
|
||||||
|
return stream.read();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] b) throws IOException {
|
||||||
|
return stream.read(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int read(byte[] b, int off, int len) throws IOException {
|
||||||
|
return stream.read(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void mark(int readlimit) {
|
||||||
|
stream.mark(readlimit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean markSupported() {
|
||||||
|
return stream.markSupported();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int readLine(byte[] b, int off, int len) throws IOException {
|
||||||
|
return stream.readLine(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reset() throws IOException {
|
||||||
|
stream.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReadListener(ReadListener arg0) {
|
||||||
|
stream.setReadListener(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public long skip(long n) throws IOException {
|
||||||
|
return stream.skip(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return stream.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,140 @@
|
||||||
|
/*
|
||||||
|
* 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 java.io.IOException;
|
||||||
|
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
|
import javax.servlet.WriteListener;
|
||||||
|
|
||||||
|
import org.apache.solr.common.util.SuppressForbidden;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides a convenient extension of the {@link ServletOutputStream} class that can be subclassed by developers wishing
|
||||||
|
* to adapt the behavior of a Stream. One such example may be to override {@link #close()} to instead be a no-op as in
|
||||||
|
* SOLR-8933.
|
||||||
|
*
|
||||||
|
* This class implements the Wrapper or Decorator pattern. Methods default to calling through to the wrapped stream.
|
||||||
|
*/
|
||||||
|
@SuppressForbidden(reason = "delegate methods")
|
||||||
|
public class ServletOutputStreamWrapper extends ServletOutputStream {
|
||||||
|
final ServletOutputStream stream;
|
||||||
|
|
||||||
|
public ServletOutputStreamWrapper(ServletOutputStream stream) {
|
||||||
|
this.stream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int hashCode() {
|
||||||
|
return stream.hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
return stream.equals(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() throws IOException {
|
||||||
|
stream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws IOException {
|
||||||
|
stream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReady() {
|
||||||
|
return stream.isReady();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(boolean arg0) throws IOException {
|
||||||
|
stream.print(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(char c) throws IOException {
|
||||||
|
stream.print(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(double d) throws IOException {
|
||||||
|
stream.print(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(float f) throws IOException {
|
||||||
|
stream.print(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(int i) throws IOException {
|
||||||
|
stream.print(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(long l) throws IOException {
|
||||||
|
stream.print(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(String arg0) throws IOException {
|
||||||
|
stream.print(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println() throws IOException {
|
||||||
|
stream.println();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(boolean b) throws IOException {
|
||||||
|
stream.println(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(char c) throws IOException {
|
||||||
|
stream.println(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(double d) throws IOException {
|
||||||
|
stream.println(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(float f) throws IOException {
|
||||||
|
stream.println(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(int i) throws IOException {
|
||||||
|
stream.println(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(long l) throws IOException {
|
||||||
|
stream.println(l);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(String s) throws IOException {
|
||||||
|
stream.println(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWriteListener(WriteListener arg0) {
|
||||||
|
stream.setWriteListener(arg0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(int b) throws IOException {
|
||||||
|
stream.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b) throws IOException {
|
||||||
|
stream.write(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void write(byte[] b, int off, int len) throws IOException {
|
||||||
|
stream.write(b, off, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toString() {
|
||||||
|
return stream.toString();
|
||||||
|
}
|
||||||
|
}
|
|
@ -20,12 +20,18 @@ import javax.servlet.FilterChain;
|
||||||
import javax.servlet.FilterConfig;
|
import javax.servlet.FilterConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.ServletInputStream;
|
import javax.servlet.ServletInputStream;
|
||||||
|
import javax.servlet.ServletOutputStream;
|
||||||
import javax.servlet.ServletRequest;
|
import javax.servlet.ServletRequest;
|
||||||
import javax.servlet.ServletResponse;
|
import javax.servlet.ServletResponse;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpServletRequestWrapper;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import javax.servlet.http.HttpServletResponseWrapper;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
import java.lang.invoke.MethodHandles;
|
import java.lang.invoke.MethodHandles;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
@ -36,6 +42,8 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import org.apache.commons.io.input.CloseShieldInputStream;
|
||||||
|
import org.apache.commons.io.output.CloseShieldOutputStream;
|
||||||
import org.apache.commons.lang.StringUtils;
|
import org.apache.commons.lang.StringUtils;
|
||||||
import org.apache.http.client.HttpClient;
|
import org.apache.http.client.HttpClient;
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
|
@ -66,6 +74,9 @@ public class SolrDispatchFilter extends BaseSolrFilter {
|
||||||
protected String abortErrorMessage = null;
|
protected String abortErrorMessage = null;
|
||||||
protected HttpClient httpClient;
|
protected HttpClient httpClient;
|
||||||
private ArrayList<Pattern> excludePatterns;
|
private ArrayList<Pattern> excludePatterns;
|
||||||
|
|
||||||
|
// Effectively immutable
|
||||||
|
private Boolean testMode = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum to define action that needs to be processed.
|
* Enum to define action that needs to be processed.
|
||||||
|
@ -80,6 +91,19 @@ public class SolrDispatchFilter extends BaseSolrFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
public SolrDispatchFilter() {
|
public SolrDispatchFilter() {
|
||||||
|
// turn on test mode when running tests
|
||||||
|
assert testMode = true;
|
||||||
|
|
||||||
|
if (testMode == null) {
|
||||||
|
testMode = false;
|
||||||
|
} else {
|
||||||
|
String tm = System.getProperty("solr.tests.doContainerStreamCloseAssert");
|
||||||
|
if (tm != null) {
|
||||||
|
testMode = Boolean.parseBoolean(tm);
|
||||||
|
} else {
|
||||||
|
testMode = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final String PROPERTIES_ATTRIBUTE = "solr.properties";
|
public static final String PROPERTIES_ATTRIBUTE = "solr.properties";
|
||||||
|
@ -202,6 +226,10 @@ public class SolrDispatchFilter extends BaseSolrFilter {
|
||||||
if (wrappedRequest.get() != null) {
|
if (wrappedRequest.get() != null) {
|
||||||
request = wrappedRequest.get();
|
request = wrappedRequest.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request = closeShield(request, retry);
|
||||||
|
response = closeShield(response, retry);
|
||||||
|
|
||||||
if (cores.getAuthenticationPlugin() != null) {
|
if (cores.getAuthenticationPlugin() != null) {
|
||||||
log.debug("User principal: {}", ((HttpServletRequest) request).getUserPrincipal());
|
log.debug("User principal: {}", ((HttpServletRequest) request).getUserPrincipal());
|
||||||
}
|
}
|
||||||
|
@ -298,4 +326,68 @@ public class SolrDispatchFilter extends BaseSolrFilter {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the request's input stream with a close shield, as if by a {@link CloseShieldInputStream}. If this is a
|
||||||
|
* retry, we will assume that the stream has already been wrapped and do nothing.
|
||||||
|
*
|
||||||
|
* @param request The request to wrap.
|
||||||
|
* @param retry If this is an original request or a retry.
|
||||||
|
* @return A request object with an {@link InputStream} that will ignore calls to close.
|
||||||
|
*/
|
||||||
|
private ServletRequest closeShield(ServletRequest request, boolean retry) {
|
||||||
|
if (testMode && !retry) {
|
||||||
|
return new HttpServletRequestWrapper((HttpServletRequest) request) {
|
||||||
|
ServletInputStream stream;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServletInputStream getInputStream() throws IOException {
|
||||||
|
// Lazy stream creation
|
||||||
|
if (stream == null) {
|
||||||
|
stream = new ServletInputStreamWrapper(super.getInputStream()) {
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
assert false : "Attempted close of request input stream.";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrap the response's output stream with a close shield, as if by a {@link CloseShieldOutputStream}. If this is a
|
||||||
|
* retry, we will assume that the stream has already been wrapped and do nothing.
|
||||||
|
*
|
||||||
|
* @param response The response to wrap.
|
||||||
|
* @param retry If this response corresponds to an original request or a retry.
|
||||||
|
* @return A response object with an {@link OutputStream} that will ignore calls to close.
|
||||||
|
*/
|
||||||
|
private ServletResponse closeShield(ServletResponse response, boolean retry) {
|
||||||
|
if (testMode && !retry) {
|
||||||
|
return new HttpServletResponseWrapper((HttpServletResponse) response) {
|
||||||
|
ServletOutputStream stream;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ServletOutputStream getOutputStream() throws IOException {
|
||||||
|
// Lazy stream creation
|
||||||
|
if (stream == null) {
|
||||||
|
stream = new ServletOutputStreamWrapper(super.getOutputStream()) {
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
assert false : "Attempted close of response output stream.";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package org.apache.solr.servlet;
|
package org.apache.solr.servlet;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -41,6 +42,7 @@ import java.util.Map;
|
||||||
import org.apache.commons.fileupload.FileItem;
|
import org.apache.commons.fileupload.FileItem;
|
||||||
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
|
||||||
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
import org.apache.commons.fileupload.servlet.ServletFileUpload;
|
||||||
|
import org.apache.commons.io.input.CloseShieldInputStream;
|
||||||
import org.apache.lucene.util.IOUtils;
|
import org.apache.lucene.util.IOUtils;
|
||||||
import org.apache.solr.common.SolrException;
|
import org.apache.solr.common.SolrException;
|
||||||
import org.apache.solr.common.SolrException.ErrorCode;
|
import org.apache.solr.common.SolrException.ErrorCode;
|
||||||
|
@ -484,7 +486,8 @@ public class SolrRequestParsers
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public InputStream getStream() throws IOException {
|
public InputStream getStream() throws IOException {
|
||||||
return req.getInputStream();
|
// Protect container owned streams from being closed by us, see SOLR-8933
|
||||||
|
return new CloseShieldInputStream(req.getInputStream());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,7 +621,8 @@ public class SolrRequestParsers
|
||||||
final Charset charset = (cs == null) ? StandardCharsets.UTF_8 : Charset.forName(cs);
|
final Charset charset = (cs == null) ? StandardCharsets.UTF_8 : Charset.forName(cs);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
in = FastInputStream.wrap( in == null ? req.getInputStream() : in);
|
// Protect container owned streams from being closed by us, see SOLR-8933
|
||||||
|
in = FastInputStream.wrap( in == null ? new CloseShieldInputStream(req.getInputStream()) : in );
|
||||||
|
|
||||||
final long bytesRead = parseFormDataContent(in, maxLength, charset, map, false);
|
final long bytesRead = parseFormDataContent(in, maxLength, charset, map, false);
|
||||||
if (bytesRead == 0L && totalLength > 0L) {
|
if (bytesRead == 0L && totalLength > 0L) {
|
||||||
|
@ -737,7 +741,9 @@ public class SolrRequestParsers
|
||||||
if (formdata.isFormData(req)) {
|
if (formdata.isFormData(req)) {
|
||||||
String userAgent = req.getHeader("User-Agent");
|
String userAgent = req.getHeader("User-Agent");
|
||||||
boolean isCurl = userAgent != null && userAgent.startsWith("curl/");
|
boolean isCurl = userAgent != null && userAgent.startsWith("curl/");
|
||||||
FastInputStream input = FastInputStream.wrap( req.getInputStream() );
|
|
||||||
|
// Protect container owned streams from being closed by us, see SOLR-8933
|
||||||
|
FastInputStream input = FastInputStream.wrap( new CloseShieldInputStream(req.getInputStream()) );
|
||||||
|
|
||||||
if (isCurl) {
|
if (isCurl) {
|
||||||
SolrParams params = autodetect(req, streams, input);
|
SolrParams params = autodetect(req, streams, input);
|
||||||
|
|
|
@ -63,7 +63,8 @@ public class JettyWebappTest extends SolrTestCaseJ4
|
||||||
super.setUp();
|
super.setUp();
|
||||||
System.setProperty("solr.solr.home", SolrJettyTestBase.legacyExampleCollection1SolrHome());
|
System.setProperty("solr.solr.home", SolrJettyTestBase.legacyExampleCollection1SolrHome());
|
||||||
System.setProperty("tests.shardhandler.randomSeed", Long.toString(random().nextLong()));
|
System.setProperty("tests.shardhandler.randomSeed", Long.toString(random().nextLong()));
|
||||||
|
System.setProperty("solr.tests.doContainerStreamCloseAssert", "false");
|
||||||
|
|
||||||
File dataDir = createTempDir().toFile();
|
File dataDir = createTempDir().toFile();
|
||||||
dataDir.mkdirs();
|
dataDir.mkdirs();
|
||||||
|
|
||||||
|
@ -94,6 +95,7 @@ public class JettyWebappTest extends SolrTestCaseJ4
|
||||||
} catch( Exception ex ) {}
|
} catch( Exception ex ) {}
|
||||||
System.clearProperty("tests.shardhandler.randomSeed");
|
System.clearProperty("tests.shardhandler.randomSeed");
|
||||||
System.clearProperty("solr.data.dir");
|
System.clearProperty("solr.data.dir");
|
||||||
|
System.clearProperty("solr.tests.doContainerStreamCloseAssert");
|
||||||
super.tearDown();
|
super.tearDown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue