1 17 18 19 package org.apache.catalina.connector; 20 21 import java.io.IOException ; 22 23 import org.apache.catalina.CometEvent; 24 import org.apache.catalina.Context; 25 import org.apache.catalina.Globals; 26 import org.apache.catalina.Wrapper; 27 import org.apache.catalina.util.StringManager; 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 import org.apache.coyote.ActionCode; 31 import org.apache.coyote.Adapter; 32 import org.apache.tomcat.util.buf.B2CConverter; 33 import org.apache.tomcat.util.buf.ByteChunk; 34 import org.apache.tomcat.util.buf.CharChunk; 35 import org.apache.tomcat.util.buf.MessageBytes; 36 import org.apache.tomcat.util.http.Cookies; 37 import org.apache.tomcat.util.http.ServerCookie; 38 import org.apache.tomcat.util.net.SocketStatus; 39 40 41 49 50 public class CoyoteAdapter 51 implements Adapter 52 { 53 private static Log log = LogFactory.getLog(CoyoteAdapter.class); 54 55 57 58 public static final int ADAPTER_NOTES = 1; 59 60 61 63 64 69 public CoyoteAdapter(Connector connector) { 70 71 super(); 72 this.connector = connector; 73 74 } 75 76 77 79 80 83 private Connector connector = null; 84 85 86 89 private static final String match = 90 ";" + Globals.SESSION_PARAMETER_NAME + "="; 91 92 93 96 protected StringManager sm = 97 StringManager.getManager(Constants.Package); 98 99 100 102 103 108 public boolean event(org.apache.coyote.Request req, 109 org.apache.coyote.Response res, SocketStatus status) { 110 111 Request request = (Request) req.getNote(ADAPTER_NOTES); 112 Response response = (Response) res.getNote(ADAPTER_NOTES); 113 114 if (request.getWrapper() != null) { 115 116 boolean error = false; 117 try { 118 if (status == SocketStatus.OPEN) { 119 request.getEvent().setEventType(CometEvent.EventType.READ); 120 request.getEvent().setEventSubType(null); 121 } else if (status == SocketStatus.DISCONNECT) { 122 request.getEvent().setEventType(CometEvent.EventType.ERROR); 123 request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT); 124 error = true; 125 } else if (status == SocketStatus.ERROR) { 126 request.getEvent().setEventType(CometEvent.EventType.ERROR); 127 request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION); 128 error = true; 129 } else if (status == SocketStatus.STOP) { 130 request.getEvent().setEventType(CometEvent.EventType.END); 131 request.getEvent().setEventSubType(CometEvent.EventSubType.SERVER_SHUTDOWN); 132 } else if (status == SocketStatus.TIMEOUT) { 133 request.getEvent().setEventType(CometEvent.EventType.ERROR); 134 request.getEvent().setEventSubType(CometEvent.EventSubType.TIMEOUT); 135 } 136 137 connector.getContainer().getPipeline().getFirst().event(request, response, request.getEvent()); 139 140 if (response.isClosed() || !request.isComet()) { 141 res.action(ActionCode.ACTION_COMET_END, null); 142 } 143 return (!error); 144 } catch (Throwable t) { 145 if (!(t instanceof IOException )) { 146 log.error(sm.getString("coyoteAdapter.service"), t); 147 } 148 error = true; 149 return false; 152 } finally { 153 if (error || response.isClosed() || !request.isComet()) { 155 request.recycle(); 156 request.setFilterChain(null); 157 response.recycle(); 158 } 159 } 160 161 } else { 162 return false; 163 } 164 } 165 166 167 170 public void service(org.apache.coyote.Request req, 171 org.apache.coyote.Response res) 172 throws Exception { 173 174 Request request = (Request) req.getNote(ADAPTER_NOTES); 175 Response response = (Response) res.getNote(ADAPTER_NOTES); 176 177 if (request == null) { 178 179 request = (Request) connector.createRequest(); 181 request.setCoyoteRequest(req); 182 response = (Response) connector.createResponse(); 183 response.setCoyoteResponse(res); 184 185 request.setResponse(response); 187 response.setRequest(request); 188 189 req.setNote(ADAPTER_NOTES, request); 191 res.setNote(ADAPTER_NOTES, response); 192 193 req.getParameters().setQueryStringEncoding 195 (connector.getURIEncoding()); 196 197 } 198 199 if (connector.getXpoweredBy()) { 200 response.addHeader("X-Powered-By", "Servlet/2.5"); 201 } 202 203 boolean comet = false; 204 205 try { 206 207 if (postParseRequest(req, request, res, response)) { 210 211 connector.getContainer().getPipeline().getFirst().invoke(request, response); 213 214 if (request.isComet()) { 215 if (!response.isClosed()) { 216 comet = true; 217 res.action(ActionCode.ACTION_COMET_BEGIN, null); 218 } else { 219 request.setFilterChain(null); 222 } 223 } 224 225 } 226 227 if (!comet) { 228 response.finishResponse(); 229 req.action(ActionCode.ACTION_POST_REQUEST , null); 230 } 231 232 } catch (IOException e) { 233 ; 234 } catch (Throwable t) { 235 log.error(sm.getString("coyoteAdapter.service"), t); 236 } finally { 237 if (!comet) { 239 request.recycle(); 240 response.recycle(); 241 } else { 242 request.clearEncoders(); 245 response.clearEncoders(); 246 } 247 } 248 249 } 250 251 252 254 255 258 protected boolean postParseRequest(org.apache.coyote.Request req, 259 Request request, 260 org.apache.coyote.Response res, 261 Response response) 262 throws Exception { 263 264 if (! req.scheme().isNull()) { 270 request.setSecure(req.scheme().equals("https")); 272 } else { 273 req.scheme().setString(connector.getScheme()); 276 request.setSecure(connector.getSecure()); 277 } 278 279 String proxyName = connector.getProxyName(); 285 int proxyPort = connector.getProxyPort(); 286 if (proxyPort != 0) { 287 req.setServerPort(proxyPort); 288 } 289 if (proxyName != null) { 290 req.serverName().setString(proxyName); 291 } 292 293 parseSessionId(req, request); 295 296 MessageBytes decodedURI = req.decodedURI(); 298 decodedURI.duplicate(req.requestURI()); 299 300 if (decodedURI.getType() == MessageBytes.T_BYTES) { 301 ByteChunk uriBB = decodedURI.getByteChunk(); 303 int semicolon = uriBB.indexOf(';', 0); 304 if (semicolon > 0) { 305 decodedURI.setBytes 306 (uriBB.getBuffer(), uriBB.getStart(), semicolon); 307 } 308 try { 310 req.getURLDecoder().convert(decodedURI, false); 311 } catch (IOException ioe) { 312 res.setStatus(400); 313 res.setMessage("Invalid URI"); 314 throw ioe; 315 } 316 if (!normalize(req.decodedURI())) { 318 res.setStatus(400); 319 res.setMessage("Invalid URI"); 320 return false; 321 } 322 convertURI(decodedURI, request); 324 } else { 325 decodedURI.toChars(); 329 CharChunk uriCC = decodedURI.getCharChunk(); 331 int semicolon = uriCC.indexOf(';'); 332 if (semicolon > 0) { 333 decodedURI.setChars 334 (uriCC.getBuffer(), uriCC.getStart(), semicolon); 335 } 336 } 337 338 String principal = req.getRemoteUser().toString(); 340 if (principal != null) { 341 request.setUserPrincipal(new CoyotePrincipal(principal)); 342 } 343 344 String authtype = req.getAuthType().toString(); 346 if (authtype != null) { 347 request.setAuthType(authtype); 348 } 349 350 MessageBytes serverName; 352 if (connector.getUseIPVHosts()) { 353 serverName = req.localName(); 354 if (serverName.isNull()) { 355 res.action(ActionCode.ACTION_REQ_LOCAL_NAME_ATTRIBUTE, null); 357 } 358 } else { 359 serverName = req.serverName(); 360 } 361 connector.getMapper().map(serverName, decodedURI, 362 request.getMappingData()); 363 request.setContext((Context) request.getMappingData().context); 364 request.setWrapper((Wrapper) request.getMappingData().wrapper); 365 366 if (!connector.getAllowTrace() 368 && req.method().equalsIgnoreCase("TRACE")) { 369 Wrapper wrapper = request.getWrapper(); 370 String header = null; 371 if (wrapper != null) { 372 String [] methods = wrapper.getServletMethods(); 373 if (methods != null) { 374 for (int i=0; i<methods.length; i++) { 375 if ("TRACE".equals(methods[i])) { 376 continue; 377 } 378 if (header == null) { 379 header = methods[i]; 380 } else { 381 header += ", " + methods[i]; 382 } 383 } 384 } 385 } 386 res.setStatus(405); 387 res.addHeader("Allow", header); 388 res.setMessage("TRACE method is not allowed"); 389 return false; 390 } 391 392 MessageBytes redirectPathMB = request.getMappingData().redirectPath; 394 if (!redirectPathMB.isNull()) { 395 String redirectPath = redirectPathMB.toString(); 396 String query = request.getQueryString(); 397 if (request.isRequestedSessionIdFromURL()) { 398 redirectPath = redirectPath + ";jsessionid=" 401 + request.getRequestedSessionId(); 402 } 403 if (query != null) { 404 redirectPath = redirectPath + "?" + query; 407 } 408 response.sendRedirect(redirectPath); 409 return false; 410 } 411 412 parseSessionCookiesId(req, request); 414 415 return true; 416 } 417 418 419 422 protected void parseSessionId(org.apache.coyote.Request req, Request request) { 423 424 ByteChunk uriBC = req.requestURI().getByteChunk(); 425 int semicolon = uriBC.indexOf(match, 0, match.length(), 0); 426 427 if (semicolon > 0) { 428 429 int start = uriBC.getStart(); 431 int end = uriBC.getEnd(); 432 433 int sessionIdStart = semicolon + match.length(); 434 int semicolon2 = uriBC.indexOf(';', sessionIdStart); 435 if (semicolon2 >= 0) { 436 request.setRequestedSessionId 437 (new String (uriBC.getBuffer(), start + sessionIdStart, 438 semicolon2 - sessionIdStart)); 439 byte[] buf = uriBC.getBuffer(); 441 for (int i = 0; i < end - start - semicolon2; i++) { 442 buf[start + semicolon + i] 443 = buf[start + i + semicolon2]; 444 } 445 uriBC.setBytes(buf, start, end - start - semicolon2 + semicolon); 446 } else { 447 request.setRequestedSessionId 448 (new String (uriBC.getBuffer(), start + sessionIdStart, 449 (end - start) - sessionIdStart)); 450 uriBC.setEnd(start + semicolon); 451 } 452 request.setRequestedSessionURL(true); 453 454 } else { 455 request.setRequestedSessionId(null); 456 request.setRequestedSessionURL(false); 457 } 458 459 } 460 461 462 465 protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) { 466 467 Cookies serverCookies = req.getCookies(); 469 int count = serverCookies.getCookieCount(); 470 if (count <= 0) 471 return; 472 473 for (int i = 0; i < count; i++) { 474 ServerCookie scookie = serverCookies.getCookie(i); 475 if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) { 476 if (!request.isRequestedSessionIdFromCookie()) { 478 convertMB(scookie.getValue()); 480 request.setRequestedSessionId 481 (scookie.getValue().toString()); 482 request.setRequestedSessionCookie(true); 483 request.setRequestedSessionURL(false); 484 if (log.isDebugEnabled()) 485 log.debug(" Requested cookie session id is " + 486 request.getRequestedSessionId()); 487 } else { 488 if (!request.isRequestedSessionIdValid()) { 489 convertMB(scookie.getValue()); 491 request.setRequestedSessionId 492 (scookie.getValue().toString()); 493 } 494 } 495 } 496 } 497 498 } 499 500 501 504 protected void convertURI(MessageBytes uri, Request request) 505 throws Exception { 506 507 ByteChunk bc = uri.getByteChunk(); 508 CharChunk cc = uri.getCharChunk(); 509 cc.allocate(bc.getLength(), -1); 510 511 String enc = connector.getURIEncoding(); 512 if (enc != null) { 513 B2CConverter conv = request.getURIConverter(); 514 try { 515 if (conv == null) { 516 conv = new B2CConverter(enc); 517 request.setURIConverter(conv); 518 } else { 519 conv.recycle(); 520 } 521 } catch (IOException e) { 522 log.error("Invalid URI encoding; using HTTP default"); 524 connector.setURIEncoding(null); 525 } 526 if (conv != null) { 527 try { 528 conv.convert(bc, cc); 529 uri.setChars(cc.getBuffer(), cc.getStart(), 530 cc.getLength()); 531 return; 532 } catch (IOException e) { 533 log.error("Invalid URI character encoding; trying ascii"); 534 cc.recycle(); 535 } 536 } 537 } 538 539 byte[] bbuf = bc.getBuffer(); 541 char[] cbuf = cc.getBuffer(); 542 int start = bc.getStart(); 543 for (int i = 0; i < bc.getLength(); i++) { 544 cbuf[i] = (char) (bbuf[i + start] & 0xff); 545 } 546 uri.setChars(cbuf, 0, bc.getLength()); 547 548 } 549 550 551 554 protected void convertMB(MessageBytes mb) { 555 556 if (mb.getType() != MessageBytes.T_BYTES) 558 return; 559 560 ByteChunk bc = mb.getByteChunk(); 561 CharChunk cc = mb.getCharChunk(); 562 cc.allocate(bc.getLength(), -1); 563 564 byte[] bbuf = bc.getBuffer(); 566 char[] cbuf = cc.getBuffer(); 567 int start = bc.getStart(); 568 for (int i = 0; i < bc.getLength(); i++) { 569 cbuf[i] = (char) (bbuf[i + start] & 0xff); 570 } 571 mb.setChars(cbuf, 0, bc.getLength()); 572 573 } 574 575 576 585 public static boolean normalize(MessageBytes uriMB) { 586 587 ByteChunk uriBC = uriMB.getByteChunk(); 588 byte[] b = uriBC.getBytes(); 589 int start = uriBC.getStart(); 590 int end = uriBC.getEnd(); 591 592 if ((end - start == 1) && b[start] == (byte) '*') 594 return true; 595 596 int pos = 0; 597 int index = 0; 598 599 for (pos = start; pos < end; pos++) { 602 if (b[pos] == (byte) '\\') 603 b[pos] = (byte) '/'; 604 if (b[pos] == (byte) 0) 605 return false; 606 } 607 608 if (b[start] != (byte) '/') { 610 return false; 611 } 612 613 for (pos = start; pos < (end - 1); pos++) { 615 if (b[pos] == (byte) '/') { 616 while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) { 617 copyBytes(b, pos, pos + 1, end - pos - 1); 618 end--; 619 } 620 } 621 } 622 623 if (((end - start) >= 2) && (b[end - 1] == (byte) '.')) { 627 if ((b[end - 2] == (byte) '/') 628 || ((b[end - 2] == (byte) '.') 629 && (b[end - 3] == (byte) '/'))) { 630 b[end] = (byte) '/'; 631 end++; 632 } 633 } 634 635 uriBC.setEnd(end); 636 637 index = 0; 638 639 while (true) { 641 index = uriBC.indexOf("/./", 0, 3, index); 642 if (index < 0) 643 break; 644 copyBytes(b, start + index, start + index + 2, 645 end - start - index - 2); 646 end = end - 2; 647 uriBC.setEnd(end); 648 } 649 650 index = 0; 651 652 while (true) { 654 index = uriBC.indexOf("/../", 0, 4, index); 655 if (index < 0) 656 break; 657 if (index == 0) 659 return false; 660 int index2 = -1; 661 for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) { 662 if (b[pos] == (byte) '/') { 663 index2 = pos; 664 } 665 } 666 copyBytes(b, start + index2, start + index + 3, 667 end - start - index - 3); 668 end = end + index2 - index - 3; 669 uriBC.setEnd(end); 670 index = index2; 671 } 672 673 uriBC.setBytes(b, start, end); 674 675 return true; 676 677 } 678 679 680 682 683 687 protected static void copyBytes(byte[] b, int dest, int src, int len) { 688 for (int pos = 0; pos < len; pos++) { 689 b[pos + dest] = b[pos + src]; 690 } 691 } 692 693 694 } 695 | Popular Tags |