1 19 20 package com.maverick.http; 21 22 import java.io.BufferedInputStream ; 23 import java.io.File ; 24 import java.io.FileOutputStream ; 25 import java.io.IOException ; 26 import java.io.InputStream ; 27 import java.io.InterruptedIOException ; 28 import java.io.OutputStream ; 29 import java.net.Socket ; 30 import java.net.UnknownHostException ; 31 import java.text.MessageFormat ; 32 import java.text.SimpleDateFormat ; 33 import java.util.Date ; 34 35 import com.maverick.ssl.SSLException; 36 import com.maverick.ssl.SSLIOException; 37 import com.maverick.ssl.SSLTransportFactory; 38 39 43 public class HttpConnection { 44 45 SocketWithLayeredTransport socket; 46 InputStream in; 47 OutputStream out; 48 OutputStream monitorInOut; 49 OutputStream monitorOutOut; 50 HttpClient client; 51 boolean isClosed = false; 52 boolean canReuse = true; 53 boolean keepAlive = true; 54 long lastAccessed; 55 HttpAuthenticator authenticator; 56 boolean monitoring = "true".equals(System.getProperty("http.connection.debug")); 58 public static final int CONNECTION_TIMEOUT_LIMIT = 120000; 59 private static int sequence = 0; 60 private static SimpleDateFormat f = new SimpleDateFormat ("HH-mm-ss-SS"); private static Object lock = new Object (); 62 63 private static boolean linger = true; 64 private static boolean noDelay = false; 65 private boolean isPooled = true; 66 67 static org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory.getLog(HttpConnection.class); 69 70 72 public HttpConnection(HttpClient client) throws UnknownHostException , IOException , HttpException, 73 UnsupportedAuthenticationException, AuthenticationCancelledException { 74 this.client = client; 75 reconnect(); 76 } 77 78 public HttpConnection(HttpClient client, SocketWithLayeredTransport socket) throws IOException { 79 this.client = client; 80 this.socket = socket; 81 this.isPooled = false; 82 83 int lingerTime = socket.getSoLinger(); 84 socket.setSoLinger(linger, false ? 0 : (lingerTime == -1 ? 0 : lingerTime)); 85 86 in = new HttpConnectionInputStream(socket.getInputStream(), 32768); 87 out = new HttpConnectionOutputStream(); 88 89 isClosed = false; 90 canReuse = true; 91 92 } 93 94 public static void setDefaultSoLinger(boolean linger) { 95 HttpConnection.linger = linger; 96 } 97 98 public static void setDefaultNoDelay(boolean noDelay) { 99 HttpConnection.noDelay = noDelay; 100 } 101 102 public synchronized void reconnect() throws UnknownHostException , IOException , HttpException, 103 UnsupportedAuthenticationException, AuthenticationCancelledException { 104 close(); 105 if (!client.isProxyConfigured()) { 106 log.debug(MessageFormat.format(Messages.getString("HttpConnection.connectingTo"), new Object [] { client.hostname, new Integer (client.port) })); this.socket = SocketWithLayeredTransportFactory.getDefault().createSocket(client.hostname, client.port); 110 this.socket.setTcpNoDelay(noDelay); 111 112 this.socket.pushTransport(client.isSecure ? SSLTransportFactory.newInstance() : null); 117 118 } else { 119 120 synchronized (client) { 121 switch (client.proxyType) { 122 case HttpClient.PROXY_HTTP: 123 case HttpClient.PROXY_HTTPS: 124 125 log.debug(MessageFormat.format(Messages.getString("HttpConnection.proxyConnect"), new Object [] { client.hostname, new Integer (client.port), client.proxyType == HttpClient.PROXY_HTTPS ? "https" : "http", client.proxyHost, new Integer (client.proxyPort) })); if (client.proxyClient == null) { 130 client.proxyClient = new HttpClient(client); 131 } 132 133 ConnectMethod proxyConnect = new ConnectMethod(client.hostname, client.port, client.isSecure); 134 HttpResponse response = client.proxyClient.execute(proxyConnect); 136 137 if (response.getStatus() == 200) { 138 socket = response.getConnection().socket; 139 } else 140 throw new IOException (MessageFormat.format(Messages.getString("HttpConnection.invalidHttpStatusCode"), new Object [] { new Integer (response.getStatus()) })); break; 142 default: 143 throw new IllegalArgumentException (MessageFormat.format(Messages.getString("HttpConnection.invalidProxyType"), new Object [] { new Integer (client.proxyType) })); } 145 } 146 } 147 148 int lingerTime = socket.getSoLinger(); 149 socket.setSoLinger(linger, false ? 0 : (lingerTime == -1 ? 0 : lingerTime)); 150 151 in = new HttpConnectionInputStream(socket.getInputStream(), 32768); 152 out = new HttpConnectionOutputStream(); 153 154 isClosed = false; 155 canReuse = true; 156 } 157 158 public boolean isMonitoring() { 159 return monitoring; 160 } 161 162 void monitor(String uri) throws IOException { 163 File dir = new File (System.getProperty("java.io.tmpdir"), client.getHost() + "." + client.getPort()); if (!dir.exists() && !dir.mkdirs()) { 165 log.error(MessageFormat.format(Messages.getString("HttpConnection.failedToCreateMaverickDebugDirectory"), new Object [] { dir })); } else { 169 synchronized (lock) { 170 File inFile = new File (dir, String.valueOf(sequence) + "_" + f.format(new Date ()) + ".response.log"); File outFile = new File (dir, String.valueOf(sequence) + "_" + f.format(new Date ()) + ".request.log"); monitorInOut = new FileOutputStream (inFile); 175 monitorOutOut = new FileOutputStream (outFile); 176 in = new MonitorInputStream(new HttpConnectionInputStream(socket.getInputStream(), 32768), monitorInOut); 177 out = new MonitorOutputStream(new HttpConnectionOutputStream(), monitorOutOut); 178 179 sequence++; 180 } 181 } 182 } 183 184 void stopMonitor() throws IOException { 185 186 try { 187 in.close(); 188 } catch (IOException ex) { 189 } 190 try { 191 out.close(); 192 } catch (IOException ex) { 193 } 194 in = socket.getInputStream(); 195 out = new HttpConnectionOutputStream(); 196 } 197 198 void updateState() { 199 this.lastAccessed = System.currentTimeMillis(); 200 } 201 202 void release() { 203 204 try { 205 if (monitoring) 206 stopMonitor(); 207 } catch (IOException ex) { 208 } 209 210 if (!canReuse) 211 close(); 212 213 if(isPooled) 214 client.connections.releaseConnection(this); 215 } 216 217 void verify() throws UnknownHostException , IOException , HttpException, UnsupportedAuthenticationException, 218 AuthenticationCancelledException { 219 220 try { 221 222 if (System.currentTimeMillis() > lastAccessed + CONNECTION_TIMEOUT_LIMIT) 223 canReuse = false; 224 else { 225 226 try { 227 socket.setSoTimeout(1); 228 in.mark(1); 229 int byteRead = in.read(); 230 if (byteRead == -1) { 231 log.debug(Messages.getString("HttpConnection.eof")); canReuse = false; 237 } else { 238 in.reset(); 239 } 240 } finally { 241 socket.setSoTimeout(0); 242 } 243 } 244 } catch (InterruptedIOException ex) { 245 } catch (SSLIOException ex) { 247 canReuse = (ex.getRealException().getStatus() == SSLException.READ_TIMEOUT); 248 } catch (IOException ex) { 249 log.debug(Messages.getString("HttpConnection.dead")); canReuse = false; 254 255 } 256 257 if (!canReuse && isPooled) 258 reconnect(); 259 } 260 261 public boolean isClosed() { 262 return isClosed; 263 } 264 265 public boolean isKeepAlive() { 266 return keepAlive; 267 } 268 269 public boolean canReuse() { 270 return canReuse; 271 } 272 273 public synchronized void close() { 274 try { 275 try { 276 if (socket != null) 277 socket.close(); 278 } catch (IOException ex) { 279 } 280 } finally { 281 if (monitorInOut != null) { 282 try { 283 monitorInOut.close(); 284 } catch (IOException ioe) { 285 } 286 } 287 if (monitorOutOut != null) { 288 try { 289 monitorOutOut.close(); 290 } catch (IOException ioe) { 291 } 292 } 293 } 294 295 isClosed = true; 296 } 297 298 public OutputStream getOutputStream() throws IOException { 299 return out; 300 } 302 303 public InputStream getInputStream() throws IOException { 304 return in; 305 } 306 307 public int getPort() { 308 return client.port; 309 } 310 311 public String getHost() { 312 return client.hostname; 313 } 314 315 public String getHostHeaderValue() { 316 return client.hostname 317 + ((client.isSecure && client.port != 443) || (!client.isSecure && client.port != 80) ? (":" + client.port) : ""); } 319 320 public boolean isSecure() { 321 return client.isSecure; 322 } 323 324 public Socket getSocket() { 325 return socket; 326 } 327 328 public void setAuthenticator(HttpAuthenticator authenticator) { 329 this.authenticator = authenticator; 330 } 331 332 public HttpAuthenticator getAuthenticator() { 333 return authenticator; 334 } 335 336 class HttpConnectionInputStream extends BufferedInputStream { 337 338 HttpConnectionInputStream(InputStream in, int len) { 339 super(in, len); 340 } 341 342 public void close() throws IOException { 343 updateState(); 344 socket.getInputStream().close(); 345 } 346 347 public int read() throws IOException { 348 updateState(); 349 return super.read(); 350 } 351 352 public int read(byte[] buf, int off, int len) throws IOException { 353 updateState(); 354 return super.read(buf, off, len); 355 } 356 } 357 358 class HttpConnectionOutputStream extends OutputStream { 359 360 public void close() throws IOException { 361 updateState(); 362 socket.getOutputStream().close(); 363 } 364 365 public void write(int b) throws IOException { 366 updateState(); 367 socket.getOutputStream().write(b); 368 } 369 370 public void write(byte[] buf, int off, int len) throws IOException { 371 updateState(); 372 socket.getOutputStream().write(buf, off, len); 373 } 374 } 375 376 class MonitorInputStream extends InputStream { 377 378 InputStream in = null; 379 OutputStream monitorOut; 380 381 MonitorInputStream(InputStream in, OutputStream monitorOut) { 382 super(); 383 this.in = in; 384 this.monitorOut = monitorOut; 385 } 386 387 392 public int available() throws IOException { 393 return in.available(); 394 } 395 396 401 public void close() throws IOException { 402 in.close(); 403 } 404 405 410 public synchronized void mark(int readlimit) { 411 in.mark(readlimit); 412 } 413 414 419 public boolean markSupported() { 420 return in.markSupported(); 421 } 422 423 428 public int read(byte[] b, int off, int len) throws IOException { 429 int r = in.read(b, off, len); 430 if (r != -1) { 431 try { 432 monitorOut.write(b, off, r); 433 monitorOut.flush(); 434 } catch (IOException ioe) { 435 } 436 } 437 return r; 438 } 439 440 445 public int read(byte[] b) throws IOException { 446 int r = in.read(b); 447 if (r != -1) { 448 try { 449 monitorOut.write(b, 0, r); 450 monitorOut.flush(); 451 } catch (IOException ioe) { 452 } 453 } 454 return r; 455 } 456 457 462 public synchronized void reset() throws IOException { 463 in.reset(); 464 } 465 466 471 public long skip(long n) throws IOException { 472 return in.skip(n); 473 } 474 475 public int read() throws IOException { 476 int r = in.read(); 477 if (r != -1) { 478 try { 479 monitorOut.write(r); 480 monitorOut.flush(); 481 } catch (IOException ioe) { 482 } 483 } 484 return r; 485 } 486 487 } 488 489 class MonitorOutputStream extends OutputStream { 490 491 OutputStream out; 492 OutputStream monitorOut; 493 494 MonitorOutputStream(OutputStream out, OutputStream monitorOut) { 495 super(); 496 this.out = out; 497 this.monitorOut = monitorOut; 498 } 499 500 505 public void close() throws IOException { 506 out.close(); 507 } 508 509 514 public void flush() throws IOException { 515 out.flush(); 516 } 517 518 523 public void write(byte[] b, int off, int len) throws IOException { 524 out.write(b, off, len); 525 try { 526 monitorOut.write(b, off, len); 527 monitorOut.flush(); 528 } catch (IOException ioe) { 529 } 530 } 531 532 537 public void write(byte[] b) throws IOException { 538 out.write(b); 539 try { 540 monitorOut.write(b); 541 monitorOut.flush(); 542 } catch (IOException ioe) { 543 } 544 } 545 546 public void write(int b) throws IOException { 547 out.write(b); 548 try { 549 monitorOut.write(b); 550 monitorOut.flush(); 551 } catch (IOException ioe) { 552 } 553 } 554 555 } 556 557 public void setCanReuse(boolean canReuse) { 558 this.canReuse = canReuse; 559 } 560 } 561
| Popular Tags
|