Chunk parsing algo, HTTP/1.0, fixing http status with tomcat
This commit is contained in:
@@ -1,12 +1,14 @@
|
||||
package ovh.alexisdelhaie.endpoint.controllers;
|
||||
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.event.ActionEvent;
|
||||
import javafx.fxml.FXML;
|
||||
import javafx.fxml.FXMLLoader;
|
||||
import javafx.fxml.Initializable;
|
||||
import javafx.scene.Parent;
|
||||
import javafx.scene.Scene;
|
||||
import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.CheckBox;
|
||||
import javafx.scene.control.ChoiceBox;
|
||||
import javafx.scene.image.Image;
|
||||
import javafx.scene.input.MouseEvent;
|
||||
import javafx.stage.Modality;
|
||||
@@ -14,8 +16,6 @@ import javafx.stage.Stage;
|
||||
import ovh.alexisdelhaie.endpoint.configuration.ConfigurationProperties;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.ResourceBundle;
|
||||
|
||||
public class ConfigurationController
|
||||
{
|
||||
@@ -27,15 +27,21 @@ public class ConfigurationController
|
||||
private CheckBox allowInvalidSsl;
|
||||
@FXML
|
||||
private CheckBox allowDowngrade;
|
||||
@FXML
|
||||
private ChoiceBox<String> httpVersion;
|
||||
|
||||
public void setStageAndSetupListeners(Stage s) {
|
||||
primaryStage = s;
|
||||
}
|
||||
|
||||
public void setConfigurationProperties(ConfigurationProperties properties) {
|
||||
String[] versions = { "HTTP/1.1", "HTTP/1.0" };
|
||||
httpVersion.setItems(FXCollections.observableArrayList(versions));
|
||||
configurationProperties = properties;
|
||||
allowInvalidSsl.setSelected(properties.getBooleanProperty("allowInvalidSsl", false));
|
||||
allowDowngrade.setSelected(properties.getBooleanProperty("allowDowngrade", true));
|
||||
httpVersion.setValue(properties.getStringProperty("httpVersion", versions[0]));
|
||||
httpVersion.setOnAction(this::onChoiceBoxValueChanged);
|
||||
}
|
||||
|
||||
@FXML
|
||||
@@ -44,13 +50,19 @@ public class ConfigurationController
|
||||
configurationProperties.setProperty(c.getId(), String.valueOf(c.isSelected()));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void onChoiceBoxValueChanged(ActionEvent event) {
|
||||
ChoiceBox<String> c = (ChoiceBox<String>) event.getSource();
|
||||
configurationProperties.setProperty(c.getId(), c.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void showAboutDialog() {
|
||||
try {
|
||||
Stage dialog = new Stage();
|
||||
Parent xml = FXMLLoader.load(getClass().getResource("about.fxml"));
|
||||
dialog.initOwner(primaryStage);
|
||||
dialog.setScene(new Scene(xml, 677, 365));
|
||||
dialog.setScene(new Scene(xml, 707, 365));
|
||||
dialog.setMaxHeight(365);
|
||||
dialog.setMinHeight(365);
|
||||
dialog.setMaxWidth(707);
|
||||
|
||||
@@ -84,6 +84,7 @@ public class Controller implements Initializable {
|
||||
|
||||
private Stage primaryStage;
|
||||
private HashMap<Integer, String> requests;
|
||||
private HashMap<Integer, String> methods;
|
||||
|
||||
private ConfigurationProperties properties;
|
||||
|
||||
@@ -91,11 +92,16 @@ public class Controller implements Initializable {
|
||||
public void initialize(URL location, ResourceBundle resources) {
|
||||
properties = new ConfigurationProperties();
|
||||
requests = new HashMap<>();
|
||||
methods = new HashMap<>();
|
||||
String[] method = { "GET", "POST", "HEAD", "PUT", "DELETE" };
|
||||
httpMethod.setItems(FXCollections.observableArrayList(method));
|
||||
httpMethod.setValue(method[0]);
|
||||
httpMethod.setOnAction(actionEvent -> httpMethodChanged());
|
||||
tabs.getSelectionModel().selectedItemProperty().addListener(
|
||||
(ov, t, t1) -> requestInput.setText((t1 != null) ? requests.get(t1.hashCode()) : "")
|
||||
(ov, t, t1) -> {
|
||||
requestInput.setText((t1 != null) ? requests.get(t1.hashCode()) : "");
|
||||
httpMethod.setValue((t1 != null) ? methods.get(t1.hashCode()) : httpMethod.getValue());
|
||||
}
|
||||
);
|
||||
createNewTab();
|
||||
}
|
||||
@@ -111,6 +117,7 @@ public class Controller implements Initializable {
|
||||
|
||||
TabPane options = new TabPane();
|
||||
TextArea ta = new TextArea();
|
||||
ta.setEditable(false);
|
||||
|
||||
options.setTabClosingPolicy(TabPane.TabClosingPolicy.UNAVAILABLE);
|
||||
options.getTabs().addAll(params, auth, headers, body, response);
|
||||
@@ -121,6 +128,7 @@ public class Controller implements Initializable {
|
||||
Tab tab = new Tab("untitled", sp);
|
||||
tab.setOnCloseRequest(arg0 -> {
|
||||
requests.remove(tab.hashCode());
|
||||
methods.remove(tab.hashCode());
|
||||
});
|
||||
|
||||
return tab;
|
||||
@@ -209,10 +217,7 @@ public class Controller implements Initializable {
|
||||
Request r = new RequestBuilder(requestInput.getText())
|
||||
.setCustomHeaders(getCustomHeaders())
|
||||
.build();
|
||||
HttpClient hc = new HttpClient(
|
||||
properties.getBooleanProperty("allowInvalidSsl", false),
|
||||
properties.getBooleanProperty("allowDowngrade", true)
|
||||
);
|
||||
HttpClient hc = new HttpClient(properties);
|
||||
switch (method) {
|
||||
case "GET" -> response = hc.get(r);
|
||||
case "POST" -> response = hc.post(r, getBody());
|
||||
@@ -395,6 +400,7 @@ public class Controller implements Initializable {
|
||||
new Thread(() -> {
|
||||
Tab t = newTab();
|
||||
requests.put(t.hashCode(), "");
|
||||
methods.put(t.hashCode(), httpMethod.getValue());
|
||||
Platform.runLater(() -> {
|
||||
tabs.getTabs().add(t);
|
||||
tabs.getSelectionModel().select(t);
|
||||
@@ -436,6 +442,11 @@ public class Controller implements Initializable {
|
||||
}
|
||||
}
|
||||
|
||||
private void httpMethodChanged() {
|
||||
Tab tab = tabs.getSelectionModel().getSelectedItem();
|
||||
methods.put(tab.hashCode(), httpMethod.getValue());
|
||||
}
|
||||
|
||||
@FXML
|
||||
private void requestInputOnKeyPressed() {
|
||||
Tab tab = tabs.getSelectionModel().getSelectedItem();
|
||||
|
||||
@@ -11,17 +11,13 @@
|
||||
<image>
|
||||
<Image url="@banner.png" />
|
||||
</image></ImageView>
|
||||
<Label layoutX="537.0" layoutY="327.0" text="Version 0.1.1 (Not finished)" AnchorPane.bottomAnchor="16.0" AnchorPane.rightAnchor="16.0">
|
||||
<font>
|
||||
<Font size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<GridPane layoutX="32.0" layoutY="123.0" prefHeight="224.0" prefWidth="348.0">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
|
||||
</columnConstraints>
|
||||
<rowConstraints>
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
|
||||
@@ -32,17 +28,22 @@
|
||||
<Font size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label text="Made with Java 14.0.2 (GUI with JavaFX 15)" GridPane.rowIndex="1">
|
||||
<Label text="Software: Java 14.0.2 (GUI: JavaFX 15)" GridPane.rowIndex="2">
|
||||
<font>
|
||||
<Font size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label text="Installer made with Delphi 10.3 Community" GridPane.rowIndex="2">
|
||||
<Label text="Installer: Delphi 10.3.3 Community" GridPane.rowIndex="3">
|
||||
<font>
|
||||
<Font size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label text="Installer Bootstrap made with Python 3" GridPane.rowIndex="3">
|
||||
<Label text="Installer Bootstrap: Python 3.8.5 [MSC v.1924 (AMD64)]" GridPane.rowIndex="4">
|
||||
<font>
|
||||
<Font size="13.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label text="Version: 0.1.2 (Not finished)" GridPane.rowIndex="1">
|
||||
<font>
|
||||
<Font size="13.0" />
|
||||
</font>
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<?import javafx.scene.control.*?>
|
||||
<?import javafx.scene.layout.*?>
|
||||
<?import javafx.scene.text.*?>
|
||||
<?import javafx.scene.control.Button?>
|
||||
<?import javafx.scene.control.CheckBox?>
|
||||
<?import javafx.scene.control.ChoiceBox?>
|
||||
<?import javafx.scene.control.Label?>
|
||||
<?import javafx.scene.layout.AnchorPane?>
|
||||
<?import javafx.scene.text.Font?>
|
||||
|
||||
<AnchorPane maxHeight="556.0" maxWidth="412.0" minHeight="556.0" minWidth="412.0" prefHeight="556.0" prefWidth="412.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="ovh.alexisdelhaie.endpoint.controllers.ConfigurationController">
|
||||
<children>
|
||||
<Label layoutX="12.0" layoutY="11.0" text="SSL">
|
||||
<font>
|
||||
<Font name="System Bold" size="12.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="13.0" layoutY="35.0" text="Allow invalid SSL certificate" />
|
||||
<CheckBox fx:id="allowInvalidSsl" layoutX="381.0" layoutY="31.0" mnemonicParsing="false" onMouseClicked="#onBooleanValueChanged" AnchorPane.rightAnchor="14.333333333333332" AnchorPane.topAnchor="32.0" />
|
||||
<Label layoutX="13.0" layoutY="64.0" text="Downgrade when SSL failed" />
|
||||
<CheckBox fx:id="allowDowngrade" layoutX="381.0" layoutY="60.0" mnemonicParsing="false" onMouseClicked="#onBooleanValueChanged" selected="true" AnchorPane.rightAnchor="14.333333333333332" AnchorPane.topAnchor="60.0" />
|
||||
<Button layoutX="14.0" layoutY="517.0" mnemonicParsing="false" onMouseClicked="#showAboutDialog" text="About" AnchorPane.bottomAnchor="14.0" AnchorPane.leftAnchor="14.0" />
|
||||
</children>
|
||||
<Label layoutX="20.0" layoutY="14.0" text="SSL">
|
||||
<font>
|
||||
<Font name="System Bold" size="12.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="20.0" layoutY="40.0" prefHeight="18.0" prefWidth="148.0" text="Allow invalid SSL certificate" />
|
||||
<CheckBox fx:id="allowInvalidSsl" layoutX="381.0" layoutY="41.0" mnemonicParsing="false" onMouseClicked="#onBooleanValueChanged" AnchorPane.rightAnchor="14.199999999999989" AnchorPane.topAnchor="41.0" />
|
||||
<Label layoutX="20.0" layoutY="59.0" prefHeight="18.0" prefWidth="148.0" text="Downgrade when SSL failed" />
|
||||
<CheckBox fx:id="allowDowngrade" layoutX="381.0" layoutY="60.0" mnemonicParsing="false" onMouseClicked="#onBooleanValueChanged" selected="true" AnchorPane.rightAnchor="14.333333333333332" AnchorPane.topAnchor="60.0" />
|
||||
<Button layoutX="14.0" layoutY="515.0" mnemonicParsing="false" onMouseClicked="#showAboutDialog" prefHeight="26.0" prefWidth="58.0" text="About" AnchorPane.bottomAnchor="15.0" AnchorPane.leftAnchor="14.0" />
|
||||
<Label layoutX="20.0" layoutY="97.0" prefHeight="18.0" prefWidth="72.0" text="Requests">
|
||||
<font>
|
||||
<Font name="System Bold" size="12.0" />
|
||||
</font>
|
||||
</Label>
|
||||
<Label layoutX="20.0" layoutY="126.0" prefHeight="18.0" prefWidth="72.0" text="HTTP version" />
|
||||
<ChoiceBox fx:id="httpVersion" layoutX="308.0" layoutY="123.0" prefHeight="26.0" prefWidth="90.0" />
|
||||
</AnchorPane>
|
||||
|
||||
@@ -53,7 +53,7 @@
|
||||
<Font name="Consolas" size="12.0" />
|
||||
</font>
|
||||
</TextArea>
|
||||
<Label text="Sended request" GridPane.columnIndex="4" GridPane.rowIndex="4" />
|
||||
<Label text="Sent request" GridPane.columnIndex="4" GridPane.rowIndex="4" />
|
||||
<GridPane fx:id="downgraded_indicator" visible="false" GridPane.columnIndex="4" GridPane.rowIndex="1">
|
||||
<columnConstraints>
|
||||
<ColumnConstraints hgrow="SOMETIMES" maxWidth="382.0" minWidth="10.0" prefWidth="30.0" />
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package ovh.alexisdelhaie.endpoint.http;
|
||||
|
||||
import ovh.alexisdelhaie.endpoint.configuration.ConfigurationProperties;
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.BufferedOutputStream;
|
||||
@@ -18,15 +20,19 @@ public class HttpClient {
|
||||
|
||||
public final static String CRLF = "\r\n";
|
||||
public final static int DEFAULT_TIMEOUT = 10000;
|
||||
public final static boolean DEFAULT_ALLOW_INVALID_SSL = false;
|
||||
public final static boolean DEFAULT_ALLOW_DOWNGRADE = true;
|
||||
public final static String DEFAULT_HTTP_VERSION = "HTTP/1.1";
|
||||
|
||||
private final boolean allowInvalidSsl;
|
||||
private final boolean allowDowngrade;
|
||||
private final String httpVersion;
|
||||
private boolean downgraded;
|
||||
|
||||
public HttpClient() { this(false, true); }
|
||||
public HttpClient(boolean allowInvalidSsl, boolean allowDowngrade) {
|
||||
this.allowInvalidSsl = allowInvalidSsl;
|
||||
this.allowDowngrade = allowDowngrade;
|
||||
public HttpClient(ConfigurationProperties props) {
|
||||
this.allowInvalidSsl = props.getBooleanProperty("allowInvalidSsl", DEFAULT_ALLOW_INVALID_SSL);
|
||||
this.allowDowngrade = props.getBooleanProperty("allowDowngrade", DEFAULT_ALLOW_DOWNGRADE);
|
||||
this.httpVersion = props.getStringProperty("httpVersion", DEFAULT_HTTP_VERSION);
|
||||
this.downgraded = false;
|
||||
}
|
||||
|
||||
@@ -139,8 +145,9 @@ public class HttpClient {
|
||||
String path = (r.getParams().isEmpty()) ?
|
||||
r.getPath() : r.getPathWithParams();
|
||||
final StringBuilder sb = new StringBuilder(method).append(" ").append(path)
|
||||
.append(" HTTP/1.1").append(CRLF);
|
||||
.append(" ").append(httpVersion).append(CRLF);
|
||||
sb.append("host: ").append(r.getHost()).append(":").append(r.getPort()).append(CRLF);
|
||||
|
||||
sb.append("connection: close").append(CRLF);
|
||||
if (!custom.containsKey("accept")) {
|
||||
sb.append("accept: */*").append(CRLF);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package ovh.alexisdelhaie.endpoint.http;
|
||||
|
||||
import ovh.alexisdelhaie.endpoint.http.parsers.Chunked;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.regex.Matcher;
|
||||
@@ -15,7 +18,7 @@ public class Response {
|
||||
private final HashMap<String, String> headers;
|
||||
private final String rawHeaders;
|
||||
private String rawResponse;
|
||||
private final String body;
|
||||
private String body;
|
||||
private int statusCode;
|
||||
private String status;
|
||||
private final long time;
|
||||
@@ -33,6 +36,7 @@ public class Response {
|
||||
this.time = time;
|
||||
request = r;
|
||||
this.downgraded = downgraded;
|
||||
parseBody();
|
||||
}
|
||||
|
||||
private void parseHeaders() {
|
||||
@@ -53,7 +57,7 @@ public class Response {
|
||||
statusCode = Integer.parseInt(m.group(2));
|
||||
status = m.group(3);
|
||||
} else {
|
||||
p = Pattern.compile("^(HTTP/1.1)\\s([0-9]{3})$");
|
||||
p = Pattern.compile("^(HTTP/1.1)\\s([0-9]{3})?(.*)$");
|
||||
m = p.matcher(l);
|
||||
if (m.matches()) {
|
||||
statusCode = Integer.parseInt(m.group(2));
|
||||
@@ -66,6 +70,19 @@ public class Response {
|
||||
}
|
||||
}
|
||||
|
||||
private void parseBody() {
|
||||
if (headers.containsKey("transfer-encoding")) {
|
||||
if (headers.get("transfer-encoding").toLowerCase().contains("chunked")) {
|
||||
ArrayList<String> chunks = Chunked.parse(body);
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
for (String chunk : chunks) {
|
||||
sb.append(chunk);
|
||||
}
|
||||
body = sb.toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String getEncoding() {
|
||||
Pattern p = Pattern.compile("(.+);\\s(.+)=(.+)");
|
||||
if (headers.containsKey("content-type")) {
|
||||
|
||||
25
src/ovh/alexisdelhaie/endpoint/http/parsers/Chunked.java
Normal file
25
src/ovh/alexisdelhaie/endpoint/http/parsers/Chunked.java
Normal file
@@ -0,0 +1,25 @@
|
||||
package ovh.alexisdelhaie.endpoint.http.parsers;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class Chunked {
|
||||
|
||||
public static ArrayList<String> parse(String body) {
|
||||
ArrayList<String> result = new ArrayList<>();
|
||||
try {
|
||||
body = body.strip();
|
||||
int length; int pos;
|
||||
do {
|
||||
pos = body.indexOf("\r\n");
|
||||
length = Integer.parseInt(body.substring(0, pos), 16);
|
||||
result.add(body.substring(pos + 2, length));
|
||||
body = body.substring(pos + 2 + length);
|
||||
} while (!body.isEmpty());
|
||||
} catch (NumberFormatException e) {
|
||||
result.add(body);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user