Merge remote-tracking branch 'airsonic/pr/898'

Conflicts:
	airsonic-main/src/main/java/org/airsonic/player/controller/StreamController.java
master
Andrew DeMaria 5 years ago
commit ab33b34a67
No known key found for this signature in database
GPG Key ID: 0A3F5E91F8364EDF
  1. 7
      airsonic-main/pom.xml
  2. 23
      airsonic-main/src/main/java/org/airsonic/player/controller/StreamController.java
  3. 2
      airsonic-main/src/main/java/org/airsonic/player/io/PlayQueueInputStream.java
  4. 19
      airsonic-main/src/main/java/org/airsonic/player/spring/LoggingExceptionResolver.java
  5. 27
      airsonic-main/src/main/java/org/airsonic/player/util/Util.java

@ -493,6 +493,13 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- Provided by the servlet container, but found by dependency:analyze even if used via reflection -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-io</artifactId>
<scope>provided</scope>
</dependency>
<dependency> <dependency>
<groupId>com.fasterxml.jackson.core</groupId> <groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId> <artifactId>jackson-core</artifactId>

@ -107,7 +107,7 @@ public class StreamController {
playQueue.addFiles(false, playlistService.getFilesInPlaylist(playlistId)); playQueue.addFiles(false, playlistService.getFilesInPlaylist(playlistId));
player.setPlayQueue(playQueue); player.setPlayQueue(playQueue);
Util.setContentLength(response, playQueue.length()); Util.setContentLength(response, playQueue.length());
LOG.info("Incoming Podcast request for playlist " + playlistId); LOG.info("{}: Incoming Podcast request for playlist {}", request.getRemoteAddr(), playlistId);
} }
response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Origin", "*");
@ -164,7 +164,7 @@ public class StreamController {
range = getRange(request, file); range = getRange(request, file);
if (settingsService.isEnableSeek() && range != null && !file.isVideo()) { if (settingsService.isEnableSeek() && range != null && !file.isVideo()) {
LOG.info("Got HTTP range: " + range); LOG.info("{}: Got HTTP range: {}", request.getRemoteAddr(), range);
response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
Util.setContentLength(response, range.isClosed() ? range.size() : fileLength - range.getFirstBytePos()); Util.setContentLength(response, range.isClosed() ? range.size() : fileLength - range.getFirstBytePos());
long lastBytePos = range.getLastBytePos() != null ? range.getLastBytePos() : fileLength - 1; long lastBytePos = range.getLastBytePos() != null ? range.getLastBytePos() : fileLength - 1;
@ -248,12 +248,22 @@ public class StreamController {
} }
} }
} }
} catch (Exception err) { } catch (IOException e) {
if("org.apache.catalina.connector.ClientAbortException".equals(err.getClass().getName())) {
LOG.info("org.apache.catalina.connector.ClientAbortException: Connection reset"); // This happens often and outside of the control of the server, so
// we catch Tomcat/Jetty "connection aborted by client" exceptions
// and display a short error message.
boolean shouldCatch = false;
shouldCatch |= Util.isInstanceOfClassName(e, "org.apache.catalina.connector.ClientAbortException");
shouldCatch |= Util.isInstanceOfClassName(e, "org.eclipse.jetty.io.EofException");
if (shouldCatch) {
LOG.info("{}: Client unexpectedly closed connection while loading {} ({})", request.getRemoteAddr(), Util.getURLForRequest(request), e.getCause().toString());
return; return;
} }
LOG.error("Error occurred in handleRequest.", err);
// Rethrow the exception in all other cases
throw e;
} finally { } finally {
if (status != null) { if (status != null) {
securityService.updateUserByteCounts(user, status.getBytesTransfered(), 0L, 0L); securityService.updateUserByteCounts(user, status.getBytesTransfered(), 0L, 0L);
@ -428,5 +438,4 @@ public class StreamController {
out.write(buf); out.write(buf);
out.flush(); out.flush();
} }
} }

@ -117,7 +117,7 @@ public class PlayQueueInputStream extends InputStream {
close(); close();
} else if (!file.equals(currentFile)) { } else if (!file.equals(currentFile)) {
close(); close();
LOG.info(player.getUsername() + " listening to \"" + FileUtil.getShortPath(file.getFile()) + "\""); LOG.info("{}: {} listening to {}", player.getIpAddress(), player.getUsername(), FileUtil.getShortPath(file.getFile()));
mediaFileService.incrementPlayCount(file); mediaFileService.incrementPlayCount(file);
// Don't scrobble REST players (except Sonos) // Don't scrobble REST players (except Sonos)

@ -1,5 +1,6 @@
package org.airsonic.player.spring; package org.airsonic.player.spring;
import org.airsonic.player.util.Util;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
@ -11,13 +12,25 @@ import javax.servlet.http.HttpServletResponse;
public class LoggingExceptionResolver implements HandlerExceptionResolver, Ordered { public class LoggingExceptionResolver implements HandlerExceptionResolver, Ordered {
private static final Logger logger = LoggerFactory.getLogger(LoggingExceptionResolver.class); private static final Logger LOG = LoggerFactory.getLogger(LoggingExceptionResolver.class);
@Override @Override
public ModelAndView resolveException( public ModelAndView resolveException(
HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e HttpServletRequest request, HttpServletResponse response, Object o, Exception e
) { ) {
logger.error("Exception occurred", e); // This happens often and outside of the control of the server, so
// we catch Tomcat/Jetty "connection aborted by client" exceptions
// and display a short error message.
boolean shouldCatch = false;
shouldCatch |= Util.isInstanceOfClassName(e, "org.apache.catalina.connector.ClientAbortException");
shouldCatch |= Util.isInstanceOfClassName(e, "org.eclipse.jetty.io.EofException");
if (shouldCatch) {
LOG.info("{}: Client unexpectedly closed connection while loading {} ({})", request.getRemoteAddr(), Util.getURLForRequest(request), e.getCause().toString());
return null;
}
// Display a full stack trace in all other cases
LOG.error("{}: An exception occurred while loading {}", request.getRemoteAddr(), Util.getURLForRequest(request), e);
return null; return null;
} }

@ -25,6 +25,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import javax.servlet.ServletResponse; import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList; import java.util.ArrayList;
@ -117,4 +118,30 @@ public final class Util {
return ""; return "";
} }
} }
/**
* Return a complete URL for the given HTTP request,
* including the query string.
*
* @param request An HTTP request instance
* @return The associated URL
*/
public static String getURLForRequest(HttpServletRequest request) {
String url = request.getRequestURL().toString();
String queryString = request.getQueryString();
if (queryString != null && queryString.length() > 0) url += "?" + queryString;
return url;
}
/**
* Return true if the given object is an instance of the class name in argument.
* If the class doesn't exist, returns false.
*/
public static boolean isInstanceOfClassName(Object o, String className) {
try {
return Class.forName(className).isInstance(o);
} catch (ClassNotFoundException e) {
return false;
}
}
} }

Loading…
Cancel
Save