mirror of
https://github.com/zxing/zxing.git
synced 2024-11-10 04:54:04 -08:00
More changes for Elastic Beanstalk -- logging, no need for DoS
git-svn-id: https://zxing.googlecode.com/svn/trunk@2537 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
parent
ceca8b4ff7
commit
6698e919e9
|
@ -56,8 +56,6 @@ import java.util.EnumMap;
|
|||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
|
@ -84,7 +82,6 @@ public final class DecodeServlet extends HttpServlet {
|
|||
// No real reason to deal with more than maybe 2 megapixels
|
||||
private static final int MAX_PIXELS = 1 << 21;
|
||||
private static final byte[] REMAINDER_BUFFER = new byte[8192];
|
||||
private static final long GC_HACK_INTERVAL_MS = 60 * 1000;
|
||||
private static final Map<DecodeHintType,Object> HINTS;
|
||||
private static final Map<DecodeHintType,Object> HINTS_PURE;
|
||||
|
||||
|
@ -97,19 +94,11 @@ public final class DecodeServlet extends HttpServlet {
|
|||
}
|
||||
|
||||
private DiskFileItemFactory diskFileItemFactory;
|
||||
private Timer gcHackTimer;
|
||||
|
||||
@Override
|
||||
public void init(ServletConfig servletConfig) {
|
||||
Logger logger = Logger.getLogger("com.google.zxing");
|
||||
logger.addHandler(new ServletContextLogHandler(servletConfig.getServletContext()));
|
||||
gcHackTimer = new Timer();
|
||||
gcHackTimer.schedule(new TimerTask() {
|
||||
@Override
|
||||
public void run() {
|
||||
System.gc(); // Hack: GC may close these weird stuck CLOSE_WAIT sockets?
|
||||
}
|
||||
}, GC_HACK_INTERVAL_MS, GC_HACK_INTERVAL_MS);
|
||||
diskFileItemFactory = new DiskFileItemFactory();
|
||||
log.info("DecodeServlet configured");
|
||||
}
|
||||
|
@ -120,7 +109,7 @@ public final class DecodeServlet extends HttpServlet {
|
|||
|
||||
String imageURIString = request.getParameter("u");
|
||||
if (imageURIString == null || imageURIString.isEmpty()) {
|
||||
log.fine("URI was empty");
|
||||
log.info("URI was empty");
|
||||
response.sendRedirect("badurl.jspx");
|
||||
return;
|
||||
}
|
||||
|
@ -135,15 +124,11 @@ public final class DecodeServlet extends HttpServlet {
|
|||
try {
|
||||
imageURL = new URI(imageURIString).toURL();
|
||||
} catch (URISyntaxException urise) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("URI was not valid: " + imageURIString);
|
||||
}
|
||||
log.info("URI was not valid: " + imageURIString);
|
||||
response.sendRedirect("badurl.jspx");
|
||||
return;
|
||||
} catch (MalformedURLException mue) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("URI was not valid: " + imageURIString);
|
||||
}
|
||||
log.info("URI was not valid: " + imageURIString);
|
||||
response.sendRedirect("badurl.jspx");
|
||||
return;
|
||||
}
|
||||
|
@ -152,9 +137,7 @@ public final class DecodeServlet extends HttpServlet {
|
|||
try {
|
||||
connection = (HttpURLConnection) imageURL.openConnection();
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("URI could not be opened: " + imageURL);
|
||||
}
|
||||
log.info("URI could not be opened: " + imageURL);
|
||||
response.sendRedirect("badurl.jspx");
|
||||
return;
|
||||
}
|
||||
|
@ -175,9 +158,7 @@ public final class DecodeServlet extends HttpServlet {
|
|||
// javax.net.ssl.SSLPeerUnverifiedException,
|
||||
// org.apache.http.NoHttpResponseException,
|
||||
// org.apache.http.client.ClientProtocolException,
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(ioe.toString());
|
||||
}
|
||||
log.info(ioe.toString());
|
||||
response.sendRedirect("badurl.jspx");
|
||||
return;
|
||||
}
|
||||
|
@ -188,14 +169,12 @@ public final class DecodeServlet extends HttpServlet {
|
|||
is = connection.getInputStream();
|
||||
|
||||
if (connection.getResponseCode() != HttpServletResponse.SC_OK) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("Unsuccessful return code: " + connection.getResponseCode());
|
||||
}
|
||||
log.info("Unsuccessful return code: " + connection.getResponseCode());
|
||||
response.sendRedirect("badurl.jspx");
|
||||
return;
|
||||
}
|
||||
if (connection.getHeaderFieldInt("Content-Length", 0) > MAX_IMAGE_SIZE) {
|
||||
log.fine("Too large");
|
||||
log.info("Too large");
|
||||
response.sendRedirect("badimage.jspx");
|
||||
return;
|
||||
}
|
||||
|
@ -204,9 +183,7 @@ public final class DecodeServlet extends HttpServlet {
|
|||
processStream(is, request, response);
|
||||
|
||||
} catch (IOException ioe) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(ioe.toString());
|
||||
}
|
||||
log.info(ioe.toString());
|
||||
response.sendRedirect("badurl.jspx");
|
||||
} finally {
|
||||
if (is != null) {
|
||||
|
@ -239,7 +216,7 @@ public final class DecodeServlet extends HttpServlet {
|
|||
throws ServletException, IOException {
|
||||
|
||||
if (!ServletFileUpload.isMultipartContent(request)) {
|
||||
log.fine("File upload was not multipart");
|
||||
log.info("File upload was not multipart");
|
||||
response.sendRedirect("badimage.jspx");
|
||||
return;
|
||||
}
|
||||
|
@ -260,16 +237,14 @@ public final class DecodeServlet extends HttpServlet {
|
|||
is.close();
|
||||
}
|
||||
} else {
|
||||
log.fine("Too large");
|
||||
log.info("Too large");
|
||||
response.sendRedirect("badimage.jspx");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (FileUploadException fue) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(fue.toString());
|
||||
}
|
||||
log.info(fue.toString());
|
||||
response.sendRedirect("badimage.jspx");
|
||||
}
|
||||
|
||||
|
@ -283,23 +258,17 @@ public final class DecodeServlet extends HttpServlet {
|
|||
try {
|
||||
image = ImageIO.read(is);
|
||||
} catch (IOException ioe) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(ioe.toString());
|
||||
}
|
||||
log.info(ioe.toString());
|
||||
// Includes javax.imageio.IIOException
|
||||
response.sendRedirect("badimage.jspx");
|
||||
return;
|
||||
} catch (CMMException cmme) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(cmme.toString());
|
||||
}
|
||||
log.info(cmme.toString());
|
||||
// Have seen this in logs
|
||||
response.sendRedirect("badimage.jspx");
|
||||
return;
|
||||
} catch (IllegalArgumentException iae) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine(iae.toString());
|
||||
}
|
||||
log.info(iae.toString());
|
||||
// Have seen this in logs for some JPEGs
|
||||
response.sendRedirect("badimage.jspx");
|
||||
return;
|
||||
|
@ -310,9 +279,7 @@ public final class DecodeServlet extends HttpServlet {
|
|||
}
|
||||
if (image.getHeight() <= 1 || image.getWidth() <= 1 ||
|
||||
image.getHeight() * image.getWidth() > MAX_PIXELS) {
|
||||
if (log.isLoggable(Level.FINE)) {
|
||||
log.fine("Dimensions too large: " + image.getWidth() + 'x' + image.getHeight());
|
||||
}
|
||||
log.info("Dimensions too large: " + image.getWidth() + 'x' + image.getHeight());
|
||||
response.sendRedirect("badimage.jspx");
|
||||
return;
|
||||
}
|
||||
|
@ -413,7 +380,6 @@ public final class DecodeServlet extends HttpServlet {
|
|||
@Override
|
||||
public void destroy() {
|
||||
log.config("DecodeServlet shutting down...");
|
||||
gcHackTimer.cancel();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,129 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed 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 com.google.zxing.web;
|
||||
|
||||
import javax.servlet.Filter;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.FilterConfig;
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* A {@link Filter} that rejects requests from hosts that are sending too many
|
||||
* requests in too short a time.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
public final class DoSFilter implements Filter {
|
||||
|
||||
private static final int MAX_ACCESSES_PER_IP_PER_TIME = 100;
|
||||
private static final long MAX_ACCESS_INTERVAL_MSEC = 60L * 1000L;
|
||||
private static final long UNBAN_INTERVAL_MSEC = 15L * 60L * 1000L;
|
||||
private static final String BAD_IPS_INIT_PARAM = "bad.ips";
|
||||
|
||||
private final IPTrie numRecentAccesses;
|
||||
private final Timer timer;
|
||||
private final Set<String> badIPAddresses;
|
||||
private final Set<String> bannedIPAddresses;
|
||||
private ServletContext context;
|
||||
|
||||
public DoSFilter() {
|
||||
numRecentAccesses = new IPTrie();
|
||||
timer = new Timer("DosFilter reset timer");
|
||||
bannedIPAddresses = Collections.synchronizedSet(new HashSet<String>());
|
||||
badIPAddresses = new HashSet<String>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) {
|
||||
context = filterConfig.getServletContext();
|
||||
timer.scheduleAtFixedRate(new ResetTask(), 0L, MAX_ACCESS_INTERVAL_MSEC);
|
||||
timer.scheduleAtFixedRate(new UnbanTask(), 0L, UNBAN_INTERVAL_MSEC);
|
||||
badIPAddresses.clear();
|
||||
String badIPsString = filterConfig.getInitParameter(BAD_IPS_INIT_PARAM);
|
||||
if (badIPsString != null) {
|
||||
badIPAddresses.addAll(Arrays.asList(badIPsString.split(",")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request,
|
||||
ServletResponse response,
|
||||
FilterChain chain) throws IOException, ServletException {
|
||||
if (isBanned(request)) {
|
||||
HttpServletResponse servletResponse = (HttpServletResponse) response;
|
||||
servletResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
|
||||
} else {
|
||||
chain.doFilter(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isBanned(ServletRequest request) {
|
||||
String remoteIPAddressString = request.getRemoteAddr();
|
||||
if (bannedIPAddresses.contains(remoteIPAddressString) || badIPAddresses.contains(remoteIPAddressString)) {
|
||||
return true;
|
||||
}
|
||||
InetAddress remoteIPAddress;
|
||||
try {
|
||||
remoteIPAddress = InetAddress.getByName(remoteIPAddressString);
|
||||
} catch (UnknownHostException uhe) {
|
||||
context.log("Can't determine host from: " + remoteIPAddressString + "; assuming banned");
|
||||
return true;
|
||||
}
|
||||
if (numRecentAccesses.incrementAndGet(remoteIPAddress) > MAX_ACCESSES_PER_IP_PER_TIME) {
|
||||
context.log("Possible DoS attack from " + remoteIPAddressString);
|
||||
bannedIPAddresses.add(remoteIPAddressString);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
timer.cancel();
|
||||
numRecentAccesses.clear();
|
||||
bannedIPAddresses.clear();
|
||||
badIPAddresses.clear();
|
||||
}
|
||||
|
||||
private final class ResetTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
numRecentAccesses.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private final class UnbanTask extends TimerTask {
|
||||
@Override
|
||||
public void run() {
|
||||
bannedIPAddresses.clear();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright 2008 ZXing authors
|
||||
*
|
||||
* Licensed 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 com.google.zxing.web;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* A trie data structure for storing a set of IP addresses efficiently.
|
||||
*
|
||||
* @author Sean Owen
|
||||
*/
|
||||
final class IPTrie {
|
||||
|
||||
private final IPTrieNode root;
|
||||
|
||||
IPTrie() {
|
||||
root = new IPTrieNode(false);
|
||||
}
|
||||
|
||||
int incrementAndGet(InetAddress ipAddress) {
|
||||
byte[] octets = ipAddress.getAddress();
|
||||
synchronized (root) {
|
||||
IPTrieNode current = root;
|
||||
int max = octets.length - 1;
|
||||
for (int offset = 0; offset < max; offset++) {
|
||||
int index = 0xFF & octets[offset];
|
||||
IPTrieNode child = current.children[index];
|
||||
if (child == null) {
|
||||
child = new IPTrieNode(offset == max - 1);
|
||||
current.children[index] = child;
|
||||
}
|
||||
current = child;
|
||||
}
|
||||
int index = 0xFF & octets[max];
|
||||
current.values[index]++;
|
||||
return current.values[index];
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
synchronized (root) {
|
||||
Arrays.fill(root.children, null);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class IPTrieNode {
|
||||
final IPTrieNode[] children;
|
||||
final int[] values;
|
||||
|
||||
private IPTrieNode(boolean terminal) {
|
||||
if (terminal) {
|
||||
children = null;
|
||||
values = new int[256];
|
||||
} else {
|
||||
children = new IPTrieNode[256];
|
||||
values = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in a new issue