Java tutorial
/* Copyright (C) 2009 Rachel Engel This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package com.isecpartners.gizmo; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.net.SocketException; import java.util.logging.Level; import java.util.zip.GZIPInputStream; import java.util.logging.Logger; import java.util.zip.InflaterInputStream; import org.apache.commons.collections.primitives.ArrayByteList; /** * * @author I entirely agree that the below manual parse of http is complicated. It does work. I recommend you dont modify it. I tried it in every scenario in every browser i could think of against a ton of * different servers, and it more or less works. If you see some good small refactoring, go for it. If you see a line where you think "i wonder what this does? well i'll delete it", please dont. * You're going to have to try it against a whole battery of clients and servers before you'll know if you've done the right thing, and it'll all end in tears. */ class HttpResponse extends HTTPMessage { public static final String ENDL = "\r\n"; ArrayByteList blist; private static final String CONTENT_LENGTH = "CONTENT-LENGTH"; private static final String TRANSFER_ENCODING = "TRANSFER-ENCODING"; private static final String CONTENT_ENCODING = "CONTENT-ENCODING"; private HttpRequest req; private boolean gzip = false; private boolean deflate = false; private HttpResponse() { } /** * * @param s Value to print into the response. * @return HttpResponse based on the input parameter s. */ static HttpResponse create(String s) { byte[] contents = s.getBytes(); ArrayByteList tempArray = new ArrayByteList(); for (int ii = 0; ii < contents.length; ii++) { tempArray.add(contents[ii]); } HttpResponse resp = new HttpResponse(); resp.setBlist(tempArray); resp.setHeader("HTTP/1.0 200 OK\r\n"); return resp; } public static HttpResponse create(InputStream in) throws FailedRequestException { HttpResponse resp = new HttpResponse(); resp.processResponse(in); return resp; } public void setRequest(HttpRequest req) { this.req = req; } public boolean isGzipped() { return gzip; } public boolean isInflated() { return deflate; } public HttpRequest getRequest() { return req; } private void append(ArrayByteList blist, StringBuffer string) { byte[] contents = string.toString().getBytes(); for (int ii = 0; ii < contents.length; ii++) { blist.add(contents[ii]); } } public String second_auth_header() { String val = ""; String WWW_AUTHENTICATE = "WWW-AUTHENTICATE"; int endlendl = contents().indexOf("\r\n\r\n"); String upper_contents = contents().substring(0, endlendl).toUpperCase(); int first = upper_contents.indexOf(WWW_AUTHENTICATE); int first_eol = upper_contents.indexOf("\r\n", first); if (first == -1) { return ""; } String first_header = upper_contents.substring(first, first_eol).split(":")[1].trim(); String second_header = ""; if (first != -1) { int second = upper_contents.indexOf(WWW_AUTHENTICATE, first + WWW_AUTHENTICATE.length()); if (second == -1) { return ""; } int eol = upper_contents.indexOf("\r\n", second); String line = upper_contents.substring(second, eol); String bits[] = line.split(":"); second_header = bits[1].trim(); } if (first_header.equalsIgnoreCase("NEGOTIATE")) { val = second_header; } else { val = first_header; } return val; } public String contents() { if (gzip) return unzipData(blist.toArray()) + "\n"; else if (deflate) return deflateData(blist.toArray()) + "\n"; return new String(blist.toArray()) + "\n"; } private String readline(InputStream in) { StringBuffer strbuf = new StringBuffer(); try { int ch_n = in.read(); char ch = (char) ch_n; while (ch != '\n' && ch_n != -1) { strbuf.append(ch); ch_n = in.read(); ch = (char) ch_n; } if (ch_n != -1) { strbuf.append(ch); } else { return null; } } catch (Exception e) { System.out.println(e); } return strbuf.toString(); } private void setBlist(ArrayByteList list) { this.blist = list; } public void processResponse(InputStream in) throws FailedRequestException { StringBuffer content = new StringBuffer(); DataInputStream inputStream = new DataInputStream(in); ArrayByteList blist = new ArrayByteList(); String header = null; int contentLength = 0; boolean isChunked = false; String line; try { line = readline(inputStream); while (line != null && !line.equals(ENDL)) { content.append(line); if (line.toUpperCase().contains(CONTENT_LENGTH) && line.toUpperCase().indexOf(CONTENT_LENGTH) == 0) { String value = line.substring(line.indexOf(CONTENT_LENGTH) + CONTENT_LENGTH.length() + 2, line.indexOf('\r')); contentLength = Integer.parseInt(value.trim()); } else if (line.toUpperCase().contains(TRANSFER_ENCODING)) { if (line.toUpperCase() .substring( line.toUpperCase().indexOf(TRANSFER_ENCODING) + "Transfer-Encoding:".length()) .contains("CHUNKED")) { isChunked = true; } } else if (line.toUpperCase().contains(CONTENT_ENCODING)) { String value = line.substring(line.indexOf(CONTENT_ENCODING) + CONTENT_ENCODING.length() + 2, line.indexOf('\r')); value = value.trim(); if (value.toUpperCase().equals("GZIP")) { this.gzip = true; } else if (value.toUpperCase().equals("DEFLATE")) { this.deflate = true; } } line = readline(inputStream); } if (line == null) { GizmoView.log(content.toString()); throw new FailedRequestException(); } content.append("\r\n"); header = content.substring(0, content.indexOf("\r\n")); append(blist, content); if (contentLength != 0) { for (int ii = 0; ii < contentLength; ii++) { blist.add(inputStream.readByte()); } } if (isChunked) { boolean isDone = false; while (!isDone) { byte current = inputStream.readByte(); blist.add(current); int size = 0; while (current != '\n') { if (current != '\r') { size *= 16; if (Character.isLetter((char) current)) { current = (byte) Character.toLowerCase((char) current); } if ((current >= '0') && (current <= '9')) { size += (current - 48); } else if ((current >= 'a') && (current <= 'f')) { size += (10 + current - 97); } } current = inputStream.readByte(); while ((char) current == ' ') { current = inputStream.readByte(); } blist.add(current); } if (size != 0) { for (int ii = 0; ii < size; ii++) { int byte1 = inputStream.readByte(); byte blah = (byte) byte1; blist.add(blah); } blist.add(inputStream.readByte()); blist.add(inputStream.readByte()); } else { byte ch = (byte) inputStream.read(); StringBuffer endstuff = new StringBuffer(); blist.add(ch); endstuff.append((char) ch); while (ch != '\n') { ch = inputStream.readByte(); endstuff.append((char) ch); blist.add(ch); } isDone = true; } } } if (inputStream.available() > 0) { try { while (true) { blist.add(inputStream.readByte()); } } catch (EOFException e) { System.out.println(e); } } } catch (IOException ex) { Logger.getLogger(HttpResponse.class.getName()).log(Level.SEVERE, null, ex); } setBlist(blist); setHeader(header); if (this.gzip) { addContents(unzipData(blist.toArray())); } else if (this.deflate) { addContents(deflateData(blist.toArray())); } else { addContents(content.toString()); } } public String deflateData(byte[] blist) { return uncompressData(blist, new InflaterInputStream(new ByteArrayInputStream(reduceToBodyBlock(blist)))); } public String unzipData(byte[] blist) { try { String str = uncompressData(blist, new GZIPInputStream(new ByteArrayInputStream(reduceToBodyBlock(blist)))); return str; } catch (IOException ex) { Logger.getLogger(HttpResponse.class.getName()).log(Level.SEVERE, null, ex); } return new String(blist); // shouldnt happen, but at least not a terrible backup action } public String uncompressData(byte[] blist, InputStream in) { StringBuffer sb = new StringBuffer(); sb.append(extractHeaderBlock(blist)); try { byte[] buf = new byte[1024]; while (in.available() > 0) { int nRead = in.read(buf); if (nRead < 0) break; byte[] buf2 = new byte[nRead]; System.arraycopy(buf, 0, buf2, 0, nRead); sb.append(new String(buf2)); } } catch (IOException ex) { Logger.getLogger(HttpResponse.class.getName()).log(Level.SEVERE, null, ex); } return sb.toString(); } public byte[] byteContents() { return blist.toArray(); } private void setHeader(String header) { this.header = header; } private String extractHeaderBlock(byte[] blist) { int pos = 0; for (int ii = 0; ii < blist.length - 4; ii++) { if (blist[ii] == 13 && blist[ii + 1] == 10 && blist[ii + 2] == 13 && blist[ii + 3] == 10) { pos = ii; break; } } byte[] buf = new byte[pos + 4]; System.arraycopy(blist, 0, buf, 0, pos + 4); return new String(buf); } private byte[] reduceToBodyBlock(byte[] blist) { int pos = 0; for (int ii = 0; ii < blist.length - 4; ii++) { if (blist[ii] == 13 && blist[ii + 1] == 10 && blist[ii + 2] == 13 && blist[ii + 3] == 10) { pos = ii; break; } } byte[] buf = new byte[blist.length - pos - 3 - 1]; System.arraycopy(blist, pos + 4, buf, 0, buf.length); return buf; } class FailedRequestException extends Exception { } }