SOLR-8683: Always consume the full request on the server, not just in the case of an error.

This commit is contained in:
markrmiller 2016-02-16 15:48:11 -05:00
parent a40118c9df
commit 9184d52f68
3 changed files with 71 additions and 72 deletions

View File

@ -172,6 +172,9 @@ Bug Fixes
* SOLR-8578: Successful or not, requests are not always fully consumed by Solrj clients and we
count on HttpClient or the JVM. (Mark Miller)
* SOLR-8683: Always consume the full request on the server, not just in the case of an error.
(Mark Miller)
Optimizations
----------------------
* SOLR-7876: Speed up queries and operations that use many terms when timeAllowed has not been

View File

@ -621,13 +621,9 @@ public class HttpSolrCall {
} finally {
try {
if (exp != null) {
try {
SimpleOrderedMap info = new SimpleOrderedMap();
int code = ResponseUtils.getErrorInfo(ex, info, log);
sendError(code, info.toString());
} finally {
consumeInput(req);
}
SimpleOrderedMap info = new SimpleOrderedMap();
int code = ResponseUtils.getErrorInfo(ex, info, log);
sendError(code, info.toString());
}
} finally {
if (core == null && localCore != null) {
@ -642,21 +638,6 @@ public class HttpSolrCall {
response.sendError(code, message);
} catch (EOFException e) {
log.info("Unable to write error response, client closed connection or we are shutting down", e);
} finally {
consumeInput(req);
}
}
// when we send back an error, we make sure we read
// the full client request so that the client does
// not hit a connection reset and we can reuse the
// connection - see SOLR-8453
private void consumeInput(HttpServletRequest req) {
try {
ServletInputStream is = req.getInputStream();
while (!is.isFinished() && is.read() != -1) {}
} catch (IOException e) {
log.info("Could not consume full client request", e);
}
}
@ -743,10 +724,6 @@ public class HttpSolrCall {
//else http HEAD request, nothing to write out, waited this long just to get ContentType
} catch (EOFException e) {
log.info("Unable to write response, client closed connection or we are shutting down", e);
} finally {
if (solrRsp.getException() != null) {
consumeInput(req);
}
}
}

View File

@ -19,6 +19,7 @@ package org.apache.solr.servlet;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
@ -185,58 +186,76 @@ public class SolrDispatchFilter extends BaseSolrFilter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain, boolean retry) throws IOException, ServletException {
if (!(request instanceof HttpServletRequest)) return;
try {
if (cores == null || cores.isShutDown()) {
log.error("Error processing the request. CoreContainer is either not initialized or shutting down.");
throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE,
"Error processing the request. CoreContainer is either not initialized or shutting down.");
}
AtomicReference<ServletRequest> wrappedRequest = new AtomicReference<>();
if (!authenticateRequest(request, response, wrappedRequest)) { // the response and status code have already been sent
return;
}
if (wrappedRequest.get() != null) {
request = wrappedRequest.get();
}
if (cores.getAuthenticationPlugin() != null) {
log.debug("User principal: {}", ((HttpServletRequest)request).getUserPrincipal());
}
// No need to even create the HttpSolrCall object if this path is excluded.
if(excludePatterns != null) {
String requestPath = ((HttpServletRequest) request).getServletPath();
String extraPath = ((HttpServletRequest)request).getPathInfo();
if (extraPath != null) { // In embedded mode, servlet path is empty - include all post-context path here for testing
requestPath += extraPath;
if (cores == null || cores.isShutDown()) {
log.error("Error processing the request. CoreContainer is either not initialized or shutting down.");
throw new SolrException(ErrorCode.SERVICE_UNAVAILABLE,
"Error processing the request. CoreContainer is either not initialized or shutting down.");
}
for (Pattern p : excludePatterns) {
Matcher matcher = p.matcher(requestPath);
if (matcher.lookingAt()) {
chain.doFilter(request, response);
return;
AtomicReference<ServletRequest> wrappedRequest = new AtomicReference<>();
if (!authenticateRequest(request, response, wrappedRequest)) { // the response and status code have already been
// sent
return;
}
if (wrappedRequest.get() != null) {
request = wrappedRequest.get();
}
if (cores.getAuthenticationPlugin() != null) {
log.debug("User principal: {}", ((HttpServletRequest) request).getUserPrincipal());
}
// No need to even create the HttpSolrCall object if this path is excluded.
if (excludePatterns != null) {
String requestPath = ((HttpServletRequest) request).getServletPath();
String extraPath = ((HttpServletRequest) request).getPathInfo();
if (extraPath != null) { // In embedded mode, servlet path is empty - include all post-context path here for
// testing
requestPath += extraPath;
}
for (Pattern p : excludePatterns) {
Matcher matcher = p.matcher(requestPath);
if (matcher.lookingAt()) {
chain.doFilter(request, response);
return;
}
}
}
}
HttpSolrCall call = getHttpSolrCall((HttpServletRequest) request, (HttpServletResponse) response, retry);
ExecutorUtil.setServerThreadFlag(Boolean.TRUE);
try {
Action result = call.call();
switch (result) {
case PASSTHROUGH:
chain.doFilter(request, response);
break;
case RETRY:
doFilter(request, response, chain, true);
break;
case FORWARD:
request.getRequestDispatcher(call.getPath()).forward(request, response);
break;
}
HttpSolrCall call = getHttpSolrCall((HttpServletRequest) request, (HttpServletResponse) response, retry);
ExecutorUtil.setServerThreadFlag(Boolean.TRUE);
try {
Action result = call.call();
switch (result) {
case PASSTHROUGH:
chain.doFilter(request, response);
break;
case RETRY:
doFilter(request, response, chain, true);
break;
case FORWARD:
request.getRequestDispatcher(call.getPath()).forward(request, response);
break;
}
} finally {
call.destroy();
ExecutorUtil.setServerThreadFlag(null);
}
} finally {
call.destroy();
ExecutorUtil.setServerThreadFlag(null);
consumeInputFully((HttpServletRequest) request);
}
}
// we make sure we read the full client request so that the client does
// not hit a connection reset and we can reuse the
// connection - see SOLR-8453 and SOLR-8683
private void consumeInputFully(HttpServletRequest req) {
try {
ServletInputStream is = req.getInputStream();
while (!is.isFinished() && is.read() != -1) {}
} catch (IOException e) {
log.info("Could not consume full client request", e);
}
}