1 16 17 package org.apache.coyote.tomcat4; 18 19 20 import java.io.IOException ; 21 import javax.servlet.http.Cookie ; 22 import javax.servlet.http.HttpServletRequest ; 23 24 import org.apache.tomcat.util.buf.B2CConverter; 25 import org.apache.tomcat.util.buf.ByteChunk; 26 import org.apache.tomcat.util.buf.CharChunk; 27 import org.apache.tomcat.util.buf.MessageBytes; 28 import org.apache.tomcat.util.http.Cookies; 29 import org.apache.tomcat.util.http.ServerCookie; 30 31 import org.apache.coyote.ActionCode; 32 import org.apache.coyote.Adapter; 33 import org.apache.coyote.Request; 34 import org.apache.coyote.Response; 35 36 import org.apache.catalina.Globals; 37 import org.apache.catalina.Logger; 38 import org.apache.catalina.util.StringManager; 39 40 41 49 50 final class CoyoteAdapter 51 implements Adapter { 52 53 54 56 57 public static final int ADAPTER_NOTES = 1; 58 59 60 62 63 69 public CoyoteAdapter(CoyoteConnector connector) { 70 71 super(); 72 this.connector = connector; 73 this.debug = connector.getDebug(); 74 75 } 76 77 78 80 81 84 private CoyoteConnector connector = null; 85 86 87 90 private int debug = 0; 91 92 93 96 private static final String match = 97 ";" + Globals.SESSION_PARAMETER_NAME + "="; 98 99 100 103 private static final char[] SESSION_ID = match.toCharArray(); 104 105 106 109 protected StringManager sm = 110 StringManager.getManager(Constants.Package); 111 112 113 115 116 119 public void service(Request req, Response res) 120 throws Exception { 121 122 CoyoteRequest request = (CoyoteRequest) req.getNote(ADAPTER_NOTES); 123 CoyoteResponse response = (CoyoteResponse) res.getNote(ADAPTER_NOTES); 124 125 if (request == null) { 126 127 request = (CoyoteRequest) connector.createRequest(); 129 request.setCoyoteRequest(req); 130 response = (CoyoteResponse) connector.createResponse(); 131 response.setCoyoteResponse(res); 132 133 request.setResponse(response); 135 response.setRequest(request); 136 137 req.setNote(ADAPTER_NOTES, request); 139 res.setNote(ADAPTER_NOTES, response); 140 141 req.getParameters().setQueryStringEncoding 143 (connector.getURIEncoding()); 144 145 } 146 147 try { 148 postParseRequest(req, request, res, response); 151 connector.getContainer().invoke(request, response); 153 response.finishResponse(); 154 155 req.action( ActionCode.ACTION_POST_REQUEST , null); 156 } catch (IOException e) { 157 ; 158 } catch (Throwable t) { 159 log(sm.getString("coyoteAdapter.service"), t); 160 } finally { 161 request.recycle(); 163 response.recycle(); 164 } 165 166 } 167 168 169 171 172 175 protected void postParseRequest(Request req, CoyoteRequest request, 176 Response res, CoyoteResponse response) 177 throws Exception { 178 if (! req.scheme().isNull()) { 184 request.setSecure(req.scheme().equals("https")); 186 } else { 187 req.scheme().setString(connector.getScheme()); 190 request.setSecure(connector.getSecure()); 191 } 192 193 if (!connector.getAllowTrace() 195 && req.method().equalsIgnoreCase("TRACE")) { 196 res.setStatus(403); 197 res.setMessage("TRACE method is not allowed"); 198 throw new IOException ("TRACE method is not allowed"); 199 } 200 201 request.setAuthorization 202 (req.getHeader(Constants.AUTHORIZATION_HEADER)); 203 String proxyName = connector.getProxyName(); 208 int proxyPort = connector.getProxyPort(); 209 if (proxyPort != 0) { 210 request.setServerPort(proxyPort); 211 req.setServerPort(proxyPort); 212 } else { 213 request.setServerPort(req.getServerPort()); 214 } 215 if (proxyName != null) { 216 request.setServerName(proxyName); 217 req.serverName().setString(proxyName); 218 } else { 219 request.setServerName(req.serverName().toString()); 220 } 221 222 req.decodedURI().duplicate(req.requestURI()); 224 try { 225 req.getURLDecoder().convert(req.decodedURI(), false); 226 } catch (IOException ioe) { 227 res.setStatus(400); 228 res.setMessage("Invalid URI"); 229 throw ioe; 230 } 231 232 if (!normalize(req.decodedURI())) { 234 res.setStatus(400); 235 res.setMessage("Invalid URI"); 236 throw new IOException ("Invalid URI"); 237 } 238 239 convertURI(req.decodedURI(), request); 241 242 parseSessionId(req, request); 244 245 if (connector.getUseURIValidationHack()) { 248 String uri = validate(request.getRequestURI()); 249 if (uri == null) { 250 res.setStatus(400); 251 res.setMessage("Invalid URI"); 252 throw new IOException ("Invalid URI"); 253 } else { 254 req.requestURI().setString(uri); 255 req.decodedURI().duplicate(req.requestURI()); 257 req.getURLDecoder().convert(req.decodedURI(), true); 258 convertURI(req.decodedURI(), request); 259 } 260 } 261 262 parseCookies(req, request); 264 265 if( request.isSecure() ) { 267 res.action(ActionCode.ACTION_REQ_SSL_ATTRIBUTE, 268 request.getCoyoteRequest()); 269 request.getAttribute(Globals.CERTIFICATES_ATTR); 271 request.getAttribute(Globals.CIPHER_SUITE_ATTR); 272 request.getAttribute(Globals.KEY_SIZE_ATTR); 273 } 274 275 String principal = req.getRemoteUser().toString(); 277 if (principal != null) { 278 request.setUserPrincipal(new CoyotePrincipal(principal)); 279 } 280 281 String authtype = req.getAuthType().toString(); 283 if (authtype != null) { 284 request.setAuthType(authtype); 285 } 286 287 } 288 289 293 protected void parseSessionId(Request req, CoyoteRequest request) { 294 295 req.decodedURI().toChars(); 296 CharChunk uriCC = req.decodedURI().getCharChunk(); 297 int semicolon = uriCC.indexOf(match, 0, match.length(), 0); 298 299 if (semicolon > 0) { 300 301 int start = uriCC.getStart(); 303 int end = uriCC.getEnd(); 304 305 int sessionIdStart = start + semicolon + match.length(); 306 int semicolon2 = uriCC.indexOf(';', sessionIdStart); 307 if (semicolon2 >= 0) { 308 request.setRequestedSessionId 309 (new String (uriCC.getBuffer(), sessionIdStart, 310 semicolon2 - semicolon - match.length())); 311 req.decodedURI().setString 312 (new String (uriCC.getBuffer(), start, semicolon) + 313 new String (uriCC.getBuffer(), 314 semicolon2, 315 end-semicolon2)); 316 } else { 317 request.setRequestedSessionId 318 (new String (uriCC.getBuffer(), sessionIdStart, 319 end - sessionIdStart)); 320 req.decodedURI().setString 321 (new String (uriCC.getBuffer(), start, semicolon)); 322 } 323 request.setRequestedSessionURL(true); 324 325 String uri = req.requestURI().toString(); 327 semicolon = uri.indexOf(match); 328 329 if (semicolon > 0) { 330 String rest = uri.substring(semicolon + match.length()); 331 semicolon2 = rest.indexOf(';'); 332 if (semicolon2 >= 0) { 333 rest = rest.substring(semicolon2); 334 } else { 335 rest = ""; 336 } 337 req.requestURI().setString(uri.substring(0, semicolon) + rest); 338 } 339 340 } else { 341 request.setRequestedSessionId(null); 342 request.setRequestedSessionURL(false); 343 } 344 345 } 346 347 348 351 protected void parseCookies(Request req, CoyoteRequest request) { 352 353 Cookies serverCookies = req.getCookies(); 354 int count = serverCookies.getCookieCount(); 355 if (count <= 0) 356 return; 357 358 Cookie [] cookies = new Cookie [count]; 359 360 int idx=0; 361 for (int i = 0; i < count; i++) { 362 ServerCookie scookie = serverCookies.getCookie(i); 363 if (scookie.getName().equals(Globals.SESSION_COOKIE_NAME)) { 364 if (!request.isRequestedSessionIdFromCookie()) { 366 request.setRequestedSessionId 368 (scookie.getValue().toString()); 369 request.setRequestedSessionCookie(true); 370 request.setRequestedSessionURL(false); 371 if (debug >= 1) 372 log(" Requested cookie session id is " + 373 ((HttpServletRequest ) request.getRequest()) 374 .getRequestedSessionId()); 375 } 376 } 377 try { 378 Cookie cookie = new Cookie (scookie.getName().toString(), 379 scookie.getValue().toString()); 380 cookie.setPath(scookie.getPath().toString()); 381 cookie.setVersion(scookie.getVersion()); 382 String domain = scookie.getDomain().toString(); 383 if (domain != null) { 384 cookie.setDomain(scookie.getDomain().toString()); 385 } 386 cookies[idx++] = cookie; 387 } catch(Exception ex) { 388 log("Bad Cookie Name: " + scookie.getName() + 389 " /Value: " + scookie.getValue(),ex); 390 } 391 } 392 if( idx < count ) { 393 Cookie [] ncookies = new Cookie [idx]; 394 System.arraycopy(cookies, 0, ncookies, 0, idx); 395 cookies = ncookies; 396 } 397 398 request.setCookies(cookies); 399 400 } 401 402 403 413 protected static String validate(String path) { 414 415 if (path == null) 416 return null; 417 418 String normalized = path; 420 421 if (normalized.startsWith("/%7E") || 423 normalized.startsWith("/%7e")) 424 normalized = "/~" + normalized.substring(4); 425 426 if ((normalized.indexOf("%25") >= 0) 429 || (normalized.indexOf("%2F") >= 0) 430 || (normalized.indexOf("%2E") >= 0) 431 || (normalized.indexOf("%5C") >= 0) 432 || (normalized.indexOf("%2f") >= 0) 433 || (normalized.indexOf("%2e") >= 0) 434 || (normalized.indexOf("%5c") >= 0)) { 435 return null; 436 } 437 438 if (normalized.equals("/.")) 439 return "/"; 440 441 if (normalized.indexOf('\\') >= 0) 443 normalized = normalized.replace('\\', '/'); 444 if (!normalized.startsWith("/")) 445 normalized = "/" + normalized; 446 447 while (true) { 449 int index = normalized.indexOf("//"); 450 if (index < 0) 451 break; 452 normalized = normalized.substring(0, index) + 453 normalized.substring(index + 1); 454 } 455 456 while (true) { 458 int index = normalized.indexOf("/./"); 459 if (index < 0) 460 break; 461 normalized = normalized.substring(0, index) + 462 normalized.substring(index + 2); 463 } 464 465 while (true) { 467 int index = normalized.indexOf("/../"); 468 if (index < 0) 469 break; 470 if (index == 0) 471 return (null); int index2 = normalized.lastIndexOf('/', index - 1); 473 normalized = normalized.substring(0, index2) + 474 normalized.substring(index + 3); 475 } 476 477 if (normalized.indexOf("/...") >= 0) 480 return (null); 481 482 return (normalized); 484 485 } 486 487 488 491 protected void convertURI(MessageBytes uri, CoyoteRequest request) 492 throws Exception { 493 494 ByteChunk bc = uri.getByteChunk(); 495 CharChunk cc = uri.getCharChunk(); 496 cc.allocate(bc.getLength(), -1); 497 498 String enc = connector.getURIEncoding(); 499 if (enc != null) { 500 B2CConverter conv = request.getURIConverter(); 501 try { 502 if (conv == null) { 503 conv = new B2CConverter(enc); 504 request.setURIConverter(conv); 505 } else { 506 conv.recycle(); 507 } 508 } catch (IOException e) { 509 log("Invalid URI encoding; using HTTP default", e); 511 connector.setURIEncoding(null); 512 } 513 if (conv != null) { 514 try { 515 conv.convert(bc, cc); 516 uri.setChars(cc.getBuffer(), cc.getStart(), 517 cc.getLength()); 518 return; 519 } catch (IOException e) { 520 if (debug >= 1) { 521 log("Invalid URI character encoding; trying ascii", e); 522 } 523 cc.recycle(); 524 } 525 } 526 } 527 528 byte[] bbuf = bc.getBuffer(); 530 char[] cbuf = cc.getBuffer(); 531 int start = bc.getStart(); 532 for (int i = 0; i < bc.getLength(); i++) { 533 cbuf[i] = (char) (bbuf[i + start] & 0xff); 534 } 535 uri.setChars(cbuf, 0, bc.getLength()); 536 537 } 538 539 540 549 public static boolean normalize(MessageBytes uriMB) { 550 551 ByteChunk uriBC = uriMB.getByteChunk(); 552 byte[] b = uriBC.getBytes(); 553 int start = uriBC.getStart(); 554 int end = uriBC.getEnd(); 555 556 if ((end - start == 1) && b[start] == (byte) '*') 558 return true; 559 560 int pos = 0; 561 int index = 0; 562 563 for (pos = start; pos < end; pos++) { 566 if (b[pos] == (byte) '\\') 567 b[pos] = (byte) '/'; 568 if (b[pos] == (byte) 0) 569 return false; 570 } 571 572 if (b[start] != (byte) '/') { 574 return false; 575 } 576 577 for (pos = start; pos < (end - 1); pos++) { 579 if (b[pos] == (byte) '/') { 580 while ((pos + 1 < end) && (b[pos + 1] == (byte) '/')) { 581 copyBytes(b, pos, pos + 1, end - pos - 1); 582 end--; 583 } 584 } 585 } 586 587 if (((end - start) > 2) && (b[end - 1] == (byte) '.')) { 591 if ((b[end - 2] == (byte) '/') 592 || ((b[end - 2] == (byte) '.') 593 && (b[end - 3] == (byte) '/'))) { 594 b[end] = (byte) '/'; 595 end++; 596 } 597 } 598 599 uriBC.setEnd(end); 600 601 index = 0; 602 603 while (true) { 605 index = uriBC.indexOf("/./", 0, 3, index); 606 if (index < 0) 607 break; 608 copyBytes(b, start + index, start + index + 2, 609 end - start - index - 2); 610 end = end - 2; 611 uriBC.setEnd(end); 612 } 613 614 index = 0; 615 616 while (true) { 618 index = uriBC.indexOf("/../", 0, 4, index); 619 if (index < 0) 620 break; 621 if (index == 0) 623 return false; 624 int index2 = -1; 625 for (pos = start + index - 1; (pos >= 0) && (index2 < 0); pos --) { 626 if (b[pos] == (byte) '/') { 627 index2 = pos; 628 } 629 } 630 copyBytes(b, start + index2, start + index + 3, 631 end - start - index - 3); 632 end = end + index2 - index - 3; 633 uriBC.setEnd(end); 634 index = index2; 635 } 636 637 uriBC.setBytes(b, start, end); 638 639 return true; 640 641 } 642 643 644 646 647 651 protected static void copyBytes(byte[] b, int dest, int src, int len) { 652 for (int pos = 0; pos < len; pos++) { 653 b[pos + dest] = b[pos + src]; 654 } 655 } 656 657 658 663 protected void log(String message) { 664 665 Logger logger = connector.getContainer().getLogger(); 666 if (logger != null) 667 logger.log("CoyoteAdapter " + message); 668 669 } 670 671 672 678 protected void log(String message, Throwable throwable) { 679 680 Logger logger = connector.getContainer().getLogger(); 681 if (logger != null) 682 logger.log("CoyoteAdapter " + message, throwable); 683 684 } 685 686 687 } 688 | Popular Tags |