package eu.airaudio.airplay.auth; import com.dd.plist.NSDictionary; import com.dd.plist.PropertyListParser; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.Socket; import java.util.Map; import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * Created by Martin on 24.05.2017. */ public class AuthUtils { static byte[] concatByteArrays(byte[]... byteArrays) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); for (byte[] bytes : byteArrays) { byteArrayOutputStream.write(bytes); } return byteArrayOutputStream.toByteArray(); } static byte[] createPList(Map<String, ? extends Object> properties) throws IOException { ByteArrayOutputStream plistOutputStream = new ByteArrayOutputStream(); NSDictionary root = new NSDictionary(); for (Map.Entry<String, ? extends Object> property : properties.entrySet()) { root.put(property.getKey(), property.getValue()); } PropertyListParser.saveAsBinary(root, plistOutputStream); return plistOutputStream.toByteArray(); } public static byte[] postData(Socket socket, String path, String contentType, byte[] data) throws IOException { DataOutputStream wr = new DataOutputStream(socket.getOutputStream()); wr.writeBytes("POST " + path + " HTTP/1.0\r\n"); wr.writeBytes("User-Agent: AirPlay/320.20\r\n"); wr.writeBytes("Connection: keep-alive\r\n"); if (data != null) { wr.writeBytes("Content-Length: " + data.length + "\r\n"); wr.writeBytes("Content-Type: " + contentType + "\r\n"); } wr.writeBytes("\r\n"); if (data != null) { wr.write(data); } wr.flush(); String line; Pattern statusPattern = Pattern.compile("HTTP[^ ]+ (\\d{3})"); Pattern contentLengthPattern = Pattern.compile("Content-Length: (\\d+)"); int contentLength = 0; int statusCode = 0; while ((line = AuthUtils.readLine(socket.getInputStream())) != null) { System.out.println(line); Matcher statusMatcher = statusPattern.matcher(line); if (statusMatcher.find()) { statusCode = Integer.parseInt(statusMatcher.group(1)); } Matcher contentLengthMatcher = contentLengthPattern.matcher(line); if (contentLengthMatcher.find()) { contentLength = Integer.parseInt(contentLengthMatcher.group(1)); } if (line.trim().isEmpty()) { break; } } if (statusCode != 200) { throw new IOException("Invalid status code " + statusCode); } try (ByteArrayOutputStream response = new ByteArrayOutputStream();) { byte[] buffer = new byte[0xFFFF]; for (int len; response.size() < contentLength && (len = socket.getInputStream().read(buffer)) != -1; ) { response.write(buffer, 0, len); } response.flush(); return response.toByteArray(); } } private static String readLine(InputStream inputStream) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); int c; for (c = inputStream.read(); c != '\n' && c != -1; c = inputStream.read()) { byteArrayOutputStream.write(c); } if (c == -1 && byteArrayOutputStream.size() == 0) { return null; } String line = byteArrayOutputStream.toString("UTF-8"); return line; } public static String randomString(final int length) { char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".toCharArray(); Random rnd = new Random(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < length; i++) sb.append(chars[rnd.nextInt(chars.length)]); return sb.toString(); } }