package be.jeffcheasey88.peeratcode.framework; import java.security.MessageDigest; import java.util.ArrayList; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.json.simple.parser.JSONParser; public class HttpUtil{ private HttpUtil(){} public static void responseHeaders(HttpWriter writer, int code, String... headers) throws Exception{ writer.write("HTTP/1.1 " + code + " " + codeMessage(code) + "\n"); for(String header : headers) writer.write(header + "\n"); writer.write("\n"); writer.flush(); } public static void skipHeaders(HttpReader reader) throws Exception{ String line; while(((line = reader.readLine()) != null) && (line.length() > 0)); } public static List readMultiPartData(HttpReader reader) throws Exception{ List list = new ArrayList<>(); reader.readLine(); while(reader.ready()){ String line; while (((line = reader.readLine()) != null) && (line.length() > 0)){ } String buffer = ""; while (((line = reader.readLine()) != null) && (!line.startsWith("------WebKitFormBoundary"))){ buffer += line; } list.add(buffer); } return list; } public static void switchToWebSocket(HttpReader reader, HttpWriter writer) throws Exception{ String key = readWebSocketKey(reader); if (key == null) throw new IllegalArgumentException(); writer.write("HTTP/1.1 101 Switching Protocols\n"); writer.write("Connection: Upgrade\n"); writer.write("Upgrade: websocket\n"); writer.write("Sec-WebSocket-Accept: " + printBase64Binary(MessageDigest.getInstance("SHA-1") .digest((key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11").getBytes("UTF-8"))) + "\n"); writer.write("\n"); writer.flush(); } private static Pattern WEBSOCKET_KEY = Pattern.compile("Sec-WebSocket-Key: (.*)"); public static String readWebSocketKey(HttpReader reader) throws Exception{ String line; String key = null; while(((line = reader.readLine()) != null) && (line.length() > 0)){ if(key != null) continue; Matcher matcher = WEBSOCKET_KEY.matcher(line); if(matcher.matches()) key = matcher.group(1); } return key; } private static Pattern AUTORIZATION = Pattern.compile("Authorization: Bearer (.*)"); public static String readAuthorization(HttpReader reader) throws Exception{ String line; String key = null; while (((line = reader.readLine()) != null) && (line.length() > 0)){ Matcher matcher = AUTORIZATION.matcher(line); if(matcher.matches()){ key = matcher.group(1); break; } } return key; } public static Object readJson(HttpReader reader) throws Exception{ String line = ""; while (reader.ready()){ char[] c = new char[1]; reader.read(c); line += c[0]; if (c[0] == '}'){ Object parse; try { parse = new JSONParser().parse(line); if (parse != null) return parse; }catch(Exception e){} } } return null; } // I found this code on StackOverFlow !!!!! (and the write too) public static String readWebSocket(HttpReader reader) throws Exception{ int buffLenth = 1024; int len = 0; byte[] b = new byte[buffLenth]; // rawIn is a Socket.getInputStream(); while (true){ len = reader.read(b); if (len != -1){ byte rLength = 0; int rMaskIndex = 2; int rDataStart = 0; // b[0] is always text in my case so no need to check; byte data = b[1]; byte op = (byte) 127; rLength = (byte) (data & op); if (rLength == (byte) 126) rMaskIndex = 4; if (rLength == (byte) 127) rMaskIndex = 10; byte[] masks = new byte[4]; int j = 0; int i = 0; for (i = rMaskIndex; i < (rMaskIndex + 4); i++){ masks[j] = b[i]; j++; } rDataStart = rMaskIndex + 4; int messLen = len - rDataStart; byte[] message = new byte[messLen]; for (i = rDataStart, j = 0; i < len; i++, j++){ message[j] = (byte) (b[i] ^ masks[j % 4]); } return new String(message); } else break; } return null; } public static void sendWebSocket(HttpWriter writer, String message) throws Exception{ byte[] rawData = message.getBytes(); int frameCount = 0; byte[] frame = new byte[10]; frame[0] = (byte) 129; if (rawData.length <= 125){ frame[1] = (byte) rawData.length; frameCount = 2; } else if (rawData.length >= 126 && rawData.length <= 65535){ frame[1] = (byte) 126; int len = rawData.length; frame[2] = (byte) ((len >> 8) & (byte) 255); frame[3] = (byte) (len & (byte) 255); frameCount = 4; } else { frame[1] = (byte) 127; int len = rawData.length; frame[2] = (byte) ((len >> 56) & (byte) 255); frame[3] = (byte) ((len >> 48) & (byte) 255); frame[4] = (byte) ((len >> 40) & (byte) 255); frame[5] = (byte) ((len >> 32) & (byte) 255); frame[6] = (byte) ((len >> 24) & (byte) 255); frame[7] = (byte) ((len >> 16) & (byte) 255); frame[8] = (byte) ((len >> 8) & (byte) 255); frame[9] = (byte) (len & (byte) 255); frameCount = 10; } int bLength = frameCount + rawData.length; byte[] reply = new byte[bLength]; int bLim = 0; for (int i = 0; i < frameCount; i++){ reply[bLim] = frame[i]; bLim++; } for (int i = 0; i < rawData.length; i++){ reply[bLim] = rawData[i]; bLim++; } writer.write(reply); writer.flush(); } private static String codeMessage(int paramInt){ switch (paramInt){ case 200: return " OK"; case 100: return " Continue"; case 201: return " Created"; case 202: return " Accepted"; case 203: return " Non-Authoritative Information"; case 204: return " No Content"; case 205: return " Reset Content"; case 206: return " Partial Content"; case 300: return " Multiple Choices"; case 301: return " Moved Permanently"; case 302: return " Temporary Redirect"; case 303: return " See Other"; case 304: return " Not Modified"; case 305: return " Use Proxy"; case 400: return " Bad Request"; case 401: return " Unauthorized"; case 402: return " Payment Required"; case 403: return " Forbidden"; case 404: return " Not Found"; case 405: return " Method Not Allowed"; case 406: return " Not Acceptable"; case 407: return " Proxy Authentication Required"; case 408: return " Request Time-Out"; case 409: return " Conflict"; case 410: return " Gone"; case 411: return " Length Required"; case 412: return " Precondition Failed"; case 413: return " Request Entity Too Large"; case 414: return " Request-URI Too Large"; case 415: return " Unsupported Media Type"; case 500: return " Internal Server Error"; case 501: return " Not Implemented"; case 502: return " Bad Gateway"; case 503: return " Service Unavailable"; case 504: return " Gateway Timeout"; case 505: return " HTTP Version Not Supported"; } return " "; } // From javax.xml.bind.DatatypeConverter private static String printBase64Binary(byte[] array){ char[] arrayOfChar = new char[(array.length + 2) / 3 * 4]; int i = _printBase64Binary(array, 0, array.length, arrayOfChar, 0); assert i == arrayOfChar.length; return new String(arrayOfChar); } private static int _printBase64Binary(byte[] paramArrayOfbyte, int paramInt1, int paramInt2, char[] paramArrayOfchar, int paramInt3){ int i = paramInt2; int j; for (j = paramInt1; i >= 3; j += 3){ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); paramArrayOfchar[paramInt3++] = encode( (paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); paramArrayOfchar[paramInt3++] = encode( (paramArrayOfbyte[j + 1] & 0xF) << 2 | paramArrayOfbyte[j + 2] >> 6 & 0x3); paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j + 2] & 0x3F); i -= 3; } if (i == 1){ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j] & 0x3) << 4); paramArrayOfchar[paramInt3++] = '='; paramArrayOfchar[paramInt3++] = '='; } if (i == 2){ paramArrayOfchar[paramInt3++] = encode(paramArrayOfbyte[j] >> 2); paramArrayOfchar[paramInt3++] = encode( (paramArrayOfbyte[j] & 0x3) << 4 | paramArrayOfbyte[j + 1] >> 4 & 0xF); paramArrayOfchar[paramInt3++] = encode((paramArrayOfbyte[j + 1] & 0xF) << 2); paramArrayOfchar[paramInt3++] = '='; } return paramInt3; } private static char encode(int paramInt){ return encodeMap[paramInt & 0x3F]; } private static final char[] encodeMap = initEncodeMap(); private static char[] initEncodeMap(){ char[] arrayOfChar = new char[64]; byte b; for (b = 0; b < 26; b++) arrayOfChar[b] = (char) (65 + b); for (b = 26; b < 52; b++) arrayOfChar[b] = (char) (97 + b - 26); for (b = 52; b < 62; b++) arrayOfChar[b] = (char) (48 + b - 52); arrayOfChar[62] = '+'; arrayOfChar[63] = '/'; return arrayOfChar; } }