This commit is contained in:
Andreas Penski (init) 2020-10-02 09:47:28 +02:00
parent 3cb1037771
commit 65f6914c3c
3 changed files with 64 additions and 5 deletions

View file

@ -507,7 +507,7 @@
<plugin> <plugin>
<groupId>net.revelc.code.formatter</groupId> <groupId>net.revelc.code.formatter</groupId>
<artifactId>formatter-maven-plugin</artifactId> <artifactId>formatter-maven-plugin</artifactId>
<version>2.12.2</version> <version>2.13.0</version>
<executions> <executions>
<execution> <execution>
<id>validate</id> <id>validate</id>
@ -519,6 +519,7 @@
</executions> </executions>
<configuration> <configuration>
<configFile>${project.basedir}/formatter.xml</configFile> <configFile>${project.basedir}/formatter.xml</configFile>
<lineEnding>LF</lineEnding>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>

View file

@ -1,11 +1,13 @@
package de.kosit.validationtool.daemon; package de.kosit.validationtool.daemon;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.net.URI; import java.net.URI;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import org.apache.commons.lang3.StringUtils;
import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpExchange;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
@ -15,6 +17,7 @@ import de.kosit.validationtool.api.Check;
import de.kosit.validationtool.api.InputFactory; import de.kosit.validationtool.api.InputFactory;
import de.kosit.validationtool.api.Result; import de.kosit.validationtool.api.Result;
import de.kosit.validationtool.impl.input.SourceInput; import de.kosit.validationtool.impl.input.SourceInput;
import de.kosit.validationtool.impl.input.StreamHelper;
import net.sf.saxon.s9api.Processor; import net.sf.saxon.s9api.Processor;
import net.sf.saxon.s9api.SaxonApiException; import net.sf.saxon.s9api.SaxonApiException;
@ -47,9 +50,9 @@ class CheckHandler extends BaseHandler {
final String requestMethod = httpExchange.getRequestMethod(); final String requestMethod = httpExchange.getRequestMethod();
// check neccessary, since gui can be disabled // check neccessary, since gui can be disabled
if (requestMethod.equals("POST")) { if (requestMethod.equals("POST")) {
final InputStream inputStream = httpExchange.getRequestBody(); final BufferedInputStream buffered = StreamHelper.wrapPeekable(httpExchange.getRequestBody());
if (inputStream.available() > 0) { if (!isMultipartFormData(httpExchange) && isContentAvailable(httpExchange, buffered)) {
final SourceInput serverInput = (SourceInput) InputFactory.read(inputStream, final SourceInput serverInput = (SourceInput) InputFactory.read(buffered,
resolveInputName(httpExchange.getRequestURI())); resolveInputName(httpExchange.getRequestURI()));
final Result result = this.implemenation.checkInput(serverInput); final Result result = this.implemenation.checkInput(serverInput);
write(httpExchange, serialize(result), APPLICATION_XML, resolveStatus(result)); write(httpExchange, serialize(result), APPLICATION_XML, resolveStatus(result));
@ -61,10 +64,29 @@ class CheckHandler extends BaseHandler {
error(httpExchange, HttpStatus.SC_METHOD_NOT_ALLOWED, "Method not supported"); error(httpExchange, HttpStatus.SC_METHOD_NOT_ALLOWED, "Method not supported");
} }
} catch (final Exception e) { } catch (final Exception e) {
log.error("Error checking entity", e);
error(httpExchange, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Internal error: " + e.getMessage()); error(httpExchange, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Internal error: " + e.getMessage());
} }
} }
private static boolean isContentAvailable(final com.sun.net.httpserver.HttpExchange httpExchange, final BufferedInputStream buffered)
throws IOException {
final String length = httpExchange.getRequestHeaders().getFirst("Content-length");
if (StringUtils.isNumeric(length)) {
return Integer.parseInt(length) > 0;
}
return streamContainsContent(buffered);
}
private static boolean isMultipartFormData(final HttpExchange httpExchange) {
return httpExchange.getRequestHeaders().getFirst("Content-type").startsWith("multipart");
}
private static boolean streamContainsContent(final BufferedInputStream requestBody) throws IOException {
return requestBody.available() > 0;
}
private static String resolveInputName(final URI requestURI) { private static String resolveInputName(final URI requestURI) {
final String path = requestURI.getPath(); final String path = requestURI.getPath();
if (path.equalsIgnoreCase("/")) { if (path.equalsIgnoreCase("/")) {

View file

@ -1,5 +1,6 @@
package de.kosit.validationtool.impl.input; package de.kosit.validationtool.impl.input;
import java.io.BufferedInputStream;
import java.io.FilterInputStream; import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -45,6 +46,35 @@ public class StreamHelper {
} }
private static class PeekableInputStream extends BufferedInputStream {
public PeekableInputStream(final InputStream in) {
super(in);
}
@Override
public synchronized int available() throws IOException {
int count = super.available();
if (count == 0) {
count = peek();
}
return count;
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private int peek() throws IOException {
try {
mark(2);
read();
read();
reset();
} catch (final IOException e) {
return 0;
}
return super.available();
}
}
@SuppressWarnings("squid:S4929") // efficient read is done by internally used stream @SuppressWarnings("squid:S4929") // efficient read is done by internally used stream
private static class CountInputStream extends FilterInputStream { private static class CountInputStream extends FilterInputStream {
@ -103,6 +133,10 @@ public class StreamHelper {
return new DigestingInputStream(input, stream, createDigest(digestAlgorithm)); return new DigestingInputStream(input, stream, createDigest(digestAlgorithm));
} }
public static BufferedInputStream wrapPeekable(final InputStream stream) {
return new PeekableInputStream(stream);
}
/** /**
* Drains the {@link Input} without further processing. This is useful to computing hashcode etc. * Drains the {@link Input} without further processing. This is useful to computing hashcode etc.
* *
@ -129,8 +163,10 @@ public class StreamHelper {
public static void drain(final InputStream input) throws IOException { public static void drain(final InputStream input) throws IOException {
final byte[] buffer = new byte[DEFAULT_BUFFER_SIZE]; final byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
// noinspection unused
int n; int n;
// noinspection StatementWithEmptyBody,UnusedAssignment
while (EOF != (n = input.read(buffer))) { while (EOF != (n = input.read(buffer))) {
// nothing // nothing
} }