Skip to content

Commit

Permalink
Code review fixes. Also improved tests checks.
Browse files Browse the repository at this point in the history
  • Loading branch information
ChGen committed Nov 2, 2023
1 parent f1925ad commit 9eafe0a
Show file tree
Hide file tree
Showing 5 changed files with 457 additions and 110 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.attribute.FileTime;
import java.text.DateFormat;
Expand Down Expand Up @@ -70,75 +69,8 @@ final class HttpTransporter extends AbstractTransporter {
RemoteRepository repository,
RepositorySystemSession session)
throws Exception {
System.err.println("Custom HttpTransporter created!!!");

// Checking http3 support is available (loaded)
PreEncodedHttpField f = new PreEncodedHttpField("Host", "localhost");
for (final HttpVersion v: HttpVersion.values()) {
int len = 0;
try {
len = f.getEncodedLength(v);
} catch (Exception ex) {
len = -1;
}
System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len);
}

// TODO: Force http3 initialization (HACK!)
final ServiceLoader<HttpFieldPreEncoder> load = ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader());
/*ServiceLoader<HttpFieldPreEncoder> load = null;
ClassLoader saveCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(PreEncodedHttpField.class.getClassLoader());
load = ServiceLoader.load(HttpFieldPreEncoder.class);
}finally {
Thread.currentThread().setContextClassLoader(saveCl);
}*/

/*System.err.println("\tCustom HttpTransporter ServiceLoader=" + load);
Stream<ServiceLoader.Provider<HttpFieldPreEncoder>> providerStream = TypeUtil.serviceProviderStream(load);
System.err.println("\tCustom HttpTransporter Stream<ServiceLoader.Provider<HttpFieldPreEncoder>> = " + providerStream);
ArrayList<Integer> calls = new ArrayList<>();
providerStream.forEach((provider) -> {
try {
calls.add(calls.size());
HttpFieldPreEncoder encoder = (HttpFieldPreEncoder)provider.get();
HttpVersion v = encoder.getHttpVersion();
System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder: encoder=" + encoder + "; ver=" + v);
} catch (RuntimeException | Error var3) {
System.err.println("\tCustom HttpTransporter Error processing encoder: " + provider.get());
}
});
System.err.println("\tCustom HttpTransporter providerStream calls=" + calls.size());*/

HashMap<HttpVersion, HttpFieldPreEncoder> encoders = new HashMap<>();
for (HttpFieldPreEncoder val: load) {
System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder val=" + val);
encoders.put(val.getHttpVersion(), val);
}

Field ff = PreEncodedHttpField.class.getDeclaredField("__encoders");
ff.setAccessible(true);
String fldDescr = ff.get(null).toString();
System.err.println("\tCustom HttpTransporter __encoders BEFORE: " + fldDescr + "; this=" + this);
@SuppressWarnings("unchecked") EnumMap<HttpVersion, HttpFieldPreEncoder> obj = (EnumMap<HttpVersion, HttpFieldPreEncoder>)ff.get(null);
if (encoders.containsKey(HttpVersion.HTTP_3) && !obj.containsKey(HttpVersion.HTTP_3)) {
System.err.println("\tCustom HttpTransporter adding to __encoders: " + obj + "; this=" + this);
obj.put(HttpVersion.HTTP_3, encoders.get(HttpVersion.HTTP_3));
}
System.err.println("\tCustom HttpTransporter __encoders AFTER: " + obj + "; this=" + this);

// Rechecking http3 support is available (loaded)
f = new PreEncodedHttpField("Host", "localhost");
for (final HttpVersion v: HttpVersion.values()) {
int len = 0;
try {
len = f.getEncodedLength(v);
} catch (Exception ex) {
len = -1;
}
System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len);
}
forceLoadHttp3Support();

if (!"http".equalsIgnoreCase(repository.getProtocol()) && !"https".equalsIgnoreCase(repository.getProtocol())) {
throw new NoTransporterException(repository);
Expand Down Expand Up @@ -286,4 +218,83 @@ private void extractChecksums(ContentResponse response, GetTask task) {
}
}
}

/**
* TOOD: For unknown reason when running inside Maven, HttpFieldPreEncoder for HTTP3 is missing.
* It is not available in Jetty static initializer when that library is loaded by Maven.
* However, it is available the moment later.
* Here I use reflection to force-register missing HttpFieldPreEncoder for HTTP3.
* @throws NoSuchFieldException
* @throws IllegalAccessException
*/
private void forceLoadHttp3Support() throws NoSuchFieldException, IllegalAccessException {
System.err.println("Custom HttpTransporter.forceLoadHttp3Support() called!");
// Checking http3 support is available (loaded)
PreEncodedHttpField f = new PreEncodedHttpField("Host", "localhost");
for (final HttpVersion v: HttpVersion.values()) {
int len = 0;
try {
len = f.getEncodedLength(v);
} catch (Exception ex) {
len = -1;
}
System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len);
}

// TODO: Force http3 initialization (HACK!)
final ServiceLoader<HttpFieldPreEncoder> load = ServiceLoader.load(HttpFieldPreEncoder.class,PreEncodedHttpField.class.getClassLoader());
/*ServiceLoader<HttpFieldPreEncoder> load = null;
ClassLoader saveCl = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(PreEncodedHttpField.class.getClassLoader());
load = ServiceLoader.load(HttpFieldPreEncoder.class);
}finally {
Thread.currentThread().setContextClassLoader(saveCl);
}*/

/*System.err.println("\tCustom HttpTransporter ServiceLoader=" + load);
Stream<ServiceLoader.Provider<HttpFieldPreEncoder>> providerStream = TypeUtil.serviceProviderStream(load);
System.err.println("\tCustom HttpTransporter Stream<ServiceLoader.Provider<HttpFieldPreEncoder>> = " + providerStream);
ArrayList<Integer> calls = new ArrayList<>();
providerStream.forEach((provider) -> {
try {
calls.add(calls.size());
HttpFieldPreEncoder encoder = (HttpFieldPreEncoder)provider.get();
HttpVersion v = encoder.getHttpVersion();
System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder: encoder=" + encoder + "; ver=" + v);
} catch (RuntimeException | Error var3) {
System.err.println("\tCustom HttpTransporter Error processing encoder: " + provider.get());
}
});
System.err.println("\tCustom HttpTransporter providerStream calls=" + calls.size());*/

HashMap<HttpVersion, HttpFieldPreEncoder> encoders = new HashMap<>();
for (HttpFieldPreEncoder val: load) {
System.err.println("\tCustom HttpTransporter HttpFieldPreEncoder val=" + val);
encoders.put(val.getHttpVersion(), val);
}

Field ff = PreEncodedHttpField.class.getDeclaredField("__encoders");
ff.setAccessible(true);
String fldDescr = ff.get(null).toString();
System.err.println("\tCustom HttpTransporter __encoders BEFORE: " + fldDescr + "; this=" + this);
@SuppressWarnings("unchecked") EnumMap<HttpVersion, HttpFieldPreEncoder> obj = (EnumMap<HttpVersion, HttpFieldPreEncoder>)ff.get(null);
if (encoders.containsKey(HttpVersion.HTTP_3) && !obj.containsKey(HttpVersion.HTTP_3)) {
System.err.println("\tCustom HttpTransporter adding to __encoders: " + obj + "; this=" + this);
obj.put(HttpVersion.HTTP_3, encoders.get(HttpVersion.HTTP_3));
}
System.err.println("\tCustom HttpTransporter __encoders AFTER: " + obj + "; this=" + this);

// Rechecking http3 support is available (loaded)
f = new PreEncodedHttpField("Host", "localhost");
for (final HttpVersion v: HttpVersion.values()) {
int len = 0;
try {
len = f.getEncodedLength(v);
} catch (Exception ex) {
len = -1;
}
System.err.println("\tCustom HttpTransporter PreEncodedHttpField v=" + v + "; len=" + len);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
import org.eclipse.aether.spi.connector.transport.GetTask;
import org.eclipse.aether.spi.connector.transport.TransportListener;
import org.eclipse.aether.spi.connector.transport.Transporter;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.jetty.client.ContentResponse;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.HttpRequestException;
Expand All @@ -23,7 +22,6 @@
import org.testcontainers.containers.InternetProtocol;
import org.testcontainers.containers.wait.strategy.ShellStrategy;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import static org.junit.Assert.*;

Expand All @@ -32,63 +30,68 @@
*/
public class MavenResolverIT {

private static GenericContainer<?> caddy;
private static GenericContainer<?> caddyAuth;
private static final String REMOTE_PATH = "commons-cli/commons-cli/1.4/commons-cli-1.4.pom";
private static final String LOCAL_PATH = "commons-cli-1.4.pom";

private static GenericContainer<?> caddyProxy;
private static GenericContainer<?> caddyProxyAuth;

@Test
public void testTransporterAuth() throws Exception {
final byte[] data = testTransporter("https://demo:demo@localhost:7444/maven2");
assertNotEquals(null, data);
System.err.println(new String(data, StandardCharsets.UTF_8));
assertTrue(data.length > 0);
final byte[] local = getClass().getClassLoader().getResourceAsStream(LOCAL_PATH).readAllBytes();
assertArrayEquals(local, data);
}

@Test(expected = HttpResponseException.class)
public void testTransporterAuthFail() throws Exception {
final byte[] data = testTransporter("https://demo1:demo1@localhost:7444/maven2");
assertNull(data);
@Test
public void testTransporterAuthFail() {
HttpResponseException exception = assertThrows(
"Invalid exception thrown", HttpResponseException.class,
() -> testTransporter("https://demo1:demo1@localhost:7444/maven2")
);
assertEquals("401", exception.getMessage());
}

@Test(expected = HttpResponseException.class)
public void testTransporterAnonAuthFail() throws Exception {
testTransporter("https://localhost:7444/maven2");
@Test
public void testTransporterAnonAuthFail() {
HttpResponseException exception = assertThrows(
"Invalid exception thrown", HttpResponseException.class,
() -> testTransporter("https://localhost:7444/maven2")
);
assertEquals("401", exception.getMessage());
}

@Test
public void testTransporterAnon() throws Exception {
final byte[] data = testTransporter("https://localhost:7443/maven2");
assertNotEquals(null, data);
System.err.println(new String(data, StandardCharsets.UTF_8));
assertTrue(data.length > 0);
}
final byte[] local = getClass().getClassLoader().getResourceAsStream(LOCAL_PATH).readAllBytes();
assertArrayEquals(local, data); }

@Test
public void testAnonTransporterSuccess() throws Exception {
final byte[] data = testTransporter("https://demo:demo@localhost:7443/maven2");
assertNotNull(data);
assertTrue(data.length > 0);
final byte[] local = getClass().getClassLoader().getResourceAsStream(LOCAL_PATH).readAllBytes();
assertArrayEquals(local, data);
}

@Test(expected = HttpRequestException.class)
public void testTransporterInvalidUrl() throws Exception {
testTransporter("https://localhost:7445/maven2");
@Test()
public void testTransporterInvalidUrl() {
HttpRequestException exception = assertThrows(
"Invalid exception thrown", HttpRequestException.class,
() -> testTransporter("https://localhost:7445/maven2")
);
assertEquals("java.net.SocketTimeoutException: connect timeout", exception.getMessage());
}

private byte[] testTransporter(final String repo) throws Exception {
final RepositorySystemSession session = newSession();
final RemoteRepository repository = newRepo(repo);
final HttpTransporterFactory factory = new HttpTransporterFactory();
TransportListener listener = new TransportListener() {
@Override
public void transportStarted(long dataOffset, long dataLength) throws TransferCancelledException {
super.transportStarted(dataOffset, dataLength);
}
@Override
public void transportProgressed(ByteBuffer data) throws TransferCancelledException {
super.transportProgressed(data);
}
};
final GetTask task = new GetTask(URI.create("commons-cli/commons-cli/1.4/commons-cli-1.4.pom")).setListener(listener);
final GetTask task = new GetTask(URI.create(REMOTE_PATH))
.setListener(new TransportListener() {});
try (final Transporter transporter = factory.newInstance(session, repository)) {
transporter.get(task);
}
Expand All @@ -111,36 +114,36 @@ public void testJettyLocalhostConnection() throws Exception {
@BeforeClass
public static void prepare() {
try {
caddy = new FixedHostPortGenericContainer<>("library/caddy:2.7.5")
caddyProxy = new FixedHostPortGenericContainer<>("library/caddy:2.7.5")
.withReuse(false)
.withFileSystemBind("src/test/resources/Caddyfile.docker", "/etc/caddy/Caddyfile")
.withFileSystemBind("src/test/resources/Caddyfile.proxy", "/etc/caddy/Caddyfile")
.withFileSystemBind("src/test/resources/stunnel.pem", "/etc/caddy/stunnel.pem")
.waitingFor(new ShellStrategy().withCommand("nc -u -z localhost 7443"))
.withFixedExposedPort(7443, 7443, InternetProtocol.UDP)
.withFixedExposedPort(8080, 8080, InternetProtocol.TCP)
.withAccessToHost(true);

caddyAuth = new FixedHostPortGenericContainer<>("library/caddy:2.7.5")
caddyProxyAuth = new FixedHostPortGenericContainer<>("library/caddy:2.7.5")
.withReuse(false)
.withFileSystemBind("src/test/resources/Caddyfile.auth.docker", "/etc/caddy/Caddyfile")
.withFileSystemBind("src/test/resources/Caddyfile.proxy.auth", "/etc/caddy/Caddyfile")
.withFileSystemBind("src/test/resources/stunnel.pem", "/etc/caddy/stunnel.pem")
.waitingFor(new ShellStrategy().withCommand("nc -u -z localhost 7444"))
.withFixedExposedPort(7444, 7444, InternetProtocol.UDP)
.withAccessToHost(true);
caddy.start();
caddyAuth.start();
caddyProxy.start();
caddyProxyAuth.start();
}
catch (Exception ex) {
System.err.println(caddy.getLogs());
System.err.println(caddyAuth.getLogs());
System.err.println(caddyProxy.getLogs());
System.err.println(caddyProxyAuth.getLogs());
throw ex;
}
}

@AfterClass
public static void finish() {
caddy.stop();
caddyAuth.stop();
caddyProxy.stop();
caddyProxyAuth.stop();
}

private static DefaultRepositorySystemSession newSession() {
Expand Down
Loading

1 comment on commit 9eafe0a

@0pdd
Copy link

@0pdd 0pdd commented on 9eafe0a Nov 2, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't able to retrieve PDD puzzles from the code base and submit them to github. If you think that it's a bug on our side, please submit it to yegor256/0pdd:

set -x && set -e && set -o pipefail && cd /tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0 && pdd -v -f /tmp/20231102-604013-6bnr0v [1]: + set -e + set -o pipefail + cd...

Please, copy and paste this stack trace to GitHub:

UserError
set -x && set -e && set -o pipefail && cd /tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0 && pdd -v -f /tmp/20231102-604013-6bnr0v [1]:
+ set -e
+ set -o pipefail
+ cd /tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0
+ pdd -v -f /tmp/20231102-604013-6bnr0v

My version is 0.23.2
Ruby version is 3.1.4 at x86_64-linux
Reading from root dir /tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0
/tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0/mvn-resolver-transport-http3/src/test/resources/ssl/client-store is a binary file (2244 bytes)
/tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0/mvn-resolver-transport-http3/src/test/resources/ssl/server-store is a binary file (2246 bytes)
/tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0/mvn-resolver-transport-http3/src/test/resources/ssl/server-store-selfsigned is a binary file (2750 bytes)
/tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0/testing/mvn-resolver-transport-http/src/test/resources/ssl/client-store is a binary file (2244 bytes)
/tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0/testing/mvn-resolver-transport-http/src/test/resources/ssl/server-store is a binary file (2246 bytes)
/tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0/testing/mvn-resolver-transport-http/src/test/resources/ssl/server-store-selfsigned is a binary file (2750 bytes)
/tmp/0pdd20231102-14-2hjry1/Z2l0QGdpdGh1Yi5jb206YXJ0aXBpZS9tYXZlbi1yZXNvbHZlci1odHRwMy1wbHVnaW4uZ2l0/testing/mvn-wagon-http-light/src/test/resources/ssl/keystore is a binary file (2246 bytes)
Reading README.md ...
Reading mvn-resolver-transport-http3/README.md ...
Reading mvn-resolver-transport-http3/pom.xml ...
Reading mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/ConnMgrConfig.java ...
Reading mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/HttpTransporter.java ...
ERROR: ERROR: mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/HttpTransporter.java; PDD::Error at mvn-resolver-transport-http3/src/main/java/com/artipie/aether/transport/http3/HttpTransporter.java:123: TODO found, but puzzle can't be parsed, most probably because TODO is not followed by a puzzle marker, as this page explains: https://github.com/cqfn/pdd#how-to-format
If you can't understand the cause of this issue or you don't know how to fix it, please submit a GitHub issue, we will try to help you: https://github.com/cqfn/pdd/issues. This tool is still in its beta version and we will appreciate your feedback. Here is where you can find more documentation: https://github.com/cqfn/pdd/blob/master/README.md.
Exit code is 1

/app/objects/git_repo.rb:73:in `rescue in block in xml'
/app/objects/git_repo.rb:70:in `block in xml'
/app/vendor/ruby-3.1.4/lib/ruby/3.1.0/tempfile.rb:317:in `open'
/app/objects/git_repo.rb:69:in `xml'
/app/objects/puzzles.rb:41:in `deploy'
/app/objects/jobs/job.rb:38:in `proceed'
/app/objects/jobs/job_starred.rb:32:in `proceed'
/app/objects/jobs/job_recorded.rb:31:in `proceed'
/app/objects/jobs/job_emailed.rb:33:in `proceed'
/app/objects/jobs/job_commiterrors.rb:33:in `proceed'
/app/objects/jobs/job_detached.rb:48:in `exclusive'
/app/objects/jobs/job_detached.rb:36:in `block in proceed'
/app/objects/jobs/job_detached.rb:36:in `fork'
/app/objects/jobs/job_detached.rb:36:in `proceed'
/app/0pdd.rb:531:in `process_request'
/app/0pdd.rb:367:in `block in <top (required)>'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1706:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1706:in `block in compile!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1019:in `block (3 levels) in route!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1037:in `route_eval'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1019:in `block (2 levels) in route!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1068:in `block in process_route'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1066:in `catch'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1066:in `process_route'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1017:in `block in route!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1014:in `each'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1014:in `route!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1138:in `block in dispatch!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1109:in `catch'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1109:in `invoke'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1133:in `dispatch!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:949:in `block in call!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1109:in `catch'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1109:in `invoke'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:949:in `call!'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:938:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-2.2.8/lib/rack/deflater.rb:44:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-protection-3.0.6/lib/rack/protection/xss_header.rb:20:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-protection-3.0.6/lib/rack/protection/path_traversal.rb:18:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-protection-3.0.6/lib/rack/protection/json_csrf.rb:28:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-protection-3.0.6/lib/rack/protection/base.rb:53:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-protection-3.0.6/lib/rack/protection/base.rb:53:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-protection-3.0.6/lib/rack/protection/frame_options.rb:33:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-2.2.8/lib/rack/logger.rb:17:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-2.2.8/lib/rack/common_logger.rb:38:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:261:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:254:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-2.2.8/lib/rack/head.rb:12:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-2.2.8/lib/rack/method_override.rb:24:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:219:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:2018:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1576:in `block in call'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1792:in `synchronize'
/app/vendor/bundle/ruby/3.1.0/gems/sinatra-3.0.6/lib/sinatra/base.rb:1576:in `call'
/app/vendor/bundle/ruby/3.1.0/gems/rack-2.2.8/lib/rack/handler/webrick.rb:95:in `service'
/app/vendor/bundle/ruby/3.1.0/gems/webrick-1.8.1/lib/webrick/httpserver.rb:140:in `service'
/app/vendor/bundle/ruby/3.1.0/gems/webrick-1.8.1/lib/webrick/httpserver.rb:96:in `run'
/app/vendor/bundle/ruby/3.1.0/gems/webrick-1.8.1/lib/webrick/server.rb:310:in `block in start_thread'

Please sign in to comment.