1 /* 2 * Copyright (c) 2011, 2014, 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 com.sun.webkit.network; 27 28 import static com.sun.webkit.network.URLs.newURL; 29 30 import java.net.MalformedURLException; 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.Arrays; 34 import java.util.concurrent.LinkedBlockingQueue; 35 import java.util.concurrent.ThreadFactory; 36 import java.util.concurrent.ThreadPoolExecutor; 37 import java.util.concurrent.TimeUnit; 38 import java.util.concurrent.atomic.AtomicInteger; 39 import java.util.logging.Level; 40 import java.util.logging.Logger; 41 42 import com.sun.webkit.WebPage; 43 44 final class NetworkContext { 45 46 private static final Logger logger = 47 Logger.getLogger(NetworkContext.class.getName()); 48 49 /** 50 * The size of the thread pool for asynchronous loaders. 51 */ 52 private static final int THREAD_POOL_SIZE = 20; 53 54 /** 55 * The thread pool keep alive time. 56 */ 57 private static final long THREAD_POOL_KEEP_ALIVE_TIME = 10000L; 58 59 /** 60 * The default value of the "http.maxConnections" system property. 61 */ 62 private static final int DEFAULT_HTTP_MAX_CONNECTIONS = 5; 63 64 /** 65 * The buffer size for the shared pool of byte buffers. 66 */ 67 private static final int BYTE_BUFFER_SIZE = 1024 * 40; 68 69 /** 70 * The thread pool used to execute asynchronous loaders. 71 */ 72 private static final ThreadPoolExecutor threadPool; 73 static { 74 threadPool = new ThreadPoolExecutor( 75 THREAD_POOL_SIZE, 76 THREAD_POOL_SIZE, 77 THREAD_POOL_KEEP_ALIVE_TIME, 78 TimeUnit.MILLISECONDS, 79 new LinkedBlockingQueue<Runnable>(), 80 new URLLoaderThreadFactory()); 81 threadPool.allowCoreThreadTimeOut(true); 82 } 83 84 /** 85 * The shared pool of byte buffers. 86 */ 87 private static final ByteBufferPool byteBufferPool = 88 ByteBufferPool.newInstance(BYTE_BUFFER_SIZE); 89 90 91 /** 92 * Non-invocable constructor. 93 */ 94 private NetworkContext() { 95 throw new AssertionError(); 96 } 97 98 99 /** 100 * Checks whether a URL is valid or not. I.E. if we do have a protocol 101 * handler to deal with it. 102 * 103 * @param url the <code>String</code> containing the url to check. 104 * @return <code>true</code> if we can handle the url. <code>false</code> 105 * otherwise. 106 */ 107 private static boolean canHandleURL(String url) { 108 java.net.URL u = null; 109 try { 110 u = newURL(url); 111 } catch (MalformedURLException malformedURLException) { 112 } 113 return u != null; 114 } 115 116 /** 117 * Starts an asynchronous load or executes a synchronous one. 118 */ 119 private static URLLoader fwkLoad(WebPage webPage, 120 boolean asynchronous, 121 String url, 122 String method, 123 String headers, 124 FormDataElement[] formDataElements, 125 long data) 126 { 127 if (logger.isLoggable(Level.FINEST)) { 128 logger.log(Level.FINEST, String.format( 129 "webPage: [%s], " + 130 "asynchronous: [%s], " + 131 "url: [%s], " + 132 "method: [%s], " + 133 "formDataElements: %s, " + 134 "data: [0x%016X], " + 135 "headers:%n%s", 136 webPage, 137 asynchronous, 138 url, 139 method, 140 formDataElements != null 141 ? Arrays.asList(formDataElements) : "[null]", 142 data, 143 Util.formatHeaders(headers))); 144 } 145 URLLoader loader = new URLLoader( 146 webPage, 147 byteBufferPool, 148 asynchronous, 149 url, 150 method, 151 headers, 152 formDataElements, 153 data); 154 if (asynchronous) { 155 threadPool.submit(loader); 156 if (logger.isLoggable(Level.FINEST)) { 157 logger.log(Level.FINEST, 158 "active count: [{0}], " + 159 "pool size: [{1}], " + 160 "max pool size: [{2}], " + 161 "task count: [{3}], " + 162 "completed task count: [{4}]", 163 new Object[] { 164 threadPool.getActiveCount(), 165 threadPool.getPoolSize(), 166 threadPool.getMaximumPoolSize(), 167 threadPool.getTaskCount(), 168 threadPool.getCompletedTaskCount()}); 169 } 170 return loader; 171 } else { 172 loader.run(); 173 return null; 174 } 175 } 176 177 /** 178 * Returns the maximum allowed number of connections per host. 179 */ 180 private static int fwkGetMaximumHTTPConnectionCountPerHost() { 181 // Our implementation employs HttpURLConnection for all 182 // HTTP exchanges, so return the value of the "http.maxConnections" 183 // system property. 184 int propValue = AccessController.doPrivileged( 185 (PrivilegedAction<Integer>) () -> Integer.getInteger("http.maxConnections", -1)); 186 return propValue >= 0 ? propValue : DEFAULT_HTTP_MAX_CONNECTIONS; 187 } 188 189 /** 190 * Thread factory for URL loader threads. 191 */ 192 private static final class URLLoaderThreadFactory implements ThreadFactory { 193 private final ThreadGroup group; 194 private final AtomicInteger index = new AtomicInteger(1); 195 196 private URLLoaderThreadFactory() { 197 SecurityManager sm = System.getSecurityManager(); 198 group = (sm != null) ? sm.getThreadGroup() 199 : Thread.currentThread().getThreadGroup(); 200 } 201 202 @Override 203 public Thread newThread(Runnable r) { 204 Thread t = new Thread(group, r, 205 "URL-Loader-" + index.getAndIncrement()); 206 t.setDaemon(true); 207 if (t.getPriority() != Thread.NORM_PRIORITY) { 208 t.setPriority(Thread.NORM_PRIORITY); 209 } 210 return t; 211 } 212 } 213 }