Skip to content
This repository
branch: master
Fetching contributors…

Octocat-spinner-32-eaf2f5

Cannot retrieve contributors at this time

file 2178 lines (1822 sloc) 77.375 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177
/*
* Copyright 2007-2011 WorldWide Conferencing, LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.liftweb
package http

import common._
import util._
import util.Helpers._
import sitemap._
import http.js.JSArtifacts
import http.js.jquery._
import http.provider._
import js._
import JE._
import JsCmds._
import auth._

import scala.xml._
import java.util.{Locale, TimeZone, ResourceBundle, Date}
import java.io.{InputStream, ByteArrayOutputStream, BufferedReader, StringReader}
import java.util.concurrent.{ConcurrentHashMap => CHash}
import scala.reflect.Manifest

import java.util.concurrent.atomic.AtomicInteger

class LiftRulesJBridge {
  def liftRules: LiftRules = LiftRules
}

sealed trait LiftRulesMocker {
  def realInstance: LiftRules
}

object LiftRulesMocker {
  implicit def toLiftRules(in: LiftRulesMocker): LiftRules = in.realInstance

  /**
* In Dev and Test mode, there's an option to stuff another LiftRules
* instance in here and use that one for mocking
*/
  object devTestLiftRulesInstance extends ThreadGlobal[LiftRules]

  /**
* This function, in Test and Dev mode will vend the instance of LiftRules.
* If there is an instance set in devTestLiftRulesInstance, that instance
* will be used, otherwise the global instance in LiftRules.prodInstance
* will be used.
*/
  @volatile var calcLiftRulesInstance: () => LiftRules =
    () => devTestLiftRulesInstance.box.openOr( LiftRules.prodInstance)
}

/**
* The data structure that contains information to determine if the
* request should be treated as a stateful or stateless request
*/
final case class StatelessReqTest(path: List[String], httpReq: HTTPRequest)

/**
* The Lift configuration singleton
*/
object LiftRules extends LiftRulesMocker {
  lazy val prodInstance: LiftRules = new LiftRules()

  private[this] val devOrTest = Props.devMode || Props.testMode

  /**
* Get the real instance of LiftRules
*/
  def realInstance: LiftRules = if (devOrTest) {
    LiftRulesMocker.calcLiftRulesInstance()
  } else prodInstance

  type DispatchPF = PartialFunction[Req, () => Box[LiftResponse]];

  /**
* The test between the path of a request and whether that path
* should result in stateless servicing of that path
*/
  type StatelessTestPF = PartialFunction[List[String], Boolean]


  /**
* The test between the path of a request, the HTTP request, and whether that path
* should result in stateless servicing of that path
*/
  type StatelessReqTestPF = PartialFunction[StatelessReqTest, Boolean]

  type RewritePF = PartialFunction[RewriteRequest, RewriteResponse]
  type SnippetPF = PartialFunction[List[String], NodeSeq => NodeSeq]
  type LiftTagPF = PartialFunction[(String, Elem, MetaData, NodeSeq, String), NodeSeq]
  type URINotFoundPF = PartialFunction[(Req, Box[Failure]), NotFound]
  type URLDecoratorPF = PartialFunction[String, String]
  type SnippetDispatchPF = PartialFunction[String, DispatchSnippet]
  type ViewDispatchPF = PartialFunction[List[String], Either[() => Box[NodeSeq], LiftView]]
  type HttpAuthProtectedResourcePF = PartialFunction[Req, Box[Role]]
  type ExceptionHandlerPF = PartialFunction[(Props.RunModes.Value, Req, Throwable), LiftResponse]
  type ResourceBundleFactoryPF = PartialFunction[(String, Locale), ResourceBundle]
  type SplitSuffixPF = PartialFunction[List[String], (List[String], String)]
  type CometCreationPF = PartialFunction[CometCreationInfo, LiftCometActor]
  /**
* A partial function that allows the application to define requests that should be
* handled by lift rather than the default handler
*/
  type LiftRequestPF = PartialFunction[Req, Boolean]

  /*
private[this] var _doneBoot = false
private[http] def doneBoot = _doneBoot

private[http] def doneBoot_=(in: Boolean) {_doneBoot = in}
*/


  /**
* Holds the failure information when a snippet can not be executed.
*/
  case class SnippetFailure(page: String, typeName: Box[String], failure: SnippetFailures.Value)

  object SnippetFailures extends Enumeration {
    val NoTypeDefined = Value(1, "No Type Defined")
    val ClassNotFound = Value(2, "Class Not Found")
    val StatefulDispatchNotMatched = Value(3, "Stateful Snippet: Dispatch Not Matched")
    val MethodNotFound = Value(4, "Method Not Found")
    val NoNameSpecified = Value(5, "No Snippet Name Specified")
    val InstantiationException = Value(6, "Exception During Snippet Instantiation")
    val DispatchSnippetNotMatched = Value(7, "Dispatch Snippet: Dispatch Not Matched")

    val StateInStateless = Value(8, "Access to Lift's statefull features from Stateless mode")
    val CometTimeout = Value(9, "Comet Component did not response to requests")
    val CometNotFound = Value(10, "Comet Component not found")
    val ExecutionFailure = Value(11, "Execution Failure")
  }

  def defaultFuncNameGenerator(runMode: Props.RunModes.Value): () => String =
    runMode match {
      case Props.RunModes.Test => S.generateTestFuncName _
      case _ => S.generateFuncName _
    }
}

/**
* LiftRules is the global object that holds all of Lift's configuration.
*/
class LiftRules() extends Factory with FormVendor with LazyLoggable {
  import LiftRules._

  private var _doneBoot = false

  /**
* Does the LiftRules instance think it's done booting?
*/
  def doneBoot = _doneBoot

  def noticesContainerId = "lift__noticesContainer__"

  /**
* If you want to make the Lift inactivity timeout shorter than
* the container inactivity timeout, set the inactivity timeout here
*/
  val sessionInactivityTimeout = new FactoryMaker[Box[Long]](Empty){}

  /**
* The function that converts a scala.text.Document to
* a String (used for JsonAST.JValue to text convertion.
* By default, use Printer.pretty for dev mode and
* Printer.compact for other modes
*/
  val jsonOutputConverter = new FactoryMaker[scala.text.Document => String]({
    import json.Printer
    if (Props.devMode) Printer.pretty _ else Printer.compact _}){}


  /**
* Set the default fadeout mechanism for Lift notices. Thus you provide a function that take a NoticeType.Value
* and decide the duration after which the fade out will start and the actual fadeout time. This is applicable
* for general notices (not associated with id-s) regardless if they are set for the page rendering, ajax
* response or Comet response.
*/
  val noticesAutoFadeOut = new FactoryMaker[(NoticeType.Value) => Box[(TimeSpan, TimeSpan)]]((notice : NoticeType.Value) => Empty){}

  /**
* Use this to apply various effects to the notices. The user function receives the NoticeType
* and the id of the element containing the specific notice. Thus it is the function's responsibility to form
* the javascript code for the visual effects. This is applicable for both ajax and non ajax contexts.
* For notices associated with ID's the user type will receive an Empty notice type. That's because the effect
* is applied on the real estate holding the notices for this ID. Typically this contains a single message.
*/
  val noticesEffects = new FactoryMaker[(Box[NoticeType.Value], String) => Box[JsCmd]]((notice: Box[NoticeType.Value], id: String) => Empty){}


  /**
* Holds user functions that will be executed very early in the request processing. The functions'
* result will be ignored.
*/
  val early = RulesSeq[(HTTPRequest) => Any]

  /**
* Holds user functions that are executed before sending the response to client. The functions'
* result will be ignored.
*/
  val beforeSend = RulesSeq[(BasicResponse, HTTPResponse, List[(String, String)], Box[Req]) => Any]

  /**
* Defines the resources that are protected by authentication and authorization. If this function
* is not defined for the input data, the resource is considered unprotected ergo no authentication
* is performed. If this function is defined and returns a Full box, it means that this resource
* is protected by authentication, and authenticated subjed must be assigned to the role returned by
* this function or to a role that is child-of this role. If this function returns Empty it means that
* this resource is protected by authentication but no authorization is performed meaning that roles are
* not verified.
*/
  val httpAuthProtectedResource = RulesSeq[HttpAuthProtectedResourcePF]

  /**
* The HTTP authentication mechanism that Lift will perform. See <i>LiftRules.protectedResource</i>
*/
  @volatile var authentication: HttpAuthentication = NoAuthentication

  /**
* A function that takes the HTTPSession and the contextPath as parameters
* and returns a LiftSession reference. This can be used in cases subclassing
* LiftSession is necessary.
*/
  @volatile var sessionCreator: (HTTPSession, String) => LiftSession = {
    case (httpSession, contextPath) => new LiftSession(contextPath, httpSession.sessionId, Full(httpSession))
  }

  /**
* A method that returns a function to create migratory sessions. If you want migratory sessions for your
* application, <code>LiftRules.sessionCreator = LiftRules.sessionCreatorForMigratorySessions</code>
*/
  def sessionCreatorForMigratorySessions: (HTTPSession, String) => LiftSession = {
    case (httpSession, contextPath) => new LiftSession(contextPath, httpSession.sessionId, Full(httpSession)) with MigratorySession
  }

  @volatile var enableContainerSessions = true

  @volatile var getLiftSession: (Req) => LiftSession = (req) => _getLiftSession(req)

  // Unique identifier for this particular instance of Lift, used for
  // tagging resources below in attachResourceId.
  private val instanceResourceId = "instance-" + Helpers.nextFuncName

  /**
* Attaches an ID entity for resource URI specified in
* link or script tags. This allows controlling browser
* resource caching. By default this just adds a query string
* parameter unique per application lifetime. More complex
* implementation could user per resource MD5 sequences thus
* "forcing" browsers to refresh the resource only when the resource
* file changes. Users can define other rules as well. Inside user's
* function it is safe to use S context as attachResourceId is called
* from inside the &lt;lift:with-resource-id&gt; snippet
*
*/
  @volatile var attachResourceId: (String) => String = (name) => {
    name + (if (name contains ("?")) "&" else "?") + instanceResourceId + "=_"
  }

  /**
* Returns a LiftSession instance.
*/
  private def _getLiftSession(req: Req): LiftSession = {
    val wp = req.path.wholePath
    val cometSessionId =
    if (wp.length >= 3 && wp.head == LiftRules.cometPath)
      Full(wp(2))
    else
      Empty

    val ret = SessionMaster.getSession(req, cometSessionId) match {
      case Full(ret) =>
        ret.fixSessionTime()
        ret

      case _ =>
        val ret = LiftSession(req)
        ret.fixSessionTime()
        SessionMaster.addSession(ret, req,
                                 req.request.userAgent,
                                 SessionMaster.getIpFromReq(req))
        ret
    }

    makeCometBreakoutDecision(ret, req)
    ret
  }

  /**
* A function that takes appropriate action in breaking out of any
* existing comet requests based on the request, browser type, etc.
*/
  @volatile var makeCometBreakoutDecision: (LiftSession, Req) => Unit =
  (session, req) => {
    // get the open sessions to the host (this means that any DNS wildcarded
    // Comet requests will not be counted), as well as all invalid/expired
    // sessions
    val (which, invalid) = session.cometForHost(req.hostAndPath)

    // get the maximum requests given the browser type
    val max = maxConcurrentRequests.vend(req) - 2 // this request and any open comet requests

    // dump the oldest requests
    which.drop(max).foreach {
      case (actor, req) => actor ! BreakOut()
    }
    invalid.foreach {
      case (actor, req) => actor ! BreakOut()
    }
  }

  /**
* The path to handle served resources
*/
  @volatile var resourceServerPath = "classpath"

  /**
* Holds the JS library specific UI artifacts. By default it uses JQuery's artifacts
*/
  @volatile var jsArtifacts: JSArtifacts = JQuery13Artifacts

  /**
* Use this PartialFunction to to automatically add static URL parameters
* to any URL reference from the markup of Ajax request.
*/
  val urlDecorate = RulesSeq[URLDecoratorPF]

  /**
* Should the JSESSIONID be encoded in the URL if cookies are
* not supported
*/
  @volatile var encodeJSessionIdInUrl_? = false

  /**
* Partial function to allow you to build a CometActor from code rather than via reflection
*/
  val cometCreation = RulesSeq[CometCreationPF]

  private def noComet(ignore: CometCreationInfo): Box[LiftCometActor] = Empty

  /**
* A factory that will vend comet creators
*/
  val cometCreationFactory: FactoryMaker[CometCreationInfo => Box[LiftCometActor]] =
  new FactoryMaker(() => noComet _) {}

  /**
* Should codes that represent entities be converted to XML
* entities when rendered?
*/
  val convertToEntity: FactoryMaker[Boolean] = new FactoryMaker(false) {}

  /**
* Certain paths within your application can be marked as stateless
* and if there is access to Lift's stateful facilities (setting
* SessionVars, updating function tables, etc.) the developer will
* receive a notice and the operation will not complete. This test
* has been deprecated in favor of statelessReqTest which also passes
* the HTTPRequest instance for testing of the user agent and other stuff.
*/
  @deprecated("Use statelessReqTest", "2.4")
  val statelessTest = RulesSeq[StatelessTestPF]


  /**
* Certain paths and requests within your application can be marked as stateless
* and if there is access to Lift's stateful facilities (setting
* SessionVars, updating function tables, etc.) the developer will
* receive a notice and the operation will not complete.
*/
  val statelessReqTest = RulesSeq[StatelessReqTestPF]

  val statelessSession: FactoryMaker[Req => LiftSession with StatelessSession] =
    new FactoryMaker((req: Req) => new LiftSession(req.contextPath,
                                                   Helpers.nextFuncName,
                                                   Empty) with
                     StatelessSession) {}


  /**
* Holds user functions that are executed after the response is sent to client. The functions' result
* will be ignored.
*/
  val afterSend = RulesSeq[(BasicResponse, HTTPResponse, List[(String, String)], Box[Req]) => Any]

  /**
* Calculate the Comet Server (by default, the server that
* the request was made on, but can do the multi-server thing
* as well)
*/
  @volatile var cometServer: () => String = () => S.contextPath

  /**
* The maximum concurrent requests. If this number of
* requests are being serviced for a given session, messages
* will be sent to all Comet requests to terminate
*/
  val maxConcurrentRequests: FactoryMaker[Req => Int] = new FactoryMaker((x: Req) => x match {
    case r if r.isIPad || r.isIPhone => 1
    case r if r.isFirefox35_+ || r.isIE8 || r.isIE9 || r.isChrome3_+ || r.isOpera9 || r.isSafari3_+ => 4
    case _ => 2
  }) {}

  /**
* A partial function that determines content type based on an incoming
* Req and Accept header
*/
  @volatile var determineContentType: PartialFunction[(Box[Req], Box[String]), String] = {
    case (_, Full(accept)) if this.useXhtmlMimeType && accept.toLowerCase.contains("application/xhtml+xml") =>
      "application/xhtml+xml; charset=utf-8"
    case _ => "text/html; charset=utf-8"
  }

  lazy val liftVersion: String = {
    val cn = """\.""".r.replaceAllIn(LiftRules.getClass.getName, "/")
    val ret: Box[String] =
    for{
      url <- Box !! LiftRules.getClass.getResource("/" + cn + ".class")
      val newUrl = new java.net.URL(url.toExternalForm.split("!")(0) + "!" + "/META-INF/MANIFEST.MF")
      str <- tryo(new String(readWholeStream(newUrl.openConnection.getInputStream), "UTF-8"))
      ma <- """Implementation-Version: (.*)""".r.findFirstMatchIn(str)
    } yield ma.group(1)

    ret openOr "Unknown Lift Version"
  }

  lazy val liftBuildDate: Date = {
    val cn = """\.""".r.replaceAllIn(LiftRules.getClass.getName, "/")
    val ret: Box[Date] =
    for{
      url <- Box !! LiftRules.getClass.getResource("/" + cn + ".class")
      val newUrl = new java.net.URL(url.toExternalForm.split("!")(0) + "!" + "/META-INF/MANIFEST.MF")
      str <- tryo(new String(readWholeStream(newUrl.openConnection.getInputStream), "UTF-8"))
      ma <- """Built-Time: (.*)""".r.findFirstMatchIn(str)
      asLong <- asLong(ma.group(1))
    } yield new Date(asLong)

    ret openOr new Date(0L)
  }

  /**
* Hooks to be run when LiftServlet.destroy is called.
*/
  val unloadHooks = RulesSeq[() => Unit]

  /**
* For each unload hook registered, run them during destroy()
*/
  private[http] def runUnloadHooks() {
    unloadHooks.toList.foreach{f =>
      tryo{f()}
    }
  }

  /**
* Set the doc type used. Use the HtmlProperties
*/
  @deprecated("Use the HtmlProperties", "2.4")
  val docType: FactoryMaker[Req => Box[String]] = new FactoryMaker( (r: Req) => r match {
    case _ if S.skipDocType => Empty
    case _ if S.getDocType._1 => S.getDocType._2
    case _ => Full(DocType.xhtmlTransitional)
  }){}

  /**
* The maximum allowed size of a complete mime multi-part POST. Default 8MB
*/
  @volatile var maxMimeSize: Long = 8 * 1024 * 1024

  /**
* Should pages that are not found be passed along the request processing chain to the
* next handler outside Lift?
*/
  @volatile var passNotFoundToChain = false

  /**
* The maximum allowed size of a single file in a mime multi-part POST.
* Default 7MB
*/
  @volatile var maxMimeFileSize: Long = 7 * 1024 * 1024

  /**
* The function referenced here is called if there's a localization lookup failure
*/
  @volatile var localizationLookupFailureNotice: Box[(String, Locale) => Unit] = Empty

  /**
* When a parameter is received either via POST or GET and does not have a
* corresponding mapping on the server, the function provided by this
* FactoryMaker will be called with the req and parameter name.
*
* By default, if the parameter looks Lift-like (i.e., it starts with an F),
* then we log a warning with the given parameter name and URI.
*/
  val handleUnmappedParameter = new FactoryMaker[(Req,String)=>Unit](
    () => { (req: Req, parameterName: String) =>
      if (parameterName.startsWith("F"))
        logger.warn("Unmapped Lift-like parameter seen in request [%s]: %s".format(req.uri, parameterName))
    }
  ) {}

  /**
* Set to false if you want to have 404's handled the same way in dev and production mode
*/
  @volatile var displayHelpfulSiteMapMessages_? = true

  /**
* The default location to send people if SiteMap access control fails. The path is
* expressed a a List[String]
*/
  @volatile var siteMapFailRedirectLocation: List[String] = List()

  private[http] def notFoundOrIgnore(requestState: Req, session: Box[LiftSession]): Box[LiftResponse] = {
    if (passNotFoundToChain) Empty
    else session match {
      case Full(session) => Full(session.checkRedirect(requestState.createNotFound))
      case _ => Full(requestState.createNotFound)
    }
  }

  /**
* Allows user adding additional Lift tags (the tags must be prefixed by lift namespace such as <lift:xxxx/>).
* Each LiftTagPF function will be called with the following parameters:
* <pre>
* - Element label,
* - The Element itselft,
* - The attributes
* - The child nodes
* - The page name
* </pre>
*/
  val liftTagProcessing = RulesSeq[LiftTagPF]

  /**
* If you don't want lift to send the application/xhtml+xml mime type to those browsers
* that understand it, then set this to { @code false }
*/
  @volatile var useXhtmlMimeType: Boolean = true


  private def _stringToXml(s: String): NodeSeq = Text(s)

  /**
* A function that defines how a String should be converted to XML
* for the localization stuff. By default, Text(s) is returned,
* but you can change this to attempt to parse the XML in the String and
* return the NodeSeq.
*/
  @volatile var localizeStringToXml: String => NodeSeq = _stringToXml _

  /**
* The base name of the resource bundle
*/
  @volatile var resourceNames: List[String] = List("lift")

  /**
* This function is called to convert the current set of Notices into
* a JsCmd that will be executed on the client to display the Notices.
*
* @see net.liftweb.builtin.snippet.Msgs
*/
  @volatile var noticesToJsCmd: () => JsCmd = () => {
    import builtin.snippet.{Msg,Msgs,MsgErrorMeta,MsgNoticeMeta,MsgWarningMeta}

    // A "wrapper" that simply returns the javascript
    val passJs = (in : JsCmd) => in

    // Delegate to Msgs for fadeout and effects
    def noticesFadeOut(noticeType: NoticeType.Value): JsCmd =
      Msgs.noticesFadeOut(noticeType, Noop, passJs)

    def groupEffects(noticeType: NoticeType.Value): JsCmd =
      Msgs.effects(Full(noticeType), noticeType.id, Noop, passJs)

    def idEffects(id : String): JsCmd =
      Msgs.effects(Empty, id, Noop, passJs)

    // Compute the global notices first
    val groupMessages = Msgs.renderNotices() match {
      case NodeSeq.Empty => JsCmds.Noop
      case xml => LiftRules.jsArtifacts.setHtml(LiftRules.noticesContainerId, xml) &
        noticesFadeOut(NoticeType.Notice) &
        noticesFadeOut(NoticeType.Warning) &
        noticesFadeOut(NoticeType.Error) &
        groupEffects(NoticeType.Notice) &
        groupEffects(NoticeType.Warning) &
        groupEffects(NoticeType.Error)
    }

    // We need to determine the full set of IDs that need messages rendered.
    val idSet = (S.idMessages((S.errors)) ++
                 S.idMessages((S.warnings)) ++
                 S.idMessages((S.notices))).map(_._1).distinct

    // Merge each Id's messages and effects into the JsCmd chain
    idSet.foldLeft(groupMessages) {
      (chain,id) => chain &
        LiftRules.jsArtifacts.setHtml(id, Msg.renderIdMsgs(id)) &
        idEffects(id)
    }
  }

  /**
* The base name of the resource bundle of the lift core code
*/
  @volatile var liftCoreResourceName = "i18n.lift-core"

  /**
* Where to send the user if there's no comet session. Note that this is
* contingent on an unchanged LiftRules.noCometSessionCommand and on
* liftComet.lift_sessionLost not being overridden client-side.
*/
  @deprecated("Use LiftRules.noCometSessionCmd.", "2.5")
  @volatile var noCometSessionPage = "/"

  /**
* The JsCmd to execute when the comet session is lost. The comet
* session is considered lost when either (a) a comet request comes
* in for a session that does not exist on the server or (b) a comet
* request comes in for a session that has no associated comet actors
* (this typically happens when the server restarts).
*
* By default, we invoke liftComet.lift_sessionLost, which can be
* overridden client-side for more complex work.
* liftComet.lift_sessionLost redirects to
* LiftRules.noCometSessionPage by default for now, though
* noCometSessionPage is deprecated and will be replaced by a
* default of reloading the current page.
*/
  val noCometSessionCmd = new FactoryMaker[JsCmd](
    () => JsCmds.Run("liftComet.lift_sessionLost()")
  ) {}

  /**
* The JsCmd to execute when the ajax session is lost. The ajax
* session is considered lost when either an ajax request comes in for
* a session that does not exist on the server.
*
* By default, we invoke liftAjax.lift_sessionLost, which can be
* overridden client-side for more complex work.
* liftAjax.lift_sessionLost reloads the page by default.
*/
  val noAjaxSessionCmd = new FactoryMaker[JsCmd](
    () => JsCmds.Run("liftAjax.lift_sessionLost()")
  ) {}

  /**
* Put a function that will calculate the request timeout based on the
* incoming request.
*/
  @volatile var calcRequestTimeout: Box[Req => Int] = Empty

  /**
* If you want the standard (non-AJAX) request timeout to be something other than
* 10 seconds, put the value here
*/
  @volatile var stdRequestTimeout: Box[Int] = Empty

  /**
* If you want the AJAX request timeout to be something other than 120 seconds, put the value here
*/
  @volatile var cometRequestTimeout: Box[Int] = Empty

  /**
* If a Comet request fails timeout for this period of time. Default value is 10 seconds
*/
  @volatile var cometFailureRetryTimeout: Long = 10 seconds

  /**
* The timeout in milliseconds of a comet ajax-request. Defaults to 5000 ms.
*/
  @volatile var cometProcessingTimeout: Long = 5 seconds

  /**
* The timeout in milliseconds of a comet render-request. Defaults to 30000 ms.
*/
  @volatile var cometRenderTimeout: Long = 30 seconds

  /**
* The dispatcher that takes a Snippet and converts it to a
* DispatchSnippet instance
*/
  val snippetDispatch = RulesSeq[SnippetDispatchPF]


  /**
* Function that generates variants on snippet names to search for, given the name from the template.
* The default implementation just returns name :: Nil (e.g. no change).
* The names are searched in order.
* See also searchSnippetsWithRequestPath for an implementation.
*/
  @volatile var snippetNamesToSearch: FactoryMaker[String => List[String]] =
      new FactoryMaker(() => (name: String) => name :: Nil) {}

  /**
* Implementation for snippetNamesToSearch that looks first in a package named by taking the current template path.
* For example, suppose the following is configured in Boot:
* LiftRules.snippetNamesToSearch.default.set(() => LiftRules.searchSnippetsWithRequestPath)
* LiftRules.addToPackages("com.mycompany.myapp")
* LiftRules.addToPackages("com.mycompany.mylib")
* The tag <lift:MySnippet> in template foo/bar/baz.html would search for the snippet in the following locations:
* - com.mycompany.myapp.snippet.foo.bar.MySnippet
* - com.mycompany.myapp.snippet.MySnippet
* - com.mycompany.mylib.snippet.foo.bar.MySnippet
* - com.mycompany.mylib.snippet.MySnippet
* - and then the Lift builtin snippet packages
*/
  def searchSnippetsWithRequestPath(name: String): List[String] =
    S.request.map(_.path.partPath.dropRight(1)) match {
      case Full(xs) if !xs.isEmpty => (xs.mkString(".") + "." + name) :: name :: Nil
      case _ => name :: Nil
    }

  /**
* Change this variable to set view dispatching
*/
  val viewDispatch = RulesSeq[ViewDispatchPF]

  private[http] def snippet(name: String): Box[DispatchSnippet] = NamedPF.applyBox(name, snippetDispatch.toList)

  /**
* If the request times out (or returns a non-Response) you can
* intercept the response here and create your own response
*/
 @volatile var requestTimedOut: Box[(Req, Any) => Box[LiftResponse]] = Empty

  /**
* A function that takes the current HTTP request and returns the current
*/
  @volatile var timeZoneCalculator: Box[HTTPRequest] => TimeZone = defaultTimeZoneCalculator _

  def defaultTimeZoneCalculator(request: Box[HTTPRequest]): TimeZone = TimeZone.getDefault

  /**
* How many times do we retry an Ajax command before calling it a failure?
*/
  @volatile var ajaxRetryCount: Box[Int] = Empty

  /**
* The JavaScript to execute at the beginning of an
* Ajax request (for example, showing the spinning working thingy)
*/
  @volatile var ajaxStart: Box[() => JsCmd] = Empty

  import FuncJBridge._

  /**
* Set the Ajax end JavaScript function. The
* Java-callable alternative to assigning the var ajaxStart
*/
  def setAjaxStart(f: Func0[JsCmd]): Unit = {
    ajaxStart = Full(f: () => JsCmd)
  }


  /**
* The function that calculates if the response should be rendered in
* IE6/7/8 compatibility mode
*/
  @volatile var calcIEMode: () => Boolean =
  () => (for (r <- S.request) yield r.isIE6 || r.isIE7 ||
          r.isIE8) openOr true

  /**
* The JavaScript to execute to log a message on the client side when
* liftAjax.lift_logError is called.
*
* If Empty no logging is performed
* The default when running in DevMode is to call lift_defaultLogError which
* will use JavaScript console if available or alert otherwise.
*
* To always use alert set:
*
* LiftRules.jsLogFunc = Full(v => JE.Call("alert",v).cmd)
*/
  @volatile var jsLogFunc: Box[JsVar => JsCmd] =
    if (Props.devMode) Full(v => JE.Call("liftAjax.lift_defaultLogError", v))
    else Empty

  /**
* The JavaScript to execute at the end of an
* Ajax request (for example, removing the spinning working thingy)
*/
  @volatile var ajaxEnd: Box[() => JsCmd] = Empty

  /**
* Set the Ajax end JavaScript function. The
* Java-callable alternative to assigning the var ajaxEnd
*/
  def setAjaxEnd(f: Func0[JsCmd]): Unit = {
    ajaxEnd = Full(f: () => JsCmd)
  }

  /**
* An XML header is inserted at the very beginning of returned XHTML pages.
* This function defines the cases in which such a header is inserted. The
* function takes a NodeResponse (the LiftResponse that is converting the
* XML to a stream of bytes), the Node (root node of the XML), and
* a Box containing the content type.
*/
  @volatile var calculateXmlHeader: (NodeResponse, Node, Box[String]) => String = {
    case _ if S.skipXmlHeader => ""
    case (_, up: Unparsed, _) => ""

    case (_, _, Empty) | (_, _, Failure(_, _, _)) =>
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"

    case (_, _, Full(s)) if (s.toLowerCase.startsWith("text/html")) =>
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"

    case (_, _, Full(s)) if (s.toLowerCase.startsWith("text/xml") ||
        s.toLowerCase.startsWith("text/xhtml") ||
        s.toLowerCase.startsWith("application/xml") ||
        s.toLowerCase.startsWith("application/xhtml+xml")) =>
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"

    case _ => ""
  }

  /**
* The default action to take when the JavaScript action fails
*/
  @volatile var ajaxDefaultFailure: Box[() => JsCmd] =
  Full(() => JsCmds.Alert(S.?("ajax.error")))

  /**
* A function that takes the current HTTP request and returns the current
*/
  @volatile var localeCalculator: Box[HTTPRequest] => Locale = defaultLocaleCalculator _

  def defaultLocaleCalculator(request: Box[HTTPRequest]) =
    request.flatMap(_.locale).openOr(Locale.getDefault())

  val resourceBundleFactories = RulesSeq[ResourceBundleFactoryPF]

  /**
* Given the current location (based on the Req.path.partPath),
* what are the resource bundles in the templates for the current
* page.
*
* @see DefaultRoutines.resourceForCurrentLoc()
*/
  val resourceForCurrentLoc: FactoryMaker[() => List[ResourceBundle]] =
    new FactoryMaker(() => () => DefaultRoutines.resourceForCurrentReq()) {}


  /**
* There may be times when you want to entirely control the templating process. You can insert
* a function to this factory that will do your custom template resolution. If the PartialFunction
* isDefinedAt the given locale/path, then that's the template returned. In this way, you can
* return Empty for a template that's not found and the template will not be found. Otherwise,
* if the function is not defined for the locale/path pair, the normal templating system will
* be used. Also, keep in mind how FactoryMaker can be used... it can be global, per request, etc.
*/
  val externalTemplateResolver: FactoryMaker[() => PartialFunction[(Locale, List[String]), Box[NodeSeq]]] =
  new FactoryMaker(() => (() => Map.empty: PartialFunction[(Locale, List[String]), Box[NodeSeq]])) {}

  /**
* There may be times when you want to entirely control the templating process. You can insert a function
* that creates a white list of snippets. The white list is the exhaustive list of snippets. The
* snippets are class/method pairs. If the partial function is defined and the result is a Full Box,
* the function is run. If the Box is an EmptyBox, then the result is a snippet lookup failure. If the
* partial function is not defined, then the normal snippet resolution mechanism is used. Please note that
* in Scala a Map is PartialFunction and you can create Maps that have a default value using the withDefaultValue
* method.
*/
  val snippetWhiteList: FactoryMaker[() => PartialFunction[(String, String), Box[NodeSeq => NodeSeq]]] =
  new FactoryMaker(() => (() => Map.empty: PartialFunction[(String, String), Box[NodeSeq => NodeSeq]])) {}

  /**
* This FactoryMaker can be used to disable the little used attributeSnippets
*/
  val allowAttributeSnippets: FactoryMaker[() => Boolean] =
  new FactoryMaker(() => () => true) {}

  private var _sitemap: Box[SiteMap] = Empty

  private var sitemapFunc: Box[() => SiteMap] = Empty

  private object sitemapRequestVar extends TransientRequestVar(resolveSitemap())

  /**
* Set the sitemap to a function that will be run to generate the sitemap.
*
* This allows for changing the SiteMap when in development mode and having
* the function re-run for each request.<br/>
*
* This is **NOT** a mechanism for dynamic SiteMap. This is a mechanism
* **ONLY** for allowing you to change the SiteMap during development.
* There will be significant performance penalties (serializing the
* service of requests... only one at a time) for changing the SiteMap.
*/
  def setSiteMapFunc(smf: () => SiteMap) {
    sitemapFunc = Full(smf)
    if (!Props.devMode) {
      resolveSitemap()
    }
  }

  /**
* Define the sitemap.
*/
  def setSiteMap(sm: SiteMap) {
    this.setSiteMapFunc(() => sm)
  }

  private def runAsSafe[T](f: => T): T = synchronized {
     val old = _doneBoot
     try {
        _doneBoot = false
        f
     } finally {
        _doneBoot = old
     }
  }

  private case class PerRequestPF[A, B](f: PartialFunction[A, B]) extends PartialFunction[A, B] {
    def isDefinedAt(a: A) = f.isDefinedAt(a)
    def apply(a: A) = f(a)
  }

  private def resolveSitemap(): Box[SiteMap] = {
    this.synchronized {
      runAsSafe {
        sitemapFunc.flatMap {
          smf =>

          LiftRules.statefulRewrite.remove {
            case PerRequestPF(_) => true
            case _ => false
          }

          val sm = smf()
          _sitemap = Full(sm)
          for (menu <- sm.menus;
               val loc = menu.loc;
               rewrite <- loc.rewritePF) LiftRules.statefulRewrite.append(PerRequestPF(rewrite))

          _sitemap
        }
      }
    }
  }

  /**
* Return the sitemap if set in Boot. If the current runMode is development
* mode, the sitemap may be recomputed on each page load.
*/
  def siteMap: Box[SiteMap] = if (Props.devMode) {
    this.synchronized {
      sitemapRequestVar.is
    }
  } else _sitemap

  /**
* A unified set of properties for managing how to treat
* HTML, XHTML, HTML5. The default behavior is to return an
* OldHtmlPropteries instance, but you can change this
* to return an Html5Properties instance any you'll get
* HTML5 support.
* LiftRules.htmlProperties.default.set((r: Req) => new Html5Properties(r.userAgent))
*/
  val htmlProperties: FactoryMaker[Req => HtmlProperties] =
    new FactoryMaker(() => (r: Req) => new Html5Properties(r.userAgent): HtmlProperties) {}

  /**
* How long should we wait for all the lazy snippets to render
*/
  val lazySnippetTimeout: FactoryMaker[TimeSpan] = new FactoryMaker(() => 30 seconds) {}

  /**
* Does the current context support parallel snippet execution
*/
  val allowParallelSnippets: FactoryMaker[Boolean] = new FactoryMaker(() => false) {}

  /**
* Update the function here that calculates particular paths to
* excluded from context path rewriting
*/
  val excludePathFromContextPathRewriting: FactoryMaker[String => Boolean] =
  new FactoryMaker(() => ((s: String) => false)) {}

  /**
* If a deferred snippet has a failure during render,
* what should we display?
*/
  val deferredSnippetFailure: FactoryMaker[Failure => NodeSeq] =
  new FactoryMaker(() => {
    failure: Failure => {
      if (Props.devMode)
        <div style="border: red solid 2px">A lift:parallel snippet failed to render.Message:{failure.msg}{failure.exception match {
          case Full(e) =>
            <pre>{e.getStackTrace.map(_.toString).mkString("\n")}</pre>
          case _ => NodeSeq.Empty
        }}<i>note: this error is displayed in the browser because
        your application is running in "development" mode.If you
        set the system property run.mode=production, this error will not
        be displayed, but there will be errors in the output logs.
        </i>
        </div>
      else NodeSeq.Empty
    }
  }) {}

  /**
* If a deferred snippet has a failure during render,
* what should we display?
*/

  val deferredSnippetTimeout: FactoryMaker[NodeSeq] =
  new FactoryMaker(() => {
        if (Props.devMode)
        <div style="border: red solid 2px">
          A deferred snippet timed out during render.

          <i>note: this error is displayed in the browser because
            your application is running in "development" mode. If you
            set the system property run.mode=production, this error will not
            be displayed, but there will be errors in the output logs.
          </i>
        </div>
        else NodeSeq.Empty
      }) {}


  /**
* Should comments be stripped from the served XHTML
*/
  val stripComments: FactoryMaker[Boolean] =
  new FactoryMaker(() => {
        if (Props.devMode)
        false
        else true
      }) {}



  private[http] val reqCnt = new AtomicInteger(0)

  @volatile private[http] var ending = false

  private[http] def bootFinished() {
    _doneBoot = true
  }

  /**
* Holds user's DispatchPF functions that will be executed in a stateless context. This means that
* no session will be created and no JSESSIONID cookie will be presented to the user (unless
* the user has presented a JSESSIONID cookie).
*/
  @deprecated("Use statelessDispatch", "2.4")
  def statelessDispatchTable = statelessDispatch

  /**
* Holds user's DispatchPF functions that will be executed in a stateless context. This means that
* no session will be created and no JSESSIONID cookie will be presented to the user (unless
* the user has presented a JSESSIONID cookie).
*
* This is the way to do stateless REST in Lift
*/
  val statelessDispatch = RulesSeq[DispatchPF]

  /**
* Add functionality around all of the HTTP request/response cycle.
* This is an optimal place to get a database connection. Note that whatever
* is loaned at the beginning of the request will not be returned until the end
* of the request. It's super-important to (1) not do anything related
* to state or touch the request objects or anything else at the beginning or
* end of the loan wrapper phase; (2) make sure that your code does not throw
* exceptions as exceptions can cause major problems.
*/
  val allAround = RulesSeq[LoanWrapper]


  private[http] def dispatchTable(req: HTTPRequest): List[DispatchPF] = {
    req match {
      case null => dispatch.toList
      case _ => SessionMaster.getSession(req, Empty) match {
        case Full(s) => S.initIfUninitted(s) {
          S.highLevelSessionDispatchList.map(_.dispatch) :::
                  dispatch.toList
        }
        case _ => dispatch.toList
      }
    }
  }


  /**
* Contains the Ajax URI path used by Lift to process Ajax requests.
*/
  @volatile var ajaxPath = "ajax_request"

  /**
* Contains the Comet URI path used by Lift to process Comet requests.
*/
  @volatile var cometPath = "comet_request"

  /**
* Computes the Comet path by adding additional tokens on top of cometPath
*/
  @volatile var calcCometPath: String => JsExp = prefix => {
    Str(prefix + "/" + cometPath + "/") +
            JsRaw("Math.floor(Math.random() * 100000000000)") +
            Str(S.session.map(session => S.encodeURL("/" + session.uniqueId)) openOr "xx") + Str("/") + JsRaw("lift_page")
  }


  /**
* If there is an alternative way of calculating the context path
* (by default returning Empty)
*
* If this function returns an Empty, the contextPath provided by the container will be used.
*
*/
  @volatile var calculateContextPath: () => Box[String] = () => Empty


  @volatile private var _context: HTTPContext = _

  /**
* Should an exception be thrown on out of scope Session and RequestVar
* access. By default, no.
*/
  @volatile var throwOnOutOfScopeVarAccess: Boolean = false

  /**
* In Dev mode and Test mode, return a non-200 response code
* if there is an error on the page (one that would result in
* the red box with the error message being displayed). This
* helps in testing automation.
*/
  @volatile var devModeFailureResponseCodeOverride: Box[Int] = Empty

  /**
* Returns the HTTPContext
*/
  def context: HTTPContext = synchronized {_context}

  /**
* Sets the HTTPContext
*/
  def setContext(in: HTTPContext): Unit = synchronized {
    if (in ne _context) {
      _context = in
    }
  }

  private var otherPackages: List[String] = Nil

  /**
* Used by Lift to construct full package names from the packages provided to addToPackages function
*/
  def buildPackage(end: String) = otherPackages.map(_ + "." + end)

  /**
* Tells Lift where to find Snippets,Views, Comet Actors and Lift ORM Model object
*/
  def addToPackages(what: String) {
    if (doneBoot) throw new IllegalStateException("Cannot modify after boot.");
    otherPackages = what :: otherPackages
  }

  /**
* Tells Lift where to find Snippets, Views, Comet Actors and Lift ORM Model object
*/
  def addToPackages(what: Package) {
    if (doneBoot) throw new IllegalStateException("Cannot modify after boot.");
    otherPackages = what.getName :: otherPackages
  }

  private val defaultFinder = getClass.getResource _

  private def resourceFinder(name: String): java.net.URL = if (null eq _context) null else _context.resource(name)

  /**
* Obtain the resource URL by name
*/
  @volatile var getResource: String => Box[java.net.URL] = defaultGetResource _

  /**
* Obtain the resource URL by name
*/
  def defaultGetResource(name: String): Box[java.net.URL] =
    for{
      rf <- (Box !! resourceFinder(name)) or (Box !! defaultFinder(name))
    } yield rf

  /**
* Open a resource by name and process its contents using the supplied function.
*/
  def doWithResource[T](name: String)(f: InputStream => T): Box[T] =
    getResource(name) map { _.openStream } map { is => try { f(is) } finally { is.close } }

  /**
* Obtain the resource as an array of bytes by name
*/
  def loadResource(name: String): Box[Array[Byte]] = doWithResource(name) { stream =>
    val buffer = new Array[Byte](2048)
    val out = new ByteArrayOutputStream
    def reader {
      val len = stream.read(buffer)
      if (len < 0) return
      else if (len > 0) out.write(buffer, 0, len)
      reader
    }
    reader
    out.toByteArray
  }

  /**
* Obtain the resource as an XML by name. If you're using this to load a template, consider using
* the Template object instead.
*
* @see Template
*/
  def loadResourceAsXml(name: String): Box[NodeSeq] = loadResourceAsString(name).flatMap(s => PCDataXmlParser(s))

  /**
* Obtain the resource as a String by name
*/
  def loadResourceAsString(name: String): Box[String] = loadResource(name).map(s => new String(s, "UTF-8"))

  /**
* Get the partial function that defines if a request should be handled by
* the application (rather than the default container handler)
*/
  val liftRequest = RulesSeq[LiftRequestPF]

  /**
* Holds the user's DispatchPF functions that will be executed in stateful context
*/
  val dispatch = RulesSeq[DispatchPF]

  /**
* Holds the user's rewrite functions that can alter the URI parts and query parameters. This rewrite
* is performed very early in the HTTP request cycle and may not include any state. This rewrite is meant
* to rewrite requests for statelessDispatch. <br/>
* Note also that rewrites should not have side effects except
* to memoize database query results. No side effects means that you should not change SessionVars
* in a rewrite.
*/
  val statelessRewrite = RulesSeq[RewritePF]

  /**
* Use statelessRewrite or statefuleRewrite
*/
  @deprecated("Use statelessRewrite or statefuleRewrite", "2.3")
  val rewrite = statelessRewrite

  /**
* Holds the user's rewrite functions that can alter the URI parts and query parameters.
* This rewrite takes place within the scope of the S state so SessionVars and other session-related
* information is available. <br/>
* Note also that rewrites should not have side effects except
* to memoize database query results. No side effects means that you should not change SessionVars
* in a rewrite. <br/>
* In general, rewrites should be considered low level access. Rather than using a rewrite to extract
* parameters out of a URL, you'll be much better off using SiteMap generally and Menu.param and Menu.params
* specifically for extracting parameters from URLs.
*/
  val statefulRewrite = RulesSeq[RewritePF]

  /**
* Holds the user's snippet functions that will be executed by lift given a certain path.
*/
  val snippets = RulesSeq[SnippetPF]

  /**
* Execute certain functions early in a Stateful Request
* This is called early in a stateful request (one that's not serviced by a stateless REST request and
* one that's not marked as a stateless HTML page request).
* @dpp strongly recommends that everything that you do related to user state is done with earlyInStateful,
* instead of using onBeginServicing.
*/
  val earlyInStateful = RulesSeq[Box[Req] => Unit]

  /**
* Execute certain functions early in a Stateful Request
*/
  val earlyInStateless = RulesSeq[Box[Req] => Unit]


  private var _configureLogging: () => Unit = _

  /**
* Holds the function that configures logging. Must be set before any loggers are created
*/
  def configureLogging: () => Unit = _configureLogging

  /**
* Holds the function that configures logging. Must be set before any loggers are created
*/
  def configureLogging_=(newConfigurer: () => Unit): Unit = {
    _configureLogging = newConfigurer
    Logger.setup = Full(newConfigurer)
  }

  configureLogging = net.liftweb.util.LoggingAutoConfigurer()

  private val _cometLogger: FatLazy[Logger] = FatLazy({
    val ret = Logger("comet_trace")
    ret
  })

  /**
* Holds the CometLogger that will be used to log comet activity
*/
  def cometLogger: Logger = _cometLogger.get

  /**
* Holds the CometLogger that will be used to log comet activity
*/
  def cometLogger_=(newLogger: Logger): Unit = _cometLogger.set(newLogger)

  /**
* Takes a Node, headers, cookies, and a session and turns it into an XhtmlResponse.
*/
  private def cvt(ns: Node, headers: List[(String, String)], cookies: List[HTTPCookie], req: Req, code:Int) =
    convertResponse({
      val ret = XhtmlResponse(ns,
        /*LiftRules.docType.vend(req)*/S.htmlProperties.docType,
        headers, cookies, code,
        S.legacyIeCompatibilityMode)
      ret._includeXmlVersion = !S.skipDocType
      ret
    }, headers, cookies, req)

  @volatile var defaultHeaders: PartialFunction[(NodeSeq, Req), List[(String, String)]] = {
    case _ =>
      val d = Helpers.nowAsInternetDate
      List("Expires" -> d,
           "Date" -> d,
           "Cache-Control" ->
           "no-cache, private, no-store",
           "Pragma" -> "no-cache" )
  }

  /**
* Runs responseTransformers
*/
  def performTransform(in: LiftResponse): LiftResponse = responseTransformers.toList.foldLeft(in) {
    case (in, pf: PartialFunction[_, _]) =>
      if (pf.isDefinedAt(in)) pf(in) else in
    case (in, f) => f(in)
  }

  /**
* Holds the user's transformer functions allowing the user to modify a LiftResponse before sending it to client.
*/
  val responseTransformers = RulesSeq[LiftResponse => LiftResponse]


  /**
* convertResponse is a PartialFunction that reduces a given Tuple4 into a
* LiftResponse that can then be sent to the browser.
*/
  var convertResponse: PartialFunction[(Any, List[(String, String)], List[HTTPCookie], Req), LiftResponse] = {
    case (r: LiftResponse, _, _, _) => r
    case (ns: Group, headers, cookies, req) => cvt(ns, headers, cookies, req, 200)
    case (ns: Node, headers, cookies, req) => cvt(ns, headers, cookies, req, 200)
    case (ns: NodeSeq, headers, cookies, req) => cvt(Group(ns), headers, cookies, req, 200)
    case ((ns: NodeSeq, code: Int), headers, cookies, req) => cvt(Group(ns), headers, cookies, req, code)
    case (SafeNodeSeq(n), headers, cookies, req) => cvt(Group(n), headers, cookies, req, 200)

    case (Full(o), headers, cookies, req) => convertResponse((o, headers, cookies, req))

    case (Some(o), headers, cookies, req) => convertResponse((o, headers, cookies, req))
    case (bad, _, _, req) => req.createNotFound
  }

  /**
* Set a snippet failure handler here. The class and method for the snippet are passed in
*/
  val snippetFailedFunc = RulesSeq[SnippetFailure => Unit].prepend(logSnippetFailure _)

  private def logSnippetFailure(sf: SnippetFailure) = logger.info("Snippet Failure: " + sf)

  /**
* Set to false if you do not want ajax/comet requests that are not
* associated with a session to call their respective session
* loss handlers (set via LiftRules.noAjaxSessionCmd and
* LiftRules.noCometSessionCmd).
*/
  @volatile var redirectAsyncOnSessionLoss = true
  @deprecated("Use redirectAsyncOnSessionLoss instead.", "2.5")
  def redirectAjaxOnSessionLoss = redirectAsyncOnSessionLoss
  @deprecated("Use redirectAsyncOnSessionLoss instead.", "2.5")
  def redirectAjaxOnSessionLoss_=(updated:Boolean) = redirectAsyncOnSessionLoss = updated

  /**
* The sequence of partial functions (pattern matching) for handling converting an exception to something to
* be sent to the browser depending on the current RunMode (development, etc.)
*
* By default it returns an XhtmlResponse containing a predefined markup. You can overwrite this by calling
* LiftRules.exceptionHandler.prepend(...). If you are calling append then your code will not be called since
* a default implementation is already appended.
*
*/
  val exceptionHandler = RulesSeq[ExceptionHandlerPF].append {
    case (Props.RunModes.Development, r, e) =>
      logger.error("Exception being returned to browser when processing " + r.uri.toString, e)
      XhtmlResponse((<html> <body>Exception occured while processing {r.uri}<pre>{showException(e)}</pre> </body> </html>), S.htmlProperties.docType, List("Content-Type" -> "text/html; charset=utf-8"), Nil, 500, S.legacyIeCompatibilityMode)

    case (_, r, e) =>
      logger.error("Exception being returned to browser when processing " + r.uri.toString, e)
      XhtmlResponse((<html> <body>Something unexpected happened while serving the page at {r.uri}</body> </html>), S.htmlProperties.docType, List("Content-Type" -> "text/html; charset=utf-8"), Nil, 500, S.legacyIeCompatibilityMode)
  }

  /**
* The list of partial function for defining the behavior of what happens when
* URI is invalid and you're not using a site map
*
*/
  val uriNotFound = RulesSeq[URINotFoundPF].prepend(NamedPF("default") {
    case (r, _) => DefaultNotFound
  })

  /**
* If you use the form attribute in a snippet invocation, what attributes should
* be copied from the snippet invocation tag to the form tag. The
* default list is "class", "id", "target", "style", "onsubmit"
*/
  val formAttrs: FactoryMaker[List[String]] = new FactoryMaker(() => List("class", "id", "target", "style", "onsubmit")) {}

  /**
* By default, Http response headers are appended. However, there are
* some headers that should only appear once (for example "expires"). This
* Vendor vends the list of header responses that can only appear once.
*/
  val overwrittenReponseHeaders: FactoryMaker[List[String]] = new FactoryMaker(() => List("expires")) {}

  /**
* A utility method to convert an exception to a string of stack traces
* @param le the exception
*
* @return the stack trace
*/
  private def showException(le: Throwable): String = {
    val ret = "Message: " + le.toString + "\n\t" +
            le.getStackTrace.map(_.toString).mkString("\n\t") + "\n"

    val also = le.getCause match {
      case null => ""
      case sub: Throwable => "\nCaught and thrown by:\n" + showException(sub)
    }

    ret + also
  }

  /**
* Modifies the root relative paths from the css url-s
*
* @param path - the path of the css resource
* @prefix - the prefix to be added on the root relative paths. If this is Empty
* the prefix will be the application context path.
*/
  def fixCSS(path: List[String], prefix: Box[String]) {

    val liftReq: LiftRules.LiftRequestPF = new LiftRules.LiftRequestPF {
      def functionName = "Default CSS Fixer"

      def isDefinedAt(r: Req): Boolean = {
        r.path.partPath == path
      }

      def apply(r: Req): Boolean = {
        r.path.partPath == path
      }
    }

    val cssFixer: LiftRules.DispatchPF = new LiftRules.DispatchPF {
      def functionName = "default css fixer"

      def isDefinedAt(r: Req): Boolean = {
        r.path.partPath == path
      }

      def apply(r: Req): () => Box[LiftResponse] = {
        val cssPath = path.mkString("/", "/", ".css")
        val css = LiftRules.loadResourceAsString(cssPath);

        () => {
          css.map(str => CSSHelpers.fixCSS(new BufferedReader(
            new StringReader(str)), prefix openOr (S.contextPath)) match {
            case (Full(c), _) => CSSResponse(c)
            case (x, input) => {
              logger.info("Fixing " + cssPath + " failed with result %s".format(x));
              CSSResponse(input)
            }
          })
        }
      }
    }
    LiftRules.dispatch.prepend(cssFixer)
    LiftRules.liftRequest.append(liftReq)
  }

  /**
* Holds user function hooks when the request is about to be processed
* It's legacy from when Lift was a lot more Rails-like. It's called literally at the very
* beginning of the servicing of the HTTP request.
* The S scope is not available nor is the DB connection available in onBeginServicing.
* We recommend using earlyInStateful.
*/
  val onBeginServicing = RulesSeq[Req => Unit]

  val preAccessControlResponse_!! = new RulesSeq[Req => Box[LiftResponse]] with FirstBox[Req, LiftResponse]

  val earlyResponse = new RulesSeq[Req => Box[LiftResponse]] with FirstBox[Req, LiftResponse]

  /**
* Holds user function hooks when the request was processed
*/
  val onEndServicing = RulesSeq[(Req, Box[LiftResponse]) => Unit]

  /**
* Tells Lift if the Comet JavaScript should be included. By default it is set to true.
*/
  @volatile var autoIncludeComet: LiftSession => Boolean = session => true

  /**
* Tells Lift if the Ajax JavaScript should be included. By default it is set to true.
*/
  @deprecated("Use autoIncludeAjaxCalc", "2.4")
  @volatile var autoIncludeAjax: LiftSession => Boolean = session => autoIncludeAjaxCalc.vend().apply(session)

  val autoIncludeAjaxCalc: FactoryMaker[() => LiftSession => Boolean] =
  new FactoryMaker(() => () => (session: LiftSession) => true) {}

  /**
* Define the XHTML validator
*/
  @volatile var xhtmlValidator: Box[XHtmlValidator] = Empty // Full(TransitionalXHTML1_0Validator)

  /**
* Returns the JavaScript that manages Ajax requests.
*/
  @volatile var renderAjaxScript: LiftSession => JsCmd = session => ScriptRenderer.ajaxScript

  @volatile var ajaxPostTimeout = 5000

  @volatile var cometGetTimeout = 140000

  /**
* Compute the headers to be sent to the browser in addition to anything else that's sent
*/
  val listOfSupplimentalHeaders: FactoryMaker[List[(String, String)]] = new FactoryMaker(() => List(("X-Lift-Version", liftVersion), ("X-Frame-Options", "SAMEORIGIN"))) {}

  @volatile var supplimentalHeaders: HTTPResponse => Unit = s => listOfSupplimentalHeaders.vend.foreach{case (k, v) => s.addHeaders(List(HTTPParam(k, v)))}

  @volatile var calcIE6ForResponse: () => Boolean = () => S.request.map(_.isIE6) openOr false

  @volatile var flipDocTypeForIE6 = true

  /**
* By default lift uses a garbage-collection mechanism of removing unused bound functions from LiftSesssion.
* Setting this to false will disable this mechanisms and there will be no Ajax polling requests attempted.
*/
  @volatile var enableLiftGC = true;

  /**
* If Lift garbage collection is enabled, functions that are not seen in the page for this period of time
* (given in milliseconds) will be discarded, hence eligible for garbage collection.
* The default value is 10 minutes.
*/
  @volatile var unusedFunctionsLifeTime: Long = 10 minutes

  /**
* The polling interval for background Ajax requests to prevent functions of being garbage collected.
* Default value is set to 75 seconds.
*/
  @volatile var liftGCPollingInterval: Long = 75 seconds

  /**
* Put a test for being logged in into this function
*/
  @volatile var loggedInTest: Box[() => Boolean] = Empty

  /**
* The polling interval for background Ajax requests to keep functions to not be garbage collected.
* This will be applied if the Ajax request will fail. Default value is set to 15 seconds.
*/
  @volatile var liftGCFailureRetryTimeout: Long = 15 seconds

  /**
* Returns the JavaScript that manages Comet requests.
*/
  @volatile var renderCometScript: LiftSession => JsCmd = session => ScriptRenderer.cometScript

  /**
* If this is Full, comet updates (partialUpdates or reRenders) are
* wrapped in a try/catch statement. The provided JsCmd is the body of
* the catch statement. Within that JsCmd, the variable "e" refers to the
* caught exception.
*
* In development mode, this defaults to Full and the command within
* invokes liftComet.lift_cometError with the exception;
* lift_cometError rethrows the exception by default. In production
* mode, this defaults to Empty.
*
* Note that if you set this to Full, it is highly advised that you
* rethrow the exception. If you fail to rethrow the exception, you
* run the risk of dropping an unpredictable number of updates (i.e.,
* if the third of 20 updates that are sent to the client in a single
* response throws an exception, none of the subsequent ones will run;
* failing to rethrow the exception means any updates that did not run
* will never be run).
*/
  val cometUpdateExceptionHandler: FactoryMaker[Box[JsCmd]] =
    new FactoryMaker[Box[JsCmd]]( () => {
      if (Props.devMode)
        Full(JE.Call("liftComet.lift_cometError", JE.JsVar("e")).cmd)
      else
        Empty
    } ) {}

  /**
* Renders that JavaScript that holds Comet identification information
*/
  @volatile var renderCometPageContents: (LiftSession, Seq[CometVersionPair]) => JsCmd =
  (session, vp) => JsCmds.Run(
    "var lift_toWatch = " + vp.map(p => p.guid.encJs + ": " + p.version).mkString("{", " , ", "}") + ";"
    )

  /**
* Holds the last update time of the Ajax request. Based on this server may return HTTP 304 status
* indicating the client to used the cached information.
*/
  @volatile var ajaxScriptUpdateTime: LiftSession => Long = session => {
    object when extends SessionVar[Long](millis)
    when.is
  }

  /**
* Determines the path parts and suffix from given path parts
*/
  val suffixSplitters = RulesSeq[SplitSuffixPF].append {
    case parts =>
      val last = parts.last
      val idx: Int = {
        val firstDot = last.indexOf(".")
        val len = last.length
        if (firstDot + 1 == len) -1 // if the dot is the last character, don't split
        else {
          if (last.indexOf(".", firstDot + 1) != -1) -1 // if there are multiple dots, don't split out
          else {
            val suffix = last.substring(firstDot + 1)
            // if the suffix isn't in the list of suffixes we care about, don't split it
            if (!LiftRules.explicitlyParsedSuffixes.contains(suffix.toLowerCase)) -1
            else firstDot
          }
        }
      }

      if (idx == -1) (parts, "")
      else (parts.dropRight(1) ::: List(last.substring(0, idx)), last.substring(idx + 1))

  }

  /**
* The list of suffixes that Lift looks for in templates.
* By default, html, xhtml, and htm
*/
  @volatile var templateSuffixes: List[String] = List("html", "xhtml", "htm")

  /**
* When a request is parsed into a Req object, certain suffixes are explicitly split from
* the last part of the request URI. If the suffix is contained in this list, it is explicitly split.
* The default list is: "html", "htm", "jpg", "png", "gif", "xml", "rss", "json" ...
*/
  @volatile var explicitlyParsedSuffixes: Set[String] = knownSuffixes

  /**
* The global multipart progress listener:
* pBytesRead - The total number of bytes, which have been read so far.
* pContentLength - The total number of bytes, which are being read. May be -1, if this number is unknown.
* pItems - The number of the field, which is currently being read. (0 = no item so far, 1 = first item is being read, ...)
*/
  @volatile var progressListener: (Long, Long, Int) => Unit = (_, _, _) => ()

  /**
* The function that converts a fieldName, contentType, fileName and an InputStream into
* a FileParamHolder. By default, create an in-memory instance. Use OnDiskFileParamHolder
* to create an on-disk version
*/
  @volatile var handleMimeFile: (String, String, String, InputStream) => FileParamHolder =
  (fieldName, contentType, fileName, inputStream) =>
          new InMemFileParamHolder(fieldName, contentType, fileName, Helpers.readWholeStream(inputStream))

  private object _mimeHeaders extends TransientRequestVar[Box[Map[String, List[String]]]](Empty)

  /**
* Returns any mimeHeaders for the currently invoked handleMimeFile.
*/
  def mimeHeaders = _mimeHeaders.get

  private[http] def withMimeHeaders[T](map: Map[String, List[String]])(f: => T): T = _mimeHeaders.doWith(Full(map))(f)

  /**
* Holds the last update time of the Comet request. Based on this server may return HTTP 304 status
* indicating the client to used the cached information.
*/
  @volatile var cometScriptUpdateTime: LiftSession => Long = session => {
    object when extends SessionVar[Long](millis)
    when.is
  }

  /**
* The name of the Ajax script that manages Ajax requests.
*/
  @volatile var ajaxScriptName: () => String = () => "liftAjax.js"

  /**
* The name of the Comet script that manages Comet requests.
*/
  @volatile var cometScriptName: () => String = () => "cometAjax.js"

  /**
* Returns the Comet script as a JavaScript response
*/
  @volatile var serveCometScript: (LiftSession, Req) => Box[LiftResponse] =
  (liftSession, requestState) => {
    val modTime = cometScriptUpdateTime(liftSession)

    requestState.testFor304(modTime) or
            Full(JavaScriptResponse(renderCometScript(liftSession),
              List("Last-Modified" -> toInternetDate(modTime),
                   "Expires" -> toInternetDate(modTime + 10.minutes),
                   "Date" -> Helpers.nowAsInternetDate,
                   "Pragma" -> "",
                   "Cache-Control" -> ""),
              Nil, 200))
  }

  /**
* Returns the Ajax script as a JavaScript response
*/
  @volatile var serveAjaxScript: (LiftSession, Req) => Box[LiftResponse] =
  (liftSession, requestState) => {
    val modTime = ajaxScriptUpdateTime(liftSession)

    requestState.testFor304(modTime) or
            Full(JavaScriptResponse(renderAjaxScript(liftSession),
              List("Last-Modified" -> toInternetDate(modTime),
                "Expires" -> toInternetDate(modTime + 10.minutes)),
              Nil, 200))
  }

  @volatile var templateCache: Box[TemplateCache[(Locale, List[String]), NodeSeq]] = Empty

  /**
* A function to format a Date... can be replaced by a function that is user-specific
Replaced by dateTimeConverter
*/
  @deprecated("Replaced by dateTimeConverter", "2.3")
  @volatile var formatDate: Date => String = date => date match {
    case null => LiftRules.dateTimeConverter.vend.formatDate(new Date(0L))
    case s => toInternetDate(s)
  }

  /**
* A function that parses a String into a Date... can be replaced by something that's user-specific
Replaced by dateTimeConverter
*/
  @deprecated("Replaced by dateTimeConverter", "2.3")
  @volatile var parseDate: String => Box[Date] = str => str match {
    case null => Empty
    case s => Helpers.toDate(s)
  }

  val dateTimeConverter: FactoryMaker[DateTimeConverter] = new FactoryMaker[DateTimeConverter]( () => DefaultDateTimeConverter ) {}

  /**
* This variable controls whether RequestVars that have been set but not subsequently
* read will be logged in Dev mode. Logging can be disabled at the per-RequestVar level
* via RequestVar.logUnreadVal
*
* @see RequestVar#logUnreadVal
*/
  @volatile var logUnreadRequestVars = true

  /** Controls whether or not the service handling timing messages (Service request (GET) ... took ... Milliseconds) are logged. Defaults to true. */
  @volatile var logServiceRequestTiming = true

  /** Provides a function that returns random names for form variables, page ids, callbacks, etc. */
  @volatile var funcNameGenerator: () => String = defaultFuncNameGenerator(Props.mode)

  import provider.servlet._
  import containers._

  /**
* Provides the async provider instance responsible for suspending/resuming requests
*/
  @deprecated("Register your povider via addSyncProvider", "2.4")
  var servletAsyncProvider: (HTTPRequest) => ServletAsyncProvider = null // (req) => new Jetty6AsyncProvider(req)

  /**
* The meta for the detected AsyncProvider given the container we're running in
*/
  lazy val asyncProviderMeta: Box[AsyncProviderMeta] =
    asyncMetaList.find(_.suspendResumeSupport_?)

  /**
* A function that converts the current Request into an AsyncProvider.
*/
  lazy val theServletAsyncProvider: Box[HTTPRequest => ServletAsyncProvider] =
    (Box !! servletAsyncProvider) or asyncProviderMeta.flatMap(_.providerFunction)

  private var asyncMetaList: List[AsyncProviderMeta] =
    List(Servlet30AsyncProvider, Jetty6AsyncProvider, Jetty7AsyncProvider)

  /**
* Register an AsyncMeta provider in addition to the default
* Jetty6, Jetty7, and Servlet 3.0 providers
*/
  def addSyncProvider(asyncMeta: AsyncProviderMeta) {
    if (doneBoot) throw new IllegalStateException("Cannot modify after boot.")
    asyncMetaList ::= asyncMeta
  }

  def updateAsyncMetaList(f: List[AsyncProviderMeta] => List[AsyncProviderMeta]) {
    if (doneBoot) throw new IllegalStateException("Cannot modify after boot.")
    asyncMetaList = f(asyncMetaList)

  }


  private def ctor() {
    appendGlobalFormBuilder(FormBuilderLocator[String]((value, setter) => SHtml.text(value, setter)))
    appendGlobalFormBuilder(FormBuilderLocator[Int]((value, setter) => SHtml.text(value.toString, s => Helpers.asInt(s).foreach((setter)))))
    appendGlobalFormBuilder(FormBuilderLocator[Boolean]((value, setter) => SHtml.checkbox(value, s => setter(s))))

    import net.liftweb.builtin.snippet._

    snippetDispatch.append(
      Map("CSS" -> CSS, "Msgs" -> Msgs, "Msg" -> Msg,
        "Menu" -> Menu, "css" -> CSS, "msgs" -> Msgs, "msg" -> Msg,
        "menu" -> Menu,
        "children" -> Children,
        "comet" -> Comet, "form" -> Form, "ignore" -> Ignore, "loc" -> Loc,
        "surround" -> Surround,
        "test_cond" -> TestCond,
        "TestCond" -> TestCond,
        "testcond" -> TestCond,
        "embed" -> Embed,
        "tail" -> Tail,
        "head" -> Head,
        "Head" -> Head,
        "with-param" -> WithParam,
        "withparam" -> WithParam,
        "WithParam" -> WithParam,
        "bind-at" -> WithParam,
        "VersionInfo" -> VersionInfo,
        "versioninfo" -> VersionInfo,
        "version_info" -> VersionInfo,
        "SkipDocType" -> SkipDocType,
        "skipdoctype" -> SkipDocType,
        "skip_doc_type" -> SkipDocType,
        "xml_group" -> XmlGroup,
        "XmlGroup" -> XmlGroup,
        "xmlgroup" -> XmlGroup,
        "lazy-load" -> LazyLoad,
        "LazyLoad" -> LazyLoad,
        "lazyload" -> LazyLoad,
        "html5" -> HTML5,
        "HTML5" -> HTML5,
        "with-resource-id" -> WithResourceId
        ))
  }
  ctor()

  object RulesSeq {
    def apply[T]: RulesSeq[T] = new RulesSeq[T]()
  }

/**
* Generic container used mainly for adding functions
*
*/
class RulesSeq[T] {
  @volatile private var rules: List[T] = Nil
  private val pre = new ThreadGlobal[List[T]]
  private val app = new ThreadGlobal[List[T]]
  private val cur = new ThreadGlobal[List[T]]

  private def safe_?(f: => Any) {
    doneBoot match {
      case false => f
      case _ => throw new IllegalStateException("Cannot modify after boot.");
    }
  }

  /**
* Sometimes it's useful to change the rule for the duration of
* a thread... prepend a rule and execute the code within
* a scope with the prepended rule
*/
  def prependWith[A](what: T)(f: => A): A = prependWith(List(what))(f)

  /**
* Sometimes it's useful to change the rule for the duration of
* a thread... append a rule and execute the code within
* a scope with the appended rule
*/
  def appendWith[A](what: T)(f: => A): A = appendWith(List(what))(f)

  /**
* Sometimes it's useful to change the rule for the duration of
* a thread... prepend rules and execute the code within
* a scope with the prepended rules
*/
  def prependWith[A](what: List[T])(f: => A): A = {
    val newList = pre.value match {
      case null => what
      case Nil => what
      case x => what ::: x
    }
    pre.doWith(newList)(doCur(f))
  }

  /**
* Sometimes it's useful to change the rules for the duration of
* a thread... append rules and execute the code within
* a scope with the appended rules
*/
  def appendWith[A](what: List[T])(f: => A): A = {
    val newList = pre.value match {
      case null => what
      case Nil => what
      case x => x ::: what
    }
    app.doWith(newList)(doCur(f))
  }

  /**
* Precompute the current rule set
*/
  private def doCur[A](f: => A): A = {
    cur.doWith((pre.value, app.value) match {
    case (null, null) | (null, Nil) | (Nil, null) | (Nil, Nil) => rules
    case (null, xs) => rules ::: xs
    case (xs, null) => xs ::: rules
    case (p, a) => p ::: rules ::: a
  })(f)
  }

  def toList: List[T] = cur.value match {
    case null => rules
    case xs => xs
  }

  def prepend(r: T): RulesSeq[T] = {
    safe_? {
      rules = r :: rules
    }
    this
  }

  private[http] def remove(f: T => Boolean) {
    safe_? {
      rules = rules.filterNot(f)
    }
  }

  def append(r: T): RulesSeq[T] = {
    safe_? {
      rules = rules ::: List(r)
    }
    this
  }
}

trait FirstBox[F, T] {
  self: RulesSeq[F => Box[T]] =>

  def firstFull(param: F): Box[T] = {
    def finder(in: List[F => Box[T]]): Box[T] = in match {
      case Nil => Empty
      case x :: xs => x(param) match {
        case Full(r) => Full(r)
        case _ => finder(xs)
      }
    }

    finder(toList)
  }
}

}

sealed trait NotFound

case object DefaultNotFound extends NotFound

final case class NotFoundAsResponse(response: LiftResponse) extends NotFound

final case class NotFoundAsTemplate(path: ParsePath) extends NotFound

final case class NotFoundAsNode(node: NodeSeq) extends NotFound

final case class BreakOut()

abstract class Bootable {
  def boot(): Unit;
}

/*
/**
* Factory object for RulesSeq instances
*/
object RulesSeq {
def apply[T]: RulesSeq[T] = new RulesSeq[T]
}
*/


private[http] case object DefaultBootstrap extends Bootable {
  def boot(): Unit = {
    val f = createInvoker("boot", Class.forName("bootstrap.liftweb.Boot").newInstance.asInstanceOf[AnyRef])
    f.map {f => f()}
  }
}

/**
* Holds the Comet identification information
*/
trait CometVersionPair {
  def guid: String

  def version: Long
}

case class CVP(guid: String, version: Long) extends CometVersionPair

case class XHTMLValidationError(msg: String, line: Int, col: Int)

trait XHtmlValidator extends Function1[Node, List[XHTMLValidationError]]

object StrictXHTML1_0Validator extends GenericValidator {
  def ngurl = "http://www.w3.org/2002/08/xhtml/xhtml1-strict.xsd"
}

abstract class GenericValidator extends XHtmlValidator with Loggable {
  import javax.xml.validation._
  import javax.xml._
  import XMLConstants._
  import java.net.URL
  import javax.xml.transform.dom._
  import javax.xml.transform.stream._
  import java.io.ByteArrayInputStream

  private lazy val sf = SchemaFactory.newInstance(W3C_XML_SCHEMA_NS_URI)

  protected def ngurl: String

  private lazy val schema = tryo(sf.newSchema(new URL(ngurl)))

  def apply(in: Node): List[XHTMLValidationError] = {
    (for{
      sc <- schema
      v <- tryo(sc.newValidator)
      source = new StreamSource(new ByteArrayInputStream(in.toString.getBytes("UTF-8")))
    } yield try {
        v.validate(source)
        Nil
      } catch {
        case e: org.xml.sax.SAXParseException =>
          List(XHTMLValidationError(e.getMessage, e.getLineNumber, e.getColumnNumber))
      }) match {
      case Full(x) => x
      case Failure(msg, _, _) =>
        logger.info("XHTML Validation Failure: " + msg)
        Nil
      case _ => Nil
    }
  }
}


object TransitionalXHTML1_0Validator extends GenericValidator {
  def ngurl = "http://www.w3.org/2002/08/xhtml/xhtml1-transitional.xsd"
}


trait FormVendor {
  /**
* Given a type manifest, vend a form
*/
  def vendForm[T](implicit man: Manifest[T]): Box[(T, T => Any) => NodeSeq] = {
    val name = man.toString
    val first: Option[List[FormBuilderLocator[_]]] = requestForms.is.get(name) orElse sessionForms.is.get(name)

    first match {
      case Some(x :: _) => Full(x.func.asInstanceOf[(T, T => Any) => NodeSeq])
      case _ => if (globalForms.containsKey(name)) {
        globalForms.get(name).headOption.map(_.func.asInstanceOf[(T, T => Any) => NodeSeq])
      } else Empty
    }
  }

  private val globalForms: CHash[String, List[FormBuilderLocator[_]]] = new CHash

  def prependGlobalFormBuilder[T](builder: FormBuilderLocator[T]) {
    globalForms.synchronized {
      val name = builder.manifest.toString
      if (globalForms.containsKey(name)) {
        globalForms.put(name, builder :: globalForms.get(name))
      } else {
        globalForms.put(name, List(builder))
      }
    }
  }

  def appendGlobalFormBuilder[T](builder: FormBuilderLocator[T]) {
    globalForms.synchronized {
      val name = builder.manifest.toString
      if (globalForms.containsKey(name)) {
        globalForms.put(name, builder :: globalForms.get(name))
      } else {
        globalForms.put(name, List(builder))
      }
    }
  }

  def prependSessionFormBuilder[T](builder: FormBuilderLocator[T]) {
    sessionForms.set(prependBuilder(builder, sessionForms))
  }

  def appendSessionFormBuilder[T](builder: FormBuilderLocator[T]) {
    sessionForms.set(appendBuilder(builder, sessionForms))
  }

  def prependRequestFormBuilder[T](builder: FormBuilderLocator[T]) {
    requestForms.set(prependBuilder(builder, requestForms))
  }

  def appendRequestFormBuilder[T](builder: FormBuilderLocator[T]) {
    requestForms.set(appendBuilder(builder, requestForms))
  }

  def doWith[F, T](builder: FormBuilderLocator[T])(f: => F): F =
    requestForms.doWith(prependBuilder(builder, requestForms))(f)


  private def prependBuilder(builder: FormBuilderLocator[_], to: Map[String, List[FormBuilderLocator[_]]]):
  Map[String, List[FormBuilderLocator[_]]] = {
    val name = builder.manifest.toString
    to + (name -> (builder :: to.getOrElse(name, Nil)))
  }

  private def appendBuilder(builder: FormBuilderLocator[_], to: Map[String, List[FormBuilderLocator[_]]]):
  Map[String, List[FormBuilderLocator[_]]] = {
    val name = builder.manifest.toString
    to + (name -> (builder :: to.getOrElse(name, Nil)))
  }


  private object sessionForms extends SessionVar[Map[String, List[FormBuilderLocator[_]]]](Map())
  private object requestForms extends SessionVar[Map[String, List[FormBuilderLocator[_]]]](Map())
}

Something went wrong with that request. Please try again.