diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java index 898dc7e2..ac25cc8c 100644 --- a/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java +++ b/src/hdskins/java/com/voxelmodpack/hdskins/skins/LegacySkinServer.java @@ -9,6 +9,8 @@ import com.mojang.authlib.minecraft.MinecraftProfileTexture; import com.mojang.authlib.yggdrasil.response.MinecraftTexturesPayload; import com.mojang.util.UUIDTypeAdapter; import com.voxelmodpack.hdskins.HDSkinManager; +import com.voxelmodpack.hdskins.upload.ThreadMultipartPostUpload; + import net.minecraft.util.Session; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -91,15 +93,7 @@ public class LegacySkinServer implements SkinServer { return CallableFutures.asyncFailableFuture(() -> { SkinServer.verifyServerConnection(session, SERVER_ID); - NetClient client = new NetClient("POST", gateway); - - client.putHeaders(createHeaders(session, upload)); - - if (upload.getImage() != null) { - client.putFile(upload.getType().toString().toLowerCase(Locale.US), "image/png", upload.getImage()); - } - - String response = client.send().text(); + String response = new ThreadMultipartPostUpload(gateway, createHeaders(session, upload)).uploadMultipart(); if (response.startsWith("ERROR: ")) { response = response.substring(7); @@ -120,12 +114,13 @@ public class LegacySkinServer implements SkinServer { Builder builder = ImmutableMap.builder() .put("user", session.getUsername()) .put("uuid", UUIDTypeAdapter.fromUUID(session.getProfile().getId())) - .put("type", upload.getType().toString().toLowerCase(Locale.US)); + .put("type", upload.getType().toString().toLowerCase(Locale.US)) + .put("model", upload.getMetadata().getOrDefault("model", "default")); if (upload.getImage() == null) { builder.put("clear", "1"); } else { - builder.put("model", upload.getMetadata().getOrDefault("mode", "default")); + builder.put(upload.getType().toString().toLowerCase(Locale.US), upload.getImage()); } return builder.build(); diff --git a/src/hdskins/java/com/voxelmodpack/hdskins/upload/ThreadMultipartPostUpload.java b/src/hdskins/java/com/voxelmodpack/hdskins/upload/ThreadMultipartPostUpload.java new file mode 100644 index 00000000..6d20489c --- /dev/null +++ b/src/hdskins/java/com/voxelmodpack/hdskins/upload/ThreadMultipartPostUpload.java @@ -0,0 +1,111 @@ +package com.voxelmodpack.hdskins.upload; + +import org.apache.commons.io.IOUtils; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.HttpURLConnection; +import java.net.URI; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Map; +import java.util.Map.Entry; + +import javax.annotation.Nullable; + +/** + * Uploader for Multipart form data + * + * @author Adam Mummery-Smith + * @deprecated Use httpmime multipart upload + */ +@Deprecated +public class ThreadMultipartPostUpload { + protected final Map sourceData; + + protected final String method; + + protected final String authorization; + + protected final String urlString; + + protected HttpURLConnection httpClient; + + protected static final String CRLF = "\r\n"; + + protected static final String twoHyphens = "--"; + + protected static final String boundary = "----------AaB03x"; + + public String response; + + public ThreadMultipartPostUpload(String method, String url, Map sourceData, @Nullable String authorization) { + this.method = method; + this.urlString = url; + this.sourceData = sourceData; + this.authorization = authorization; + } + + public ThreadMultipartPostUpload(String url, Map sourceData) { + this("POST", url, sourceData, null); + } + + public String uploadMultipart() throws IOException { + // open a URL connection + URL url = new URL(this.urlString); + + // Open a HTTP connection to the URL + this.httpClient = (HttpURLConnection) url.openConnection(); + this.httpClient.setDoOutput(true); + this.httpClient.setUseCaches(false); + + this.httpClient.setRequestMethod(this.method); + this.httpClient.setRequestProperty("Connection", "Close"); + this.httpClient.addRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"); // For CloudFlare + + if (this.sourceData.size() > 0) { + this.httpClient.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + } + + if (this.authorization != null) { + this.httpClient.addRequestProperty("Authorization", this.authorization); + } + + try (DataOutputStream outputStream = new DataOutputStream(this.httpClient.getOutputStream())) { + + for (Entry data : this.sourceData.entrySet()) { + outputStream.writeBytes(twoHyphens + boundary + CRLF); + + String paramName = data.getKey(); + Object paramData = data.getValue(); + + if (paramData instanceof URI) { + Path uploadPath = Paths.get((URI) paramData); + + outputStream.writeBytes("Content-Disposition: form-data; name=\"" + paramName + "\"; filename=\"" + uploadPath.getFileName() + "\"" + CRLF); + outputStream.writeBytes("Content-Type: image/png" + CRLF + CRLF); + + + Files.copy(uploadPath, outputStream); + } else { + outputStream.writeBytes("Content-Disposition: form-data; name=\"" + paramName + "\"" + CRLF + CRLF); + + outputStream.writeBytes(paramData.toString()); + } + + outputStream.writeBytes(ThreadMultipartPostUpload.CRLF); + } + + outputStream.writeBytes(twoHyphens + boundary + twoHyphens + CRLF); + } + + try (InputStream input = this.httpClient.getInputStream()) { + return IOUtils.toString(input, StandardCharsets.UTF_8); + } + } + +} \ No newline at end of file