001package org.apache.maven.wagon.shared.http; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.maven.wagon.ResourceDoesNotExistException; 023import org.apache.maven.wagon.TransferFailedException; 024import org.apache.maven.wagon.authorization.AuthorizationException; 025import org.apache.maven.wagon.proxy.ProxyInfo; 026import org.codehaus.plexus.util.StringUtils; 027 028/** 029 * Helper for HTTP related messages. 030 * <p> 031 * <b>Important notice on Reason Phrase</b>: 032 * <ul> 033 * <li>reason phrase was <a href="https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html">defined by initial HTTP/1.1 034 * RFC 2616</a>: <cite>The Reason-Phrase is intended to give a short textual description of the Status-Code. The 035 * Status-Code is intended for use by automata and the Reason-Phrase is intended for the human user. The client is not 036 * required to examine or display the Reason- Phrase.</cite></li> 037 * <li>it has been later largely deprecated in <a href="https://tools.ietf.org/html/rfc7230#section-3.1.2">the updated 038 * HTTP/1.1 RFC-7230</a>: <cite>The reason-phrase element exists for the sole purpose of providing a textual description 039 * associated with the numeric status code, mostly out of deference to earlier Internet application protocols that were 040 * more frequently used with interactive text clients. A client SHOULD ignore the reason-phrase content.</cite></li> 041 * <li>it has been removed from <a href="https://tools.ietf.org/html/rfc7540#section-8.1.2.4">HTTP/2 RFC 7540</a>: 042 * <cite>HTTP/2 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status 043 * line.</cite>.</li> 044 * </ul> 045 * The use of Reason Phrase done here to improve the message to the end-user (particularly in case of failures) will 046 * disappear while HTTP/2 is deployed: a new mechanism to provide such a message needs to be defined... 047 * 048 * @since 3.3.4 049 */ 050public class HttpMessageUtils 051{ 052 // status codes here to avoid checkstyle magic number and not have have hard depend on non-wagon classes 053 private static final int SC_UNAUTHORIZED = 401; 054 private static final int SC_FORBIDDEN = 403; 055 private static final int SC_NOT_FOUND = 404; 056 private static final int SC_PROXY_AUTH_REQUIRED = 407; 057 private static final int SC_GONE = 410; 058 059 /** 060 * A HTTP status code used to indicate that the actual response status code is not known at time of message 061 * generation. 062 */ 063 public static final int UNKNOWN_STATUS_CODE = -1; 064 065 /** 066 * Format a consistent HTTP transfer debug message combining url, status code, status line reason phrase and HTTP 067 * proxy server info. 068 * <p> 069 * Url will always be included in the message. A status code other than {@link #UNKNOWN_STATUS_CODE} will be 070 * included. A reason phrase will only be included if non-empty and status code is not {@link #UNKNOWN_STATUS_CODE}. 071 * Proxy information will only be included if not null. 072 * 073 * @param url the required non-null URL associated with the message 074 * @param statusCode an HTTP response status code 075 * @param reasonPhrase an HTTP status line reason phrase 076 * @param proxyInfo proxy server used during the transfer, may be null if none used 077 * @return a formatted debug message combining the parameters of this method 078 * @throws NullPointerException if url is null 079 */ 080 public static String formatTransferDebugMessage( String url, int statusCode, String reasonPhrase, 081 ProxyInfo proxyInfo ) 082 { 083 String msg = url; 084 if ( statusCode != UNKNOWN_STATUS_CODE ) 085 { 086 msg += " -- status code: " + statusCode; 087 if ( StringUtils.isNotEmpty( reasonPhrase ) ) 088 { 089 msg += ", reason phrase: " + reasonPhrase; 090 } 091 } 092 if ( proxyInfo != null ) 093 { 094 msg += " -- " + proxyInfo.toString(); 095 } 096 return msg; 097 } 098 099 /** 100 * Format a consistent message for HTTP related {@link TransferFailedException}. 101 * <p> 102 * This variation typically used in cases where there is no HTTP transfer response data to extract status code and 103 * reason phrase from. Equivalent to calling {@link #formatTransferFailedMessage(String, int, String, ProxyInfo)} 104 * with {@link #UNKNOWN_STATUS_CODE} and null reason phrase. 105 * 106 * @param url the URL associated with the message 107 * @param proxyInfo proxy server used during the transfer, may be null if none used 108 * @return a formatted failure message combining the parameters of this method 109 */ 110 public static String formatTransferFailedMessage( String url, ProxyInfo proxyInfo ) 111 { 112 return formatTransferFailedMessage( url, UNKNOWN_STATUS_CODE, null, 113 proxyInfo ); 114 } 115 116 /** 117 * Format a consistent message for HTTP related {@link TransferFailedException}. 118 * 119 * @param url the URL associated with the message 120 * @param statusCode an HTTP response status code or {@link #UNKNOWN_STATUS_CODE} 121 * @param reasonPhrase an HTTP status line reason phrase or null if the reason phrase unknown 122 * @param proxyInfo proxy server used during the transfer, may be null if none used 123 * @return a formatted failure message combining the parameters of this method 124 */ 125 public static String formatTransferFailedMessage( String url, int statusCode, String reasonPhrase, 126 ProxyInfo proxyInfo ) 127 { 128 return formatMessage( "Transfer failed for ", url, statusCode, reasonPhrase, proxyInfo ); 129 } 130 131 /** 132 * Format a consistent message for HTTP related {@link AuthorizationException}. 133 * <p> 134 * The message will always include the URL and status code provided. If empty, the reason phrase is substituted with 135 * a common reason based on status code. {@link ProxyInfo} is only included in the message if not null. 136 * 137 * @param url the URL associated with the message 138 * @param statusCode an HTTP response status code related to auth 139 * @param reasonPhrase an HTTP status line reason phrase 140 * @param proxyInfo proxy server used during the transfer, may be null if none used 141 * @return a consistent message for a HTTP related {@link AuthorizationException} 142 */ 143 public static String formatAuthorizationMessage( String url, int statusCode, String reasonPhrase, 144 ProxyInfo proxyInfo ) 145 { 146 switch ( statusCode ) 147 { 148 case SC_UNAUTHORIZED: // no credentials or auth was not valid 149 return formatMessage( "Authentication failed for ", url, statusCode, reasonPhrase, null ); 150 151 case SC_FORBIDDEN: // forbidden based on permissions usually 152 return formatMessage( "Authorization failed for ", url, statusCode, reasonPhrase, null ); 153 154 case SC_PROXY_AUTH_REQUIRED: 155 return formatMessage( "HTTP proxy server authentication failed for ", url, statusCode, 156 reasonPhrase, null ); 157 158 default: 159 break; 160 } 161 162 return formatMessage( "Authorization failed for ", url, statusCode, reasonPhrase, proxyInfo ); 163 } 164 165 /** 166 * Format a consistent message for HTTP related {@link ResourceDoesNotExistException}. 167 * <p> 168 * The message will always include the URL and status code provided. If empty, the reason phrase is substituted with 169 * the commonly used reason phrases per status code. {@link ProxyInfo} is only included if not null. 170 * 171 * @param url the URL associated with the message 172 * @param statusCode an HTTP response status code related to resources not being found 173 * @param reasonPhrase an HTTP status line reason phrase 174 * @param proxyInfo proxy server used during the transfer, may be null if none used 175 * @return a consistent message for a HTTP related {@link ResourceDoesNotExistException} 176 */ 177 public static String formatResourceDoesNotExistMessage( String url, int statusCode, String reasonPhrase, 178 ProxyInfo proxyInfo ) 179 { 180 return formatMessage( "Resource missing at ", url, statusCode, reasonPhrase, proxyInfo ); 181 } 182 183 private static String formatMessage( String message, String url, int statusCode, String reasonPhrase, 184 ProxyInfo proxyInfo ) 185 { 186 String msg = message + url; 187 if ( statusCode != UNKNOWN_STATUS_CODE ) 188 { 189 msg += " " + statusCode; 190 191 if ( StringUtils.isNotEmpty( reasonPhrase ) ) 192 { 193 msg += " " + reasonPhrase; 194 } 195 else 196 { 197 switch ( statusCode ) 198 { 199 case SC_UNAUTHORIZED: 200 msg += " Unauthorized"; 201 break; 202 203 case SC_FORBIDDEN: 204 msg += " Forbidden"; 205 break; 206 207 case SC_NOT_FOUND: 208 msg += " Not Found"; 209 break; 210 211 case SC_PROXY_AUTH_REQUIRED: 212 msg += " Proxy Authentication Required"; 213 break; 214 215 case SC_GONE: 216 msg += " Gone"; 217 break; 218 219 default: 220 break; 221 } 222 } 223 } 224 if ( proxyInfo != null ) 225 { 226 msg += " " + proxyInfo.toString(); 227 } 228 return msg; 229 } 230}