1 /* 2 * Copyright (c) 2015, 2017, 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.incubator.http.internal.common; 27 28 import jdk.incubator.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.incubator.http.internal.frame.DataFrame; 37 import jdk.incubator.http.internal.frame.Http2Frame; 38 import jdk.incubator.http.internal.frame.WindowUpdateFrame; 39 40 import javax.net.ssl.SNIServerName; 41 import javax.net.ssl.SSLParameters; 42 43 /** 44 * -Djava.net.HttpClient.log= 45 * errors,requests,headers, 46 * frames[:control:data:window:all..],content,ssl,trace 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 static int logging; 69 70 // Frame types: "control", "data", "window", "all" 71 public static final int CONTROL = 1; // all except DATA and WINDOW_UPDATES 72 public static final int DATA = 2; 73 public static final int WINDOW_UPDATES = 4; 74 public static final int ALL = CONTROL| DATA | WINDOW_UPDATES; 75 static int frametypes; 76 77 static final System.Logger logger; 78 79 static { 80 String s = Utils.getNetProperty(logProp); 81 if (s == null) { 82 logging = OFF; 83 } else { 84 String[] vals = s.split(","); 85 for (String val : vals) { 86 switch (val.toLowerCase(Locale.US)) { 87 case "errors": 88 logging |= ERRORS; 89 break; 90 case "requests": 91 logging |= REQUESTS; 92 break; 93 case "headers": 94 logging |= HEADERS; 95 break; 96 case "content": 97 logging |= CONTENT; 98 break; 99 case "ssl": 100 logging |= SSL; 101 break; 102 case "trace": 103 logging |= TRACE; 104 break; 105 case "all": 106 logging |= CONTENT|HEADERS|REQUESTS|FRAMES|ERRORS|TRACE|SSL; 107 break; 108 } 109 if (val.startsWith("frames")) { 110 logging |= FRAMES; 111 String[] types = val.split(":"); 112 if (types.length == 1) { 113 frametypes = CONTROL | DATA | WINDOW_UPDATES; 114 } else { 115 for (String type : types) { 116 switch (type.toLowerCase()) { 117 case "control": 118 frametypes |= CONTROL; 119 break; 120 case "data": 121 frametypes |= DATA; 122 break; 123 case "window": 124 frametypes |= WINDOW_UPDATES; 125 break; 126 case "all": 127 frametypes = ALL; 128 break; 129 } 130 } 131 } 132 } 133 } 134 } 135 if (logging != OFF) { 136 logger = System.getLogger("jdk.httpclient.HttpClient"); 137 } else { 138 logger = null; 139 } 140 } 141 public static boolean errors() { 142 return (logging & ERRORS) != 0; 143 } 144 145 public static boolean requests() { 146 return (logging & REQUESTS) != 0; 147 } 148 149 public static boolean headers() { 150 return (logging & HEADERS) != 0; 151 } 152 153 public static boolean trace() { 154 return (logging & TRACE) != 0; 155 } 156 157 public static boolean ssl() { 158 return (logging & SSL) != 0; 159 } 160 161 public static boolean frames() { 162 return (logging & FRAMES) != 0; 163 } 164 165 public static void logError(String s, Object... s1) { 166 if (errors()) { 167 logger.log(Level.INFO, "ERROR: " + s, s1); 168 } 169 } 170 171 public static void logError(Throwable t) { 172 if (errors()) { 173 String s = Utils.stackTrace(t); 174 logger.log(Level.INFO, "ERROR: " + s); 175 } 176 } 177 178 public static void logSSL(String s, Object... s1) { 179 if (ssl()) { 180 logger.log(Level.INFO, "SSL: " + s, s1); 181 } 182 } 183 184 public static void logSSL(Supplier<String> msgSupplier) { 185 if (ssl()) { 186 logger.log(Level.INFO, "SSL: " + msgSupplier.get()); 187 } 188 } 189 190 public static void logTrace(String s, Object... s1) { 191 if (trace()) { 192 String format = "TRACE: " + s; 193 logger.log(Level.INFO, format, s1); 194 } 195 } 196 197 public static void logRequest(String s, Object... s1) { 198 if (requests()) { 199 logger.log(Level.INFO, "REQUEST: " + s, s1); 200 } 201 } 202 203 public static void logResponse(Supplier<String> supplier) { 204 if (requests()) { 205 logger.log(Level.INFO, "RESPONSE: " + supplier.get()); 206 } 207 } 208 209 public static void logHeaders(String s, Object... s1) { 210 if (headers()) { 211 logger.log(Level.INFO, "HEADERS: " + s, s1); 212 } 213 } 214 215 public static boolean loggingFrame(Class<? extends Http2Frame> clazz) { 216 if (frametypes == ALL) { 217 return true; 218 } 219 if (clazz == DataFrame.class) { 220 return (frametypes & DATA) != 0; 221 } else if (clazz == WindowUpdateFrame.class) { 222 return (frametypes & WINDOW_UPDATES) != 0; 223 } else { 224 return (frametypes & CONTROL) != 0; 225 } 226 } 227 228 public static void logFrames(Http2Frame f, String direction) { 229 if (frames() && loggingFrame(f.getClass())) { 230 logger.log(Level.INFO, "FRAME: " + direction + ": " + f.toString()); 231 } 232 } 233 234 public static void logParams(SSLParameters p) { 235 if (!Log.ssl()) { 236 return; 237 } 238 239 if (p == null) { 240 Log.logSSL("SSLParameters: Null params"); 241 return; 242 } 243 244 final StringBuilder sb = new StringBuilder("SSLParameters:"); 245 final List<Object> params = new ArrayList<>(); 246 if (p.getCipherSuites() != null) { 247 for (String cipher : p.getCipherSuites()) { 248 sb.append("\n cipher: {") 249 .append(params.size()).append("}"); 250 params.add(cipher); 251 } 252 } 253 254 // SSLParameters.getApplicationProtocols() can't return null 255 // JDK 8 EXCL START 256 for (String approto : p.getApplicationProtocols()) { 257 sb.append("\n application protocol: {") 258 .append(params.size()).append("}"); 259 params.add(approto); 260 } 261 // JDK 8 EXCL END 262 263 if (p.getProtocols() != null) { 264 for (String protocol : p.getProtocols()) { 265 sb.append("\n protocol: {") 266 .append(params.size()).append("}"); 267 params.add(protocol); 268 } 269 } 270 271 if (p.getServerNames() != null) { 272 for (SNIServerName sname : p.getServerNames()) { 273 sb.append("\n server name: {") 274 .append(params.size()).append("}"); 275 params.add(sname.toString()); 276 } 277 } 278 sb.append('\n'); 279 280 Log.logSSL(sb.toString(), params.toArray()); 281 } 282 283 public static void dumpHeaders(StringBuilder sb, String prefix, HttpHeaders headers) { 284 if (headers != null) { 285 Map<String,List<String>> h = headers.map(); 286 Set<Map.Entry<String,List<String>>> entries = h.entrySet(); 287 for (Map.Entry<String,List<String>> entry : entries) { 288 String key = entry.getKey(); 289 List<String> values = entry.getValue(); 290 sb.append(prefix).append(key).append(":"); 291 for (String value : values) { 292 sb.append(' ').append(value); 293 } 294 sb.append('\n'); 295 } 296 } 297 } 298 299 300 // not instantiable 301 private Log() {} 302 }