1 /* 2 * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.net.http.common; 27 28 import java.net.http.HttpHeaders; 29 30 import java.util.ArrayList; 31 import java.util.List; 32 import java.util.Locale; 33 import java.util.Map; 34 import java.util.Set; 35 import java.util.function.Supplier; 36 import jdk.internal.net.http.frame.DataFrame; 37 import jdk.internal.net.http.frame.Http2Frame; 38 import jdk.internal.net.http.frame.WindowUpdateFrame; 39 40 import javax.net.ssl.SNIServerName; 41 import javax.net.ssl.SSLParameters; 42 43 /** 44 * -Djdk.httpclient.HttpClient.log= 45 * errors,requests,headers, 46 * frames[:control:data:window:all..],content,ssl,trace,channel 47 * 48 * Any of errors, requests, headers or content are optional. 49 * 50 * Other handlers may be added. All logging is at level INFO 51 * 52 * Logger name is "jdk.httpclient.HttpClient" 53 */ 54 // implements System.Logger in order to be skipped when printing the caller's 55 // information 56 public abstract class Log implements System.Logger { 57 58 static final String logProp = "jdk.httpclient.HttpClient.log"; 59 60 public static final int OFF = 0; 61 public static final int ERRORS = 0x1; 62 public static final int REQUESTS = 0x2; 63 public static final int HEADERS = 0x4; 64 public static final int CONTENT = 0x8; 65 public static final int FRAMES = 0x10; 66 public static final int SSL = 0x20; 67 public static final int TRACE = 0x40; 68 public static final int CHANNEL = 0x80; 69 static int logging; 70 71 // Frame types: "control", "data", "window", "all" 72 public static final int CONTROL = 1; // all except DATA and WINDOW_UPDATES 73 public static final int DATA = 2; 74 public static final int WINDOW_UPDATES = 4; 75 public static final int ALL = CONTROL| DATA | WINDOW_UPDATES; 76 static int frametypes; 77 78 static final System.Logger logger; 79 80 static { 81 String s = Utils.getNetProperty(logProp); 82 if (s == null) { 83 logging = OFF; 84 } else { 85 String[] vals = s.split(","); 86 for (String val : vals) { 87 switch (val.toLowerCase(Locale.US)) { 88 case "errors": 89 logging |= ERRORS; 90 break; 91 case "requests": 92 logging |= REQUESTS; 93 break; 94 case "headers": 95 logging |= HEADERS; 96 break; 97 case "content": 98 logging |= CONTENT; 99 break; 100 case "ssl": 101 logging |= SSL; 102 break; 103 case "channel": 104 logging |= CHANNEL; 105 break; 106 case "trace": 107 logging |= TRACE; 108 break; 109 case "all": 110 logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS|TRACE|SSL| CHANNEL; 111 frametypes |= ALL; 112 break; 113 default: 114 // ignore bad values 115 } 116 if (val.startsWith("frames")) { 117 logging |= FRAMES; 118 String[] types = val.split(":"); 119 if (types.length == 1) { 120 frametypes = CONTROL | DATA | WINDOW_UPDATES; 121 } else { 122 for (String type : types) { 123 switch (type.toLowerCase(Locale.US)) { 124 case "control": 125 frametypes |= CONTROL; 126 break; 127 case "data": 128 frametypes |= DATA; 129 break; 130 case "window": 131 frametypes |= WINDOW_UPDATES; 132 break; 133 case "all": 134 frametypes = ALL; 135 break; 136 default: 137 // ignore bad values 138 } 139 } 140 } 141 } 142 } 143 } 144 if (logging != OFF) { 145 logger = System.getLogger("jdk.httpclient.HttpClient"); 146 } else { 147 logger = null; 148 } 149 } 150 public static boolean errors() { 151 return (logging & ERRORS) != 0; 152 } 153 154 public static boolean requests() { 155 return (logging & REQUESTS) != 0; 156 } 157 158 public static boolean headers() { 159 return (logging & HEADERS) != 0; 160 } 161 162 public static boolean trace() { 163 return (logging & TRACE) != 0; 164 } 165 166 public static boolean ssl() { 167 return (logging & SSL) != 0; 168 } 169 170 public static boolean frames() { 171 return (logging & FRAMES) != 0; 172 } 173 174 public static boolean channel() { 175 return (logging & CHANNEL) != 0; 176 } 177 178 public static void logError(String s, Object... s1) { 179 if (errors()) { 180 logger.log(Level.INFO, "ERROR: " + s, s1); 181 } 182 } 183 184 public static void logError(Throwable t) { 185 if (errors()) { 186 String s = Utils.stackTrace(t); 187 logger.log(Level.INFO, "ERROR: " + s); 188 } 189 } 190 191 public static void logSSL(String s, Object... s1) { 192 if (ssl()) { 193 logger.log(Level.INFO, "SSL: " + s, s1); 194 } 195 } 196 197 public static void logSSL(Supplier<String> msgSupplier) { 198 if (ssl()) { 199 logger.log(Level.INFO, "SSL: " + msgSupplier.get()); 200 } 201 } 202 203 public static void logChannel(String s, Object... s1) { 204 if (channel()) { 205 logger.log(Level.INFO, "CHANNEL: " + s, s1); 206 } 207 } 208 209 public static void logChannel(Supplier<String> msgSupplier) { 210 if (channel()) { 211 logger.log(Level.INFO, "CHANNEL: " + msgSupplier.get()); 212 } 213 } 214 215 public static void logTrace(String s, Object... s1) { 216 if (trace()) { 217 String format = "MISC: " + s; 218 logger.log(Level.INFO, format, s1); 219 } 220 } 221 222 public static void logRequest(String s, Object... s1) { 223 if (requests()) { 224 logger.log(Level.INFO, "REQUEST: " + s, s1); 225 } 226 } 227 228 public static void logResponse(Supplier<String> supplier) { 229 if (requests()) { 230 logger.log(Level.INFO, "RESPONSE: " + supplier.get()); 231 } 232 } 233 234 public static void logHeaders(String s, Object... s1) { 235 if (headers()) { 236 logger.log(Level.INFO, "HEADERS: " + s, s1); 237 } 238 } 239 240 public static boolean loggingFrame(Class<? extends Http2Frame> clazz) { 241 if (frametypes == ALL) { 242 return true; 243 } 244 if (clazz == DataFrame.class) { 245 return (frametypes & DATA) != 0; 246 } else if (clazz == WindowUpdateFrame.class) { 247 return (frametypes & WINDOW_UPDATES) != 0; 248 } else { 249 return (frametypes & CONTROL) != 0; 250 } 251 } 252 253 public static void logFrames(Http2Frame f, String direction) { 254 if (frames() && loggingFrame(f.getClass())) { 255 logger.log(Level.INFO, "FRAME: " + direction + ": " + f.toString()); 256 } 257 } 258 259 public static void logParams(SSLParameters p) { 260 if (!Log.ssl()) { 261 return; 262 } 263 264 if (p == null) { 265 Log.logSSL("SSLParameters: Null params"); 266 return; 267 } 268 269 final StringBuilder sb = new StringBuilder("SSLParameters:"); 270 final List<Object> params = new ArrayList<>(); 271 if (p.getCipherSuites() != null) { 272 for (String cipher : p.getCipherSuites()) { 273 sb.append("\n cipher: {") 274 .append(params.size()).append("}"); 275 params.add(cipher); 276 } 277 } 278 279 // SSLParameters.getApplicationProtocols() can't return null 280 // JDK 8 EXCL START 281 for (String approto : p.getApplicationProtocols()) { 282 sb.append("\n application protocol: {") 283 .append(params.size()).append("}"); 284 params.add(approto); 285 } 286 // JDK 8 EXCL END 287 288 if (p.getProtocols() != null) { 289 for (String protocol : p.getProtocols()) { 290 sb.append("\n protocol: {") 291 .append(params.size()).append("}"); 292 params.add(protocol); 293 } 294 } 295 296 if (p.getEndpointIdentificationAlgorithm() != null) { 297 sb.append("\n endpointIdAlg: {") 298 .append(params.size()).append("}"); 299 params.add(p.getEndpointIdentificationAlgorithm()); 300 } 301 302 if (p.getServerNames() != null) { 303 for (SNIServerName sname : p.getServerNames()) { 304 sb.append("\n server name: {") 305 .append(params.size()).append("}"); 306 params.add(sname.toString()); 307 } 308 } 309 sb.append('\n'); 310 311 Log.logSSL(sb.toString(), params.toArray()); 312 } 313 314 public static void dumpHeaders(StringBuilder sb, String prefix, HttpHeaders headers) { 315 if (headers != null) { 316 Map<String,List<String>> h = headers.map(); 317 Set<Map.Entry<String,List<String>>> entries = h.entrySet(); 318 String sep = ""; 319 for (Map.Entry<String,List<String>> entry : entries) { 320 String key = entry.getKey(); 321 List<String> values = entry.getValue(); 322 if (values == null || values.isEmpty()) { 323 // should not happen 324 sb.append(sep); 325 sb.append(prefix).append(key).append(':'); 326 sep = "\n"; 327 continue; 328 } 329 for (String value : values) { 330 sb.append(sep); 331 sb.append(prefix).append(key).append(':'); 332 sb.append(' ').append(value); 333 sep = "\n"; 334 } 335 } 336 sb.append('\n'); 337 } 338 } 339 340 341 // not instantiable 342 private Log() {} 343 }