1 29 30 package com.caucho.server.hmux; 31 32 import com.caucho.log.Log; 33 import com.caucho.server.cluster.BackingManager; 34 import com.caucho.server.cluster.Cluster; 35 import com.caucho.server.connection.AbstractHttpRequest; 36 import com.caucho.server.connection.Connection; 37 import com.caucho.server.dispatch.DispatchServer; 38 import com.caucho.server.dispatch.Invocation; 39 import com.caucho.server.dispatch.InvocationDecoder; 40 import com.caucho.server.http.InvocationKey; 41 import com.caucho.server.port.ServerRequest; 42 import com.caucho.server.webapp.ErrorPageManager; 43 import com.caucho.util.ByteBuffer; 44 import com.caucho.util.CharBuffer; 45 import com.caucho.util.CharSegment; 46 import com.caucho.vfs.ClientDisconnectException; 47 import com.caucho.vfs.ReadStream; 48 import com.caucho.vfs.StreamImpl; 49 import com.caucho.vfs.WriteStream; 50 51 import java.io.IOException ; 52 import java.io.InputStream ; 53 import java.io.InterruptedIOException ; 54 import java.net.InetAddress ; 55 import java.security.cert.CertificateFactory ; 56 import java.security.cert.X509Certificate ; 57 import java.util.ArrayList ; 58 import java.util.Collections ; 59 import java.util.Enumeration ; 60 import java.util.HashSet ; 61 import java.util.logging.Level ; 62 import java.util.logging.Logger ; 63 64 132 public class HmuxRequest extends AbstractHttpRequest 133 implements ServerRequest { 134 private static final Logger log = Log.open(HmuxRequest.class); 135 136 public static final int HMUX_CHANNEL = 'C'; 138 public static final int HMUX_ACK = 'A'; 139 public static final int HMUX_ERROR = 'E'; 140 public static final int HMUX_YIELD = 'Y'; 141 public static final int HMUX_QUIT = 'Q'; 142 public static final int HMUX_EXIT = 'X'; 143 144 public static final int HMUX_DATA = 'D'; 145 public static final int HMUX_URI = 'U'; 146 public static final int HMUX_STRING = 'S'; 147 public static final int HMUX_HEADER = 'H'; 148 public static final int HMUX_PROTOCOL = 'P'; 149 public static final int HMUX_META_HEADER = 'M'; 150 151 public static final int CSE_NULL = '?'; 153 public static final int CSE_PATH_INFO = 'b'; 154 public static final int CSE_PROTOCOL = 'c'; 155 public static final int CSE_REMOTE_USER = 'd'; 156 public static final int CSE_QUERY_STRING = 'e'; 157 public static final int HMUX_FLUSH = 'f'; 158 public static final int CSE_SERVER_PORT = 'g'; 159 public static final int CSE_REMOTE_HOST = 'h'; 160 public static final int CSE_REMOTE_ADDR = 'i'; 161 public static final int CSE_REMOTE_PORT = 'j'; 162 public static final int CSE_REAL_PATH = 'k'; 163 public static final int CSE_SCRIPT_FILENAME = 'l'; 164 public static final int HMUX_METHOD = 'm'; 165 public static final int CSE_AUTH_TYPE = 'n'; 166 public static final int CSE_URI = 'o'; 167 public static final int CSE_CONTENT_LENGTH = 'p'; 168 public static final int CSE_CONTENT_TYPE = 'q'; 169 public static final int CSE_IS_SECURE = 'r'; 170 public static final int HMUX_STATUS = 's'; 171 public static final int CSE_CLIENT_CERT = 't'; 172 public static final int CSE_SERVER_TYPE = 'u'; 173 public static final int HMUX_SERVER_NAME = 'v'; 174 175 public static final int CSE_SEND_HEADER = 'G'; 176 177 public static final int CSE_DATA = 'D'; 178 public static final int CSE_FLUSH = 'F'; 179 public static final int CSE_KEEPALIVE = 'K'; 180 public static final int CSE_ACK = 'A'; 181 public static final int CSE_END = 'Z'; 182 public static final int CSE_CLOSE = 'X'; 183 184 public static final int CSE_QUERY = 'Q'; 186 public static final int CSE_PING = 'P'; 187 188 public static final int HMUX_CLUSTER_PROTOCOL = 0x101; 189 public static final int HMUX_DISPATCH_PROTOCOL = 0x102; 190 191 public enum ProtocolResult { 192 QUIT, 193 EXIT, 194 YIELD 195 }; 196 197 static final int HTTP_0_9 = 0x0009; 198 static final int HTTP_1_0 = 0x0100; 199 static final int HTTP_1_1 = 0x0101; 200 201 private static final int HEADER_CAPACITY = 256; 202 203 static final CharBuffer _getCb = new CharBuffer("GET"); 204 static final CharBuffer _headCb = new CharBuffer("HEAD"); 205 static final CharBuffer _postCb = new CharBuffer("POST"); 206 207 private final CharBuffer _method; private String _methodString; private CharBuffer _host; private int _port; 213 private ByteBuffer _uri; private CharBuffer _protocol; private int _version; 216 217 private CharBuffer _remoteAddr; 218 private CharBuffer _remoteHost; 219 private CharBuffer _serverName; 220 private CharBuffer _serverPort; 221 private CharBuffer _remotePort; 222 223 private boolean _isSecure; 224 private ByteBuffer _clientCert; 225 226 private CharBuffer []_headerKeys; 227 private CharBuffer []_headerValues; 228 private int _headerSize; 229 230 private byte []_lengthBuf; 231 232 private int _serverType; 233 234 private WriteStream _rawWrite; 236 private WriteStream _writeStream; 238 239 private ServletFilter _filter; 241 private int _pendingData; 242 243 private InvocationKey _invocationKey = new InvocationKey(); 244 245 private CharBuffer _cb1; 246 private CharBuffer _cb2; 247 private boolean _hasRequest; 248 249 private AbstractClusterRequest _clusterRequest; 250 private HmuxDispatchRequest _dispatchRequest; 251 private BackingManager _backingManager; 252 private Cluster _cluster; 253 254 private ErrorPageManager _errorManager = new ErrorPageManager(); 255 256 private int _srunIndex; 257 258 public HmuxRequest(DispatchServer server, Connection conn) 259 { 260 super(server, conn); 261 262 _response = new HmuxResponse(this); 263 264 _rawWrite = conn.getWriteStream(); 265 _writeStream = new WriteStream(); 266 _writeStream.setReuseBuffer(true); 267 268 270 _cluster = Cluster.getLocal(); 271 if (_cluster != null) { 272 try { 273 Class cl = Class.forName("com.caucho.server.hmux.HmuxClusterRequest"); 274 275 _clusterRequest = (AbstractClusterRequest) cl.newInstance(); 276 _clusterRequest.setRequest(this); 277 _clusterRequest.setCluster(_cluster); 278 } catch (ClassNotFoundException e) { 279 log.finer(e.toString()); 280 } catch (Throwable e) { 281 log.log(Level.FINER, e.toString(), e); 282 } 283 } 284 285 _dispatchRequest = new HmuxDispatchRequest(this); 286 287 _uri = new ByteBuffer(); 288 289 _method = new CharBuffer(); 290 _host = new CharBuffer(); 291 _protocol = new CharBuffer(); 292 293 _headerKeys = new CharBuffer[HEADER_CAPACITY]; 294 _headerValues = new CharBuffer[_headerKeys.length]; 295 for (int i = 0; i < _headerKeys.length; i++) { 296 _headerKeys[i] = new CharBuffer(); 297 _headerValues[i] = new CharBuffer(); 298 } 299 300 _remoteHost = new CharBuffer(); 301 _remoteAddr = new CharBuffer(); 302 _serverName = new CharBuffer(); 303 _serverPort = new CharBuffer(); 304 _remotePort = new CharBuffer(); 305 306 _clientCert = new ByteBuffer(); 307 308 _cb1 = new CharBuffer(); 309 _cb2 = new CharBuffer(); 310 311 _lengthBuf = new byte[16]; 312 313 _filter = new ServletFilter(); 314 } 315 316 public boolean isWaitForRead() 317 { 318 return true; 319 } 320 321 328 public boolean handleRequest() 329 throws IOException 330 { 331 Thread thread = Thread.currentThread(); 333 thread.setContextClassLoader(_server.getClassLoader()); 334 335 if (log.isLoggable(Level.FINE)) 336 log.fine(dbgId() + "start request"); 337 338 _filter.init(this, _rawRead, _rawWrite); 339 _writeStream.init(_filter); 340 342 _response.init(_writeStream); 343 344 _serverType = 0; 345 _uri.setLength(0); 346 347 boolean hasRequest = false; 348 349 try { 350 start(); 351 _response.start(); 352 353 try { 354 if (! scanHeaders()) { 355 killKeepalive(); 356 return false; 357 } 358 else if (_uri.size() == 0) { 359 return true; 360 } 361 } catch (InterruptedIOException e) { 362 killKeepalive(); 363 log.fine(dbgId() + "interrupted keepalive"); 364 return false; 365 } 366 367 if (_isSecure) 368 getClientCertificate(); 369 370 hasRequest = true; 371 373 if (_server == null || _server.isDestroyed()) { 374 log.fine(dbgId() + "server is closed"); 375 376 try { 377 _writeStream.setDisableClose(false); 378 _writeStream.close(); 379 } catch (Throwable e) { 380 } 381 382 try { 383 _readStream.setDisableClose(false); 384 _readStream.close(); 385 } catch (Throwable e) { 386 } 387 388 return false; 389 } 390 391 _filter.setPending(_pendingData); 392 393 try { 394 if (_method.getLength() == 0) 395 throw new RuntimeException ("HTTP protocol exception"); 396 397 _invocationKey.init(_isSecure, 398 getHost(), getServerPort(), 399 _uri.getBuffer(), _uri.getLength()); 400 401 Invocation invocation; 402 403 invocation = _server.getInvocation(_invocationKey); 404 405 if (invocation == null) { 406 invocation = _server.createInvocation(); 407 408 if (_host != null) 409 invocation.setHost(_host.toString()); 410 411 invocation.setPort(getServerPort()); 412 413 InvocationDecoder decoder = _server.getInvocationDecoder(); 414 415 decoder.splitQueryAndUnescape(invocation, 416 _uri.getBuffer(), 417 _uri.getLength()); 418 419 _server.buildInvocation(_invocationKey.clone(), invocation); 420 } 421 422 setInvocation(invocation); 423 424 invocation.service(this, _response); 425 } catch (ClientDisconnectException e) { 426 throw e; 427 } catch (Throwable e) { 428 try { 429 _errorManager.sendServletError(e, this, _response); 430 } catch (ClientDisconnectException e1) { 431 throw e1; 432 } catch (Exception e1) { 433 log.log(Level.FINE, e1.toString(), e1); 434 } 435 436 return false; 437 } 438 } finally { 439 if (! hasRequest) 440 _response.setHeaderWritten(true); 441 442 try { 443 finish(); 444 _response.finish(); 445 } catch (ClientDisconnectException e) { 446 throw e; 447 } catch (Exception e) { 448 killKeepalive(); 449 log.log(Level.FINE, dbgId() + e, e); 450 } 451 452 try { 453 _writeStream.setDisableClose(false); 454 _writeStream.close(); 455 } catch (ClientDisconnectException e) { 456 killKeepalive(); 457 log.log(Level.FINE, dbgId() + e, e); 458 459 throw e; 460 } catch (Exception e) { 461 killKeepalive(); 462 log.log(Level.FINE, dbgId() + e, e); 463 } 464 465 try { 466 _readStream.setDisableClose(false); 467 _readStream.close(); 468 } catch (Exception e) { 469 killKeepalive(); 470 log.log(Level.FINE, dbgId() + e, e); 471 } 472 } 473 474 boolean allowKeepalive = isKeepalive(); 475 476 if (log.isLoggable(Level.FINE)) { 477 if (allowKeepalive) 478 log.fine(dbgId() + "complete request - keepalive"); 479 else 480 log.fine(dbgId() + "complete request"); 481 } 482 483 return allowKeepalive; 484 } 485 486 489 protected boolean initStream(ReadStream readStream, 490 ReadStream rawStream) 491 throws IOException 492 { 493 readStream.init(_filter, null); 494 495 return true; 496 } 497 498 private void getClientCertificate() 499 { 500 String cipher = getHeader("SSL_CIPHER"); 501 if (cipher == null) 502 cipher = getHeader("HTTPS_CIPHER"); 503 if (cipher != null) 504 setAttribute("javax.servlet.request.cipher_suite", cipher); 505 506 String keySize = getHeader("SSL_CIPHER_USEKEYSIZE"); 507 if (keySize == null) 508 keySize = getHeader("SSL_SECRETKEYSIZE"); 509 if (keySize != null) 510 setAttribute("javax.servlet.request.key_size", keySize); 511 512 if (_clientCert.size() == 0) 513 return; 514 515 try { 516 CertificateFactory cf = CertificateFactory.getInstance("X.509"); 517 InputStream is = _clientCert.createInputStream(); 518 Object cert = cf.generateCertificate(is); 519 is.close(); 520 setAttribute("javax.servlet.request.X509Certificate", cert); 521 setAttribute(com.caucho.server.security.AbstractAuthenticator.LOGIN_NAME, 522 ((X509Certificate ) cert).getSubjectDN()); 523 } catch (Throwable e) { 524 log.log(Level.FINE, e.toString(), e); 525 } 526 } 527 528 532 public boolean isTop() 533 { 534 return true; 535 } 536 537 protected boolean checkLogin() 538 { 539 return true; 540 } 541 542 545 protected void start() 546 throws IOException 547 { 548 super.start(); 549 550 _method.clear(); 551 _methodString = null; 552 _protocol.clear(); 553 _version = 0; 554 _uri.clear(); 555 _host.clear(); 556 _port = 0; 557 558 _headerSize = 0; 559 560 _remoteHost.clear(); 561 _remoteAddr.clear(); 562 _serverName.clear(); 563 _serverPort.clear(); 564 _remotePort.clear(); 565 566 _clientCert.clear(); 567 568 _pendingData = 0; 569 570 _isSecure = false; 571 } 572 573 576 private boolean scanHeaders() 577 throws IOException 578 { 579 boolean hasURI = false; 580 CharBuffer cb = _cb; 581 boolean isLoggable = log.isLoggable(Level.FINE); 582 ReadStream is = _rawRead; 583 int code; 584 int len; 585 586 while (true) { 587 code = is.read(); 588 589 switch (code) { 590 case -1: 591 if (isLoggable) 592 log.fine(dbgId() + "end of file"); 593 return false; 594 595 case HMUX_CHANNEL: 596 int channel = (is.read() << 8) + is.read(); 597 598 if (isLoggable) 599 log.fine(dbgId() + "channel " + channel); 600 break; 601 602 case HMUX_QUIT: 603 if (isLoggable) 604 log.fine(dbgId() + (char) code + ": end of request"); 605 606 return hasURI; 607 608 case HMUX_EXIT: 609 if (isLoggable) 610 log.fine(dbgId() + (char) code + ": end of socket"); 611 612 killKeepalive(); 613 614 return hasURI; 615 616 case HMUX_PROTOCOL: 617 len = (is.read() << 8) + is.read(); 618 619 if (len != 4) { 620 log.fine(dbgId() + (char) code + ": protocol length (" + len + ") must be 4."); 621 killKeepalive(); 622 return false; 623 } 624 625 int value = ((is.read() << 24) + 626 (is.read() << 16) + 627 (is.read() << 8) + 628 (is.read())); 629 630 int result = HMUX_EXIT; 631 boolean isKeepalive = false; 632 if (value == HMUX_CLUSTER_PROTOCOL) { 633 if (isLoggable) 634 log.fine(dbgId() + (char) code + ": cluster protocol"); 635 _filter.setClientClosed(true); 636 637 if (_server == null || _server.isDestroyed()) { 638 return false; 639 } 640 641 result = _clusterRequest.handleRequest(is, _rawWrite); 642 } 643 else if (value == HMUX_DISPATCH_PROTOCOL) { 644 if (isLoggable) 645 log.fine(dbgId() + (char) code + ": dispatch protocol"); 646 _filter.setClientClosed(true); 647 648 if (_server == null || _server.isDestroyed()) { 649 return false; 650 } 651 652 isKeepalive = _dispatchRequest.handleRequest(is, _rawWrite); 653 654 if (isKeepalive) 655 result = HMUX_QUIT; 656 else 657 result = HMUX_EXIT; 658 } 659 else { 660 log.fine(dbgId() + (char) code + ": unknown protocol (" + value + ")"); 661 result = HMUX_EXIT; 662 } 663 664 if (result == HMUX_YIELD) 665 break; 666 else { 667 if (result == HMUX_QUIT && ! allowKeepalive()) 668 result = HMUX_EXIT; 669 670 if (result == HMUX_QUIT) { 671 _rawWrite.write(HMUX_QUIT); 672 _rawWrite.flush(); 673 } 674 else { 675 _rawWrite.write(HMUX_EXIT); 676 _rawWrite.close(); 677 } 678 679 return result == HMUX_QUIT; 680 } 681 682 case HMUX_URI: 683 hasURI = true; 684 len = (is.read() << 8) + is.read(); 685 _uri.setLength(len); 686 _rawRead.readAll(_uri.getBuffer(), 0, len); 687 if (isLoggable) 688 log.fine(dbgId() + (char) code + ":uri " + _uri); 689 break; 690 691 case HMUX_METHOD: 692 len = (is.read() << 8) + is.read(); 693 is.readAll(_method, len); 694 if (isLoggable) 695 log.fine(dbgId() + 696 (char) code + ":method " + _method); 697 break; 698 699 case CSE_REAL_PATH: 700 len = (is.read() << 8) + is.read(); 701 _cb1.clear(); 702 _rawRead.readAll(_cb1, len); 703 code = _rawRead.read(); 704 if (code != HMUX_STRING) 705 throw new IOException ("protocol expected HMUX_STRING"); 706 _cb2.clear(); 707 _rawRead.readAll(_cb2, readLength()); 708 709 if (isLoggable) 711 log.fine(dbgId() + (char) code + " " + 712 _cb1.toString() + "->" + _cb2.toString()); 713 break; 715 716 case CSE_REMOTE_HOST: 717 len = (is.read() << 8) + is.read(); 718 _rawRead.readAll(_remoteHost, len); 719 if (isLoggable) 720 log.fine(dbgId() + (char) code + " " + _remoteHost); 721 break; 722 723 case CSE_REMOTE_ADDR: 724 len = (is.read() << 8) + is.read(); 725 _rawRead.readAll(_remoteAddr, len); 726 if (isLoggable) 727 log.fine(dbgId() + (char) code + " " + _remoteAddr); 728 break; 729 730 case HMUX_SERVER_NAME: 731 len = (is.read() << 8) + is.read(); 732 _rawRead.readAll(_serverName, len); 733 if (isLoggable) 734 log.fine(dbgId() + (char) code + " server-host: " + _serverName); 735 break; 736 737 case CSE_REMOTE_PORT: 738 len = (is.read() << 8) + is.read(); 739 _rawRead.readAll(_remotePort, len); 740 if (isLoggable) 741 log.fine(dbgId() + (char) code + 742 " remote-port: " + _remotePort); 743 break; 744 745 case CSE_SERVER_PORT: 746 len = (is.read() << 8) + is.read(); 747 _rawRead.readAll(_serverPort, len); 748 if (isLoggable) 749 log.fine(dbgId() + (char) code + 750 " server-port: " + _serverPort); 751 break; 752 753 case CSE_QUERY_STRING: 754 len = (is.read() << 8) + is.read(); 755 if (len > 0) { 756 _uri.add('?'); 757 _uri.ensureCapacity(_uri.getLength() + len); 758 _rawRead.readAll(_uri.getBuffer(), _uri.getLength(), len); 759 _uri.setLength(_uri.getLength() + len); 760 } 761 break; 762 763 case CSE_PROTOCOL: 764 len = (is.read() << 8) + is.read(); 765 _rawRead.readAll(_protocol, len); 766 if (isLoggable) 767 log.fine(dbgId() + (char) code + " protocol: " + _protocol); 768 for (int i = 0; i < len; i++) { 769 char ch = _protocol.charAt(i); 770 if (ch >= '0' && ch <= '9') 771 _version = 16 * _version + ch - '0'; 772 else if (ch == '.') 773 _version = 16 * _version; 774 } 775 break; 776 777 case HMUX_HEADER: 778 len = (is.read() << 8) + is.read(); 779 780 int headerSize = _headerSize; 781 782 CharBuffer key = _headerKeys[headerSize]; 783 key.clear(); 784 785 CharBuffer valueCb = _headerValues[headerSize]; 786 valueCb.clear(); 787 788 _rawRead.readAll(key, len); 789 code = _rawRead.read(); 790 if (code != HMUX_STRING) 791 throw new IOException ("protocol expected HMUX_STRING at " + (char) code); 792 _rawRead.readAll(valueCb, readLength()); 793 794 addHeaderInt(key.getBuffer(), 0, key.length(), valueCb); 795 796 if (isLoggable) 797 log.fine(dbgId() + "H " + key + "=" + valueCb); 798 799 _headerSize++; 800 break; 801 802 case CSE_CONTENT_LENGTH: 803 len = (is.read() << 8) + is.read(); 804 if (_headerKeys.length <= _headerSize) 805 resizeHeaders(); 806 _headerKeys[_headerSize].clear(); 807 _headerKeys[_headerSize].append("Content-Length"); 808 _headerValues[_headerSize].clear(); 809 _rawRead.readAll(_headerValues[_headerSize], len); 810 811 if (isLoggable) 812 log.fine(dbgId() + (char) code + " content-length=" + 813 _headerValues[_headerSize]); 814 _headerSize++; 815 break; 816 817 case CSE_CONTENT_TYPE: 818 len = (is.read() << 8) + is.read(); 819 if (_headerKeys.length <= _headerSize) 820 resizeHeaders(); 821 _headerKeys[_headerSize].clear(); 822 _headerKeys[_headerSize].append("Content-Type"); 823 _headerValues[_headerSize].clear(); 824 _rawRead.readAll(_headerValues[_headerSize], len); 825 if (isLoggable) 826 log.fine(dbgId() + (char) code + " content-type=" + 827 _headerValues[_headerSize]); 828 _headerSize++; 829 break; 830 831 case CSE_IS_SECURE: 832 len = (is.read() << 8) + is.read(); 833 _isSecure = true; 834 if (isLoggable) 835 log.fine(dbgId() + "secure"); 836 _rawRead.skip(len); 837 break; 838 839 case CSE_CLIENT_CERT: 840 len = (is.read() << 8) + is.read(); 841 _clientCert.clear(); 842 _clientCert.setLength(len); 843 _rawRead.readAll(_clientCert.getBuffer(), 0, len); 844 if (isLoggable) 845 log.fine(dbgId() + (char) code + " cert=" + _clientCert + 846 " len:" + len); 847 break; 848 849 case CSE_SERVER_TYPE: 850 len = (is.read() << 8) + is.read(); 851 _cb1.clear(); 852 _rawRead.readAll(_cb1, len); 853 if (isLoggable) 854 log.fine(dbgId() + (char) code + " server=" + _cb1); 855 if (_cb1.length() > 0) 856 _serverType = _cb1.charAt(0); 857 break; 858 859 case CSE_REMOTE_USER: 860 len = (is.read() << 8) + is.read(); 861 _cb.clear(); 862 _rawRead.readAll(_cb, len); 863 if (isLoggable) 864 log.fine(dbgId() + (char) code + " " + _cb); 865 setAttribute(com.caucho.server.security.AbstractAuthenticator.LOGIN_NAME, 866 new com.caucho.security.BasicPrincipal(_cb.toString())); 867 break; 868 869 case CSE_DATA: 870 len = (is.read() << 8) + is.read(); 871 _pendingData = len; 872 if (isLoggable) 873 log.fine(dbgId() + (char) code + " post-data: " + len); 874 return hasURI; 875 876 default: 877 len = (is.read() << 8) + is.read(); 878 879 if (isLoggable) 880 log.fine(dbgId() + (char) code + " " + len); 881 is.skip(len); 882 break; 883 } 884 } 885 886 888 } 890 891 private void resizeHeaders() 892 { 893 CharBuffer []newKeys = new CharBuffer[_headerSize * 2]; 894 CharBuffer []newValues = new CharBuffer[_headerSize * 2]; 895 896 for (int i = 0; i < _headerSize; i++) { 897 newKeys[i] = _headerKeys[i]; 898 newValues[i] = _headerValues[i]; 899 } 900 901 for (int i = _headerSize; i < newKeys.length; i++) { 902 newKeys[i] = new CharBuffer(); 903 newValues[i] = new CharBuffer(); 904 } 905 906 _headerKeys = newKeys; 907 _headerValues = newValues; 908 } 909 910 private int readLength() 911 throws IOException 912 { 913 return ((_rawRead.read() << 8) + _rawRead.read()); 914 } 915 916 919 public String getMethod() 920 { 921 if (_methodString == null) { 922 CharSegment cb = getMethodBuffer(); 923 if (cb.length() == 0) { 924 _methodString = "GET"; 925 return _methodString; 926 } 927 928 switch (cb.charAt(0)) { 929 case 'G': 930 _methodString = cb.equals(_getCb) ? "GET" : cb.toString(); 931 break; 932 933 case 'H': 934 _methodString = cb.equals(_headCb) ? "HEAD" : cb.toString(); 935 break; 936 937 case 'P': 938 _methodString = cb.equals(_postCb) ? "POST" : cb.toString(); 939 break; 940 941 default: 942 _methodString = cb.toString(); 943 } 944 } 945 946 return _methodString; 947 948 } 949 950 public CharSegment getMethodBuffer() 951 { 952 return _method; 953 } 954 955 958 protected CharBuffer getHost() 959 { 960 if (_host.length() > 0) 961 return _host; 962 963 _host.append(_serverName); 964 _host.toLowerCase(); 965 966 return _host; 967 } 968 969 public final byte []getUriBuffer() 970 { 971 return _uri.getBuffer(); 972 } 973 974 public final int getUriLength() 975 { 976 return _uri.getLength(); 977 } 978 979 982 public String getProtocol() 983 { 984 return _protocol.toString(); 985 } 986 987 public CharSegment getProtocolBuffer() 988 { 989 return _protocol; 990 } 991 992 final int getVersion() 993 { 994 return _version; 995 } 996 997 1000 public boolean isSecure() 1001 { 1002 return _isSecure; 1003 } 1004 1005 1008 public String getHeader(String key) 1009 { 1010 CharSegment buf = getHeaderBuffer(key); 1011 if (buf != null) 1012 return buf.toString(); 1013 else 1014 return null; 1015 } 1016 1017 public CharSegment getHeaderBuffer(String key) 1018 { 1019 for (int i = 0; i < _headerSize; i++) { 1020 CharBuffer test = _headerKeys[i]; 1021 1022 if (test.equalsIgnoreCase(key)) 1023 return _headerValues[i]; 1024 } 1025 1026 return null; 1027 } 1028 1029 public CharSegment getHeaderBuffer(char []buf, int length) 1030 { 1031 for (int i = 0; i < _headerSize; i++) { 1032 CharBuffer test = _headerKeys[i]; 1033 1034 if (test.length() != length) 1035 continue; 1036 1037 char []keyBuf = test.getBuffer(); 1038 int j; 1039 for (j = 0; j < length; j++) { 1040 char a = buf[j]; 1041 char b = keyBuf[j]; 1042 if (a == b) 1043 continue; 1044 1045 if (a >= 'A' && a <= 'Z') 1046 a += 'a' - 'A'; 1047 if (b >= 'A' && b <= 'Z') 1048 b += 'a' - 'A'; 1049 if (a != b) 1050 break; 1051 } 1052 1053 if (j == length) 1054 return _headerValues[i]; 1055 } 1056 1057 return null; 1058 } 1059 1060 public void setHeader(String key, String value) 1061 { 1062 if (_headerKeys.length <= _headerSize) 1063 resizeHeaders(); 1064 1065 _headerKeys[_headerSize].clear(); 1066 _headerKeys[_headerSize].append(key); 1067 _headerValues[_headerSize].clear(); 1068 _headerValues[_headerSize].append(value); 1069 _headerSize++; 1070 } 1071 1072 public void getHeaderBuffers(String key, ArrayList <CharSegment> values) 1073 { 1074 CharBuffer cb = _cb; 1075 1076 cb.clear(); 1077 cb.append(key); 1078 1079 int size = _headerSize; 1080 for (int i = 0; i < size; i++) { 1081 CharBuffer test = _headerKeys[i]; 1082 if (test.equalsIgnoreCase(cb)) 1083 values.add(_headerValues[i]); 1084 } 1085 } 1086 1087 public Enumeration getHeaderNames() 1088 { 1089 HashSet <String > names = new HashSet <String >(); 1090 for (int i = 0; i < _headerSize; i++) 1091 names.add(_headerKeys[i].toString()); 1092 1093 return Collections.enumeration(names); 1094 } 1095 1096 1101 public String getRequestURI() 1102 { 1103 if (_serverType == 'R') 1104 return super.getRequestURI(); 1105 1106 String _rawURI = super.getRequestURI(); 1107 CharBuffer cb = CharBuffer.allocate(); 1108 1109 for (int i = 0; i < _rawURI.length(); i++) { 1110 char ch = _rawURI.charAt(i); 1111 1112 switch (ch) { 1113 case ' ': 1114 case '?': 1115 addHex(cb, ch); 1116 break; 1117 1118 default: 1119 cb.append(ch); 1120 break; 1121 } 1122 } 1123 1124 return cb.close(); 1125 } 1126 1127 1133 private void addHex(CharBuffer cb, int ch) 1134 { 1135 cb.append('%'); 1136 1137 int d = (ch >> 4) & 0xf; 1138 if (d < 10) 1139 cb.append((char) ('0' + d)); 1140 else 1141 cb.append((char) ('a' + d - 10)); 1142 1143 d = ch & 0xf; 1144 if (d < 10) 1145 cb.append((char) ('0' + d)); 1146 else 1147 cb.append((char) ('a' + d - 10)); 1148 } 1149 1150 1153 public String getServerName() 1154 { 1155 CharBuffer host = getHost(); 1156 if (host == null) { 1157 InetAddress addr = getConnection().getRemoteAddress(); 1158 return addr.getHostName(); 1159 } 1160 1161 int p = host.indexOf(':'); 1162 if (p >= 0) 1163 return host.substring(0, p); 1164 else 1165 return host.toString(); 1166 } 1167 1168 public int getServerPort() 1169 { 1170 int len = _serverPort.length(); 1171 int port = 0; 1172 for (int i = 0; i < len; i++) { 1173 char ch = _serverPort.charAt(i); 1174 port = 10 * port + ch - '0'; 1175 } 1176 1177 return port; 1178 } 1179 1180 public String getRemoteAddr() 1181 { 1182 return _remoteAddr.toString(); 1183 } 1184 1185 public void getRemoteAddr(CharBuffer cb) 1186 { 1187 cb.append(_remoteAddr); 1188 } 1189 1190 public int printRemoteAddr(byte []buffer, int offset) 1191 throws IOException 1192 { 1193 char []buf = _remoteAddr.getBuffer(); 1194 int len = _remoteAddr.getLength(); 1195 1196 for (int i = 0; i < len; i++) 1197 buffer[offset + i] = (byte) buf[i]; 1198 1199 return offset + len; 1200 } 1201 1202 public String getRemoteHost() 1203 { 1204 return _remoteHost.toString(); 1205 } 1206 1207 1210 protected void connectionClose() 1211 { 1212 } 1214 1215 void writeStatus(CharBuffer message) 1217 throws IOException 1218 { 1219 int channel = 2; 1220 1221 WriteStream os = _rawWrite; 1222 1223 os.write(HMUX_CHANNEL); 1224 os.write(channel >> 8); 1225 os.write(channel); 1226 1227 writeString(HMUX_STATUS, message); 1228 } 1229 1230 1233 void sendHeader() 1234 throws IOException 1235 { 1236 writeString(CSE_SEND_HEADER, ""); 1237 } 1238 1239 1245 void writeHeader(String key, String value) 1246 throws IOException 1247 { 1248 writeString(HMUX_HEADER, key); 1249 writeString(HMUX_STRING, value); 1250 } 1251 1252 1258 void writeHeader(String key, CharBuffer value) 1259 throws IOException 1260 { 1261 writeString(HMUX_HEADER, key); 1262 writeString(HMUX_STRING, value); 1263 } 1264 1265 void writeString(int code, String value) 1266 throws IOException 1267 { 1268 int len = value.length(); 1269 1270 WriteStream os = _rawWrite; 1271 1272 os.write(code); 1273 os.write(len >> 8); 1274 os.write(len); 1275 os.print(value); 1276 1277 if (log.isLoggable(Level.FINE)) 1278 log.fine(dbgId() + (char)code + " " + value); 1279 } 1280 1281 void writeString(int code, CharBuffer cb) 1282 throws IOException 1283 { 1284 int len = cb.length(); 1285 1286 WriteStream os = _rawWrite; 1287 1288 os.write(code); 1289 os.write(len >> 8); 1290 os.write(len); 1291 os.print(cb.getBuffer(), 0, len); 1292 1293 if (log.isLoggable(Level.FINE)) 1294 log.fine(dbgId() + (char)code + " " + cb); 1295 } 1296 1297 public void protocolCloseEvent() 1298 { 1299 } 1300 1301 public final String dbgId() 1302 { 1303 String id = _server.getServerId(); 1304 1305 if (id.equals("")) 1306 return "[" + getConnection().getId() + "] "; 1307 else 1308 return "[" + id + ":" + getConnection().getId() + "] "; 1309 } 1310 1311 public String toString() 1312 { 1313 return "HmuxRequest" + dbgId(); 1314 } 1315 1316 1321 static class ServletFilter extends StreamImpl { 1322 HmuxRequest _request; 1323 ReadStream _is; 1324 WriteStream _os; 1325 byte []_buffer = new byte[16]; 1326 int _pendingData; 1327 boolean _needsAck; 1328 boolean _isClosed; 1329 boolean _isClientClosed; 1330 1331 ServletFilter() 1332 { 1333 } 1334 1335 void init(HmuxRequest request, 1336 ReadStream nextRead, WriteStream nextWrite) 1337 { 1338 _request = request; 1339 _is = nextRead; 1340 _os = nextWrite; 1341 _pendingData = 0; 1342 _isClosed = false; 1343 _isClientClosed = false; 1344 _needsAck = false; 1345 } 1346 1347 void setPending(int pendingData) 1348 { 1349 _pendingData = pendingData; 1350 } 1351 1352 void setClientClosed(boolean isClientClosed) 1353 { 1354 _isClientClosed = isClientClosed; 1355 } 1356 1357 public boolean canRead() 1358 { 1359 return true; 1360 } 1361 1362 public int getAvailable() 1363 { 1364 return _pendingData; 1365 } 1366 1367 1370 public int read(byte []buf, int offset, int length) 1371 throws IOException 1372 { 1373 int sublen = _pendingData; 1374 ReadStream is = _is; 1375 1376 if (sublen <= 0) 1377 return -1; 1378 1379 if (length < sublen) 1380 sublen = length; 1381 1382 int readLen = is.read(buf, offset, sublen); 1383 _pendingData -= readLen; 1384 1385 if (log.isLoggable(Level.FINEST)) 1386 log.finest(new String (buf, offset, readLen)); 1387 1388 while (_pendingData == 0) { 1389 if (_needsAck) { 1390 int channel = 2; 1391 1392 _os.write(HMUX_ACK); 1393 _os.write(channel >> 8); 1394 _os.write(channel); 1395 1396 if (log.isLoggable(Level.FINE)) 1397 log.fine(_request.dbgId() + "A:ack channel 2"); 1398 } 1399 1400 _needsAck = false; 1401 1402 int code = is.read(); 1403 1404 if (code == HMUX_DATA) { 1405 int len = (is.read() << 8) + is.read(); 1406 1407 if (log.isLoggable(Level.FINE)) 1408 log.fine(_request.dbgId() + "D:post-data " + len); 1409 1410 _pendingData = len; 1411 } 1412 else if (code == HMUX_QUIT) { 1413 if (log.isLoggable(Level.FINE)) 1414 log.fine(_request.dbgId() + "Q:quit"); 1415 1416 return readLen; 1417 } 1418 else if (code == HMUX_EXIT) { 1419 if (log.isLoggable(Level.FINE)) 1420 log.fine(_request.dbgId() + "X:exit"); 1421 1422 _request.killKeepalive(); 1423 return readLen; 1424 } 1425 else if (code == HMUX_YIELD) { 1426 _needsAck = true; 1427 } 1428 else if (code == HMUX_CHANNEL) { 1429 int channel = (is.read() << 8) + is.read(); 1430 1431 if (log.isLoggable(Level.FINE)) 1432 log.fine(_request.dbgId() + "channel " + channel); 1433 } 1434 else if (code < 0) { 1435 _request.killKeepalive(); 1436 1437 return readLen; 1438 } 1439 else { 1440 _request.killKeepalive(); 1441 1442 int len = (is.read() << 8) + is.read(); 1443 1444 if (log.isLoggable(Level.FINE)) 1445 log.fine(_request.dbgId() + "unknown `" + (char) code + "' " + len); 1446 1447 is.skip(len); 1448 } 1449 } 1450 1451 return readLen; 1452 } 1453 1454 public boolean canWrite() 1455 { 1456 return true; 1457 } 1458 1459 1462 public void write(byte []buf, int offset, int length, boolean isEnd) 1463 throws IOException 1464 { 1465 if (log.isLoggable(Level.FINE)) { 1466 log.fine(_request.dbgId() + (char) HMUX_DATA + ":data " + length); 1467 1468 if (log.isLoggable(Level.FINEST)) 1469 log.finest(_request.dbgId() + "data <" + new String (buf, offset, length) + ">"); 1470 } 1471 1472 byte []tempBuf = _buffer; 1473 1474 while (length > 0) { 1475 int sublen = length; 1476 1477 if (32 * 1024 < sublen) 1478 sublen = 32 * 1024; 1479 1480 tempBuf[0] = HMUX_DATA; 1482 tempBuf[1] = (byte) (sublen >> 8); 1483 tempBuf[2] = (byte) sublen; 1484 1485 _os.write(tempBuf, 0, 3); 1486 _os.write(buf, offset, sublen); 1487 1488 length -= sublen; 1489 offset += sublen; 1490 } 1491 } 1492 1493 public void flush() 1494 throws IOException 1495 { 1496 if (log.isLoggable(Level.FINE)) 1497 log.fine(_request.dbgId() + (char) HMUX_FLUSH + ":flush"); 1498 1499 _os.write(HMUX_FLUSH); 1500 _os.write(0); 1501 _os.write(0); 1502 _os.flush(); 1503 } 1504 1505 public void close() 1506 throws IOException 1507 { 1508 if (_isClosed) 1509 return; 1510 1511 _isClosed = true; 1512 1513 if (_pendingData > 0) { 1514 _is.skip(_pendingData); 1515 _pendingData = 0; 1516 } 1517 1518 boolean keepalive = _request.allowKeepalive(); 1519 1520 if (! _isClientClosed) { 1521 if (log.isLoggable(Level.FINE)) { 1522 if (keepalive) 1523 log.fine(_request.dbgId() + (char) HMUX_QUIT + ": quit channel"); 1524 else 1525 log.fine(_request.dbgId() + (char) HMUX_EXIT + ": exit socket"); 1526 } 1527 1528 if (keepalive) 1529 _os.write(HMUX_QUIT); 1530 else 1531 _os.write(HMUX_EXIT); 1532 } 1533 1534 if (keepalive) 1535 _os.flush(); 1536 else 1537 _os.close(); 1538 } 1540 } 1541} 1542 | Popular Tags |