undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com Patches, unit tests, benchmarks, whitepaper, and outreach briefs. Public domain — no copyright claimed. Use freely.
This commit is contained in:
commit
0a580b313d
70422 changed files with 17213626 additions and 0 deletions
|
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver.simpleserver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.System.Logger;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.time.ZoneId;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.UnaryOperator;
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.HttpHandler;
|
||||
import com.sun.net.httpserver.HttpHandlers;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static com.sun.net.httpserver.HttpExchange.RSPBODY_EMPTY;
|
||||
|
||||
/**
|
||||
* A basic HTTP file server handler for static content.
|
||||
*
|
||||
* <p> Must be given an absolute pathname to the directory to be served.
|
||||
* Supports only HEAD and GET requests. Directory listings and files can be
|
||||
* served, content types are supported on a best-guess basis.
|
||||
*/
|
||||
public final class FileServerHandler implements HttpHandler {
|
||||
|
||||
private static final List<String> SUPPORTED_METHODS = List.of("HEAD", "GET");
|
||||
private static final List<String> UNSUPPORTED_METHODS =
|
||||
List.of("CONNECT", "DELETE", "OPTIONS", "PATCH", "POST", "PUT", "TRACE");
|
||||
private static final String FAVICON_RESOURCE_PATH =
|
||||
"/sun/net/httpserver/simpleserver/resources/favicon.ico";
|
||||
private static final String FAVICON_LAST_MODIFIED = "Mon, 23 May 1995 11:11:11 GMT";
|
||||
|
||||
private final Path root;
|
||||
private final UnaryOperator<String> mimeTable;
|
||||
private final Logger logger;
|
||||
|
||||
private FileServerHandler(Path root, UnaryOperator<String> mimeTable) {
|
||||
root = root.normalize();
|
||||
if (!Files.exists(root))
|
||||
throw new IllegalArgumentException("Path does not exist: " + root);
|
||||
if (!root.isAbsolute())
|
||||
throw new IllegalArgumentException("Path is not absolute: " + root);
|
||||
if (!Files.isDirectory(root))
|
||||
throw new IllegalArgumentException("Path is not a directory: " + root);
|
||||
if (!Files.isReadable(root))
|
||||
throw new IllegalArgumentException("Path is not readable: " + root);
|
||||
this.root = root;
|
||||
this.mimeTable = mimeTable;
|
||||
this.logger = System.getLogger("com.sun.net.httpserver");
|
||||
}
|
||||
|
||||
private static final HttpHandler NOT_IMPLEMENTED_HANDLER =
|
||||
HttpHandlers.of(501, Headers.of(), "");
|
||||
|
||||
private static final HttpHandler METHOD_NOT_ALLOWED_HANDLER =
|
||||
HttpHandlers.of(405, Headers.of("Allow", "HEAD, GET"), "");
|
||||
|
||||
public static HttpHandler create(Path root, UnaryOperator<String> mimeTable) {
|
||||
var fallbackHandler = HttpHandlers.handleOrElse(
|
||||
r -> UNSUPPORTED_METHODS.contains(r.getRequestMethod()),
|
||||
METHOD_NOT_ALLOWED_HANDLER,
|
||||
NOT_IMPLEMENTED_HANDLER);
|
||||
return HttpHandlers.handleOrElse(
|
||||
r -> SUPPORTED_METHODS.contains(r.getRequestMethod()),
|
||||
new FileServerHandler(root, mimeTable), fallbackHandler);
|
||||
}
|
||||
|
||||
private void handleHEAD(HttpExchange exchange, Path path) throws IOException {
|
||||
handleSupportedMethod(exchange, path, false);
|
||||
}
|
||||
|
||||
private void handleGET(HttpExchange exchange, Path path) throws IOException {
|
||||
handleSupportedMethod(exchange, path, true);
|
||||
}
|
||||
|
||||
private void handleSupportedMethod(HttpExchange exchange, Path path, boolean writeBody)
|
||||
throws IOException {
|
||||
if (Files.isDirectory(path)) {
|
||||
if (missingSlash(exchange)) {
|
||||
handleMovedPermanently(exchange);
|
||||
return;
|
||||
}
|
||||
if (indexFile(path) != null) {
|
||||
serveFile(exchange, indexFile(path), writeBody);
|
||||
} else {
|
||||
listFiles(exchange, path, writeBody);
|
||||
}
|
||||
} else {
|
||||
serveFile(exchange, path, writeBody);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleMovedPermanently(HttpExchange exchange) throws IOException {
|
||||
exchange.getResponseHeaders().set("Location", getRedirectURI(exchange.getRequestURI()));
|
||||
exchange.sendResponseHeaders(301, RSPBODY_EMPTY);
|
||||
}
|
||||
|
||||
private void handleForbidden(HttpExchange exchange) throws IOException {
|
||||
exchange.sendResponseHeaders(403, RSPBODY_EMPTY);
|
||||
}
|
||||
|
||||
private void handleNotFound(HttpExchange exchange) throws IOException {
|
||||
String fileNotFound = ResourceBundleHelper.getMessage("html.not.found");
|
||||
var bytes = (openHTML
|
||||
+ "<h1>" + fileNotFound + "</h1>\n"
|
||||
+ "<p>" + sanitize.apply(exchange.getRequestURI().getPath()) + "</p>\n"
|
||||
+ closeHTML).getBytes(UTF_8);
|
||||
exchange.getResponseHeaders().set("Content-Type", "text/html; charset=UTF-8");
|
||||
|
||||
if (exchange.getRequestMethod().equals("HEAD")) {
|
||||
exchange.getResponseHeaders().set("Content-Length", Integer.toString(bytes.length));
|
||||
exchange.sendResponseHeaders(404, RSPBODY_EMPTY);
|
||||
} else {
|
||||
exchange.sendResponseHeaders(404, bytes.length);
|
||||
try (OutputStream os = exchange.getResponseBody()) {
|
||||
os.write(bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void discardRequestBody(HttpExchange exchange) throws IOException {
|
||||
try (InputStream is = exchange.getRequestBody()) {
|
||||
is.skip(Integer.MAX_VALUE);
|
||||
}
|
||||
}
|
||||
|
||||
private String getRedirectURI(URI uri) {
|
||||
String query = uri.getRawQuery();
|
||||
String redirectPath = uri.getRawPath() + "/";
|
||||
return query == null ? redirectPath : redirectPath + "?" + query;
|
||||
}
|
||||
|
||||
private static boolean missingSlash(HttpExchange exchange) {
|
||||
return !exchange.getRequestURI().getPath().endsWith("/");
|
||||
}
|
||||
|
||||
private static String contextPath(HttpExchange exchange) {
|
||||
String context = exchange.getHttpContext().getPath();
|
||||
if (!context.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Context path invalid: " + context);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private static String requestPath(HttpExchange exchange) {
|
||||
String request = exchange.getRequestURI().getPath();
|
||||
if (!request.startsWith("/")) {
|
||||
throw new IllegalArgumentException("Request path invalid: " + request);
|
||||
}
|
||||
return request;
|
||||
}
|
||||
|
||||
// Checks that the request does not escape context.
|
||||
private static void checkRequestWithinContext(String requestPath,
|
||||
String contextPath) {
|
||||
if (requestPath.equals(contextPath)) {
|
||||
return; // context path requested, e.g. context /foo, request /foo
|
||||
}
|
||||
String contextPathWithTrailingSlash = contextPath.endsWith("/")
|
||||
? contextPath : contextPath + "/";
|
||||
if (!requestPath.startsWith(contextPathWithTrailingSlash)) {
|
||||
throw new IllegalArgumentException("Request not in context: " + contextPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Checks that path is, or is within, the root.
|
||||
private static Path checkPathWithinRoot(Path path, Path root) {
|
||||
if (!path.startsWith(root)) {
|
||||
throw new IllegalArgumentException("Request not in root");
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
// Returns the request URI path relative to the context.
|
||||
private static String relativeRequestPath(HttpExchange exchange) {
|
||||
String context = contextPath(exchange);
|
||||
String request = requestPath(exchange);
|
||||
checkRequestWithinContext(request, context);
|
||||
return request.substring(context.length());
|
||||
}
|
||||
|
||||
private Path mapToPath(HttpExchange exchange, Path root) {
|
||||
try {
|
||||
assert root.isAbsolute() && Files.isDirectory(root); // checked during creation
|
||||
String uriPath = relativeRequestPath(exchange);
|
||||
String[] pathSegment = uriPath.split("/");
|
||||
|
||||
// resolve each path segment against the root
|
||||
Path path = root;
|
||||
for (var segment : pathSegment) {
|
||||
if (!URIPathSegment.isSupported(segment)) {
|
||||
return null; // stop resolution, null results in 404 response
|
||||
}
|
||||
path = path.resolve(segment);
|
||||
if (!Files.isReadable(path) || isHiddenOrSymLink(path)) {
|
||||
return null; // stop resolution
|
||||
}
|
||||
}
|
||||
path = path.normalize();
|
||||
return checkPathWithinRoot(path, root);
|
||||
} catch (Exception e) {
|
||||
logger.log(System.Logger.Level.TRACE,
|
||||
"FileServerHandler: request URI path resolution failed", e);
|
||||
return null; // could not resolve request URI path
|
||||
}
|
||||
}
|
||||
|
||||
private static Path indexFile(Path path) {
|
||||
Path html = path.resolve("index.html");
|
||||
Path htm = path.resolve("index.htm");
|
||||
return Files.exists(html) ? html : Files.exists(htm) ? htm : null;
|
||||
}
|
||||
|
||||
private static boolean isFavIconRequest(HttpExchange exchange) {
|
||||
return "/favicon.ico".equals(exchange.getRequestURI().getPath());
|
||||
}
|
||||
|
||||
private void serveDefaultFavIcon(HttpExchange exchange, boolean writeBody)
|
||||
throws IOException
|
||||
{
|
||||
var respHdrs = exchange.getResponseHeaders();
|
||||
try (var stream = getClass().getModule().getResourceAsStream(FAVICON_RESOURCE_PATH)) {
|
||||
var bytes = stream.readAllBytes();
|
||||
respHdrs.set("Content-Type", "image/x-icon");
|
||||
respHdrs.set("Last-Modified", FAVICON_LAST_MODIFIED);
|
||||
if (writeBody) {
|
||||
exchange.sendResponseHeaders(200, bytes.length);
|
||||
try (OutputStream os = exchange.getResponseBody()) {
|
||||
os.write(bytes);
|
||||
}
|
||||
} else {
|
||||
respHdrs.set("Content-Length", Integer.toString(bytes.length));
|
||||
exchange.sendResponseHeaders(200, RSPBODY_EMPTY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void serveFile(HttpExchange exchange, Path path, boolean writeBody)
|
||||
throws IOException
|
||||
{
|
||||
var respHdrs = exchange.getResponseHeaders();
|
||||
respHdrs.set("Content-Type", mediaType(path.toString()));
|
||||
respHdrs.set("Last-Modified", getLastModified(path));
|
||||
if (writeBody) {
|
||||
exchange.sendResponseHeaders(200, Files.size(path));
|
||||
try (InputStream fis = Files.newInputStream(path);
|
||||
OutputStream os = exchange.getResponseBody()) {
|
||||
fis.transferTo(os);
|
||||
}
|
||||
} else {
|
||||
respHdrs.set("Content-Length", Long.toString(Files.size(path)));
|
||||
exchange.sendResponseHeaders(200, RSPBODY_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
private void listFiles(HttpExchange exchange, Path path, boolean writeBody)
|
||||
throws IOException
|
||||
{
|
||||
var respHdrs = exchange.getResponseHeaders();
|
||||
respHdrs.set("Content-Type", "text/html; charset=UTF-8");
|
||||
respHdrs.set("Last-Modified", getLastModified(path));
|
||||
var bodyBytes = dirListing(exchange, path).getBytes(UTF_8);
|
||||
if (writeBody) {
|
||||
exchange.sendResponseHeaders(200, bodyBytes.length);
|
||||
try (OutputStream os = exchange.getResponseBody()) {
|
||||
os.write(bodyBytes);
|
||||
}
|
||||
} else {
|
||||
respHdrs.set("Content-Length", Integer.toString(bodyBytes.length));
|
||||
exchange.sendResponseHeaders(200, RSPBODY_EMPTY);
|
||||
}
|
||||
}
|
||||
|
||||
private static final String openHTML = """
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
</head>
|
||||
<body>
|
||||
""";
|
||||
|
||||
private static final String closeHTML = """
|
||||
</body>
|
||||
</html>
|
||||
""";
|
||||
|
||||
private static final String hrefListItemTemplate = """
|
||||
<li><a href="%s">%s</a></li>
|
||||
""";
|
||||
|
||||
private static String hrefListItemFor(URI uri) {
|
||||
return hrefListItemTemplate.formatted(uri.toASCIIString(), sanitize.apply(uri.getPath()));
|
||||
}
|
||||
|
||||
private static String dirListing(HttpExchange exchange, Path path) throws IOException {
|
||||
String dirListing = ResourceBundleHelper.getMessage("html.dir.list");
|
||||
var sb = new StringBuilder(openHTML
|
||||
+ "<h1>" + dirListing + " "
|
||||
+ sanitize.apply(exchange.getRequestURI().getPath())
|
||||
+ "</h1>\n"
|
||||
+ "<ul>\n");
|
||||
try (var paths = Files.list(path)) {
|
||||
paths.filter(p -> Files.isReadable(p) && !isHiddenOrSymLink(p))
|
||||
.map(p -> path.toUri().relativize(p.toUri()))
|
||||
.forEach(uri -> sb.append(hrefListItemFor(uri)));
|
||||
}
|
||||
sb.append("</ul>\n");
|
||||
sb.append(closeHTML);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static String getLastModified(Path path) throws IOException {
|
||||
var fileTime = Files.getLastModifiedTime(path);
|
||||
return fileTime.toInstant().atZone(ZoneId.of("GMT"))
|
||||
.format(DateTimeFormatter.RFC_1123_DATE_TIME);
|
||||
}
|
||||
|
||||
private static boolean isHiddenOrSymLink(Path path) {
|
||||
try {
|
||||
return Files.isHidden(path) || Files.isSymbolicLink(path);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Default for unknown content types, as per RFC 2046
|
||||
private static final String DEFAULT_CONTENT_TYPE = "application/octet-stream";
|
||||
|
||||
private String mediaType(String file) {
|
||||
String type = mimeTable.apply(file);
|
||||
return type != null ? type : DEFAULT_CONTENT_TYPE;
|
||||
}
|
||||
|
||||
// A non-exhaustive map of reserved-HTML and special characters to their
|
||||
// equivalent entity.
|
||||
private static final Map<Integer, String> RESERVED_CHARS = Map.of(
|
||||
(int) '&' , "&" ,
|
||||
(int) '<' , "<" ,
|
||||
(int) '>' , ">" ,
|
||||
(int) '"' , """ ,
|
||||
(int) '\'' , "'" ,
|
||||
(int) '/' , "/" );
|
||||
|
||||
// A function that takes a string and returns a sanitized version of that
|
||||
// string with the reserved-HTML and special characters replaced with their
|
||||
// equivalent entity.
|
||||
private static final UnaryOperator<String> sanitize =
|
||||
file -> file.chars().collect(StringBuilder::new,
|
||||
(sb, c) -> sb.append(RESERVED_CHARS.getOrDefault(c, Character.toString(c))),
|
||||
StringBuilder::append).toString();
|
||||
|
||||
@Override
|
||||
public void handle(HttpExchange exchange) throws IOException {
|
||||
assert List.of("GET", "HEAD").contains(exchange.getRequestMethod());
|
||||
try (exchange) {
|
||||
discardRequestBody(exchange);
|
||||
boolean isHeadRequest = exchange.getRequestMethod().equals("HEAD");
|
||||
Path path = mapToPath(exchange, root);
|
||||
if (path != null) {
|
||||
exchange.setAttribute("request-path", path.toString()); // store for OutputFilter
|
||||
if (!Files.exists(path) || !Files.isReadable(path) || isHiddenOrSymLink(path)) {
|
||||
handleNotFound(exchange);
|
||||
} else if (isHeadRequest) {
|
||||
handleHEAD(exchange, path);
|
||||
} else {
|
||||
handleGET(exchange, path);
|
||||
}
|
||||
} else {
|
||||
if (isFavIconRequest(exchange)) {
|
||||
try {
|
||||
serveDefaultFavIcon(exchange, !isHeadRequest);
|
||||
return;
|
||||
} catch (IOException ignore) {
|
||||
// fall through to send the not-found response
|
||||
}
|
||||
}
|
||||
exchange.setAttribute("request-path", "could not resolve request URI path");
|
||||
handleNotFound(exchange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver.simpleserver;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Programmatic entry point to start the jwebserver tool.
|
||||
*/
|
||||
public class JWebServer {
|
||||
|
||||
private static final String SYS_PROP_MAX_CONNECTIONS = "jdk.httpserver.maxConnections";
|
||||
private static final String DEFAULT_JWEBSERVER_MAX_CONNECTIONS = "200";
|
||||
|
||||
private static final String SYS_PROP_ENHANCED_EXCEP = "jdk.includeInExceptions";
|
||||
private static final String DEFAULT_ENHANCED_EXCEP = "net";
|
||||
/**
|
||||
* This constructor should never be called.
|
||||
*/
|
||||
private JWebServer() { throw new AssertionError(); }
|
||||
|
||||
/**
|
||||
* The main entry point.
|
||||
*
|
||||
* <p> The command line arguments are parsed and the server is started. If
|
||||
* started successfully, the server will run on a new non-daemon thread,
|
||||
* and this method will return. Otherwise, if the server is not started
|
||||
* successfully, e.g. an error is encountered while parsing the arguments
|
||||
* or an I/O error occurs, the server is not started and this method invokes
|
||||
* System::exit with an appropriate exit code.
|
||||
*
|
||||
* <p> If the system property "sun.net.httpserver.maxReqTime" has not been
|
||||
* set by the user, it is set to a value of 5 seconds. This is to prevent
|
||||
* the server from hanging indefinitely, for example in the case of an HTTPS
|
||||
* request.
|
||||
*
|
||||
* @param args the command-line options
|
||||
* @throws NullPointerException if {@code args} is {@code null}, or if there
|
||||
* are any {@code null} values in the {@code args} array
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
setMaxReqTime();
|
||||
setEnhancedExceptions();
|
||||
setMaxConnectionsIfNotSet();
|
||||
|
||||
int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true), "jwebserver", args);
|
||||
if (ec != 0) {
|
||||
System.exit(ec);
|
||||
} // otherwise, the server has either been started successfully and
|
||||
// runs in another non-daemon thread, or -h or -version have been
|
||||
// passed and the main thread has exited normally.
|
||||
}
|
||||
|
||||
public static final String MAXREQTIME_KEY = "sun.net.httpserver.maxReqTime";
|
||||
public static final String MAXREQTIME_VAL = "5";
|
||||
|
||||
private static void setMaxReqTime() {
|
||||
if (System.getProperty(MAXREQTIME_KEY) == null) {
|
||||
System.setProperty(MAXREQTIME_KEY, MAXREQTIME_VAL);
|
||||
}
|
||||
}
|
||||
|
||||
static void setEnhancedExceptions() {
|
||||
if (System.getProperty(SYS_PROP_ENHANCED_EXCEP) != null) {
|
||||
// an explicit value has already been set, so we don't override it
|
||||
return;
|
||||
}
|
||||
System.setProperty(SYS_PROP_ENHANCED_EXCEP, DEFAULT_ENHANCED_EXCEP);
|
||||
}
|
||||
|
||||
static void setMaxConnectionsIfNotSet() {
|
||||
if (System.getProperty(SYS_PROP_MAX_CONNECTIONS) == null) {
|
||||
System.setProperty(SYS_PROP_MAX_CONNECTIONS, DEFAULT_JWEBSERVER_MAX_CONNECTIONS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver.simpleserver;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* Programmatic entry point to start "java -m jdk.httpserver".
|
||||
*/
|
||||
public class Main {
|
||||
|
||||
/**
|
||||
* This constructor should never be called.
|
||||
*/
|
||||
private Main() { throw new AssertionError(); }
|
||||
|
||||
/**
|
||||
* The main entry point.
|
||||
*
|
||||
* <p> The command line arguments are parsed and the server is started. If
|
||||
* started successfully, the server will run on a new non-daemon thread,
|
||||
* and this method will return. Otherwise, if the server is not started
|
||||
* successfully, e.g. an error is encountered while parsing the arguments
|
||||
* or an I/O error occurs, the server is not started and this method invokes
|
||||
* System::exit with an appropriate exit code.
|
||||
*
|
||||
* <p> If the system property "sun.net.httpserver.maxReqTime" has not been
|
||||
* set by the user, it is set to a value of 5 seconds. This is to prevent
|
||||
* the server from hanging indefinitely, for example in the case of an HTTPS
|
||||
* request.
|
||||
*
|
||||
* @param args the command-line options
|
||||
* @throws NullPointerException if {@code args} is {@code null}, or if there
|
||||
* are any {@code null} values in the {@code args} array
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
setMaxReqTime();
|
||||
JWebServer.setMaxConnectionsIfNotSet();
|
||||
|
||||
int ec = SimpleFileServerImpl.start(new PrintWriter(System.out, true), "java", args);
|
||||
if (ec != 0) {
|
||||
System.exit(ec);
|
||||
} // otherwise, the server has either been started successfully and
|
||||
// runs in another non-daemon thread, or -h or -version have been
|
||||
// passed and the main thread has exited normally.
|
||||
}
|
||||
|
||||
public static final String MAXREQTIME_KEY = "sun.net.httpserver.maxReqTime";
|
||||
public static final String MAXREQTIME_VAL = "5";
|
||||
|
||||
private static void setMaxReqTime() {
|
||||
if (System.getProperty(MAXREQTIME_KEY) == null) {
|
||||
System.setProperty(MAXREQTIME_KEY, MAXREQTIME_VAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver.simpleserver;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.time.OffsetDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.function.Consumer;
|
||||
import com.sun.net.httpserver.Filter;
|
||||
import com.sun.net.httpserver.Headers;
|
||||
import com.sun.net.httpserver.HttpExchange;
|
||||
import com.sun.net.httpserver.SimpleFileServer.OutputLevel;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
/**
|
||||
* A Filter that outputs log messages about an HttpExchange. The implementation
|
||||
* uses a {@link Filter#afterHandler(String, Consumer) post-processing filter}.
|
||||
*
|
||||
* <p> If the outputLevel is INFO, the format is based on the
|
||||
* <a href='https://www.w3.org/Daemon/User/Config/Logging.html#common-logfile-format'>Common Logfile Format</a>.
|
||||
* In this case the output includes the following information about an exchange:
|
||||
*
|
||||
* <p> remotehost rfc931 authuser [date] "request line" status bytes
|
||||
*
|
||||
* <p> Example:
|
||||
* 127.0.0.1 - - [22/Jun/2000:13:55:36 -0700] "GET /example.txt HTTP/1.1" 200 -
|
||||
*
|
||||
* <p> The fields rfc931, authuser and bytes are not captured in the implementation
|
||||
* and are always represented as '-'.
|
||||
*
|
||||
* <p> If the outputLevel is VERBOSE, the output additionally includes the
|
||||
* absolute path of the resource requested, if it has been
|
||||
* {@linkplain HttpExchange#setAttribute(String, Object) provided} via the
|
||||
* attribute {@code "request-path"}, as well as the request and response headers
|
||||
* of the exchange.
|
||||
*/
|
||||
public final class OutputFilter extends Filter {
|
||||
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MMM/yyyy:HH:mm:ss Z");
|
||||
private final PrintStream printStream;
|
||||
private final OutputLevel outputLevel;
|
||||
private final Filter filter;
|
||||
|
||||
private OutputFilter(OutputStream os, OutputLevel outputLevel) {
|
||||
printStream = new PrintStream(os, true, UTF_8);
|
||||
this.outputLevel = outputLevel;
|
||||
var description = "HttpExchange OutputFilter (outputLevel: " + outputLevel + ")";
|
||||
this.filter = Filter.afterHandler(description, operation());
|
||||
}
|
||||
|
||||
public static OutputFilter create(OutputStream os, OutputLevel outputLevel) {
|
||||
if (outputLevel.equals(OutputLevel.NONE)) {
|
||||
throw new IllegalArgumentException("Not a valid outputLevel: " + outputLevel);
|
||||
}
|
||||
return new OutputFilter(os, outputLevel);
|
||||
}
|
||||
|
||||
private Consumer<HttpExchange> operation() {
|
||||
return e -> {
|
||||
String s = e.getRemoteAddress().getHostString() + " "
|
||||
+ "- - " // rfc931 and authuser
|
||||
+ "[" + OffsetDateTime.now().format(FORMATTER) + "] "
|
||||
+ "\"" + e.getRequestMethod() + " " + e.getRequestURI() + " " + e.getProtocol() + "\" "
|
||||
+ e.getResponseCode() + " -"; // bytes
|
||||
printStream.println(s);
|
||||
|
||||
if (outputLevel.equals(OutputLevel.VERBOSE)) {
|
||||
if (e.getAttribute("request-path") instanceof String requestPath) {
|
||||
printStream.println("Resource requested: " + requestPath);
|
||||
}
|
||||
logHeaders(">", e.getRequestHeaders());
|
||||
logHeaders("<", e.getResponseHeaders());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void logHeaders(String sign, Headers headers) {
|
||||
headers.forEach((name, values) -> {
|
||||
var sb = new StringBuilder();
|
||||
var it = values.iterator();
|
||||
while (it.hasNext()) {
|
||||
sb.append(it.next());
|
||||
if (it.hasNext()) {
|
||||
sb.append(", ");
|
||||
}
|
||||
}
|
||||
printStream.println(sign + " " + name + ": " + sb);
|
||||
});
|
||||
printStream.println(sign);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(HttpExchange exchange, Chain chain) throws IOException {
|
||||
try {
|
||||
filter.doFilter(exchange, chain);
|
||||
} catch (Throwable t) {
|
||||
if (!outputLevel.equals(OutputLevel.NONE)) {
|
||||
reportError(ResourceBundleHelper.getMessage("err.server.handle.failed",
|
||||
t.getMessage()));
|
||||
}
|
||||
throw t;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String description() { return filter.description(); }
|
||||
|
||||
private void reportError(String message) {
|
||||
printStream.println(ResourceBundleHelper.getMessage("error.prefix") + " " + message);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver.simpleserver;
|
||||
|
||||
import java.text.MessageFormat;
|
||||
import java.util.Locale;
|
||||
import java.util.MissingResourceException;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
class ResourceBundleHelper {
|
||||
static final ResourceBundle bundle;
|
||||
|
||||
static {
|
||||
try {
|
||||
bundle = ResourceBundle.getBundle("sun.net.httpserver.simpleserver.resources.simpleserver");
|
||||
} catch (MissingResourceException e) {
|
||||
throw new InternalError("Cannot find simpleserver resource bundle for locale " + Locale.getDefault());
|
||||
}
|
||||
}
|
||||
|
||||
static String getMessage(String key, Object... args) {
|
||||
try {
|
||||
return MessageFormat.format(bundle.getString(key), args);
|
||||
} catch (MissingResourceException e) {
|
||||
throw new InternalError("Missing message: " + key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,257 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
package sun.net.httpserver.simpleserver;
|
||||
|
||||
import com.sun.net.httpserver.HttpServer;
|
||||
import com.sun.net.httpserver.SimpleFileServer;
|
||||
import com.sun.net.httpserver.SimpleFileServer.OutputLevel;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.Inet6Address;
|
||||
import java.net.InetAddress;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.Locale;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* A class that provides a simple HTTP file server to serve the content of
|
||||
* a given directory.
|
||||
*
|
||||
* <p> The server is an HttpServer bound to a given address. It comes with an
|
||||
* HttpHandler that serves files from a given directory path
|
||||
* (and its subdirectories) on the default file system, and an optional Filter
|
||||
* that prints log messages related to the exchanges handled by the server to
|
||||
* a given output stream.
|
||||
*
|
||||
* <p> Unless specified as arguments, the default values are:<ul>
|
||||
* <li>bind address: 127.0.0.1 or ::1 (loopback)</li>
|
||||
* <li>directory: current working directory</li>
|
||||
* <li>outputLevel: info</li></ul>
|
||||
* <li>port: 8000</li>
|
||||
* <p>
|
||||
* The implementation is provided via the main entry point of the jdk.httpserver
|
||||
* module.
|
||||
*/
|
||||
final class SimpleFileServerImpl {
|
||||
private static final InetAddress LOOPBACK_ADDR = InetAddress.getLoopbackAddress();
|
||||
private static final int DEFAULT_PORT = 8000;
|
||||
private static final Path DEFAULT_ROOT = Path.of("").toAbsolutePath();
|
||||
private static final OutputLevel DEFAULT_OUTPUT_LEVEL = OutputLevel.INFO;
|
||||
private static boolean addrSpecified = false;
|
||||
|
||||
private SimpleFileServerImpl() { throw new AssertionError(); }
|
||||
|
||||
/**
|
||||
* Starts a simple HTTP file server created on a directory.
|
||||
*
|
||||
* @param writer the writer to which output should be written
|
||||
* @param args the command line options
|
||||
* @param launcher the launcher the server is started from
|
||||
* @throws NullPointerException if any of the arguments are {@code null},
|
||||
* or if there are any {@code null} values in the {@code args} array
|
||||
* @return startup status code
|
||||
*/
|
||||
static int start(PrintWriter writer, String launcher, String[] args) {
|
||||
Objects.requireNonNull(args);
|
||||
for (var arg : args) {
|
||||
Objects.requireNonNull(arg);
|
||||
}
|
||||
Out out = new Out(writer);
|
||||
|
||||
InetAddress addr = LOOPBACK_ADDR;
|
||||
int port = DEFAULT_PORT;
|
||||
Path root = DEFAULT_ROOT;
|
||||
OutputLevel outputLevel = DEFAULT_OUTPUT_LEVEL;
|
||||
|
||||
// parse options
|
||||
Iterator<String> options = Arrays.asList(args).iterator();
|
||||
String option = null;
|
||||
String optionArg = null;
|
||||
try {
|
||||
while (options.hasNext()) {
|
||||
option = options.next();
|
||||
switch (option) {
|
||||
case "-h", "-?", "--help" -> {
|
||||
out.showHelp(launcher);
|
||||
return Startup.OK.statusCode;
|
||||
}
|
||||
case "-version", "--version" -> {
|
||||
out.showVersion(launcher);
|
||||
return Startup.OK.statusCode;
|
||||
}
|
||||
case "-b", "--bind-address" -> {
|
||||
addr = InetAddress.getByName(optionArg = options.next());
|
||||
addrSpecified = true;
|
||||
}
|
||||
case "-d", "--directory" ->
|
||||
root = Path.of(optionArg = options.next());
|
||||
case "-o", "--output" ->
|
||||
outputLevel = Enum.valueOf(OutputLevel.class,
|
||||
(optionArg = options.next()).toUpperCase(Locale.ROOT));
|
||||
case "-p", "--port" ->
|
||||
port = Integer.parseInt(optionArg = options.next());
|
||||
default -> throw new AssertionError();
|
||||
}
|
||||
}
|
||||
} catch (AssertionError ae) {
|
||||
out.reportError(ResourceBundleHelper.getMessage("err.unknown.option", option));
|
||||
out.showUsage(launcher);
|
||||
return Startup.CMDERR.statusCode;
|
||||
} catch (NoSuchElementException nsee) {
|
||||
out.reportError(ResourceBundleHelper.getMessage("err.missing.arg", option));
|
||||
out.showOption(option);
|
||||
return Startup.CMDERR.statusCode;
|
||||
} catch (Exception e) {
|
||||
out.reportError(ResourceBundleHelper.getMessage("err.invalid.arg", option, optionArg));
|
||||
e.printStackTrace(out.writer);
|
||||
return Startup.CMDERR.statusCode;
|
||||
} finally {
|
||||
out.flush();
|
||||
}
|
||||
|
||||
// configure and start server
|
||||
try {
|
||||
root = realPath(root);
|
||||
var socketAddr = new InetSocketAddress(addr, port);
|
||||
var server = SimpleFileServer.createFileServer(socketAddr, root, outputLevel);
|
||||
server.start();
|
||||
out.printStartMessage(root, server);
|
||||
} catch (Throwable t) {
|
||||
out.reportError(ResourceBundleHelper.getMessage("err.server.config.failed", t.getMessage()));
|
||||
return Startup.SYSERR.statusCode;
|
||||
} finally {
|
||||
out.flush();
|
||||
}
|
||||
return Startup.OK.statusCode;
|
||||
}
|
||||
|
||||
private static Path realPath(Path root) {
|
||||
|
||||
// `toRealPath()` invocation below already checks if file exists, though
|
||||
// there is no way to figure out if it fails due to a non-existent file.
|
||||
// Hence, checking the existence here first to deliver the user a more
|
||||
// descriptive message.
|
||||
if (!Files.exists(root)) {
|
||||
throw new IllegalArgumentException("Path does not exist: " + root);
|
||||
}
|
||||
|
||||
// Obtain the real path
|
||||
try {
|
||||
return root.toRealPath();
|
||||
} catch (IOException exception) {
|
||||
throw new IllegalArgumentException("Path is invalid: " + root, exception);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class Out {
|
||||
private final PrintWriter writer;
|
||||
private Out() { throw new AssertionError(); }
|
||||
|
||||
Out(PrintWriter writer) {
|
||||
this.writer = Objects.requireNonNull(writer);
|
||||
}
|
||||
|
||||
void printStartMessage(Path root, HttpServer server)
|
||||
throws UnknownHostException
|
||||
{
|
||||
String port = Integer.toString(server.getAddress().getPort());
|
||||
var inetAddr = server.getAddress().getAddress();
|
||||
var isAnyLocal = inetAddr.isAnyLocalAddress();
|
||||
var addr = isAnyLocal ? InetAddress.getLocalHost().getHostAddress() : inetAddr.getHostAddress();
|
||||
if (!addrSpecified) {
|
||||
writer.println(ResourceBundleHelper.getMessage("loopback.info"));
|
||||
}
|
||||
if (inetAddr instanceof Inet6Address && addr.contains(":") && !addr.startsWith("[")) {
|
||||
// we use the "addr" when printing the URL, so make sure it
|
||||
// conforms to RFC-2732, section 2:
|
||||
// To use a literal IPv6 address in a URL, the literal
|
||||
// address should be enclosed in "[" and "]" characters.
|
||||
addr = "[" + addr + "]";
|
||||
}
|
||||
if (isAnyLocal) {
|
||||
writer.println(ResourceBundleHelper.getMessage("msg.start.anylocal", root, addr, port));
|
||||
} else {
|
||||
writer.println(ResourceBundleHelper.getMessage("msg.start.other", root, addr, port));
|
||||
}
|
||||
}
|
||||
|
||||
void showUsage(String launcher) {
|
||||
writer.println(ResourceBundleHelper.getMessage("usage." + launcher));
|
||||
}
|
||||
|
||||
void showVersion(String launcher) {
|
||||
writer.println(ResourceBundleHelper.getMessage("version", launcher, System.getProperty("java.version")));
|
||||
}
|
||||
|
||||
void showHelp(String launcher) {
|
||||
writer.println(ResourceBundleHelper.getMessage("usage." + launcher));
|
||||
writer.println(ResourceBundleHelper.getMessage("options", LOOPBACK_ADDR.getHostAddress()));
|
||||
}
|
||||
|
||||
void showOption(String option) {
|
||||
switch (option) {
|
||||
case "-b", "--bind-address" ->
|
||||
writer.println(ResourceBundleHelper.getMessage("opt.bindaddress", LOOPBACK_ADDR.getHostAddress()));
|
||||
case "-d", "--directory" ->
|
||||
writer.println(ResourceBundleHelper.getMessage("opt.directory"));
|
||||
case "-o", "--output" ->
|
||||
writer.println(ResourceBundleHelper.getMessage("opt.output"));
|
||||
case "-p", "--port" ->
|
||||
writer.println(ResourceBundleHelper.getMessage("opt.port"));
|
||||
}
|
||||
}
|
||||
|
||||
void reportError(String message) {
|
||||
writer.println(ResourceBundleHelper.getMessage("error.prefix") + " " + message);
|
||||
}
|
||||
|
||||
void flush() {
|
||||
writer.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private enum Startup {
|
||||
/** Started with no errors */
|
||||
OK(0),
|
||||
/** Not started, bad command-line arguments */
|
||||
CMDERR(1),
|
||||
/** Not started, system error or resource exhaustion */
|
||||
SYSERR(2);
|
||||
|
||||
Startup(int statusCode) {
|
||||
this.statusCode = statusCode;
|
||||
}
|
||||
public final int statusCode;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
|
|
@ -0,0 +1,80 @@
|
|||
#
|
||||
# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
usage.java=\
|
||||
Usage: java -m jdk.httpserver [-b bind address] [-p port] [-d directory]\n\
|
||||
\ [-o none|info|verbose] [-h to show options]\n\
|
||||
\ [-version to show version information]
|
||||
|
||||
usage.jwebserver=\
|
||||
Usage: jwebserver [-b bind address] [-p port] [-d directory]\n\
|
||||
\ [-o none|info|verbose] [-h to show options]\n\
|
||||
\ [-version to show version information]
|
||||
|
||||
version=\
|
||||
{0} {1}
|
||||
|
||||
options=\
|
||||
Options:\n\
|
||||
-b, --bind-address - Address to bind to. Default: {0} (loopback).\n\
|
||||
\ For all interfaces use "-b 0.0.0.0" or "-b ::".\n\
|
||||
-d, --directory - Directory to serve. Default: current directory.\n\
|
||||
-o, --output - Output format. none|info|verbose. Default: info.\n\
|
||||
-p, --port - Port to listen on. Default: 8000.\n\
|
||||
-h, -?, --help - Prints this help message and exits.\n\
|
||||
-version, --version - Prints version information and exits.\n\
|
||||
To stop the server, press Ctrl + C.
|
||||
|
||||
opt.bindaddress=\
|
||||
-b, --bind-address - Address to bind to. Default: {0} (loopback).\n\
|
||||
\ For all interfaces use "-b 0.0.0.0" or "-b ::".
|
||||
opt.directory=\
|
||||
-d, --directory - Directory to serve. Default: current directory.
|
||||
opt.output=\
|
||||
-o, --output - Output format. none|info|verbose. Default: info.
|
||||
opt.port=\
|
||||
-p, --port - Port to listen on. Default: 8000.
|
||||
|
||||
loopback.info=\
|
||||
Binding to loopback by default. For all interfaces use "-b 0.0.0.0" or "-b ::".
|
||||
|
||||
msg.start.anylocal=\
|
||||
Serving {0} and subdirectories on 0.0.0.0 (all interfaces) port {2}\n\
|
||||
URL http://{1}:{2}/
|
||||
|
||||
msg.start.other=\
|
||||
Serving {0} and subdirectories on {1} port {2}\n\
|
||||
URL http://{1}:{2}/
|
||||
|
||||
error.prefix=Error:
|
||||
|
||||
err.unknown.option=unknown option: {0}
|
||||
err.missing.arg=no value given for {0}
|
||||
err.invalid.arg=invalid value given for {0}: {1}
|
||||
err.server.config.failed=server config failed: {0}
|
||||
err.server.handle.failed=server exchange handling failed: {0}
|
||||
|
||||
html.dir.list=Directory listing for
|
||||
html.not.found=File not found
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
usage.java=Verwendung: java -m jdk.httpserver [-b bind address] [-p port] [-d directory]\n [-o none|info|verbose] [-h zum Anzeigen von Optionen]\n [-version zum Anzeigen der Versionsinformationen]
|
||||
|
||||
usage.jwebserver=Verwendung: jwebserver [-b bind address] [-p port] [-d directory]\n [-o none|info|verbose] [-h zum Anzeigen von Optionen]\n [-version zum Anzeigen von Versionsinformationen]
|
||||
|
||||
version={0} {1}
|
||||
|
||||
options=Optionen:\n-b, --bind-address - Adresse, an die das Binding erfolgt. Standard: {0} (Loopback).\n Verwenden Sie für alle Schnittstellen "-b 0.0.0.0" oder "-b ::".\n-d, --directory - Zu bedienendes Verzeichnis. Standard: Aktuelles Verzeichnis.\n-o, --output - Ausgabeformat. none|info|verbose. Standard: info.\n-p, --port - Port, auf dem gehorcht wird. Standard: 8000.\n-h, -?, --help - Gibt diese Hilfemeldung aus und beendet.\n-version, --version - Gibt Versionsinformationen aus und beendet.\nDrücken Sie zum Stoppen des Servers Strg+C.
|
||||
|
||||
opt.bindaddress=-b, --bind-address - Adresse, an die das Binding erfolgt. Standard: {0} (Loopback).\n Verwenden Sie für alle Schnittstellen "-b 0.0.0.0" oder "-b ::".
|
||||
opt.directory=-d, --directory - Zu bedienendes Verzeichnis. Standard: Aktuelles Verzeichnis.
|
||||
opt.output=-o, --output - Ausgabeformat. none|info|verbose. Standard: info.
|
||||
opt.port=-p, --port - Port, auf dem gehorcht wird. Standard: 8000.
|
||||
|
||||
loopback.info=Binding an Loopback als Standard. Verwenden Sie für alle Schnittstellen "-b 0.0.0.0" oder "-b ::".
|
||||
|
||||
msg.start.anylocal=Bedient {0} und Unterverzeichnisse auf 0.0.0.0 (alle Schnittstellen) Port {2}\nURL http://{1}:{2}/
|
||||
|
||||
msg.start.other=Bedient {0} und Unterverzeichnisse auf {1} Port {2}\nURL http://{1}:{2}/
|
||||
|
||||
error.prefix=Fehler:
|
||||
|
||||
err.unknown.option=unbekannte Option: {0}
|
||||
err.missing.arg=kein Wert angegeben für {0}
|
||||
err.invalid.arg=ungültiger Wert angegeben für {0}: {1}
|
||||
err.server.config.failed=Serverkonfiguration nicht erfolgreich: {0}
|
||||
err.server.handle.failed=Handling des Serveraustauschs nicht erfolgreich: {0}
|
||||
|
||||
html.dir.list=Verzeichnisliste für
|
||||
html.not.found=Datei wurde nicht gefunden
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
usage.java=使用方法: java -m jdk.httpserver [-b bind address] [-p port] [-d directory]\n [-o none|info|verbose] [-h to show options]\n [-version to show version information]
|
||||
|
||||
usage.jwebserver=使用方法: jwebserver [-b bind address] [-p port] [-d directory]\n [-o none|info|verbose] [-h to show options]\n [-version to show version information]
|
||||
|
||||
version={0} {1}
|
||||
|
||||
options=オプション:\n-b, --bind-address - バインド先アドレス。デフォルト: {0} (ループバック)。\n すべてのインタフェースで"-b 0.0.0.0"または"-b ::"を使用します。\n-d, --directory - 使用するディレクトリ。デフォルト: 現在のディレクトリ。\n-o, --output - 出力形式。none|info|verbose。デフォルト: info。\n-p, --port - リスニングするポート。デフォルト: 8000。\n-h, -?, --help - ヘルプ・メッセージを出力して終了します。\n-version, --version - バージョン情報を出力して終了します。\nサーバーを停止するには、[Ctrl]+[C]を押します。
|
||||
|
||||
opt.bindaddress=-b, --bind-address - バインド先アドレス。デフォルト: {0} (ループバック).\n すべてのインタフェースで"-b 0.0.0.0"または"-b ::"を使用します。
|
||||
opt.directory=-d, --directory - 使用するディレクトリ。デフォルト: 現在のディレクトリ。
|
||||
opt.output=-o, --output - 出力形式。none|info|verbose. デフォルト: info。
|
||||
opt.port=-p, --port - リスニングするポート。デフォルト: 8000。
|
||||
|
||||
loopback.info=デフォルトでループバックにバインドします。すべてのインタフェースで"-b 0.0.0.0"または"-b ::"を使用します。
|
||||
|
||||
msg.start.anylocal={0}およびサブディレクトリを0.0.0.0 (すべてのインタフェース)ポート{2}で使用します\nURL http://{1}:{2}/
|
||||
|
||||
msg.start.other={0}およびサブディレクトリを{1}ポート{2}で使用します\nURL http://{1}:{2}/
|
||||
|
||||
error.prefix=エラー:
|
||||
|
||||
err.unknown.option=不明なオプション: {0}
|
||||
err.missing.arg={0}に値が指定されていません
|
||||
err.invalid.arg={0}に無効な値が指定されました: {1}
|
||||
err.server.config.failed=サーバーの構成に失敗しました: {0}
|
||||
err.server.handle.failed=サーバー交換処理が失敗しました: {0}
|
||||
|
||||
html.dir.list=次のディレクトリ・リスト
|
||||
html.not.found=ファイルが見つかりませんでした
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
#
|
||||
# Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
|
||||
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
#
|
||||
# This code is free software; you can redistribute it and/or modify it
|
||||
# under the terms of the GNU General Public License version 2 only, as
|
||||
# published by the Free Software Foundation. Oracle designates this
|
||||
# particular file as subject to the "Classpath" exception as provided
|
||||
# by Oracle in the LICENSE file that accompanied this code.
|
||||
#
|
||||
# This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
# version 2 for more details (a copy is included in the LICENSE file that
|
||||
# accompanied this code).
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License version
|
||||
# 2 along with this work; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
#
|
||||
# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
# or visit www.oracle.com if you need additional information or have any
|
||||
# questions.
|
||||
#
|
||||
|
||||
usage.java=用法:java -m jdk.httpserver [-b 绑定地址] [-p 端口] [-d 目录]\n [-o none|info|verbose] [-h 显示选项]\n [-version 显示版本信息]
|
||||
|
||||
usage.jwebserver=用法:jwebserver [-b 绑定地址] [-p 端口] [-d 目录]\n [-o none|info|verbose] [-h 显示选项]\n [-version 显示版本信息]
|
||||
|
||||
version={0} {1}
|
||||
|
||||
options=选项:\n-b, --bind-address - 要绑定到的地址。默认值:{0}(环回)。\n 如果要表示所有接口,请使用 "-b 0.0.0.0" 或 "-b ::"。\n-d, --directory - 要为其提供服务的目录。默认值:当前目录。\n-o, --output - 输出格式。none|info|verbose。默认值:info。\n-p, --port - 要监听的端口。默认值:8000。\n-h, -?, --help - 输出此帮助消息并退出。\n-version, --version - 输出版本信息并退出。\n要停止服务器,请按 Ctrl + C。
|
||||
|
||||
opt.bindaddress=-b, --bind-address - 要绑定到的地址。默认值:{0}(环回)。\n 如果要表示所有接口,请使用 "-b 0.0.0.0" 或 "-b ::"。
|
||||
opt.directory=-d, --directory - 要为其提供服务的目录。默认值:当前目录。
|
||||
opt.output=-o, --output - 输出格式。none|info|verbose。默认值:info。
|
||||
opt.port=-p, --port - 要监听的端口。默认值:8000。
|
||||
|
||||
loopback.info=默认情况下绑定到环回。如果要表示所有接口,请使用 "-b 0.0.0.0" 或 "-b ::"。
|
||||
|
||||
msg.start.anylocal=为 0.0.0.0(所有接口)端口 {2} 上的 {0} 及子目录提供服务\nURL http://{1}:{2}/
|
||||
|
||||
msg.start.other=为 {1} 端口 {2} 上的 {0} 及子目录提供服务\nURL http://{1}:{2}/
|
||||
|
||||
error.prefix=错误:
|
||||
|
||||
err.unknown.option=未知选项: {0}
|
||||
err.missing.arg=没有为{0}指定值
|
||||
err.invalid.arg=为 {0} 提供的值无效:{1}
|
||||
err.server.config.failed=服务器配置失败:{0}
|
||||
err.server.handle.failed=服务器交换处理失败:{0}
|
||||
|
||||
html.dir.list=以下项的目录列表
|
||||
html.not.found=找不到文件
|
||||
Loading…
Add table
Add a link
Reference in a new issue