[git-bridge] Update jetty to v12 (#30221)

GitOrigin-RevId: 44b3f754b3dbced8a2ac47472e113ef4cae30c50
This commit is contained in:
Miguel Serrano
2025-12-17 10:22:42 +01:00
committed by Copybot
parent b79a723630
commit 48e7f8042b
26 changed files with 307 additions and 320 deletions

View File

@@ -16,10 +16,11 @@
<fmt.plugin.version>2.23</fmt.plugin.version>
<junit.version>4.13.2</junit.version>
<jmock.junit4.version>2.13.1</jmock.junit4.version>
<jetty.servlet.version>9.4.57.v20241219</jetty.servlet.version>
<jetty.version>12.1.5</jetty.version>
<jakarta.servlet.version>6.1.0</jakarta.servlet.version>
<gson.version>2.13.2</gson.version>
<async.http.client.version>3.0.3</async.http.client.version>
<jgit.version>6.10.1.202505221210-r</jgit.version>
<jgit.version>7.5.0.202512021534-r</jgit.version>
<sqlite.jdbc.version>3.41.2.2</sqlite.jdbc.version>
<joda.time.version>2.9.9</joda.time.version>
<google.oauth.client.version>1.39.0</google.oauth.client.version>
@@ -104,17 +105,23 @@
<version>${jmock.junit4.version}</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-servlet -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty.servlet.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty/jetty-server -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty.servlet.version}</version>
<version>${jetty.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.eclipse.jetty.ee10/jetty-ee10-servlet -->
<dependency>
<groupId>org.eclipse.jetty.ee10</groupId>
<artifactId>jetty-ee10-servlet</artifactId>
<version>${jetty.version}</version>
</dependency>
<!-- Jakarta Servlet API -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>${jakarta.servlet.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>

View File

@@ -1,7 +1,7 @@
package uk.ac.ic.wlgitbridge.application;
import jakarta.servlet.ServletException;
import java.io.IOException;
import javax.servlet.ServletException;
import uk.ac.ic.wlgitbridge.application.config.Config;
import uk.ac.ic.wlgitbridge.application.exception.ArgsException;
import uk.ac.ic.wlgitbridge.application.exception.ConfigFileException;

View File

@@ -1,60 +0,0 @@
package uk.ac.ic.wlgitbridge.application.jetty;
import org.eclipse.jetty.util.log.Logger;
/*
* Created by Winston on 03/11/14.
*/
public class NullLogger implements Logger {
@Override
public String getName() {
return "null_logger";
}
@Override
public void warn(String s, Object... objects) {}
@Override
public void warn(Throwable throwable) {}
@Override
public void warn(String s, Throwable throwable) {}
@Override
public void info(String s, Object... objects) {}
@Override
public void info(Throwable throwable) {}
@Override
public void info(String s, Throwable throwable) {}
@Override
public boolean isDebugEnabled() {
return false;
}
@Override
public void setDebugEnabled(boolean b) {}
@Override
public void debug(String s, Object... objects) {}
@Override
public void debug(String s, long l) {}
@Override
public void debug(Throwable throwable) {}
@Override
public void debug(String s, Throwable throwable) {}
@Override
public Logger getLogger(String s) {
return this;
}
@Override
public void ignore(Throwable throwable) {}
}

View File

@@ -1,8 +1,8 @@
package uk.ac.ic.wlgitbridge.git.handler;
import com.google.api.client.auth.oauth2.Credential;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceivePack;
import org.eclipse.jgit.transport.resolver.ReceivePackFactory;

View File

@@ -1,9 +1,9 @@
package uk.ac.ic.wlgitbridge.git.handler;
import com.google.api.client.auth.oauth2.Credential;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ServiceMayNotContinueException;

View File

@@ -1,6 +1,6 @@
package uk.ac.ic.wlgitbridge.git.handler;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.UploadPack;
import org.eclipse.jgit.transport.resolver.UploadPackFactory;

View File

@@ -1,7 +1,7 @@
package uk.ac.ic.wlgitbridge.git.servlet;
import javax.servlet.ServletException;
import org.eclipse.jetty.servlet.ServletContextHandler;
import jakarta.servlet.ServletException;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jgit.http.server.GitServlet;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
import uk.ac.ic.wlgitbridge.bridge.repo.RepoStore;

View File

@@ -1,9 +1,9 @@
package uk.ac.ic.wlgitbridge.git.servlet;
import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletContext;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
/*
* Created by Winston on 02/11/14.

View File

@@ -64,7 +64,7 @@ public class RepositoryObjectTreeWalker {
String path = treeWalk.getPathString();
ObjectId objectId = treeWalk.getObjectId(0);
if (!repository.hasObject(objectId)) {
if (!repository.getObjectDatabase().has(objectId)) {
throw new InvalidGitRepository();
}
ObjectLoader obj = repository.open(objectId);

View File

@@ -1,14 +1,16 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.util.Log;
public class CORSHandler extends AbstractHandler {
public class CORSHandler extends Handler.Abstract {
private final Set<String> allowedCorsOrigins;
public CORSHandler(String[] allowedCorsOrigins) {
@@ -16,32 +18,34 @@ public class CORSHandler extends AbstractHandler {
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException {
public boolean handle(Request request, Response response, Callback callback) throws Exception {
HttpField originField = request.getHeaders().getField(HttpHeader.ORIGIN);
String origin = originField != null ? originField.getValue() : null;
String origin = request.getHeader("Origin");
if (origin == null) {
return; // Not a CORS request
return false; // Not a CORS request
}
final boolean ok = allowedCorsOrigins.contains(origin);
if (ok) {
response.setHeader("Access-Control-Allow-Origin", origin);
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Allow-Methods", "GET, HEAD, PUT, POST, DELETE");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
response.setHeader("Access-Control-Max-Age", "86400"); // cache for 24h
response.getHeaders().put("Access-Control-Allow-Origin", origin);
response.getHeaders().put("Access-Control-Allow-Credentials", "true");
response.getHeaders().put("Access-Control-Allow-Methods", "GET, HEAD, PUT, POST, DELETE");
response.getHeaders().put("Access-Control-Allow-Headers", "Authorization, Content-Type");
response.getHeaders().put("Access-Control-Max-Age", "86400"); // cache for 24h
}
String method = baseRequest.getMethod();
String method = request.getMethod();
if ("OPTIONS".equals(method)) {
Log.debug("OPTIONS <- {}", target);
baseRequest.setHandled(true);
String path = Request.getPathInContext(request);
Log.debug("OPTIONS <- {}", path);
if (ok) {
response.setStatus(200);
response.setStatus(HttpStatus.OK_200);
} else {
response.setStatus(403);
response.setStatus(HttpStatus.FORBIDDEN_403);
}
callback.succeeded();
return true;
}
return false;
}
}

View File

@@ -1,28 +1,28 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import java.io.BufferedWriter;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.management.ManagementFactory;
import javax.management.JMException;
import javax.management.ObjectName;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.util.Log;
public class DiagnosticsHandler extends AbstractHandler {
public class DiagnosticsHandler extends Handler.Abstract {
public DiagnosticsHandler() {}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String method = baseRequest.getMethod();
if (("GET".equals(method)) && target != null && target.matches("^/diags/?$")) {
baseRequest.setHandled(true);
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String method = request.getMethod();
String path = Request.getPathInContext(request);
if (("GET".equals(method)) && path != null && path.matches("^/diags/?$")) {
Log.debug(method + " <- /diags");
String detail;
@@ -33,18 +33,28 @@ public class DiagnosticsHandler extends AbstractHandler {
summary = execute("vmNativeMemory", "summary");
} catch (JMException e) {
Log.error("Failed to get native memory detail: " + e.getMessage());
response.setStatus(500);
return;
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
callback.succeeded();
return true;
}
response.setContentType("text/plain");
response.setStatus(200);
response.getHeaders().put("Content-Type", "text/plain");
response.setStatus(HttpStatus.OK_200);
response.getWriter().write(summary);
response.getWriter().write("\n----------\n\n");
response.getWriter().write(detail);
response.getWriter().flush();
Writer writer =
new BufferedWriter(new OutputStreamWriter(Content.Sink.asOutputStream(response)));
try {
writer.write(summary);
writer.write("\n----------\n\n");
writer.write(detail);
writer.flush();
} finally {
writer.close();
callback.succeeded();
}
return true;
}
return false;
}
public static String execute(String command, String... args) throws JMException {

View File

@@ -1,13 +1,12 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
@@ -29,26 +28,26 @@ public class FileHandler extends ResourceHandler {
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
if (!"GET".equals(baseRequest.getMethod())) return;
LOG.debug("GET <- {}", baseRequest.getRequestURI());
public boolean handle(Request request, Response response, Callback callback) throws Exception {
if (!"GET".equals(request.getMethod())) return false;
String path = Request.getPathInContext(request);
LOG.debug("GET <- {}", request.getHttpURI());
Matcher docKeyMatcher = DOC_KEY_PATTERN.matcher(target);
if (!docKeyMatcher.matches()) return;
Matcher docKeyMatcher = DOC_KEY_PATTERN.matcher(path);
if (!docKeyMatcher.matches()) return false;
String docKey = docKeyMatcher.group(1);
String apiKey = request.getParameter("key");
if (apiKey == null) return;
Fields parameters = Request.getParameters(request);
String apiKey = parameters != null ? parameters.getValue("key") : null;
if (apiKey == null) return false;
try {
bridge.checkPostbackKey(docKey, apiKey);
} catch (InvalidPostbackKeyException e) {
LOG.warn("INVALID POST BACK KEY: docKey={} apiKey={}", docKey, apiKey);
return;
return false;
}
super.handle(target, baseRequest, request, response);
return super.handle(request, response, callback);
}
}

View File

@@ -1,21 +1,23 @@
package uk.ac.ic.wlgitbridge.server;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.Filter;
import jakarta.servlet.ServletException;
import java.io.File;
import java.net.BindException;
import java.nio.file.Paths;
import java.util.EnumSet;
import javax.servlet.DispatcherType;
import javax.servlet.Filter;
import javax.servlet.ServletException;
import org.eclipse.jetty.ee10.servlet.FilterHolder;
import org.eclipse.jetty.ee10.servlet.ServletContextHandler;
import org.eclipse.jetty.ee10.servlet.ServletHolder;
import org.eclipse.jetty.ee10.servlet.SessionHandler;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.server.handler.*;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.server.handler.ContextHandler;
import org.eclipse.jetty.server.handler.DefaultHandler;
import org.eclipse.jetty.util.resource.ResourceFactory;
import uk.ac.ic.wlgitbridge.application.config.Config;
import uk.ac.ic.wlgitbridge.application.jetty.NullLogger;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
import uk.ac.ic.wlgitbridge.bridge.db.DBStore;
import uk.ac.ic.wlgitbridge.bridge.db.sqlite.SqliteDBStore;
@@ -48,7 +50,6 @@ public class GitBridgeServer {
private String apiBaseURL;
public GitBridgeServer(Config config) throws ServletException {
org.eclipse.jetty.util.log.Log.setLog(new NullLogger());
this.port = config.getPort();
this.rootGitDirectoryPath = config.getRootGitDirectory();
RepoStore repoStore =
@@ -109,7 +110,7 @@ public class GitBridgeServer {
connector.setIdleTimeout(config.getIdleTimeout());
this.jettyServer.addConnector(connector);
HandlerCollection handlers = new HandlerList();
Handler.Sequence handlers = new Handler.Sequence();
handlers.addHandler(new CORSHandler(config.getAllowedCorsOrigins()));
handlers.addHandler(initApiHandler());
handlers.addHandler(initBaseHandler());
@@ -120,7 +121,7 @@ public class GitBridgeServer {
private Handler initBaseHandler() {
ContextHandler base = new ContextHandler();
base.setContextPath("/");
HandlerCollection handlers = new HandlerList();
Handler.Sequence handlers = new Handler.Sequence();
handlers.addHandler(new StatusHandler(bridge));
handlers.addHandler(new HealthCheckHandler(bridge));
handlers.addHandler(new GitLfsHandler(bridge));
@@ -134,7 +135,7 @@ public class GitBridgeServer {
ContextHandler api = new ContextHandler();
api.setContextPath("/api");
HandlerCollection handlers = new HandlerList();
Handler.Sequence handlers = new Handler.Sequence();
handlers.addHandler(initResourceHandler());
handlers.addHandler(new PostbackHandler(bridge));
handlers.addHandler(new ProjectDeletionHandler(bridge));
@@ -149,8 +150,8 @@ public class GitBridgeServer {
private Handler initGitHandler(Config config, RepoStore repoStore, SnapshotApi snapshotApi)
throws ServletException {
final ServletContextHandler servletContextHandler =
new ServletContextHandler(ServletContextHandler.SESSIONS);
final ServletContextHandler servletContextHandler = new ServletContextHandler();
servletContextHandler.setSessionHandler(new SessionHandler());
if (config.getOauth2Server() != null) {
Filter filter =
new Oauth2Filter(snapshotApi, config.getOauth2Server(), config.isUserPasswordEnabled());
@@ -166,8 +167,10 @@ public class GitBridgeServer {
}
private Handler initResourceHandler() {
ResourceHandler resourceHandler = new FileHandler(bridge);
resourceHandler.setResourceBase(new File(rootGitDirectoryPath, ".wlgb/atts").getAbsolutePath());
FileHandler resourceHandler = new FileHandler(bridge);
File attDir = new File(rootGitDirectoryPath, ".wlgb/atts");
resourceHandler.setBaseResource(
ResourceFactory.of(resourceHandler).newResource(attDir.toPath()));
return resourceHandler;
}
}

View File

@@ -1,14 +1,16 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
import uk.ac.ic.wlgitbridge.util.Log;
public class GitLfsHandler extends AbstractHandler {
public class GitLfsHandler extends Handler.Abstract {
private final Bridge bridge;
@@ -17,20 +19,22 @@ public class GitLfsHandler extends AbstractHandler {
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException {
String method = baseRequest.getMethod();
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String method = request.getMethod();
String path = Request.getPathInContext(request);
if (("POST".equals(method))
&& target != null
&& target.matches("^/[0-9a-z]+\\.git/info/lfs/objects/batch/?$")) {
&& path != null
&& path.matches("^/[0-9a-z]+\\.git/info/lfs/objects/batch/?$")) {
Log.debug(method + " <- /<project>.git/info/lfs/objects/batch");
response.setContentType("application/vnd.git-lfs+json");
response.setStatus(422);
response
.getWriter()
.println("{\"message\": \"ERROR: Git LFS is not supported on Overleaf\"}");
baseRequest.setHandled(true);
response.getHeaders().put("Content-Type", "application/vnd.git-lfs+json");
response.setStatus(HttpStatus.UNPROCESSABLE_ENTITY_422);
ByteBuffer responseBuffer =
ByteBuffer.wrap(
"{\"message\": \"ERROR: Git LFS is not supported on Overleaf\"}\n"
.getBytes(StandardCharsets.UTF_8));
response.write(true, responseBuffer, callback);
return true;
}
return false;
}
}

View File

@@ -1,14 +1,16 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
import uk.ac.ic.wlgitbridge.util.Log;
public class HealthCheckHandler extends AbstractHandler {
public class HealthCheckHandler extends Handler.Abstract {
private final Bridge bridge;
@@ -17,23 +19,24 @@ public class HealthCheckHandler extends AbstractHandler {
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException {
String method = baseRequest.getMethod();
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String method = request.getMethod();
String path = Request.getPathInContext(request);
if (("GET".equals(method) || "HEAD".equals(method))
&& target != null
&& target.matches("^/health_check/?$")) {
&& path != null
&& path.matches("^/health_check/?$")) {
Log.debug(method + " <- /health_check");
baseRequest.setHandled(true);
response.setContentType("text/plain");
response.getHeaders().put("Content-Type", "text/plain");
if (bridge.healthCheck()) {
response.setStatus(200);
response.getWriter().println("ok");
response.setStatus(HttpStatus.OK_200);
response.write(true, ByteBuffer.wrap("ok\n".getBytes(StandardCharsets.UTF_8)), callback);
} else {
response.setStatus(500);
response.getWriter().println("failed");
response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR_500);
response.write(
true, ByteBuffer.wrap("failed\n".getBytes(StandardCharsets.UTF_8)), callback);
}
return true;
}
return false;
}
}

View File

@@ -5,13 +5,13 @@ import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpHeaders;
import com.google.api.client.http.HttpRequest;
import com.google.api.client.http.HttpResponse;
import jakarta.servlet.*;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import uk.ac.ic.wlgitbridge.bridge.snapshot.SnapshotApi;
import uk.ac.ic.wlgitbridge.util.Instance;

View File

@@ -2,21 +2,24 @@ package uk.ac.ic.wlgitbridge.server;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import jakarta.servlet.ServletException;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
import uk.ac.ic.wlgitbridge.snapshot.push.exception.UnexpectedPostbackException;
import uk.ac.ic.wlgitbridge.util.Log;
import uk.ac.ic.wlgitbridge.util.Util;
/*
* Created by Winston on 16/11/14.
*/
public class PostbackHandler extends AbstractHandler {
public class PostbackHandler extends Handler.Abstract {
private final Bridge bridge;
@@ -25,14 +28,13 @@ public class PostbackHandler extends AbstractHandler {
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
Log.debug("PostbackHandler: " + baseRequest.getMethod() + " <- " + baseRequest.getHttpURI());
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String target = Request.getPathInContext(request);
Log.debug("PostbackHandler: " + request.getMethod() + " <- " + request.getHttpURI());
try {
if (request.getMethod().equals("POST") && target.endsWith("postback")) {
response.setContentType("application/json");
String contents = Util.getContentsOfReader(request.getReader());
response.getHeaders().put("Content-Type", "application/json");
String contents = Content.Source.asString(request);
String[] parts = target.split("/");
if (parts.length < 4) {
throw new ServletException();
@@ -46,16 +48,17 @@ public class PostbackHandler extends AbstractHandler {
try {
postbackContents.processPostback();
} catch (UnexpectedPostbackException e) {
response.setStatus(HttpServletResponse.SC_CONFLICT);
response.setStatus(HttpStatus.CONFLICT_409);
body.add("code", new JsonPrimitive("unexpectedPostback"));
response.getWriter().println(body);
baseRequest.setHandled(true);
return;
response.write(
true, ByteBuffer.wrap((body + "\n").getBytes(StandardCharsets.UTF_8)), callback);
return true;
}
response.setStatus(HttpServletResponse.SC_OK);
response.setStatus(HttpStatus.OK_200);
body.add("code", new JsonPrimitive("success"));
response.getWriter().println(body);
baseRequest.setHandled(true);
response.write(
true, ByteBuffer.wrap((body + "\n").getBytes(StandardCharsets.UTF_8)), callback);
return true;
}
} catch (IOException e) {
Log.warn("IOException when handling postback to target: " + target, e);
@@ -67,5 +70,6 @@ public class PostbackHandler extends AbstractHandler {
Log.warn("RuntimeException when handling postback to target: " + target, e);
throw e;
}
return false;
}
}

View File

@@ -1,22 +1,17 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.server.handler.ErrorHandler;
import org.eclipse.jetty.util.Callback;
public class ProductionErrorHandler extends ErrorHandler {
@Override
public void handle(
String target,
org.eclipse.jetty.server.Request baseRequest,
HttpServletRequest request,
HttpServletResponse response)
throws IOException {
response
.getWriter()
.append("{\"message\":\"HTTP error ")
.append(String.valueOf(response.getStatus()))
.append("\"}");
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String message = "{\"message\":\"HTTP error " + response.getStatus() + "\"}";
response.write(true, ByteBuffer.wrap(message.getBytes(StandardCharsets.UTF_8)), callback);
return true;
}
}

View File

@@ -1,15 +1,15 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
public class ProjectDeletionHandler extends AbstractHandler {
public class ProjectDeletionHandler extends Handler.Abstract {
private final Bridge bridge;
private final Pattern routePattern = Pattern.compile("^/projects/([0-9a-f]{24})$");
@@ -19,17 +19,18 @@ public class ProjectDeletionHandler extends AbstractHandler {
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException {
String method = baseRequest.getMethod();
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String method = request.getMethod();
String target = Request.getPathInContext(request);
Matcher matcher = routePattern.matcher(target);
if (method.equals("DELETE") && target != null && matcher.matches()) {
String projectName = matcher.group(1);
response.setContentType("text/plain");
response.setStatus(204);
response.getHeaders().put("Content-Type", "text/plain");
response.setStatus(HttpStatus.NO_CONTENT_204);
this.bridge.deleteProject(projectName);
baseRequest.setHandled(true);
callback.succeeded();
return true;
}
return false;
}
}

View File

@@ -4,44 +4,48 @@ import io.prometheus.client.CollectorRegistry;
import io.prometheus.client.exporter.common.TextFormat;
import io.prometheus.client.hotspot.DefaultExports;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import org.eclipse.jetty.http.HttpField;
import org.eclipse.jetty.http.HttpHeader;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import org.eclipse.jetty.util.Fields;
import uk.ac.ic.wlgitbridge.util.Log;
public class PrometheusHandler extends AbstractHandler {
public class PrometheusHandler extends Handler.Abstract {
public PrometheusHandler() {
DefaultExports.initialize();
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
String method = baseRequest.getMethod();
if (("GET".equals(method)) && target != null && target.matches("^/metrics/?$")) {
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String method = request.getMethod();
String path = Request.getPathInContext(request);
if (("GET".equals(method)) && path != null && path.matches("^/metrics/?$")) {
Log.debug(method + " <- /metrics");
this.printMetrics(request, response);
baseRequest.setHandled(true);
this.printMetrics(request, response, callback);
return true;
}
return false;
}
private void printMetrics(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setStatus(200);
String contentType = TextFormat.chooseContentType(request.getHeader("Accept"));
response.setContentType(contentType);
private void printMetrics(Request request, Response response, Callback callback)
throws Exception {
response.setStatus(HttpStatus.OK_200);
HttpField acceptField = request.getHeaders().getField(HttpHeader.ACCEPT);
String accept = acceptField != null ? acceptField.getValue() : null;
String contentType = TextFormat.chooseContentType(accept);
response.getHeaders().put("Content-Type", contentType);
Writer writer = new BufferedWriter(response.getWriter());
Writer writer =
new BufferedWriter(new OutputStreamWriter(Content.Sink.asOutputStream(response)));
try {
TextFormat.writeFormat(
@@ -51,15 +55,24 @@ public class PrometheusHandler extends AbstractHandler {
writer.flush();
} finally {
writer.close();
callback.succeeded();
}
}
private Set<String> parse(HttpServletRequest req) {
String[] includedParam = req.getParameterValues("name[]");
if (includedParam == null) {
return Collections.emptySet();
} else {
private Set<String> parse(Request req) {
try {
Fields parameters = Request.getParameters(req);
if (parameters == null) {
return Collections.emptySet();
}
List<String> values = parameters.getValues("name[]");
if (values == null || values.isEmpty()) {
return Collections.emptySet();
}
String[] includedParam = values.toArray(new String[0]);
return new HashSet<String>(Arrays.asList(includedParam));
} catch (Exception e) {
return Collections.emptySet();
}
}
}

View File

@@ -1,14 +1,15 @@
package uk.ac.ic.wlgitbridge.server;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.bridge.Bridge;
import uk.ac.ic.wlgitbridge.util.Log;
public class StatusHandler extends AbstractHandler {
public class StatusHandler extends Handler.Abstract {
private final Bridge bridge;
@@ -17,18 +18,19 @@ public class StatusHandler extends AbstractHandler {
}
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException {
String method = baseRequest.getMethod();
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String method = request.getMethod();
String target = Request.getPathInContext(request);
if (("GET".equals(method) || "HEAD".equals(method))
&& target != null
&& target.matches("^/status/?$")) {
Log.debug(method + " <- /status");
baseRequest.setHandled(true);
response.setContentType("text/plain");
response.setStatus(200);
response.getWriter().println("ok");
response.setStatus(HttpStatus.OK_200);
response.getHeaders().put("Content-Type", "text/plain");
response.write(
true, java.nio.ByteBuffer.wrap("ok\n".getBytes(StandardCharsets.UTF_8)), callback);
return true;
}
return false;
}
}

View File

@@ -8,8 +8,8 @@ import com.google.gson.JsonObject;
import java.io.IOException;
import java.util.Arrays;
import java.util.concurrent.*;
import javax.servlet.http.HttpServletResponse;
import org.asynchttpclient.AsyncHttpClient;
import org.eclipse.jetty.http.HttpStatus;
import uk.ac.ic.wlgitbridge.snapshot.exception.FailedConnectionException;
import uk.ac.ic.wlgitbridge.util.Instance;
import uk.ac.ic.wlgitbridge.util.Log;
@@ -72,17 +72,16 @@ public abstract class Request<T extends Result> {
if (cause instanceof HttpResponseException) {
HttpResponseException httpCause = (HttpResponseException) cause;
int sc = httpCause.getStatusCode();
if (sc == HttpServletResponse.SC_UNAUTHORIZED
|| sc == HttpServletResponse.SC_FORBIDDEN) { // 401, 403
if (sc == HttpStatus.UNAUTHORIZED_401 || sc == HttpStatus.FORBIDDEN_403) {
throw new ForbiddenException();
} else if (sc == 429) { // Too many requests
} else if (sc == HttpStatus.TOO_MANY_REQUESTS_429) {
throw new MissingRepositoryException(
Arrays.asList(
"Rate-limit exceeded. Please wait a while and try again.",
"",
"If this is unexpected, please contact us at support@overleaf.com, or",
"see https://www.overleaf.com/learn/how-to/Git_integration for more information."));
} else if (sc == HttpServletResponse.SC_CONFLICT) { // 409
} else if (sc == HttpStatus.CONFLICT_409) {
try {
JsonObject json = Instance.gson.fromJson(httpCause.getContent(), JsonObject.class);
String code = json.get("code").getAsString();
@@ -105,7 +104,7 @@ public abstract class Request<T extends Result> {
| NullPointerException _e) { // json parse errors
throw new MissingRepositoryException(Arrays.asList("Conflict: 409"));
}
} else if (sc == HttpServletResponse.SC_NOT_FOUND) { // 404
} else if (sc == HttpStatus.NOT_FOUND_404) {
try {
JsonObject json = Instance.gson.fromJson(httpCause.getContent(), JsonObject.class);
String message = json.get("message").getAsString();

View File

@@ -1,23 +1,25 @@
package uk.ac.ic.wlgitbridge.snapshot.servermock.server;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.http.HttpStatus;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
public class MockOAuthRequestHandler extends AbstractHandler {
public class MockOAuthRequestHandler extends Handler.Abstract {
@Override
public void handle(
String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException {
String method = baseRequest.getMethod();
if (method.equals("GET") && target.equals("/oauth/token/info")) {
response.setContentType("application/json");
response.setStatus(HttpServletResponse.SC_OK);
response.getWriter().println("{}");
baseRequest.setHandled(true);
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String method = request.getMethod();
String path = Request.getPathInContext(request);
if (method.equals("GET") && path.equals("/oauth/token/info")) {
response.getHeaders().put("Content-Type", "application/json");
response.setStatus(HttpStatus.OK_200);
response.write(true, ByteBuffer.wrap("{}\n".getBytes(StandardCharsets.UTF_8)), callback);
return true;
}
return false;
}
}

View File

@@ -1,11 +1,12 @@
package uk.ac.ic.wlgitbridge.snapshot.servermock.server;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import org.eclipse.jetty.io.Content;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.AbstractHandler;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.Callback;
import uk.ac.ic.wlgitbridge.snapshot.servermock.exception.InvalidAPICallException;
import uk.ac.ic.wlgitbridge.snapshot.servermock.response.*;
import uk.ac.ic.wlgitbridge.util.Log;
@@ -13,7 +14,7 @@ import uk.ac.ic.wlgitbridge.util.Log;
/*
* Created by Winston on 09/01/15.
*/
public class MockSnapshotRequestHandler extends AbstractHandler {
public class MockSnapshotRequestHandler extends Handler.Abstract {
private final SnapshotResponseBuilder responseBuilder;
@@ -22,25 +23,25 @@ public class MockSnapshotRequestHandler extends AbstractHandler {
}
@Override
public void handle(
String target,
final Request baseRequest,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException {
public boolean handle(Request request, Response response, Callback callback) throws Exception {
String path = Request.getPathInContext(request);
boolean handled;
try {
String requestBody = Content.Source.asString(request);
final SnapshotResponse snapshotResponse =
responseBuilder.buildWithTarget(target, baseRequest.getMethod());
response.getWriter().println(snapshotResponse.respond());
new PostbackThread(baseRequest.getReader(), snapshotResponse.postback()).startIfNotNull();
responseBuilder.buildWithTarget(path, request.getMethod());
String responseText = snapshotResponse.respond() + "\n";
response.write(
true, ByteBuffer.wrap(responseText.getBytes(StandardCharsets.UTF_8)), callback);
new PostbackThread(requestBody, snapshotResponse.postback()).startIfNotNull();
handled = true;
} catch (InvalidAPICallException e) {
handled = false;
} catch (RuntimeException e) {
Log.warn("Runtime exception when handling request", e);
callback.succeeded();
handled = true;
}
baseRequest.setHandled(handled);
return handled;
}
}

View File

@@ -1,11 +1,11 @@
package uk.ac.ic.wlgitbridge.snapshot.servermock.server;
import java.io.File;
import org.eclipse.jetty.server.Handler;
import org.eclipse.jetty.server.NetworkConnector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerCollection;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.server.handler.ResourceHandler;
import org.eclipse.jetty.util.resource.ResourceFactory;
import uk.ac.ic.wlgitbridge.snapshot.servermock.response.SnapshotResponseBuilder;
import uk.ac.ic.wlgitbridge.snapshot.servermock.state.SnapshotAPIState;
import uk.ac.ic.wlgitbridge.util.Log;
@@ -23,14 +23,14 @@ public class MockSnapshotServer {
server = new Server(port);
responseBuilder = new SnapshotResponseBuilder();
HandlerList handlers = new HandlerList();
Handler.Sequence handlers = new Handler.Sequence();
handlers.addHandler(new MockOAuthRequestHandler());
handlers.addHandler(getHandlerForResourceBase(resourceBase));
server.setHandler(handlers);
}
private HandlerCollection getHandlerForResourceBase(File resourceBase) {
HandlerCollection handlers = new HandlerCollection();
private Handler.Sequence getHandlerForResourceBase(File resourceBase) {
Handler.Sequence handlers = new Handler.Sequence();
handlers.addHandler(new MockSnapshotRequestHandler(responseBuilder));
handlers.addHandler(resourceHandlerWithBase(resourceBase));
return handlers;
@@ -38,7 +38,8 @@ public class MockSnapshotServer {
private ResourceHandler resourceHandlerWithBase(File resourceBase) {
ResourceHandler resourceHandler = new ResourceHandler();
resourceHandler.setResourceBase(resourceBase.getAbsolutePath());
resourceHandler.setBaseResource(
ResourceFactory.of(resourceHandler).newResource(resourceBase.toPath()));
return resourceHandler;
}

View File

@@ -4,7 +4,6 @@ import static org.asynchttpclient.Dsl.*;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import java.io.Reader;
import java.util.concurrent.ExecutionException;
import uk.ac.ic.wlgitbridge.util.Log;
@@ -16,9 +15,9 @@ public class PostbackThread extends Thread {
private String url;
private String postback;
public PostbackThread(Reader reader, String postback) {
if (postback != null) {
url = new Gson().fromJson(reader, JsonObject.class).get("postbackUrl").getAsString();
public PostbackThread(String requestBody, String postback) {
if (postback != null && requestBody != null && !requestBody.isEmpty()) {
url = new Gson().fromJson(requestBody, JsonObject.class).get("postbackUrl").getAsString();
this.postback = postback;
}
}