package com.xenoage.zong.desktop.utils.http; import com.xenoage.utils.jse.io.JseStreamUtils; import com.xenoage.utils.kernel.Tuple2; import java.io.*; import java.net.InetSocketAddress; import java.net.Socket; import java.util.ArrayList; import static com.xenoage.utils.kernel.Tuple2.t; /** * This class sends an report by HTTP POST * to the server (domain {@value #SERVER_HOST}, port {@value #SERVER_PORT}, * path {@value #SERVER_PAGE}). * The report consists of a list * of files (filename and data block) that have to * be registered before. * * When everything went ok, this class expects the * server to answer with "OK" (must be the last two * characters of the response). Otherwise, an error * has occurred. * * The user gets notified with an {@link IOException} * when sending the report has failed. * * @author Andreas Wenger */ public class HttpReport { public static final String SERVER_HOST = "www.xenoage.com"; public static final int SERVER_PORT = 80; public static final String SERVER_PAGE = "/zong/report/report.php"; private ArrayList<Tuple2<String, byte[]>> files = new ArrayList<>(); /** * Registers another data block to be sent. */ public void registerData(String filename, String data) { if (filename.length() == 0) throw new IllegalArgumentException("filename may not be empty"); files.add(t(filename, data.getBytes())); } /** * Registers another data block to be sent. */ public void registerData(String filename, InputStream in) throws IOException { if (filename.length() == 0) throw new IllegalArgumentException("filename may not be empty"); byte[] data = JseStreamUtils.readToByteArray(in); files.add(t(filename, data)); } /** * Sends the report. */ public void send() throws IOException { if (files.size() == 0) { throw new IOException("register at least one data block before sending"); } //total length of data int totalDataLength = 0; for (Tuple2<String, byte[]> b : files) { totalDataLength += b.get2().length; } //commands for filenames //noinspection Convert2Diamond ArrayList<String> dataCommands = new ArrayList<>(); int totalDataCommandLength = 0; int fileIndex = 0; for (Tuple2<String, byte[]> b : files) { String dataCommand = getDataCommand(b.get1(), fileIndex++); dataCommands.add(dataCommand); totalDataCommandLength += dataCommand.length() + "\r\n".getBytes().length; } Socket socket = new Socket(); socket.connect(new InetSocketAddress(SERVER_HOST, SERVER_PORT), 5000); //5 sec timeout DataOutputStream raw = new DataOutputStream(socket.getOutputStream()); OutputStreamWriter wr = new OutputStreamWriter(raw); String trail = "--delimiter--\r\n"; String header = "POST " + SERVER_PAGE + " HTTP/1.0\r\n" + "Accept: */*\r\n" + "Referer: http://localhost\r\n" + "Accept-Language: de\r\n" + "Content-Type: multipart/form-data; boundary=delimiter\r\n" + "User_Agent: TESTAGENT\r\n" + "Host: " + SERVER_HOST + "\r\n" + "Content-Length: " + (totalDataLength + totalDataCommandLength + trail.length()) + "\r\n" //+ "Connection: Keep-Alive\r\n" + "Pragma: no-cache\r\n" + "\r\n"; wr.write(header); for (int i = 0; i < files.size(); i++) { wr.write(dataCommands.get(i)); wr.flush(); raw.write(files.get(i).get2()); raw.flush(); wr.write("\r\n"); wr.flush(); } wr.write(trail); wr.flush(); BufferedReader rd = new BufferedReader(new InputStreamReader(socket.getInputStream())); String text = "", line; while ((line = rd.readLine()) != null) { text += line + "\n"; } wr.close(); raw.close(); socket.close(); //remove "\n" and "\r" at the end while (text.endsWith("\r") || text.endsWith("\n")) text = text.substring(0, text.length() - 1); if (!text.endsWith("OK")) { throw new IOException("Failed. Server answers: " + text); } } private String getDataCommand(String filename, int index) { return "--delimiter\r\n" + "Content-Disposition: form-data; name=\"file" + index + "\"; filename=\"" + filename + "\"\r\n" + "\r\n"; } }