All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.codemagi.burp.parser.HttpResponse Maven / Gradle / Ivy

Go to download

The Burp Suite Utils project provides developers with APIs for building Burp Suite Extensions.

There is a newer version: 1.2.5
Show newest version
package com.codemagi.burp.parser;

import burp.ICookie;
import burp.impl.Cookie;
import com.codemagi.burp.BaseExtender;
import com.codemagi.burp.Utils;
import java.io.*;
import java.text.ParseException;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Generic http response parser. Messages are of the general form:
 * 
 * status_line
 * header: value
 * header: value
 * header: value
 * ...
 * 
where status_line is something like *
HTTP/1.1 200 OK
* *

* This class will parse all the header/value pairs and store them in a * ({@link java.util.LinkedHashMap}), and parse the first line as 'command'. The * LinkedHashMap will assure that an iterator will visit the fields in * the order they were originally sent/parsed. * * The body of the HTTP response is stored as-is in the 'body' member. * * KNOWN ISSUE: Some HTTP responses contain duplicate header names. This class * will replace duplicate headers in the order they are found. E.g. the value of * the second header with the same name will replace the first. * * @author August Detlefsen [augustd at codemagi dot com] */ public class HttpResponse { //protected URL url; protected Integer responseCode; protected String responseReason; protected String version; protected String body; protected LinkedHashMap headers = new LinkedHashMap<>(); protected LinkedHashMap sortedHeaders = null; protected List cookies = new ArrayList<>(); /** * Private no-argument constructor is only used internally by static factory * methods. */ private HttpResponse() { } /** * Constructor for creating an HttpMessage from a URL and an HTTP method. * * This method will create an HTTP/1.1 request with the URI passed in the * 'url' parameter. A 'Host' header will be set with the host portion of the * 'url' parameter * * @param responseCode The HTTP response code * @param responseReason The HTTP response message */ public HttpResponse(Integer responseCode, String responseReason) { this.responseCode = responseCode; this.responseReason = responseReason; this.version = "HTTP/1.1"; } public Integer getResponseCode() { return responseCode; } public void setResponseCode(Integer responseCode) { this.responseCode = responseCode; } public String getResponseReason() { return responseReason; } public void setResponseReason(String responseReason) { this.responseReason = responseReason; } public String getVersion() { return version; } /** * * @return The body of the POST request, if there is one */ public String getBody() { return Utils.noNulls(body); } /** * Returns the map of HTTP headers contained in this message, sorted by * lower case character order. * * If the map of sorted headers has already been created that will be * returned. Otherwise, a new LinkedHashMap will be constructed and cached * for future use. * * @return A LinkedHashMap containing the sorted HTTP headers, using the * header names as the hash key * @see java.util.LinkedHashMap */ public LinkedHashMap getHeadersSorted() { if (sortedHeaders != null) { return sortedHeaders; } sortedHeaders = new LinkedHashMap<>(headers.size()); List headerEntries = new ArrayList(headers.entrySet()); Collections.sort(headerEntries, new HeaderComparator()); for (Map.Entry entry : headerEntries) { String name = (String) entry.getKey(); String value = (String) entry.getValue(); sortedHeaders.put(name, value); } return sortedHeaders; } /** * Returns the map of HTTP headers contained in this message, in their * original order. * * @return A LinkedHashMap containing the HTTP headers */ public LinkedHashMap getHeaders() { return headers; } /** * Sets a header field value based on its name. * * @param name The header name to set * @param value The header value to set * @return the previous value or null if the field was previously unset. */ public final String setHeader(String name, String value) { sortedHeaders = null; return headers.put(name, value); } public String getHeader(String name) { return headers.get(name); } /** * Removes a header based on its name * @param name The name of the header to remove */ public void removeHeader(String name) { sortedHeaders = null; headers.remove(name); } public List getCookies() { return cookies; } public void setCookies(List cookies) { this.cookies = cookies; } public void addCookie(ICookie newCookie) { cookies.add(newCookie); } /** * Returns the _first_ cookie matching cookieName. Objects returned * by this method are of the class burp.impl.Cookie which implements the * burp.ICookie interface. * * @param cookieName The name of the cookie to return * @return The cookie, or null if there is no cookie by that name in the response. */ public ICookie getCookie(String cookieName) { for (ICookie cookie : cookies) { if (cookie.getName().equals(cookieName)) { return cookie; } } return null; } /** * Sets the Content-Length header to the current size of the response body * * @return The length of the body content */ public int getContentLength() { int contentLength = Utils.noNulls(body).length(); return contentLength; } public void setContentLength() { int contentLength = Utils.noNulls(body).length(); setHeader("Content-Length", contentLength + ""); } /** * Sets the body of the HTTP request and updates the Content-Length header. * NOTE: This value will override any parameters previously set * * @param body The new request body */ public void setBody(String body) { this.body = body; this.setContentLength(); } /** * Parses a new HttpMessage using {@link #parse(InputStream)} with out as * null. * * @param in The InputStream to parse * @return An HttpMessage object parsed from the InputStream * @throws java.io.IOException Any IO Exceptions will be thrown */ public static HttpResponse parseMessage(InputStream in) throws IOException { HttpResponse m = new HttpResponse(); m.parse(in); return m; } /** * Parses a new HttpMessage using {@link #parse(InputStream)} with out as * null. * * @param in The array of bytes to parse * @return An HttpMessage object parsed from the array * @throws java.io.IOException Any IO Exceptions will be thrown */ public static HttpResponse parseMessage(byte[] in) throws IOException { HttpResponse m = new HttpResponse(); m.parse(new ByteArrayInputStream(in)); return m; } public static HttpResponse parseMessage(String in) throws IOException { if (in != null) { return parseMessage(in.getBytes()); } return new HttpResponse(); } /** * Parses an http message from an input stream. The first line of input is * save in the protected command variable. The subsequent lines are * put into a linked hash as field/value pairs. Input is parsed until a * blank line is reached, after which any data should appear. * * @param in An InputStream containing a valid HTTP message */ private void parse(InputStream in) throws IOException { BufferedReader bin = new BufferedReader(new InputStreamReader(in)); String currLine = bin.readLine(); //parse the command to get the request method parseCommand(currLine); //parse headers currLine = bin.readLine(); while (currLine != null) { if (Utils.isEmpty(currLine)) { break; //we have reached the end of the headers } //split the headers into name-value pairs String[] split = currLine.split(": "); if (split.length < 2) { split = new String[]{ split[0], "" }; } String headerName = Utils.trim(split[0]); String headerValue = Utils.trim(split[1]); headers.put(headerName, headerValue); //handle cookies separately if ("Set-Cookie".equalsIgnoreCase(headerName)) { try { Cookie cookie = Cookie.parseCookie(headerValue); addCookie(cookie); } catch (ParseException ex) { BaseExtender.printStackTrace(ex); } } currLine = bin.readLine(); } //parse the body, if there is one StringBuilder bodyBuilder = new StringBuilder(); int c; while ((c = bin.read()) != -1) { //Since c is an integer, cast it to a char. If it isn't -1, it will be in the correct range of char. bodyBuilder.append( (char)c ) ; } this.body = bodyBuilder.toString(); } private void parseCommand(String command) { if (Utils.isEmpty(command)) { return; } String[] parts = command.split(" ", 3); version = (parts.length > 0) ? parts[0] : ""; responseCode = (parts.length > 1) ? Integer.parseInt(parts[1]) : 0; responseReason = (parts.length > 2) ? parts[2] : ""; } @Override public String toString() { StringBuilder output = new StringBuilder(1024); //Add the command output.append(version).append(" "); output.append(responseCode).append(" "); output.append(responseReason).append("\r\n"); //add the headers for (Map.Entry header : headers.entrySet()) { output.append(header.getKey()); output.append(": "); output.append(Utils.noNulls(header.getValue())); output.append("\r\n"); } output.append("\r\n"); //add the request body output.append(getBody()); return output.toString(); } public byte[] getBytes() { return toString().getBytes(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy