com.isecpartners.gizmo.HttpResponse.java Source code

Java tutorial

Introduction

Here is the source code for com.isecpartners.gizmo.HttpResponse.java

Source

/*
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 {
    }
}