mirror of
https://github.com/2006-Scape/apollo.git
synced 2026-07-06 16:51:37 +00:00
Merge branch 'resource'.
This commit is contained in:
@@ -9,11 +9,13 @@ import io.netty.handler.codec.http.HttpRequest;
|
|||||||
import io.netty.handler.codec.http.HttpResponse;
|
import io.netty.handler.codec.http.HttpResponse;
|
||||||
import io.netty.handler.codec.http.HttpResponseStatus;
|
import io.netty.handler.codec.http.HttpResponseStatus;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apollo.fs.IndexedFileSystem;
|
import org.apollo.fs.IndexedFileSystem;
|
||||||
import org.apollo.update.resource.CombinedResourceProvider;
|
import org.apollo.update.resource.CombinedResourceProvider;
|
||||||
@@ -21,6 +23,8 @@ import org.apollo.update.resource.HypertextResourceProvider;
|
|||||||
import org.apollo.update.resource.ResourceProvider;
|
import org.apollo.update.resource.ResourceProvider;
|
||||||
import org.apollo.update.resource.VirtualResourceProvider;
|
import org.apollo.update.resource.VirtualResourceProvider;
|
||||||
|
|
||||||
|
import com.google.common.base.Charsets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A worker which services HTTP requests.
|
* A worker which services HTTP requests.
|
||||||
*
|
*
|
||||||
@@ -31,7 +35,7 @@ public final class HttpRequestWorker extends RequestWorker<HttpRequest, Resource
|
|||||||
/**
|
/**
|
||||||
* The default character set.
|
* The default character set.
|
||||||
*/
|
*/
|
||||||
private static final Charset CHARACTER_SET = Charset.forName("ISO-8859-1");
|
private static final Charset CHARACTER_SET = Charsets.ISO_8859_1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The value of the server header.
|
* The value of the server header.
|
||||||
@@ -41,7 +45,7 @@ public final class HttpRequestWorker extends RequestWorker<HttpRequest, Resource
|
|||||||
/**
|
/**
|
||||||
* The directory with web files.
|
* The directory with web files.
|
||||||
*/
|
*/
|
||||||
private static final File WWW_DIRECTORY = new File("./data/www/");
|
private static final Path WWW_DIRECTORY = Paths.get("data/www");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the HTTP request worker.
|
* Creates the HTTP request worker.
|
||||||
@@ -50,8 +54,7 @@ public final class HttpRequestWorker extends RequestWorker<HttpRequest, Resource
|
|||||||
* @param fs The file system.
|
* @param fs The file system.
|
||||||
*/
|
*/
|
||||||
public HttpRequestWorker(UpdateDispatcher dispatcher, IndexedFileSystem fs) {
|
public HttpRequestWorker(UpdateDispatcher dispatcher, IndexedFileSystem fs) {
|
||||||
super(dispatcher, new CombinedResourceProvider(new VirtualResourceProvider(fs), new HypertextResourceProvider(
|
super(dispatcher, new CombinedResourceProvider(new VirtualResourceProvider(fs), new HypertextResourceProvider(WWW_DIRECTORY)));
|
||||||
WWW_DIRECTORY)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -115,21 +118,18 @@ public final class HttpRequestWorker extends RequestWorker<HttpRequest, Resource
|
|||||||
@Override
|
@Override
|
||||||
protected void service(ResourceProvider provider, Channel channel, HttpRequest request) throws IOException {
|
protected void service(ResourceProvider provider, Channel channel, HttpRequest request) throws IOException {
|
||||||
String path = request.getUri();
|
String path = request.getUri();
|
||||||
ByteBuffer buf = provider.get(path);
|
Optional<ByteBuffer> buf = provider.get(path);
|
||||||
|
|
||||||
ByteBuf wrapped;
|
|
||||||
HttpResponseStatus status = HttpResponseStatus.OK;
|
HttpResponseStatus status = HttpResponseStatus.OK;
|
||||||
|
|
||||||
String mime = getMimeType(request.getUri());
|
String mime = getMimeType(request.getUri());
|
||||||
|
|
||||||
if (buf == null) {
|
if (!buf.isPresent()) {
|
||||||
status = HttpResponseStatus.NOT_FOUND;
|
status = HttpResponseStatus.NOT_FOUND;
|
||||||
wrapped = createErrorPage(status, "The page you requested could not be found.");
|
|
||||||
mime = "text/html";
|
mime = "text/html";
|
||||||
} else {
|
|
||||||
wrapped = Unpooled.wrappedBuffer(buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ByteBuf wrapped = buf.isPresent() ? Unpooled.wrappedBuffer(buf.get()) : createErrorPage(status, "The page you requested could not be found.");
|
||||||
|
|
||||||
HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), status);
|
HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), status);
|
||||||
|
|
||||||
response.headers().set("Date", new Date());
|
response.headers().set("Date", new Date());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import io.netty.channel.ChannelFutureListener;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apollo.fs.IndexedFileSystem;
|
import org.apollo.fs.IndexedFileSystem;
|
||||||
import org.apollo.net.codec.jaggrab.JagGrabRequest;
|
import org.apollo.net.codec.jaggrab.JagGrabRequest;
|
||||||
@@ -38,12 +39,13 @@ public final class JagGrabRequestWorker extends RequestWorker<JagGrabRequest, Re
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void service(ResourceProvider provider, Channel channel, JagGrabRequest request) throws IOException {
|
protected void service(ResourceProvider provider, Channel channel, JagGrabRequest request) throws IOException {
|
||||||
ByteBuffer buf = provider.get(request.getFilePath());
|
Optional<ByteBuffer> buffer = provider.get(request.getFilePath());
|
||||||
if (buf == null) {
|
|
||||||
channel.close();
|
if (buffer.isPresent()) {
|
||||||
} else {
|
ByteBuf wrapped = Unpooled.wrappedBuffer(buffer.get());
|
||||||
ByteBuf wrapped = Unpooled.wrappedBuffer(buf);
|
|
||||||
channel.writeAndFlush(new JagGrabResponse(wrapped)).addListener(ChannelFutureListener.CLOSE);
|
channel.writeAndFlush(new JagGrabResponse(wrapped)).addListener(ChannelFutureListener.CLOSE);
|
||||||
|
} else {
|
||||||
|
channel.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ package org.apollo.update.resource;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A resource provider composed of multiple resource providers.
|
* A resource provider composed of multiple resource providers.
|
||||||
*
|
*
|
||||||
* @author Graham
|
* @author Graham
|
||||||
*/
|
*/
|
||||||
public final class CombinedResourceProvider extends ResourceProvider {
|
public final class CombinedResourceProvider implements ResourceProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of resource providers.
|
* An array of resource providers.
|
||||||
@@ -30,13 +31,13 @@ public final class CombinedResourceProvider extends ResourceProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer get(String path) throws IOException {
|
public Optional<ByteBuffer> get(String path) throws IOException {
|
||||||
for (ResourceProvider provider : providers) {
|
for (ResourceProvider provider : providers) {
|
||||||
if (provider.accept(path)) {
|
if (provider.accept(path)) {
|
||||||
return provider.get(path);
|
return provider.get(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,62 +1,67 @@
|
|||||||
package org.apollo.update.resource;
|
package org.apollo.update.resource;
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.nio.channels.FileChannel;
|
||||||
import java.nio.channels.FileChannel.MapMode;
|
import java.nio.channels.FileChannel.MapMode;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link ResourceProvider} which provides additional hypertext resources.
|
* A {@link ResourceProvider} which provides additional hypertext resources.
|
||||||
*
|
*
|
||||||
* @author Graham
|
* @author Graham
|
||||||
*/
|
*/
|
||||||
public final class HypertextResourceProvider extends ResourceProvider {
|
public final class HypertextResourceProvider implements ResourceProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base directory from which documents are served.
|
* The base {@link Path} from which documents are served.
|
||||||
*/
|
*/
|
||||||
private final File base;
|
private final Path base;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new hypertext resource provider with the specified base directory.
|
* Creates a new hypertext resource provider with the specified base directory.
|
||||||
*
|
*
|
||||||
* @param base The base directory.
|
* @param base The base directory.
|
||||||
*/
|
*/
|
||||||
public HypertextResourceProvider(File base) {
|
public HypertextResourceProvider(Path base) {
|
||||||
this.base = base;
|
this.base = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(String path) throws IOException {
|
public boolean accept(String path) throws IOException {
|
||||||
File file = new File(base, path);
|
Path file = base.resolve(path);
|
||||||
URI target = file.toURI().normalize();
|
|
||||||
if (target.toASCIIString().startsWith(base.toURI().normalize().toASCIIString())) {
|
URI target = file.toUri().normalize();
|
||||||
if (file.isDirectory()) {
|
if (!target.toASCIIString().startsWith(base.toUri().normalize().toASCIIString())) {
|
||||||
file = new File(file, "index.html");
|
return false;
|
||||||
}
|
|
||||||
return file.exists();
|
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
|
if (Files.isDirectory(file)) {
|
||||||
|
file = file.resolve("index.html");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Files.exists(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer get(String path) throws IOException {
|
public Optional<ByteBuffer> get(String path) throws IOException {
|
||||||
File file = new File(base, path);
|
Path root = base.resolve(path);
|
||||||
if (file.isDirectory()) {
|
|
||||||
file = new File(file, "index.html");
|
if (Files.isDirectory(root)) {
|
||||||
}
|
root = root.resolve("index.html");
|
||||||
if (!file.exists()) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer buffer;
|
if (!Files.exists(root)) {
|
||||||
try (RandomAccessFile raf = new RandomAccessFile(file, "r")) {
|
return Optional.empty();
|
||||||
buffer = raf.getChannel().map(MapMode.READ_ONLY, 0, raf.length());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer;
|
try (FileChannel channel = FileChannel.open(root)) {
|
||||||
|
ByteBuffer buf = channel.map(MapMode.READ_ONLY, 0, Files.size(root));
|
||||||
|
return Optional.of(buf);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,13 +2,14 @@ package org.apollo.update.resource;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A class which provides resources.
|
* A class which provides resources.
|
||||||
*
|
*
|
||||||
* @author Graham
|
* @author Graham
|
||||||
*/
|
*/
|
||||||
public abstract class ResourceProvider {
|
public interface ResourceProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks that this provider can fulfil a request to the specified resource.
|
* Checks that this provider can fulfil a request to the specified resource.
|
||||||
@@ -17,15 +18,16 @@ public abstract class ResourceProvider {
|
|||||||
* @return {@code true} if the provider can fulfil a request to the resource, {@code false} otherwise.
|
* @return {@code true} if the provider can fulfil a request to the resource, {@code false} otherwise.
|
||||||
* @throws IOException If an I/O error occurs.
|
* @throws IOException If an I/O error occurs.
|
||||||
*/
|
*/
|
||||||
public abstract boolean accept(String path) throws IOException;
|
public boolean accept(String path) throws IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a resource by its path.
|
* The resource data, as a {@link ByteBuffer}, wrapped in an {@link Optional}.
|
||||||
*
|
*
|
||||||
* @param path The path.
|
* @param path The path to the resource.
|
||||||
* @return The resource, or {@code null} if it doesn't exist.
|
* @return A {@code ByteBuffer} representation of a resource if it exists otherwise {@link Optional#empty()} is
|
||||||
* @throws IOException If an I/O error occurs.
|
* returned.
|
||||||
|
* @throws IOException If some I/O exception occurs.
|
||||||
*/
|
*/
|
||||||
public abstract ByteBuffer get(String path) throws IOException;
|
public Optional<ByteBuffer> get(String path) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,10 @@ package org.apollo.update.resource;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import org.apollo.fs.IndexedFileSystem;
|
import org.apollo.fs.IndexedFileSystem;
|
||||||
|
|
||||||
@@ -11,13 +15,12 @@ import org.apollo.fs.IndexedFileSystem;
|
|||||||
*
|
*
|
||||||
* @author Graham
|
* @author Graham
|
||||||
*/
|
*/
|
||||||
public final class VirtualResourceProvider extends ResourceProvider {
|
public final class VirtualResourceProvider implements ResourceProvider {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An array of valid prefixes.
|
* A {@link List} of valid prefixes.
|
||||||
*/
|
*/
|
||||||
private static final String[] VALID_PREFIXES = { "crc", "title", "config", "interface", "media", "versionlist", "textures",
|
private static final List<String> VALID_PREFIXES = Arrays.asList("/crc", "/title", "/config", "/interface", "/media", "/versionlist", "/textures", "/wordenc", "/sounds");
|
||||||
"wordenc", "sounds" };
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The file system.
|
* The file system.
|
||||||
@@ -35,36 +38,34 @@ public final class VirtualResourceProvider extends ResourceProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(String path) throws IOException {
|
public boolean accept(String path) throws IOException {
|
||||||
for (String prefix : VALID_PREFIXES) {
|
Objects.requireNonNull(path);
|
||||||
if (path.startsWith("/" + prefix)) {
|
|
||||||
return true;
|
return VALID_PREFIXES.stream().anyMatch(path::startsWith);
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ByteBuffer get(String path) throws IOException {
|
public Optional<ByteBuffer> get(String path) throws IOException {
|
||||||
if (path.startsWith("/crc")) {
|
if (path.startsWith("/crc")) {
|
||||||
return fs.getCrcTable();
|
return Optional.of(fs.getCrcTable());
|
||||||
} else if (path.startsWith("/title")) {
|
} else if (path.startsWith("/title")) {
|
||||||
return fs.getFile(0, 1);
|
return Optional.of(fs.getFile(0, 1));
|
||||||
} else if (path.startsWith("/config")) {
|
} else if (path.startsWith("/config")) {
|
||||||
return fs.getFile(0, 2);
|
return Optional.of(fs.getFile(0, 2));
|
||||||
} else if (path.startsWith("/interface")) {
|
} else if (path.startsWith("/interface")) {
|
||||||
return fs.getFile(0, 3);
|
return Optional.of(fs.getFile(0, 3));
|
||||||
} else if (path.startsWith("/media")) {
|
} else if (path.startsWith("/media")) {
|
||||||
return fs.getFile(0, 4);
|
return Optional.of(fs.getFile(0, 4));
|
||||||
} else if (path.startsWith("/versionlist")) {
|
} else if (path.startsWith("/versionlist")) {
|
||||||
return fs.getFile(0, 5);
|
return Optional.of(fs.getFile(0, 5));
|
||||||
} else if (path.startsWith("/textures")) {
|
} else if (path.startsWith("/textures")) {
|
||||||
return fs.getFile(0, 6);
|
return Optional.of(fs.getFile(0, 6));
|
||||||
} else if (path.startsWith("/wordenc")) {
|
} else if (path.startsWith("/wordenc")) {
|
||||||
return fs.getFile(0, 7);
|
return Optional.of(fs.getFile(0, 7));
|
||||||
} else if (path.startsWith("/sounds")) {
|
} else if (path.startsWith("/sounds")) {
|
||||||
return fs.getFile(0, 8);
|
return Optional.of(fs.getFile(0, 8));
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user