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

org.parosproxy.paros.network.HttpResponseHeader Maven / Gradle / Ivy

Go to download

The Zed Attack Proxy (ZAP) is an easy to use integrated penetration testing tool for finding vulnerabilities in web applications. It is designed to be used by people with a wide range of security experience and as such is ideal for developers and functional testers who are new to penetration testing. ZAP provides automated scanners as well as a set of tools that allow you to find security vulnerabilities manually.

The newest version!
/*
 * Created on Jun 14, 2004
 *
 * Paros and its related class files.
 *
 * Paros is an HTTP/HTTPS proxy for assessing web application security.
 * Copyright (C) 2003-2004 Chinotec Technologies Company
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the Clarified Artistic License
 * as published by the Free Software Foundation.
 *
 * 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
 * Clarified Artistic License for more details.
 *
 * You should have received a copy of the Clarified Artistic License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
// ZAP: 2012/03/15 Added the @Override annotation to the appropriate methods.
// Moved to this class the method getCookieParams().
// ZAP: 2012/06/24 Added new method of getting cookies from the request header.
// ZAP: 2012/07/11 Added method to check if response type is text/html (isHtml())
// ZAP: 2012/08/06 Modified isText() to also consider javascript as text
// ZAP: 2013/02/12 Modified isText() to also consider atom+xml as text
// ZAP: 2013/03/08 Improved parse error reporting
// ZAP: 2014/02/21 i1046: The getHttpCookies() method in the HttpResponseHeader does not properly
// set the domain
// ZAP: 2014/04/09 i1145: Cookie parsing error if a comma is used
// ZAP: 2015/02/26 Include json as a text content type
// ZAP: 2016/06/17 Remove redundant initialisations of instance variables
// ZAP: 2017/03/21 Add method to check if response type is json (isJson())
// ZAP: 2017/11/10 Allow to set the status code and reason.
// ZAP: 2018/02/06 Make the lower/upper case changes locale independent (Issue 4327).
// ZAP: 2018/07/23 Add CSP headers.
// ZAP: 2018/08/15 Add Server header.
// ZAP: 2019/06/01 Normalise line endings.
// ZAP: 2019/06/05 Normalise format/style.
// ZAP: 2019/12/09 Address deprecation of getHeaders(String) Vector method.
// ZAP: 2020/11/10 Add convenience method isCss().
// ZAP: 2020/11/26 Use Log4j 2 classes for logging.
// ZAP: 2021/05/14 Remove redundant type arguments.
// ZAP: 2022/09/12 Allow arbitrary HTTP versions.
// ZAP: 2022/09/21 Use format specifiers instead of concatenation when logging.
// ZAP: 2022/11/22 Lower case the HTTP field names for compatibility with HTTP/2.
// ZAP: 2023/01/10 Tidy up logger.
package org.parosproxy.paros.network;

import java.net.HttpCookie;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class HttpResponseHeader extends HttpHeader {

    /**
     * The {@code Content-Security-Policy} response header.
     *
     * @since 2.8.0
     */
    public static final String CSP = "content-security-policy";

    /**
     * The {@code Content-Security-Policy-Report-Only} response header.
     *
     * @since 2.8.0
     */
    public static final String CSP_REPORT_ONLY = "content-security-policy-report-only";

    /**
     * The {@code X-Content-Security-Policy} response header.
     *
     * @since 2.8.0
     */
    public static final String XCSP = "x-content-security-policy";

    /**
     * The {@code X-WebKit-CSP} response header.
     *
     * @since 2.8.0
     */
    public static final String WEBKIT_CSP = "x-webkit-csp";

    /**
     * The {@code Server} response header.
     *
     * @since 2.8.0
     */
    public static final String SERVER = "server";

    private static final long serialVersionUID = 2812716126742059785L;
    private static final Logger LOGGER = LogManager.getLogger(HttpResponseHeader.class);

    public static final String HTTP_CLIENT_BAD_REQUEST = "HTTP/1.0 400 Bad request" + CRLF + CRLF;
    private static final String _CONTENT_TYPE_CSS = "css";
    private static final String _CONTENT_TYPE_IMAGE = "image";
    private static final String _CONTENT_TYPE_TEXT = "text";
    private static final String _CONTENT_TYPE_HTML = "html";
    private static final String _CONTENT_TYPE_JAVASCRIPT = "javascript";
    private static final String _CONTENT_TYPE_JSON = "json";
    private static final String _CONTENT_TYPE_XML = "xml";

    static final Pattern patternStatusLine =
            Pattern.compile(
                    p_VERSION + p_SP + p_STATUS_CODE + " *" + p_REASON_PHRASE,
                    Pattern.CASE_INSENSITIVE);
    private static final Pattern patternPartialStatusLine =
            Pattern.compile("\\A *" + p_VERSION, Pattern.CASE_INSENSITIVE);

    private String mStatusCodeString;
    private int mStatusCode;
    private String mReasonPhrase;

    public HttpResponseHeader() {
        mStatusCodeString = "";
        mReasonPhrase = "";
    }

    public HttpResponseHeader(String data) throws HttpMalformedHeaderException {
        super(data);
    }

    @Override
    public void clear() {
        super.clear();
        mStatusCodeString = "";
        mStatusCode = 0;
        mReasonPhrase = "";
    }

    @Override
    public void setMessage(String data) throws HttpMalformedHeaderException {
        super.setMessage(data);
        try {
            parse();
        } catch (HttpMalformedHeaderException e) {
            mMalformedHeader = true;
            throw e;
        }
    }

    @Override
    public void setVersion(String version) {
        mVersion = version.toUpperCase(Locale.ROOT);
    }

    /**
     * Gets the status code.
     *
     * @return the status code.
     * @see #setStatusCode(int)
     */
    public int getStatusCode() {
        return mStatusCode;
    }

    /**
     * Sets the status code.
     *
     * 

status-code = 3DIGIT * * @param statusCode the new status code. * @throws IllegalArgumentException if the given status code is not a (positive) 3 digit number. * @see #getStatusCode() * @since 2.7.0 */ public void setStatusCode(int statusCode) { if (statusCode < 100 || statusCode > 999) { throw new IllegalArgumentException( "The status code must be a (positive) 3 digit number."); } this.mStatusCode = statusCode; } /** * Gets the reason phrase. * * @return the reason phrase. * @see #setReasonPhrase(String) */ public String getReasonPhrase() { return mReasonPhrase; } /** * Sets the reason phrase. * *

If {@code null} it's set an empty string. * * @param reasonPhrase the new reason phrase. * @see #getReasonPhrase() * @since 2.7.0 */ public void setReasonPhrase(String reasonPhrase) { this.mReasonPhrase = reasonPhrase != null ? reasonPhrase : ""; } private void parse() throws HttpMalformedHeaderException { Matcher matcher = patternStatusLine.matcher(mStartLine); if (!matcher.find()) { mMalformedHeader = true; throw new HttpMalformedHeaderException("Failed to find pattern: " + patternStatusLine); } mVersion = matcher.group(1); mStatusCodeString = matcher.group(2); setReasonPhrase(matcher.group(3)); try { mStatusCode = Integer.parseInt(mStatusCodeString); } catch (NumberFormatException e) { mMalformedHeader = true; throw new HttpMalformedHeaderException("Unexpected status code: " + mStatusCodeString); } } @Override public int getContentLength() { int len = super.getContentLength(); if ((mStatusCode >= 100 && mStatusCode < 200) || mStatusCode == HttpStatusCode.NO_CONTENT || mStatusCode == HttpStatusCode.NOT_MODIFIED) { return 0; } else if (mStatusCode >= 200 && mStatusCode < 300) { return len; } else if (len > 0) { return len; } else { return 0; } } public static HttpResponseHeader getError(String msg) { HttpResponseHeader res = null; try { res = new HttpResponseHeader(msg); } catch (HttpMalformedHeaderException e) { } return res; } @Override public boolean isImage() { return hasContentType(_CONTENT_TYPE_IMAGE); } @Override public boolean isText() { return hasContentType( _CONTENT_TYPE_TEXT, _CONTENT_TYPE_HTML, _CONTENT_TYPE_JAVASCRIPT, _CONTENT_TYPE_JSON, _CONTENT_TYPE_XML); } public boolean isHtml() { return hasContentType(_CONTENT_TYPE_HTML); } public boolean isXml() { return hasContentType(_CONTENT_TYPE_XML); } public boolean isJson() { return hasContentType(_CONTENT_TYPE_JSON); } public boolean isJavaScript() { return hasContentType(_CONTENT_TYPE_JAVASCRIPT); } public boolean isCss() { return hasContentType(_CONTENT_TYPE_CSS); } public static boolean isStatusLine(String data) { return patternPartialStatusLine.matcher(data).find(); } @Override public String getPrimeHeader() { String prime = getVersion() + " " + getStatusCode(); if (getReasonPhrase() != null && !getReasonPhrase().equals("")) { prime = prime + " " + getReasonPhrase(); } return prime; } // ZAP: Added method for working directly with HttpCookie /** * Parses the response headers and build a lis of all the http cookies set. For the cookies * whose domain could not be determined, the {@code defaultDomain} is set. * * @param defaultDomain the default domain * @return the http cookies */ public List getHttpCookies(String defaultDomain) { List cookies = new LinkedList<>(); List cookiesS = getHeaderValues(HttpHeader.SET_COOKIE); for (String c : cookiesS) { cookies.addAll(parseCookieString(c, defaultDomain)); } cookiesS = getHeaderValues(HttpHeader.SET_COOKIE2); for (String c : cookiesS) { cookies.addAll(parseCookieString(c, defaultDomain)); } return cookies; } private List parseCookieString(String c, String defaultDomain) { try { List parsedCookies = HttpCookie.parse(c); if (defaultDomain != null) { for (HttpCookie cookie : parsedCookies) { if (cookie.getDomain() == null) { cookie.setDomain(defaultDomain); } } } return parsedCookies; } catch (IllegalArgumentException e) { if (c.indexOf(',') >= 0) { try { // Some sites seem to use comma separators, which HttpCookie doesn't like, try // replacing them List parsedCookies = HttpCookie.parse(c.replace(',', ';')); if (defaultDomain != null) { for (HttpCookie cookie : parsedCookies) { if (cookie.getDomain() == null) { cookie.setDomain(defaultDomain); } } } return parsedCookies; } catch (IllegalArgumentException e2) { LOGGER.error("Failed to parse cookie: {}", c, e); } } } return new ArrayList<>(); } /** * Parses the response headers and build a lis of all the http cookies set.
* NOTE: For the cookies whose domain could not be determined, no domain is set, so this must be * taken into account. * * @return the http cookies * @deprecated Use the {@link #getHttpCookies(String)} method to take into account the default * domain for cookie */ @Deprecated public List getHttpCookies() { return getHttpCookies(null); } // ZAP: Added method. public TreeSet getCookieParams() { TreeSet set = new TreeSet<>(); Iterator cookiesIt = getHeaderValues(HttpHeader.SET_COOKIE).iterator(); while (cookiesIt.hasNext()) { set.add(new HtmlParameter(cookiesIt.next())); } Iterator cookies2It = getHeaderValues(HttpHeader.SET_COOKIE2).iterator(); while (cookies2It.hasNext()) { set.add(new HtmlParameter(cookies2It.next())); } return set; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy