Compare commits

...

10 Commits

Author SHA1 Message Date
Mike Primm 1c32aebff9 Set to 0.19.1 - need bug fix release 2011-06-29 21:10:43 -05:00
Mike Primm 1102c08b3e Don't throw exception on bogus absolute path (http://xxx//blah) 2011-06-29 14:16:12 -05:00
Mike Primm e6a8e54172 Add better URI path normalization, option to allow symlinks in web
path
2011-06-29 13:40:02 -05:00
Mike Primm e2b55c3b54 Add some cleanup to help avoid exceptions on /reload and shutdown/disable 2011-06-29 01:37:09 -05:00
Mike Primm faceab68f1 Fix WorldGuard regions support to include WG5 polygon support 2011-06-29 00:43:39 -05:00
Mike Primm 2863dd0acc Put timeout on read lock used by web server - make sure it can't be indefinite 2011-06-28 22:33:11 -05:00
Mike Primm 48fea32500 Tighten up lock release logic on I/O and other exceptions
Make version in plugin.yml string so that 0.20 isn't 0.2
2011-06-28 22:13:42 -05:00
Mike Primm f118ada39e Fix 'visibleregions' option on JSON (gotta kill those parallel code
paths at some point....)
2011-06-28 11:00:05 -05:00
Mike Primm edf898ae1a Fix "center" processing - broke it with URL args change :< 2011-06-27 20:38:26 -05:00
FrozenCow bf29c09522 Changed version to 0.20. 2011-06-27 21:44:12 +02:00
16 changed files with 349 additions and 201 deletions
+3
View File
@@ -106,6 +106,9 @@ webserver-port: 8123
# Disables Webserver portion of Dynmap (Advanced users only)
disable-webserver: false
# Enable/disable having the web server allow symbolic links (true=compatible with existing code, false=more secure (default))
allow-symlinks: true
# Period between tile renders for fullrender, in seconds (non-zero to pace fullrenders, lessen CPU load)
timesliceinterval: 0.0
+1 -1
View File
@@ -2,7 +2,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>org.dynmap</groupId>
<artifactId>dynmap</artifactId>
<version>0.19</version>
<version>0.19.1</version>
<name>dynmap</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+7 -3
View File
@@ -136,10 +136,14 @@ public class DynmapPlugin extends JavaPlugin {
}
}
int port = configuration.getInteger("webserver-port", 8123);
boolean allow_symlinks = configuration.getBoolean("allow-symlinks", false);
if(allow_symlinks)
Log.verboseinfo("Web server is permitting symbolic links");
else
Log.verboseinfo("Web server is not permitting symbolic links");
webServer = new HttpServer(bindAddress, port);
webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web"))));
webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory));
webServer.handlers.put("/", new FilesystemHandler(getFile(configuration.getString("webpath", "web")), allow_symlinks));
webServer.handlers.put("/tiles/", new FilesystemHandler(tilesDirectory, allow_symlinks));
webServer.handlers.put("/up/configuration", new ClientConfigurationHandler(this));
}
+25 -21
View File
@@ -301,8 +301,9 @@ public class DynmapWorld {
im = ImageIO.read(f);
} catch (IOException e) {
} catch (IndexOutOfBoundsException e) {
} finally {
FileLockManager.releaseReadLock(f);
}
FileLockManager.releaseReadLock(f);
if(im != null) {
im.getRGB(0, 0, width, height, argb, 0, width); /* Read data */
im.flush();
@@ -333,27 +334,30 @@ public class DynmapWorld {
}
}
FileLockManager.getWriteLock(zf);
TileHashManager hashman = MapManager.mapman.hashman;
long crc = hashman.calculateTileHash(kzIm.argb_buf); /* Get hash of tile */
int tilex = ztx/step/2;
int tiley = ty/step/2;
String key = world.getName()+".z"+pd.zoomprefix+pd.baseprefix;
if((!zf.exists()) || (crc != MapManager.mapman.hashman.getImageHashCode(key, null, tilex, tiley))) {
try {
if(!zf.getParentFile().exists())
zf.getParentFile().mkdirs();
FileLockManager.imageIOWrite(zIm, "png", zf);
Debug.debug("Saved zoom-out tile at " + zf.getPath());
} catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e);
try {
TileHashManager hashman = MapManager.mapman.hashman;
long crc = hashman.calculateTileHash(kzIm.argb_buf); /* Get hash of tile */
int tilex = ztx/step/2;
int tiley = ty/step/2;
String key = world.getName()+".z"+pd.zoomprefix+pd.baseprefix;
if((!zf.exists()) || (crc != MapManager.mapman.hashman.getImageHashCode(key, null, tilex, tiley))) {
try {
if(!zf.getParentFile().exists())
zf.getParentFile().mkdirs();
FileLockManager.imageIOWrite(zIm, "png", zf);
Debug.debug("Saved zoom-out tile at " + zf.getPath());
} catch (IOException e) {
Debug.error("Failed to save zoom-out tile: " + zf.getName(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save zoom-out tile (NullPointerException): " + zf.getName(), e);
}
hashman.updateHashCode(key, null, tilex, tiley, crc);
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
}
hashman.updateHashCode(key, null, tilex, tiley, crc);
MapManager.mapman.pushUpdate(this.world, new Client.Tile(zfname));
enqueueZoomOutUpdate(zf, pd.zoomlevel+1);
} finally {
FileLockManager.releaseWriteLock(zf);
KzedMap.freeBufferedImage(kzIm);
}
FileLockManager.releaseWriteLock(zf);
KzedMap.freeBufferedImage(kzIm);
}
}
+30 -25
View File
@@ -10,6 +10,7 @@ import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
@@ -99,29 +100,36 @@ public class MapManager {
@Override
public void execute(final Runnable r) {
final Runnable rr = r;
super.execute(new Runnable() {
public void run() {
try {
try {
super.execute(new Runnable() {
public void run() {
try {
r.run();
} catch (Exception x) {
Log.severe("Exception during render job: " + r);
x.printStackTrace();
} catch (Exception x) {
Log.severe("Exception during render job: " + r);
x.printStackTrace();
}
}
}
});
});
} catch (RejectedExecutionException rxe) { /* Pool shutdown - nominal for reload or unload */
}
}
@Override
public ScheduledFuture<?> schedule(final Runnable command, long delay, TimeUnit unit) {
return super.schedule(new Runnable() {
public void run() {
try {
command.run();
} catch (Exception x) {
Log.severe("Exception during render job: " + command);
x.printStackTrace();
try {
return super.schedule(new Runnable() {
public void run() {
try {
command.run();
} catch (Exception x) {
Log.severe("Exception during render job: " + command);
x.printStackTrace();
}
}
}
}, delay, unit);
}, delay, unit);
} catch (RejectedExecutionException rxe) {
return null; /* Pool shut down when we reload or unload */
}
}
}
/* This always runs on render pool threads - no bukkit calls from here */
@@ -137,7 +145,7 @@ public class MapManager {
MapTile tile = null;
int rendercnt = 0;
CommandSender sender;
long starttime;
long timeaccum;
/* Full world, all maps render */
FullWorldRenderState(DynmapWorld dworld, Location l, CommandSender sender) {
@@ -173,7 +181,7 @@ public class MapManager {
/* If render queue is empty, start next map */
if(renderQueue.isEmpty()) {
if(map_index >= 0) { /* Finished a map? */
double msecpertile = (double)(tstart - starttime) / (double)((rendercnt>0)?rendercnt:1);
double msecpertile = (double)timeaccum / (double)((rendercnt>0)?rendercnt:1);
sender.sendMessage("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' of world '" +
world.world.getName() + "' completed - " + rendercnt + " tiles rendered (" + String.format("%.2f", msecpertile) + " msec/tile).");
}
@@ -187,7 +195,6 @@ public class MapManager {
return;
}
map = world.maps.get(map_index);
starttime = System.currentTimeMillis();
/* Now, prime the render queue */
for (MapTile mt : map.getTiles(loc)) {
@@ -241,8 +248,9 @@ public class MapManager {
found.remove(tile);
if(!cache.isEmpty()) {
rendercnt++;
timeaccum += System.currentTimeMillis() - tstart;
if((rendercnt % 100) == 0) {
double msecpertile = (double)(System.currentTimeMillis() - starttime) / (double)rendercnt;
double msecpertile = (double)timeaccum / (double)rendercnt;
sender.sendMessage("Full render of map '" + world.maps.get(map_index).getClass().getSimpleName() + "' on world '" +
w.getName() + "' in progress - " + rendercnt + " tiles rendered (" + String.format("%.2f", msecpertile) + " msec/tile).");
}
@@ -496,10 +504,7 @@ public class MapManager {
}
public void stopRendering() {
if(renderpool != null) {
renderpool.shutdown();
renderpool = null;
}
renderpool.shutdown();
tileQueue.stop();
}
+48 -42
View File
@@ -271,61 +271,67 @@ public class FlatMap extends MapType {
}
}
/* Test to see if we're unchanged from older tile */
FileLockManager.getWriteLock(outputFile);
TileHashManager hashman = MapManager.mapman.hashman;
long crc = hashman.calculateTileHash(argb_buf);
boolean tile_update = false;
if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), null, t.x, t.y))) {
/* Wrap buffer as buffered image */
Debug.debug("saving image " + outputFile.getPath());
if(!outputFile.getParentFile().exists())
outputFile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im.buf_img, "png", outputFile);
} catch (IOException e) {
Debug.error("Failed to save image: " + outputFile.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e);
FileLockManager.getWriteLock(outputFile);
try {
if((!outputFile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), null, t.x, t.y))) {
/* Wrap buffer as buffered image */
Debug.debug("saving image " + outputFile.getPath());
if(!outputFile.getParentFile().exists())
outputFile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im.buf_img, "png", outputFile);
} catch (IOException e) {
Debug.error("Failed to save image: " + outputFile.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + outputFile.getPath(), e);
}
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
hashman.updateHashCode(tile.getKey(), null, t.x, t.y, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile);
tile_update = true;
}
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getFilename()));
hashman.updateHashCode(tile.getKey(), null, t.x, t.y, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(outputFile);
tile_update = true;
else {
Debug.debug("skipping image " + outputFile.getPath() + " - hash match");
}
} finally {
FileLockManager.releaseWriteLock(outputFile);
KzedMap.freeBufferedImage(im);
}
else {
Debug.debug("skipping image " + outputFile.getPath() + " - hash match");
}
KzedMap.freeBufferedImage(im);
FileLockManager.releaseWriteLock(outputFile);
MapManager.mapman.updateStatistics(tile, null, true, tile_update, !rendered);
/* If day too, handle it */
if(night_and_day) {
File dayfile = new File(tile.getDynmapWorld().worldtilepath, tile.getDayFilename());
FileLockManager.getWriteLock(dayfile);
crc = hashman.calculateTileHash(argb_buf_day);
if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), "day", t.x, t.y))) {
Debug.debug("saving image " + dayfile.getPath());
if(!dayfile.getParentFile().exists())
dayfile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im_day.buf_img, "png", dayfile);
} catch (IOException e) {
Debug.error("Failed to save image: " + dayfile.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + dayfile.getPath(), e);
FileLockManager.getWriteLock(dayfile);
try {
if((!dayfile.exists()) || (crc != hashman.getImageHashCode(tile.getKey(), "day", t.x, t.y))) {
Debug.debug("saving image " + dayfile.getPath());
if(!dayfile.getParentFile().exists())
dayfile.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(im_day.buf_img, "png", dayfile);
} catch (IOException e) {
Debug.error("Failed to save image: " + dayfile.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + dayfile.getPath(), e);
}
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getDayFilename()));
hashman.updateHashCode(tile.getKey(), "day", t.x, t.y, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(dayfile);
tile_update = true;
}
MapManager.mapman.pushUpdate(tile.getWorld(), new Client.Tile(tile.getDayFilename()));
hashman.updateHashCode(tile.getKey(), "day", t.x, t.y, crc);
tile.getDynmapWorld().enqueueZoomOutUpdate(dayfile);
tile_update = true;
else {
Debug.debug("skipping image " + dayfile.getPath() + " - hash match");
tile_update = false;
}
} finally {
FileLockManager.releaseWriteLock(dayfile);
KzedMap.freeBufferedImage(im_day);
}
else {
Debug.debug("skipping image " + dayfile.getPath() + " - hash match");
tile_update = false;
}
KzedMap.freeBufferedImage(im_day);
FileLockManager.releaseWriteLock(dayfile);
MapManager.mapman.updateStatistics(tile, "day", true, tile_update, !rendered);
}
@@ -256,29 +256,32 @@ public class DefaultTileRenderer implements MapTileRenderer {
int oy = (mtile.py == zmtile.getTileY())?0:KzedMap.tileHeight/2;
/* Test to see if we're unchanged from older tile */
FileLockManager.getWriteLock(fname);
TileHashManager hashman = MapManager.mapman.hashman;
long crc = hashman.calculateTileHash(img.argb_buf);
boolean updated_fname = false;
int tx = mtile.px/KzedMap.tileWidth;
int ty = mtile.py/KzedMap.tileHeight;
if((!fname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), null, tx, ty))) {
Debug.debug("saving image " + fname.getPath());
if(!fname.getParentFile().exists())
fname.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(img.buf_img, "png", fname);
} catch (IOException e) {
Debug.error("Failed to save image: " + fname.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e);
FileLockManager.getWriteLock(fname);
try {
if((!fname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), null, tx, ty))) {
Debug.debug("saving image " + fname.getPath());
if(!fname.getParentFile().exists())
fname.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(img.buf_img, "png", fname);
} catch (IOException e) {
Debug.error("Failed to save image: " + fname.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + fname.getPath(), e);
}
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getFilename()));
hashman.updateHashCode(mtile.getKey(), null, tx, ty, crc);
updated_fname = true;
}
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getFilename()));
hashman.updateHashCode(mtile.getKey(), null, tx, ty, crc);
updated_fname = true;
} finally {
FileLockManager.releaseWriteLock(fname);
KzedMap.freeBufferedImage(img);
}
KzedMap.freeBufferedImage(img);
FileLockManager.releaseWriteLock(fname);
MapManager.mapman.updateStatistics(mtile, null, true, updated_fname, !rendered);
mtile.file = fname;
@@ -287,25 +290,28 @@ public class DefaultTileRenderer implements MapTileRenderer {
File dfname = new File(mtile.getDynmapWorld().worldtilepath, mtile.getDayFilename());
if(img_day != null) {
FileLockManager.getWriteLock(dfname);
crc = hashman.calculateTileHash(img.argb_buf);
if((!dfname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), "day", tx, ty))) {
Debug.debug("saving image " + dfname.getPath());
if(!dfname.getParentFile().exists())
dfname.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(img_day.buf_img, "png", dfname);
} catch (IOException e) {
Debug.error("Failed to save image: " + dfname.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + dfname.getPath(), e);
FileLockManager.getWriteLock(dfname);
try {
if((!dfname.exists()) || (crc != hashman.getImageHashCode(mtile.getKey(), "day", tx, ty))) {
Debug.debug("saving image " + dfname.getPath());
if(!dfname.getParentFile().exists())
dfname.getParentFile().mkdirs();
try {
FileLockManager.imageIOWrite(img_day.buf_img, "png", dfname);
} catch (IOException e) {
Debug.error("Failed to save image: " + dfname.getPath(), e);
} catch (java.lang.NullPointerException e) {
Debug.error("Failed to save image (NullPointerException): " + dfname.getPath(), e);
}
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getDayFilename()));
hashman.updateHashCode(mtile.getKey(), "day", tx, ty, crc);
updated_dfname = true;
}
MapManager.mapman.pushUpdate(mtile.getWorld(), new Client.Tile(mtile.getDayFilename()));
hashman.updateHashCode(mtile.getKey(), "day", tx, ty, crc);
updated_dfname = true;
} finally {
FileLockManager.releaseWriteLock(dfname);
KzedMap.freeBufferedImage(img_day);
}
KzedMap.freeBufferedImage(img_day);
FileLockManager.releaseWriteLock(dfname);
MapManager.mapman.updateStatistics(mtile, "day", true, updated_dfname, !rendered);
}
@@ -313,30 +319,36 @@ public class DefaultTileRenderer implements MapTileRenderer {
// make the zoomed tile here
boolean ztile_updated = false;
FileLockManager.getWriteLock(zoomFile);
if(updated_fname || (!zoomFile.exists())) {
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
MapManager.mapman.pushUpdate(zmtile.getWorld(),
try {
if(updated_fname || (!zoomFile.exists())) {
saveZoomedTile(zmtile, zoomFile, zimg, ox, oy, null);
MapManager.mapman.pushUpdate(zmtile.getWorld(),
new Client.Tile(zmtile.getFilename()));
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile);
ztile_updated = true;
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile);
ztile_updated = true;
}
} finally {
FileLockManager.releaseWriteLock(zoomFile);
KzedMap.freeBufferedImage(zimg);
}
KzedMap.freeBufferedImage(zimg);
FileLockManager.releaseWriteLock(zoomFile);
MapManager.mapman.updateStatistics(zmtile, null, true, ztile_updated, !rendered);
if(zimg_day != null) {
File zoomFile_day = new File(zmtile.getDynmapWorld().worldtilepath, zmtile.getDayFilename());
ztile_updated = false;
FileLockManager.getWriteLock(zoomFile_day);
if(updated_dfname || (!zoomFile_day.exists())) {
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
MapManager.mapman.pushUpdate(zmtile.getWorld(),
try {
if(updated_dfname || (!zoomFile_day.exists())) {
saveZoomedTile(zmtile, zoomFile_day, zimg_day, ox, oy, "day");
MapManager.mapman.pushUpdate(zmtile.getWorld(),
new Client.Tile(zmtile.getDayFilename()));
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile_day);
ztile_updated = true;
zmtile.getDynmapWorld().enqueueZoomOutUpdate(zoomFile_day);
ztile_updated = true;
}
} finally {
FileLockManager.releaseWriteLock(zoomFile_day);
KzedMap.freeBufferedImage(zimg_day);
}
KzedMap.freeBufferedImage(zimg_day);
FileLockManager.releaseWriteLock(zoomFile_day);
MapManager.mapman.updateStatistics(zmtile, "day", true, ztile_updated, !rendered);
}
}
@@ -4,6 +4,9 @@ import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.bukkit.World;
@@ -67,6 +70,19 @@ public class RegionsComponent extends ClientComponent {
File webWorldPath = new File(plugin.getWebPath()+"/standalone/", outputFileName);
Map<?, ?> regionData = (Map<?, ?>) regionConfig.getProperty(configuration.getString("basenode", "regions"));
/* See if we have explicit list of regions to report - limit to this list if we do */
List<String> idlist = configuration.getStrings("visibleregions", null);
if(idlist != null) {
@SuppressWarnings("unchecked")
HashSet<String> ids = new HashSet<String>((Collection<? extends String>) regionData.keySet());
for(String id : ids) {
/* If not in list, remove it */
if(!idlist.contains(id)) {
regionData.remove(id);
}
}
}
if (webWorldPath.isAbsolute())
outputFile = webWorldPath;
else {
@@ -18,7 +18,7 @@ public class FileLockManager {
* Get write lock on file - exclusive lock, no other writers or readers
* @throws InterruptedException
*/
public static void getWriteLock(File f) {
public static boolean getWriteLock(File f) {
String fn = f.getPath();
synchronized(lock) {
boolean got_lock = false;
@@ -29,6 +29,7 @@ public class FileLockManager {
lock.wait();
} catch (InterruptedException ix) {
Log.severe("getWriteLock(" + fn + ") interrupted");
return false;
}
}
else {
@@ -38,6 +39,7 @@ public class FileLockManager {
}
}
//Log.info("getWriteLock(" + f + ")");
return true;
}
/**
* Release write lock
@@ -60,10 +62,17 @@ public class FileLockManager {
/**
* Get read lock on file - multiple readers allowed, blocks writers
*/
public static void getReadLock(File f) {
public static boolean getReadLock(File f) {
return getReadLock(f, -1);
}
/**
* Get read lock on file - multiple readers allowed, blocks writers - with timeout (msec)
*/
public static boolean getReadLock(File f, long timeout) {
String fn = f.getPath();
synchronized(lock) {
boolean got_lock = false;
boolean first_wait = true;
while(!got_lock) {
Integer lockcnt = filelocks.get(fn); /* Get lock count */
if(lockcnt == null) {
@@ -76,14 +85,23 @@ public class FileLockManager {
}
else { /* Write lock in place */
try {
lock.wait();
if((timeout > 0) && (!first_wait)) { /* We already waited */
return false;
}
if(timeout < 0)
lock.wait();
else
lock.wait(timeout);
first_wait = false;
} catch (InterruptedException ix) {
Log.severe("getReadLock(" + fn + ") interrupted");
return false;
}
}
}
}
//Log.info("getReadLock(" + f + ")");
return true;
}
/**
* Release read lock
+6 -3
View File
@@ -45,13 +45,15 @@ public class HttpServer extends Thread {
public void run() {
try {
ServerSocket s = sock;
while (listeningThread == Thread.currentThread()) {
try {
Socket socket = sock.accept();
Socket socket = s.accept();
HttpServerConnection requestThread = new HttpServerConnection(socket, this);
requestThread.start();
} catch (IOException e) {
Log.info("map WebServer.run() stops with IOException");
if(listeningThread != null) /* Only report this if we didn't initiate the shutdown */
Log.info("map WebServer.run() stops with IOException");
break;
}
}
@@ -63,13 +65,14 @@ public class HttpServer extends Thread {
public void shutdown() {
Log.info("Shutting down webserver...");
listeningThread = null;
try {
if (sock != null) {
sock.close();
sock = null;
}
} catch (IOException e) {
Log.warning("Exception while closing socket for webserver shutdown", e);
}
listeningThread = null;
}
}
@@ -131,7 +131,6 @@ public class HttpServerConnection extends Thread {
HttpRequest request = new HttpRequest();
request.rmtaddr = rmtaddr;
if (!readRequestHeader(in, request)) {
socket.close();
return;
}
@@ -174,7 +173,6 @@ public class HttpServerConnection extends Thread {
}
if (handler == null) {
socket.close();
return;
}
@@ -186,10 +184,7 @@ public class HttpServerConnection extends Thread {
throw e;
} catch (Exception e) {
Log.severe("HttpHandler '" + handler + "' has thown an exception", e);
if (socket != null) {
out.flush();
socket.close();
}
out.flush();
return;
}
@@ -211,37 +206,28 @@ public class HttpServerConnection extends Thread {
if (responseBody == null) {
Debug.debug("Response was given without Content-Length by '" + handler + "' for path '" + request.path + "'.");
out.flush();
socket.close();
return;
}
}
out.flush();
if (!isKeepalive) {
out.flush();
socket.close();
return;
}
out.flush();
}
} catch (IOException e) {
if (socket != null) {
try {
socket.close();
} catch (IOException ex) {
}
}
return;
} catch (Exception e) {
if (socket != null) {
try {
socket.close();
} catch (IOException ex) {
}
}
Log.severe("Exception while handling request: ", e);
e.printStackTrace();
return;
} finally {
if (socket != null) {
try {
socket.close();
} catch (IOException ex) {
}
}
}
}
}
@@ -111,20 +111,13 @@ public abstract class FileHandler implements HttpHandler {
while ((readBytes = fileInput.read(readBuffer)) > 0) {
out.write(readBuffer, 0, readBytes);
}
} catch (IOException e) {
throw e;
} finally {
freeReadBuffer(readBuffer);
if(fileInput != null) {
closeFileInput(path, fileInput);
fileInput = null;
}
}
} catch (Exception e) {
} finally {
if (fileInput != null) {
try { closeFileInput(path, fileInput); fileInput = null; } catch (IOException ex) { }
}
throw e;
}
}
}
@@ -5,6 +5,7 @@ import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import org.dynmap.Log;
import org.dynmap.utils.FileLockManager;
@@ -15,22 +16,37 @@ import org.dynmap.web.HttpResponse;
public class FilesystemHandler extends FileHandler {
private File root;
public FilesystemHandler(File root) {
private boolean allow_symlinks = false;
private String root_path;
public FilesystemHandler(File root, boolean allow_symlinks) {
if (!root.isDirectory())
throw new IllegalArgumentException();
this.root = root;
this.allow_symlinks = allow_symlinks;
this.root_path = root.getAbsolutePath();
}
@Override
protected InputStream getFileInput(String path, HttpRequest request, HttpResponse response) {
if(path == null) return null;
path = getNormalizedPath(path); /* Resolve out relative stuff - nothing allowed above webroot */
File file = new File(root, path);
FileLockManager.getReadLock(file);
if(!file.isFile())
return null;
if(!FileLockManager.getReadLock(file, 5000)) { /* Wait up to 5 seconds for lock */
Log.severe("Timeout waiting for lock on file " + file.getPath());
return null;
}
FileInputStream result = null;
try {
if (file.getCanonicalPath().startsWith(root.getAbsolutePath()) && file.isFile()) {
FileInputStream result;
String fpath;
if(allow_symlinks)
fpath = file.getAbsolutePath();
else
fpath = file.getCanonicalPath();
if (fpath.startsWith(root_path)) {
try {
result = new FileInputStream(file);
} catch (FileNotFoundException e) {
FileLockManager.releaseReadLock(file);
return null;
}
response.fields.put(HttpField.ContentLength, Long.toString(file.length()));
@@ -38,14 +54,42 @@ public class FilesystemHandler extends FileHandler {
}
} catch(IOException ex) {
Log.severe("Unable to get canoical path of requested file.", ex);
} finally {
if(result == null) FileLockManager.releaseReadLock(file);
}
FileLockManager.releaseReadLock(file);
return null;
}
protected void closeFileInput(String path, InputStream in) throws IOException {
super.closeFileInput(path, in);
File file = new File(root, path);
FileLockManager.releaseReadLock(file);
path = getNormalizedPath(path);
try {
super.closeFileInput(path, in);
} finally {
File file = new File(root, path);
FileLockManager.releaseReadLock(file);
}
}
public static String getNormalizedPath(String p) {
p = p.replace('\\', '/');
String[] tok = p.split("/");
int i, j;
for(i = 0, j = 0; i < tok.length; i++) {
if((tok[i] == null) || (tok[i].length() == 0) || (tok[i].equals("."))) {
tok[i] = null;
}
else if(tok[i].equals("..")) {
if(j > 0) { j--; tok[j] = null; }
tok[i] = null;
}
else {
tok[j] = tok[i];
j++;
}
}
String path = "";
for(i = 0; i < j; i++) {
if(tok[i] != null)
path = path + "/" + tok[i];
}
return path;
}
}
+1 -1
View File
@@ -1,6 +1,6 @@
name: dynmap
main: org.dynmap.DynmapPlugin
version: 0.19
version: "0.19.1"
authors: [FrozenCow, mikeprimm, zeeZ]
softdepend: [Permissions]
commands:
+19 -11
View File
@@ -131,18 +131,15 @@ DynMap.prototype = {
if(urlarg != "") {
me.defaultworld.defaultmap = me.defaultworld.maps[urlarg] || me.defaultworld.defaultmap;
}
urlarg = parseInt(me.getParameterByName('x'),10);
if(urlarg != NaN) {
urlarg = me.getIntParameterByName('x');
if(urlarg != null)
me.defaultworld.center.x = urlarg;
}
urlarg = parseInt(me.getParameterByName('y'),10);
if(urlarg != NaN) {
urlarg = me.getIntParameterByName('y');
if(urlarg != null)
me.defaultworld.center.y = urlarg;
}
urlarg = parseInt(me.getParameterByName('z'), 10);
if(urlarg != NaN) {
urlarg = me.getIntParameterByName('z');
if(urlarg != null)
me.defaultworld.center.z = urlarg;
}
},
initialize: function() {
var me = this;
@@ -155,8 +152,9 @@ DynMap.prototype = {
.addClass('map')
.appendTo(container);
var urlzoom = parseInt(me.getParameterByName('zoom'),10);
if(urlzoom != NaN) { me.options.defaultzoom = urlzoom; }
var urlzoom = me.getIntParameterByName('zoom');
if(urlzoom != null)
me.options.defaultzoom = urlzoom;
var map = this.map = new google.maps.Map(mapContainer.get(0), {
zoom: me.options.defaultzoom || 0,
@@ -625,6 +623,16 @@ DynMap.prototype = {
return "";
else
return decodeURIComponent(results[1].replace(/\+/g, " "));
},
getIntParameterByName: function(name) {
var v = this.getParameterByName(name);
if(v != "") {
v = parseInt(v, 10);
if(v != NaN) {
return v;
}
}
return null;
}
// TODO: Enable hash-links.
/* updateLink: function() {
+48 -2
View File
@@ -1,9 +1,55 @@
regionConstructors['polygon'] = function(map, name, region)
{
if(region.points) {
var i;
if(regionCfg.use3dregions) {
var toppts = [];
var botpts = [];
for(i = 0; i < region.points.length; i++) {
toppts.push(map.getProjection().fromWorldToLatLng(region.points[i].x,
region['max-y'], region.points[i].z));
botpts.push(map.getProjection().fromWorldToLatLng(region.points[i].x,
region['min-y'], region.points[i].z));
}
for(i = 0; i < region.points.length; i++) {
regionPolygons[name+'_side'+i] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
paths: [
toppts[i], botpts[i], botpts[(i+1)%region.points.length], toppts[(i+1)%region.points.length]
], map: map }));
google.maps.event.addListener(regionPolygons[name+'_side'+i] , 'click', function(event) {
regionInfo(event, name, region);
});
}
regionPolygons[name+'_bottom'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
paths: botpts, map: map }));
google.maps.event.addListener(regionPolygons[name+'_bottom'] , 'click', function(event) {
regionInfo(event, name, region);
});
regionPolygons[name+'_top'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
paths: toppts, map: map }));
google.maps.event.addListener(regionPolygons[name+'_top'] , 'click', function(event) {
regionInfo(event, name, region);
});
}
else {
var pts = [];
var yy = (region['min-y']+region['max-y'])/2;
for(i = 0; i < region.points.length; i++) {
pts.push(map.getProjection().fromWorldToLatLng(region.points[i].x,
yy, region.points[i].z));
}
regionPolygons[name+'_bottom'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {
paths: pts, map: map }));
google.maps.event.addListener(regionPolygons[name+'_bottom'] , 'click', function(event) {
regionInfo(event, name, region);
});
}
return;
}
if(!region.min || !region.max)
return;
if(region.max.y > 64)
region.max.y = 64;
if(region.max.y <= region.min.y)
region.min.y = region.max.y - 1;
if(regionCfg.use3dregions)
{
regionPolygons[name+'_bottom'] = new google.maps.Polygon($.extend(regionCfg.regionstyle, {