Mirroring servlet-spec 4.0.1 at 5574e9b

See https://github.com/javaee/servlet-spec/releases/tag/4.0.1

Change-Id: I40d8dcc8c5740e7af051a54bbd9fc3aca77a67d7
diff --git a/third_party/servlet-spec/CONTRIBUTING.md b/third_party/servlet-spec/CONTRIBUTING.md
new file mode 100644
index 0000000..7630913
--- /dev/null
+++ b/third_party/servlet-spec/CONTRIBUTING.md
@@ -0,0 +1,30 @@
+---
+
+---
+
+# Source Code Submissions 
+We welcome your contributions and look forward to collaborating with you. We can only accept source code repository 
+submissions from users who have signed and returned the Oracle 
+Contributor Agreement. You will find details and the agreement to sign at this OTN web page: 
+[Oracle Contributor Agreement](http://www.oracle.com/technetwork/community/oca-486395.html). 
+
+# Other Contributions
+For all project Submissions other than source code repository contributions, the following also applies: Oracle does 
+not claim ownership of Your Submissions. However, in order to fulfill 
+the purposes of this project, You must give Oracle and all Users 
+the right to post, access, discuss, use, publish, disseminate, and refine 
+Your Submissions. 
+
+In legalese: *You hereby grant to Oracle and all 
+Users a royalty-free, perpetual, irrevocable, worldwide, non-exclusive, 
+and fully sub-licensable right and license, under Your intellectual 
+property rights, to reproduce, modify, adapt, publish, translate, create 
+derivative works from, distribute, perform, display, and use Your 
+Submissions (in whole or part) and to incorporate or implement them in 
+other works in any form, media, or technology now known or later 
+developed, all subject to the obligation to retain any copyright notices 
+included in Your Submissions. All Users, Oracle, and their 
+sublicensees are responsible for any modifications they make to the 
+Submissions of others.*
+
+Copyright © 2017 Oracle and/or its affiliates. All rights reserved.
diff --git a/third_party/servlet-spec/LICENSE b/third_party/servlet-spec/LICENSE
new file mode 100644
index 0000000..b1c74f9
--- /dev/null
+++ b/third_party/servlet-spec/LICENSE
@@ -0,0 +1,759 @@
+COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.1
+
+1. Definitions.
+
+    1.1. "Contributor" means each individual or entity that creates or
+    contributes to the creation of Modifications.
+
+    1.2. "Contributor Version" means the combination of the Original
+    Software, prior Modifications used by a Contributor (if any), and
+    the Modifications made by that particular Contributor.
+
+    1.3. "Covered Software" means (a) the Original Software, or (b)
+    Modifications, or (c) the combination of files containing Original
+    Software with files containing Modifications, in each case including
+    portions thereof.
+
+    1.4. "Executable" means the Covered Software in any form other than
+    Source Code.
+
+    1.5. "Initial Developer" means the individual or entity that first
+    makes Original Software available under this License.
+
+    1.6. "Larger Work" means a work which combines Covered Software or
+    portions thereof with code not governed by the terms of this License.
+
+    1.7. "License" means this document.
+
+    1.8. "Licensable" means having the right to grant, to the maximum
+    extent possible, whether at the time of the initial grant or
+    subsequently acquired, any and all of the rights conveyed herein.
+
+    1.9. "Modifications" means the Source Code and Executable form of
+    any of the following:
+
+    A. Any file that results from an addition to, deletion from or
+    modification of the contents of a file containing Original Software
+    or previous Modifications;
+
+    B. Any new file that contains any part of the Original Software or
+    previous Modification; or
+
+    C. Any new file that is contributed or otherwise made available
+    under the terms of this License.
+
+    1.10. "Original Software" means the Source Code and Executable form
+    of computer software code that is originally released under this
+    License.
+
+    1.11. "Patent Claims" means any patent claim(s), now owned or
+    hereafter acquired, including without limitation, method, process,
+    and apparatus claims, in any patent Licensable by grantor.
+
+    1.12. "Source Code" means (a) the common form of computer software
+    code in which modifications are made and (b) associated
+    documentation included in or with such code.
+
+    1.13. "You" (or "Your") means an individual or a legal entity
+    exercising rights under, and complying with all of the terms of,
+    this License. For legal entities, "You" includes any entity which
+    controls, is controlled by, or is under common control with You. For
+    purposes of this definition, "control" means (a) the power, direct
+    or indirect, to cause the direction or management of such entity,
+    whether by contract or otherwise, or (b) ownership of more than
+    fifty percent (50%) of the outstanding shares or beneficial
+    ownership of such entity.
+
+2. License Grants.
+
+    2.1. The Initial Developer Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and subject
+    to third party intellectual property claims, the Initial Developer
+    hereby grants You a world-wide, royalty-free, non-exclusive license:
+
+    (a) under intellectual property rights (other than patent or
+    trademark) Licensable by Initial Developer, to use, reproduce,
+    modify, display, perform, sublicense and distribute the Original
+    Software (or portions thereof), with or without Modifications,
+    and/or as part of a Larger Work; and
+
+    (b) under Patent Claims infringed by the making, using or selling of
+    Original Software, to make, have made, use, practice, sell, and
+    offer for sale, and/or otherwise dispose of the Original Software
+    (or portions thereof).
+
+    (c) The licenses granted in Sections 2.1(a) and (b) are effective on
+    the date Initial Developer first distributes or otherwise makes the
+    Original Software available to a third party under the terms of this
+    License.
+
+    (d) Notwithstanding Section 2.1(b) above, no patent license is
+    granted: (1) for code that You delete from the Original Software, or
+    (2) for infringements caused by: (i) the modification of the
+    Original Software, or (ii) the combination of the Original Software
+    with other software or devices.
+
+    2.2. Contributor Grant.
+
+    Conditioned upon Your compliance with Section 3.1 below and subject
+    to third party intellectual property claims, each Contributor hereby
+    grants You a world-wide, royalty-free, non-exclusive license:
+
+    (a) under intellectual property rights (other than patent or
+    trademark) Licensable by Contributor to use, reproduce, modify,
+    display, perform, sublicense and distribute the Modifications
+    created by such Contributor (or portions thereof), either on an
+    unmodified basis, with other Modifications, as Covered Software
+    and/or as part of a Larger Work; and
+
+    (b) under Patent Claims infringed by the making, using, or selling
+    of Modifications made by that Contributor either alone and/or in
+    combination with its Contributor Version (or portions of such
+    combination), to make, use, sell, offer for sale, have made, and/or
+    otherwise dispose of: (1) Modifications made by that Contributor (or
+    portions thereof); and (2) the combination of Modifications made by
+    that Contributor with its Contributor Version (or portions of such
+    combination).
+
+    (c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective
+    on the date Contributor first distributes or otherwise makes the
+    Modifications available to a third party.
+
+    (d) Notwithstanding Section 2.2(b) above, no patent license is
+    granted: (1) for any code that Contributor has deleted from the
+    Contributor Version; (2) for infringements caused by: (i) third
+    party modifications of Contributor Version, or (ii) the combination
+    of Modifications made by that Contributor with other software
+    (except as part of the Contributor Version) or other devices; or (3)
+    under Patent Claims infringed by Covered Software in the absence of
+    Modifications made by that Contributor.
+
+3. Distribution Obligations.
+
+    3.1. Availability of Source Code.
+
+    Any Covered Software that You distribute or otherwise make available
+    in Executable form must also be made available in Source Code form
+    and that Source Code form must be distributed only under the terms
+    of this License. You must include a copy of this License with every
+    copy of the Source Code form of the Covered Software You distribute
+    or otherwise make available. You must inform recipients of any such
+    Covered Software in Executable form as to how they can obtain such
+    Covered Software in Source Code form in a reasonable manner on or
+    through a medium customarily used for software exchange.
+
+    3.2. Modifications.
+
+    The Modifications that You create or to which You contribute are
+    governed by the terms of this License. You represent that You
+    believe Your Modifications are Your original creation(s) and/or You
+    have sufficient rights to grant the rights conveyed by this License.
+
+    3.3. Required Notices.
+
+    You must include a notice in each of Your Modifications that
+    identifies You as the Contributor of the Modification. You may not
+    remove or alter any copyright, patent or trademark notices contained
+    within the Covered Software, or any notices of licensing or any
+    descriptive text giving attribution to any Contributor or the
+    Initial Developer.
+
+    3.4. Application of Additional Terms.
+
+    You may not offer or impose any terms on any Covered Software in
+    Source Code form that alters or restricts the applicable version of
+    this License or the recipients' rights hereunder. You may choose to
+    offer, and to charge a fee for, warranty, support, indemnity or
+    liability obligations to one or more recipients of Covered Software.
+    However, you may do so only on Your own behalf, and not on behalf of
+    the Initial Developer or any Contributor. You must make it
+    absolutely clear that any such warranty, support, indemnity or
+    liability obligation is offered by You alone, and You hereby agree
+    to indemnify the Initial Developer and every Contributor for any
+    liability incurred by the Initial Developer or such Contributor as a
+    result of warranty, support, indemnity or liability terms You offer.
+
+    3.5. Distribution of Executable Versions.
+
+    You may distribute the Executable form of the Covered Software under
+    the terms of this License or under the terms of a license of Your
+    choice, which may contain terms different from this License,
+    provided that You are in compliance with the terms of this License
+    and that the license for the Executable form does not attempt to
+    limit or alter the recipient's rights in the Source Code form from
+    the rights set forth in this License. If You distribute the Covered
+    Software in Executable form under a different license, You must make
+    it absolutely clear that any terms which differ from this License
+    are offered by You alone, not by the Initial Developer or
+    Contributor. You hereby agree to indemnify the Initial Developer and
+    every Contributor for any liability incurred by the Initial
+    Developer or such Contributor as a result of any such terms You offer.
+
+    3.6. Larger Works.
+
+    You may create a Larger Work by combining Covered Software with
+    other code not governed by the terms of this License and distribute
+    the Larger Work as a single product. In such a case, You must make
+    sure the requirements of this License are fulfilled for the Covered
+    Software.
+
+4. Versions of the License.
+
+    4.1. New Versions.
+
+    Oracle is the initial license steward and may publish revised and/or
+    new versions of this License from time to time. Each version will be
+    given a distinguishing version number. Except as provided in Section
+    4.3, no one other than the license steward has the right to modify
+    this License.
+
+    4.2. Effect of New Versions.
+
+    You may always continue to use, distribute or otherwise make the
+    Covered Software available under the terms of the version of the
+    License under which You originally received the Covered Software. If
+    the Initial Developer includes a notice in the Original Software
+    prohibiting it from being distributed or otherwise made available
+    under any subsequent version of the License, You must distribute and
+    make the Covered Software available under the terms of the version
+    of the License under which You originally received the Covered
+    Software. Otherwise, You may also choose to use, distribute or
+    otherwise make the Covered Software available under the terms of any
+    subsequent version of the License published by the license steward.
+
+    4.3. Modified Versions.
+
+    When You are an Initial Developer and You want to create a new
+    license for Your Original Software, You may create and use a
+    modified version of this License if You: (a) rename the license and
+    remove any references to the name of the license steward (except to
+    note that the license differs from this License); and (b) otherwise
+    make it clear that the license contains terms which differ from this
+    License.
+
+5. DISCLAIMER OF WARRANTY.
+
+    COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+    WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED,
+    INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE
+    IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR
+    NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF
+    THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE
+    DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY
+    OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING,
+    REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN
+    ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS
+    AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+6. TERMINATION.
+
+    6.1. This License and the rights granted hereunder will terminate
+    automatically if You fail to comply with terms herein and fail to
+    cure such breach within 30 days of becoming aware of the breach.
+    Provisions which, by their nature, must remain in effect beyond the
+    termination of this License shall survive.
+
+    6.2. If You assert a patent infringement claim (excluding
+    declaratory judgment actions) against Initial Developer or a
+    Contributor (the Initial Developer or Contributor against whom You
+    assert such claim is referred to as "Participant") alleging that the
+    Participant Software (meaning the Contributor Version where the
+    Participant is a Contributor or the Original Software where the
+    Participant is the Initial Developer) directly or indirectly
+    infringes any patent, then any and all rights granted directly or
+    indirectly to You by such Participant, the Initial Developer (if the
+    Initial Developer is not the Participant) and all Contributors under
+    Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice
+    from Participant terminate prospectively and automatically at the
+    expiration of such 60 day notice period, unless if within such 60
+    day period You withdraw Your claim with respect to the Participant
+    Software against such Participant either unilaterally or pursuant to
+    a written agreement with Participant.
+
+    6.3. If You assert a patent infringement claim against Participant
+    alleging that the Participant Software directly or indirectly
+    infringes any patent where such claim is resolved (such as by
+    license or settlement) prior to the initiation of patent
+    infringement litigation, then the reasonable value of the licenses
+    granted by such Participant under Sections 2.1 or 2.2 shall be taken
+    into account in determining the amount or value of any payment or
+    license.
+
+    6.4. In the event of termination under Sections 6.1 or 6.2 above,
+    all end user licenses that have been validly granted by You or any
+    distributor hereunder prior to termination (excluding licenses
+    granted to You by any distributor) shall survive termination.
+
+7. LIMITATION OF LIABILITY.
+
+    UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+    (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE
+    INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF
+    COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE
+    TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR
+    CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT
+    LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER
+    FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR
+    LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE
+    POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT
+    APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH
+    PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH
+    LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR
+    LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION
+    AND LIMITATION MAY NOT APPLY TO YOU.
+
+8. U.S. GOVERNMENT END USERS.
+
+    The Covered Software is a "commercial item," as that term is defined
+    in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+    software" (as that term is defined at 48 C.F.R. §
+    252.227-7014(a)(1)) and "commercial computer software documentation"
+    as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent
+    with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4
+    (June 1995), all U.S. Government End Users acquire Covered Software
+    with only those rights set forth herein. This U.S. Government Rights
+    clause is in lieu of, and supersedes, any other FAR, DFAR, or other
+    clause or provision that addresses Government rights in computer
+    software under this License.
+
+9. MISCELLANEOUS.
+
+    This License represents the complete agreement concerning subject
+    matter hereof. If any provision of this License is held to be
+    unenforceable, such provision shall be reformed only to the extent
+    necessary to make it enforceable. This License shall be governed by
+    the law of the jurisdiction specified in a notice contained within
+    the Original Software (except to the extent applicable law, if any,
+    provides otherwise), excluding such jurisdiction's conflict-of-law
+    provisions. Any litigation relating to this License shall be subject
+    to the jurisdiction of the courts located in the jurisdiction and
+    venue specified in a notice contained within the Original Software,
+    with the losing party responsible for costs, including, without
+    limitation, court costs and reasonable attorneys' fees and expenses.
+    The application of the United Nations Convention on Contracts for
+    the International Sale of Goods is expressly excluded. Any law or
+    regulation which provides that the language of a contract shall be
+    construed against the drafter shall not apply to this License. You
+    agree that You alone are responsible for compliance with the United
+    States export administration regulations (and the export control
+    laws and regulation of any other countries) when You use, distribute
+    or otherwise make available any Covered Software.
+
+10. RESPONSIBILITY FOR CLAIMS.
+
+    As between Initial Developer and the Contributors, each party is
+    responsible for claims and damages arising, directly or indirectly,
+    out of its utilization of rights under this License and You agree to
+    work with Initial Developer and Contributors to distribute such
+    responsibility on an equitable basis. Nothing herein is intended or
+    shall be deemed to constitute any admission of liability.
+
+------------------------------------------------------------------------
+
+NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION
+LICENSE (CDDL)
+
+The code released under the CDDL shall be governed by the laws of the
+State of California (excluding conflict-of-law provisions). Any
+litigation relating to this License shall be subject to the jurisdiction
+of the Federal Courts of the Northern District of California and the
+state courts of the State of California, with venue lying in Santa Clara
+County, California.
+
+
+
+  The GNU General Public License (GPL) Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor
+Boston, MA 02110-1335
+USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+
+Preamble
+
+The licenses for most software are designed to take away your freedom to
+share and change it. By contrast, the GNU General Public License is
+intended to guarantee your freedom to share and change free software--to
+make sure the software is free for all its users. This General Public
+License applies to most of the Free Software Foundation's software and
+to any other program whose authors commit to using it. (Some other Free
+Software Foundation software is covered by the GNU Library General
+Public License instead.) You can apply it to your programs, too.
+
+When we speak of free software, we are referring to freedom, not price.
+Our General Public Licenses are designed to make sure that you have the
+freedom to distribute copies of free software (and charge for this
+service if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs; and that you know you can do these things.
+
+To protect your rights, we need to make restrictions that forbid anyone
+to deny you these rights or to ask you to surrender the rights. These
+restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+For example, if you distribute copies of such a program, whether gratis
+or for a fee, you must give the recipients all the rights that you have.
+You must make sure that they, too, receive or can get the source code.
+And you must show them these terms so they know their rights.
+
+We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+Finally, any free program is threatened constantly by software patents.
+We wish to avoid the danger that redistributors of a free program will
+individually obtain patent licenses, in effect making the program
+proprietary. To prevent this, we have made it clear that any patent must
+be licensed for everyone's free use or not licensed at all.
+
+The precise terms and conditions for copying, distribution and
+modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+0. This License applies to any program or other work which contains a
+notice placed by the copyright holder saying it may be distributed under
+the terms of this General Public License. The "Program", below, refers
+to any such program or work, and a "work based on the Program" means
+either the Program or any derivative work under copyright law: that is
+to say, a work containing the Program or a portion of it, either
+verbatim or with modifications and/or translated into another language.
+(Hereinafter, translation is included without limitation in the term
+"modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of running
+the Program is not restricted, and the output from the Program is
+covered only if its contents constitute a work based on the Program
+(independent of having been made by running the Program). Whether that
+is true depends on what the Program does.
+
+1. You may copy and distribute verbatim copies of the Program's source
+code as you receive it, in any medium, provided that you conspicuously
+and appropriately publish on each copy an appropriate copyright notice
+and disclaimer of warranty; keep intact all the notices that refer to
+this License and to the absence of any warranty; and give any other
+recipients of the Program a copy of this License along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+2. You may modify your copy or copies of the Program or any portion of
+it, thus forming a work based on the Program, and copy and distribute
+such modifications or work under the terms of Section 1 above, provided
+that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any part
+    thereof, to be licensed as a whole at no charge to all third parties
+    under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a notice
+    that there is no warranty (or else, saying that you provide a
+    warranty) and that users may redistribute the program under these
+    conditions, and telling the user how to view a copy of this License.
+    (Exception: if the Program itself is interactive but does not
+    normally print such an announcement, your work based on the Program
+    is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program, and
+can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based on
+the Program, the distribution of the whole must be on the terms of this
+License, whose permissions for other licensees extend to the entire
+whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of a
+storage or distribution medium does not bring the other work under the
+scope of this License.
+
+3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections 1
+    and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your cost
+    of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer to
+    distribute corresponding source code. (This alternative is allowed
+    only for noncommercial distribution and only if you received the
+    program in object code or executable form with such an offer, in
+    accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source code
+means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to control
+compilation and installation of the executable. However, as a special
+exception, the source code distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies the
+executable.
+
+If distribution of executable or object code is made by offering access
+to copy from a designated place, then offering equivalent access to copy
+the source code from the same place counts as distribution of the source
+code, even though third parties are not compelled to copy the source
+along with the object code.
+
+4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt otherwise
+to copy, modify, sublicense or distribute the Program is void, and will
+automatically terminate your rights under this License. However, parties
+who have received copies, or rights, from you under this License will
+not have their licenses terminated so long as such parties remain in
+full compliance.
+
+5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and all
+its terms and conditions for copying, distributing or modifying the
+Program or works based on it.
+
+6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further restrictions
+on the recipients' exercise of the rights granted herein. You are not
+responsible for enforcing compliance by third parties to this License.
+
+7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot distribute
+so as to satisfy simultaneously your obligations under this License and
+any other pertinent obligations, then as a consequence you may not
+distribute the Program at all. For example, if a patent license would
+not permit royalty-free redistribution of the Program by all those who
+receive copies directly or indirectly through you, then the only way you
+could satisfy both it and this License would be to refrain entirely from
+distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is implemented
+by public license practices. Many people have made generous
+contributions to the wide range of software distributed through that
+system in reliance on consistent application of that system; it is up to
+the author/donor to decide if he or she is willing to distribute
+software through any other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is believed to be
+a consequence of the rest of this License.
+
+8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License may
+add an explicit geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or among countries
+not thus excluded. In such case, this License incorporates the
+limitation as if written in the body of this License.
+
+9. The Free Software Foundation may publish revised and/or new
+versions of the General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Program does not specify a version
+number of this License, you may choose any version ever published by the
+Free Software Foundation.
+
+10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the
+author to ask for permission. For software which is copyrighted by the
+Free Software Foundation, write to the Free Software Foundation; we
+sometimes make exceptions for this. Our decision will be guided by the
+two goals of preserving the free status of all derivatives of our free
+software and of promoting the sharing and reuse of software generally.
+
+NO WARRANTY
+
+11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
+ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH
+YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL
+NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR
+DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL
+DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM
+(INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED
+INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF
+THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
+OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+
+END OF TERMS AND CONDITIONS
+
+How to Apply These Terms to Your New Programs
+
+If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+To do so, attach the following notices to the program. It is safest to
+attach them to the start of each source file to most effectively convey
+the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    One line to give the program's name and a brief idea of what it does.
+    Copyright (C) <year> <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful, but
+    WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+    General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type
+    `show w'. This is free software, and you are welcome to redistribute
+    it under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the
+appropriate parts of the General Public License. Of course, the commands
+you use may be called something other than `show w' and `show c'; they
+could even be mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+    Yoyodyne, Inc., hereby disclaims all copyright interest in the
+    program `Gnomovision' (which makes passes at compilers) written by
+    James Hacker.
+
+    signature of Ty Coon, 1 April 1989
+    Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications
+with the library. If this is what you want to do, use the GNU Library
+General Public License instead of this License.
+
+#
+
+Certain source files distributed by Oracle America, Inc. and/or its
+affiliates are subject to the following clarification and special
+exception to the GPLv2, based on the GNU Project exception for its
+Classpath libraries, known as the GNU Classpath Exception, but only
+where Oracle has expressly included in the particular source file's
+header the words "Oracle designates this particular file as subject to
+the "Classpath" exception as provided by Oracle in the LICENSE file
+that accompanied this code."
+
+You should also note that Oracle includes multiple, independent
+programs in this software package. Some of those programs are provided
+under licenses deemed incompatible with the GPLv2 by the Free Software
+Foundation and others.  For example, the package includes programs
+licensed under the Apache License, Version 2.0.  Such programs are
+licensed to you under their original licenses.
+
+Oracle facilitates your further distribution of this package by adding
+the Classpath Exception to the necessary parts of its GPLv2 code, which
+permits you to use that code in combination with other independent
+modules not licensed under the GPLv2.  However, note that this would
+not permit you to commingle code under an incompatible license with
+Oracle's GPLv2 licensed code by, for example, cutting and pasting such
+code into a file also containing Oracle's GPLv2 licensed code and then
+distributing the result.  Additionally, if you were to remove the
+Classpath Exception from any of the files to which it applies and
+distribute the result, you would likely be required to license some or
+all of the other code in that distribution under the GPLv2 as well, and
+since the GPLv2 is incompatible with the license terms of some items
+included in the distribution by Oracle, removing the Classpath
+Exception could therefore effectively compromise your ability to
+further distribute the package.
+
+Proceed with caution and we recommend that you obtain the advice of a
+lawyer skilled in open source matters before removing the Classpath
+Exception or making modifications to this package which may
+subsequently be redistributed and/or involve the use of third party
+software.
+
+CLASSPATH EXCEPTION
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License version 2 cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from or
+based on this library.  If you modify this library, you may extend this
+exception to your version of the library, but you are not obligated to
+do so.  If you do not wish to do so, delete this exception statement
+from your version.
diff --git a/third_party/servlet-spec/README.md b/third_party/servlet-spec/README.md
new file mode 100644
index 0000000..5cd7451
--- /dev/null
+++ b/third_party/servlet-spec/README.md
@@ -0,0 +1,22 @@
+Java Servlet API
+================
+
+Building
+--------
+
+Prerequisites:
+
+* JDK8+
+* Maven 3.0.3+
+
+Run the build: 
+
+`mvn install`
+
+The build runs copyright check and generates the jar, sources-jar and javadoc-jar by default.
+
+Checking findbugs
+-----------------
+
+`mvn -DskipTests -Dfindbugs.threshold=Low findbugs:findbugs`
+
diff --git a/third_party/servlet-spec/copyright-exclude b/third_party/servlet-spec/copyright-exclude
new file mode 100644
index 0000000..2430b60
--- /dev/null
+++ b/third_party/servlet-spec/copyright-exclude
@@ -0,0 +1,10 @@
+copyright-exclude
+LICENSE
+README
+CONTRIBUTING.md
+src/main/javadoc/doc-files/expert-draft-bg-blank.graffle
+src/main/javadoc/doc-files/expert-draft-bg-blank.png
+src/main/javadoc/doc-files/expert-draft-bg-non-blank.graffle
+src/main/javadoc/doc-files/expert-draft-bg-non-blank.png
+src/main/javadoc/doc-files/expert-draft-bg.png
+src/main/javadoc/doc-files/speclicense.html
diff --git a/third_party/servlet-spec/exclude.xml b/third_party/servlet-spec/exclude.xml
new file mode 100644
index 0000000..fbc3147
--- /dev/null
+++ b/third_party/servlet-spec/exclude.xml
@@ -0,0 +1,53 @@
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+<FindBugsFilter>
+    <!--
+         Shing Wai Chan has discussed this issue with Bill Shannon.
+         The ServletRequestEvent is not intended to be a Serializable,
+         which is inherited from java.util.EventObject.
+     -->
+    <Match>
+        <Class name="javax.servlet.ServletRequestEvent"/>
+        <Bug pattern="SE_TRANSIENT_FIELD_NOT_RESTORED"/>
+    </Match>
+</FindBugsFilter>
diff --git a/third_party/servlet-spec/pom.xml b/third_party/servlet-spec/pom.xml
new file mode 100644
index 0000000..1a1198e
--- /dev/null
+++ b/third_party/servlet-spec/pom.xml
@@ -0,0 +1,375 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>net.java</groupId>
+        <artifactId>jvnet-parent</artifactId>
+        <version>3</version>
+    </parent>
+
+    <groupId>javax.servlet</groupId>
+    <artifactId>javax.servlet-api</artifactId>
+    <packaging>jar</packaging>
+    <version>4.0.1</version>
+
+    <properties>
+        <spec.version>4.0</spec.version>
+        <extension.name>javax.servlet</extension.name>
+        <bundle.symbolicName>javax.servlet-api</bundle.symbolicName>
+        <bundle.version>4.0.0</bundle.version>
+        <window.title>Java Servlet 4.0</window.title>
+        <doc.title>Java Servlet 4.0 API Specification</doc.title>
+        <vendor.name>Oracle Corporation</vendor.name>
+        <implementation.vendor.id>org.glassfish</implementation.vendor.id>
+        <findbugs.version>3.0.4</findbugs.version>
+        <findbugs.exclude>exclude.xml</findbugs.exclude>
+        <findbugs.threshold>Low</findbugs.threshold>
+        <copyright-plugin.version>1.49</copyright-plugin.version>
+    </properties>
+    <name>Java Servlet API</name>
+
+    <url>https://javaee.github.io/servlet-spec/</url>
+
+    <developers>
+        <developer>
+            <id>edburns</id>
+            <name>Ed Burns</name>
+            <url>http://purl.oclc.org/NET/edburns/</url>
+            <organization>Oracle</organization>
+            <roles>
+              <role>co-lead</role>
+              <role>developer</role>
+            </roles>
+        </developer>
+        <developer>
+            <id>shingwaichan</id>
+            <name>Shing Wai Chan</name>
+            <organization>Oracle</organization>
+            <roles>
+                <role>lead</role>
+                <role>developer</role>
+            </roles>
+        </developer>
+    </developers>
+    <distributionManagement>
+        <snapshotRepository>
+            <id>jvnet-nexus-snapshots</id>
+            <name>Java.net Nexus Snapshots Repository</name>
+            <url>https://maven.java.net/content/repositories/snapshots/</url>
+        </snapshotRepository>
+        <repository>
+            <id>jvnet-nexus-staging</id>
+            <name>Java.net Nexus Staging Repository</name>
+            <url>https://maven.java.net/service/local/staging/deploy/maven2/</url>
+        </repository>
+    </distributionManagement>
+
+    <organization>
+        <name>GlassFish Community</name>
+        <url>https://javaee.github.io</url>
+    </organization>
+    <licenses>
+        <license>
+            <name>CDDL + GPLv2 with classpath exception</name>
+            <url>https://oss.oracle.com/licenses/CDDL+GPL-1.1</url>
+            <distribution>repo</distribution>
+            <comments>A business-friendly OSS license</comments>
+        </license>
+    </licenses>
+    <issueManagement>
+        <system>github</system>
+        <url>https://github.com/javaee/servlet-spec/issues</url>
+    </issueManagement>
+    <mailingLists>
+        <mailingList>
+            <name>Servlet Developer</name>
+            <archive>servlet-spec@javaee.groups.io</archive>
+        </mailingList>
+    </mailingLists>
+    <scm>
+        <connection>scm:git:https://github.com/javaee/servlet-spec.git</connection>
+        <developerConnection>scm:git:git@github.com:javaee/servlet-spec.git</developerConnection>
+        <url>https://github.com/javaee/servlet-spec</url>
+      <tag>4.0.1</tag>
+  </scm>
+
+    <build>
+        <plugins>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <compilerArgument>-Xlint:all</compilerArgument>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <version>1.4.3</version>
+                <configuration>
+                    <supportedProjectTypes>
+                        <supportedProjectType>jar</supportedProjectType>
+                    </supportedProjectTypes>
+                    <instructions>
+                        <Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName>
+                        <Bundle-Description>
+                            Java(TM) Servlet ${spec.version} API Design Specification
+                        </Bundle-Description>
+                        <Bundle-Version>${bundle.version}</Bundle-Version>
+                        <Extension-Name>${extension.name}</Extension-Name>
+                        <Specification-Version>${spec.version}</Specification-Version>
+                        <Specification-Vendor>${vendor.name}</Specification-Vendor>
+                        <Implementation-Version>${project.version}</Implementation-Version>
+                        <Implementation-Vendor>${project.organization.name}</Implementation-Vendor>
+                        <Implementation-Vendor-Id>${implementation.vendor.id}</Implementation-Vendor-Id>
+                    </instructions>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>bundle-manifest</id>
+                        <phase>process-classes</phase>
+                        <goals>
+                            <goal>manifest</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>2.4</version>
+                <configuration>
+                    <archive>
+                        <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+                    </archive>
+                    <excludes>
+                        <exclude>**/*.java</exclude>
+                    </excludes>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-remote-resources-plugin</artifactId>
+                <version>1.2.1</version>
+                <executions>
+                  <execution>
+                    <goals>
+                      <goal>process</goal>
+                    </goals>
+                    <configuration>
+                      <resourceBundles>
+                        <resourceBundle>org.glassfish:legal:1.1</resourceBundle>
+                      </resourceBundles>
+                    </configuration>
+                  </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.1</version>
+                <configuration>
+                    <includePom>true</includePom>
+                </configuration>
+                <executions>
+                    <execution>
+                       <id>attach-sources</id>
+                       <goals>
+                           <goal>jar-no-fork</goal> 
+                       </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>2.10.4</version>
+                <configuration>
+                    <sourcepath>src</sourcepath>
+                    <doctitle>${doc.title}</doctitle>
+                    <windowtitle>${window.title}</windowtitle>
+                    <stylesheetfile>javax.servlet-api.css</stylesheetfile>
+                    <docfilessubdirs>true</docfilessubdirs>
+                    <groups>
+                        <group>
+                            <title>Servlet API Documentation</title>
+                            <packages>javax.servlet</packages>
+                        </group>
+                    </groups>
+                    <bottom>
+<![CDATA[Copyright &#169; 1999-2017,
+    <a href="http://www.oracle.com">Oracle</a>
+    and/or its affiliates. All Rights Reserved.
+    Use is subject to
+    <a href="{@docRoot}/doc-files/speclicense.html" target="_top">license terms</a>.
+    Portions Copyright &#169; 1999-2002 The Apache Software Foundation.
+]]>
+                    </bottom>
+                    <tags>
+                        <tag>
+                            <name>implSpec</name>
+                            <placement>a</placement>
+                            <head>Implementation Requirements:</head>
+                        </tag>
+                        <tag>
+                            <name>param</name>
+                        </tag>
+                        <tag>
+                            <name>return</name>
+                        </tag>
+                        <tag>
+                            <name>throws</name>
+                        </tag>
+                        <tag>
+                            <name>since</name>
+                        </tag>
+                        <tag>
+                            <name>version</name>
+                        </tag>
+                        <tag>
+                            <name>serialData</name>
+                        </tag>
+                        <tag>
+                            <name>factory</name>
+                        </tag>
+                        <tag>
+                            <name>see</name>
+                        </tag>
+                    </tags>
+                </configuration>
+                <executions>
+                    <execution>
+                      <goals>
+                        <goal>jar</goal>
+                      </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>findbugs-maven-plugin</artifactId>
+                <version>${findbugs.version}</version>
+                <configuration>
+                    <threshold>${findbugs.threshold}</threshold>
+                    <excludeFilterFile>${findbugs.exclude}</excludeFilterFile>
+                    <findbugsXmlOutput>true</findbugsXmlOutput>
+                    <findbugsXmlWithMessages>true</findbugsXmlWithMessages>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-release-plugin</artifactId>
+                <version>2.5.3</version>
+                <configuration>
+                    <mavenExecutorId>forked-path</mavenExecutorId>
+                    <useReleaseProfile>false</useReleaseProfile>
+                    <tagNameFormat>@{project.version}</tagNameFormat>
+                    <arguments>${release.arguments}</arguments>
+                </configuration>
+                <dependencies>
+                    <dependency>
+                        <groupId>org.apache.maven.scm</groupId>
+                        <artifactId>maven-scm-provider-gitexe</artifactId>
+                        <version>1.8.1</version>
+                    </dependency>
+                </dependencies>
+            </plugin>
+            <plugin>
+                <groupId>org.glassfish.copyright</groupId>
+                <artifactId>glassfish-copyright-maven-plugin</artifactId>
+                <version>${copyright-plugin.version}</version>
+                <configuration>
+                    <scm>git</scm>
+                    <scmOnly>true</scmOnly>
+                    <excludeFile>
+                        ${basedir}/copyright-exclude
+                    </excludeFile>
+                    <ignoreYear>true</ignoreYear>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>check-copyright</id>
+                        <phase>process-test-sources</phase>
+                        <goals>
+                            <goal>copyright</goal>
+                            <goal>check</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/java</directory>
+                <includes>
+                    <include>**/*.properties</include>
+                    <include>**/*.html</include>
+                </includes>
+            </resource>
+            <resource>
+                <directory>src/main/resources</directory>
+                <excludes>
+                    <exclude>META-INF/README</exclude>
+                </excludes>
+            </resource>
+        </resources>
+    </build>
+    <reporting>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>findbugs-maven-plugin</artifactId>
+                <version>${findbugs.version}</version>
+                <configuration>
+                    <threshold>${findbugs.threshold}</threshold>
+                    <excludeFilterFile>${findbugs.exclude}</excludeFilterFile>
+                </configuration>
+            </plugin>
+        </plugins>
+    </reporting>
+</project>
diff --git a/third_party/servlet-spec/release.sh b/third_party/servlet-spec/release.sh
new file mode 100755
index 0000000..6229b24
--- /dev/null
+++ b/third_party/servlet-spec/release.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+#
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+#
+# Copyright (c) 2012-2017 Oracle and/or its affiliates. All rights reserved.
+#
+# The contents of this file are subject to the terms of either the GNU
+# General Public License Version 2 only ("GPL") or the Common Development
+# and Distribution License("CDDL") (collectively, the "License").  You
+# may not use this file except in compliance with the License.  You can
+# obtain a copy of the License at
+# https://oss.oracle.com/licenses/CDDL+GPL-1.1
+# or LICENSE.txt.  See the License for the specific
+# language governing permissions and limitations under the License.
+#
+# When distributing the software, include this License Header Notice in each
+# file and include the License file at LICENSE.txt.
+#
+# GPL Classpath Exception:
+# Oracle designates this particular file as subject to the "Classpath"
+# exception as provided by Oracle in the GPL Version 2 section of the License
+# file that accompanied this code.
+#
+# Modifications:
+# If applicable, add the following below the License Header, with the fields
+# enclosed by brackets [] replaced by your own identifying information:
+# "Portions Copyright [year] [name of copyright owner]"
+#
+# Contributor(s):
+# If you wish your version of this file to be governed by only the CDDL or
+# only the GPL Version 2, indicate your decision by adding "[Contributor]
+# elects to include this software in this distribution under the [CDDL or GPL
+# Version 2] license."  If you don't indicate a single choice of license, a
+# recipient has the option to distribute your version of this file under
+# either the CDDL, the GPL Version 2 or to extend the choice of license to
+# its licensees as provided above.  However, if you add GPL Version 2 code
+# and therefore, elected the GPL Version 2 license, then the option applies
+# only if the new code is made subject to such option by the copyright
+# holder.
+#
+
+#------------------------------------------------------   
+#-- BE SURE TO HAVE THE FOLLOWING IN YOUR SETTINGS.XML
+#------------------------------------------------------
+#
+#    <servers>
+#        <server>
+#            <id>jvnet-nexus-staging</id>
+#            <username>jvnet_id</username>
+#            <password>password</password>
+#        </server>
+#    </servers>
+#    <profiles>
+#      <profile>
+#        <id>release</id>
+#        <properties>
+#          <release.arguments>-Dhttps.proxyHost=www-proxy.us.oracle.com -Dhttps.proxyPort=80 -Dgpg.passphrase=glassfish -Pjvnet-release</release.arguments>
+#        </properties>
+#        <activation>
+#          <activeByDefault>false</activeByDefault>
+#        </activation>
+#      </profile>
+#    </profiles>
+
+# see the following URL for gpg issues
+# https://docs.sonatype.org/display/Repository/How+To+Generate+PGP+Signatures+With+Maven#HowToGeneratePGPSignaturesWithMaven-GenerateaKeyPair
+
+# login to nexus at maven.java.net and release (Close) the artifact
+# https://maven.java.net/index.html#stagingRepositories
+
+# More information:
+# https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide#SonatypeOSSMavenRepositoryUsageGuide-8.ReleaseIt
+# http://aseng-wiki.us.oracle.com/asengwiki/display/GlassFish/Migrating+Maven+deployment+to+maven.java.net
+
+mvn -B release:prepare -Prelease
+mvn -B release:perform -Prelease
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/AsyncContext.java b/third_party/servlet-spec/src/main/java/javax/servlet/AsyncContext.java
new file mode 100644
index 0000000..68e29e6
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/AsyncContext.java
@@ -0,0 +1,515 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+/**
+ * Class representing the execution context for an asynchronous operation
+ * that was initiated on a ServletRequest.
+ *
+ * <p>An AsyncContext is created and initialized by a call to
+ * {@link ServletRequest#startAsync()} or
+ * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}.
+ * Repeated invocations of these methods will return the same AsyncContext
+ * instance, reinitialized as appropriate.
+ *
+ * <p>In the event that an asynchronous operation has timed out, the
+ * container must run through these steps:
+ * <ol>
+ * <li>Invoke, at their {@link AsyncListener#onTimeout onTimeout} method, all
+ * {@link AsyncListener} instances registered with the ServletRequest
+ * on which the asynchronous operation was initiated.</li>
+ * <li>If none of the listeners called {@link #complete} or any of the
+ * {@link #dispatch} methods, perform an error dispatch with a status code
+ * equal to <tt>HttpServletResponse.SC_INTERNAL_SERVER_ERROR</tt>.</li>
+ * <li>If no matching error page was found, or the error page did not call
+ * {@link #complete} or any of the {@link #dispatch} methods, call
+ * {@link #complete}.</li>
+ * </ol>
+ *
+ * @since Servlet 3.0
+ */
+public interface AsyncContext {
+
+    /**
+     * The name of the request attribute under which the original
+     * request URI is made available to the target of a
+     * {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)} 
+     */
+    static final String ASYNC_REQUEST_URI = "javax.servlet.async.request_uri";
+
+    /**
+     * The name of the request attribute under which the original
+     * context path is made available to the target of a
+     * {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)} 
+     */
+    static final String ASYNC_CONTEXT_PATH = "javax.servlet.async.context_path";
+
+    /**
+     * The name of the request attribute under which the original
+     * {@link javax.servlet.http.HttpServletMapping} is made available to the target of a
+     * {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)} 
+     */
+    static final String ASYNC_MAPPING = "javax.servlet.async.mapping";
+
+    /**
+     * The name of the request attribute under which the original
+     * path info is made available to the target of a
+     * {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)} 
+     */
+    static final String ASYNC_PATH_INFO = "javax.servlet.async.path_info";
+
+    /**
+     * The name of the request attribute under which the original
+     * servlet path is made available to the target of a
+     * {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)}  
+     */
+    static final String ASYNC_SERVLET_PATH = "javax.servlet.async.servlet_path";
+
+    /**
+     * The name of the request attribute under which the original
+     * query string is made available to the target of a
+     * {@link #dispatch(String)} or {@link #dispatch(ServletContext,String)} 
+     */
+    static final String ASYNC_QUERY_STRING = "javax.servlet.async.query_string";
+
+
+    /**
+     * Gets the request that was used to initialize this AsyncContext
+     * by calling {@link ServletRequest#startAsync()} or
+     * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}.
+     *
+     * @return the request that was used to initialize this AsyncContext
+     *
+     * @exception IllegalStateException  if {@link #complete} or any of the
+     *                                  {@link #dispatch} methods has been
+     *                                  called in the asynchronous cycle
+     */
+    public ServletRequest getRequest();
+
+
+    /**
+     * Gets the response that was used to initialize this AsyncContext
+     * by calling {@link ServletRequest#startAsync()} or
+     * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}.
+     *
+     * @return the response that was used to initialize this AsyncContext
+     *
+     * @exception IllegalStateException  if {@link #complete} or any of the
+     *                                  {@link #dispatch} methods has been
+     *                                  called in the asynchronous cycle
+     */
+    public ServletResponse getResponse();
+
+
+    /**
+     * Checks if this AsyncContext was initialized with the original or
+     * application-wrapped request and response objects.
+     * 
+     * <p>This information may be used by filters invoked in the
+     * <i>outbound</i> direction, after a request was put into
+     * asynchronous mode, to determine whether any request and/or response
+     * wrappers that they added during their <i>inbound</i> invocation need
+     * to be preserved for the duration of the asynchronous operation, or may
+     * be released.
+     *
+     * @return true if this AsyncContext was initialized with the original
+     * request and response objects by calling
+     * {@link ServletRequest#startAsync()}, or if it was initialized by
+     * calling
+     * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)},
+     * and neither the ServletRequest nor ServletResponse arguments 
+     * carried any application-provided wrappers; false otherwise
+     */
+    public boolean hasOriginalRequestAndResponse();
+
+
+    /**
+     * Dispatches the request and response objects of this AsyncContext
+     * to the servlet container.
+     * 
+     * <p>If the asynchronous cycle was started with
+     * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)},
+     * and the request passed is an instance of HttpServletRequest,
+     * then the dispatch is to the URI returned by
+     * {@link javax.servlet.http.HttpServletRequest#getRequestURI}.
+     * Otherwise, the dispatch is to the URI of the request when it was
+     * last dispatched by the container.
+     *
+     * <p>The following sequence illustrates how this will work:
+     * <pre>{@code
+     * // REQUEST dispatch to /url/A
+     * AsyncContext ac = request.startAsync();
+     * ...
+     * ac.dispatch(); // ASYNC dispatch to /url/A
+     * 
+     * // REQUEST to /url/A
+     * // FORWARD dispatch to /url/B
+     * request.getRequestDispatcher("/url/B").forward(request,response);
+     * // Start async operation from within the target of the FORWARD
+     * // dispatch
+     * ac = request.startAsync();
+     * ...
+     * ac.dispatch(); // ASYNC dispatch to /url/A
+     * 
+     * // REQUEST to /url/A
+     * // FORWARD dispatch to /url/B
+     * request.getRequestDispatcher("/url/B").forward(request,response);
+     * // Start async operation from within the target of the FORWARD
+     * // dispatch
+     * ac = request.startAsync(request,response);
+     * ...
+     * ac.dispatch(); // ASYNC dispatch to /url/B
+     * }</pre>
+     *
+     * <p>This method returns immediately after passing the request
+     * and response objects to a container managed thread, on which the
+     * dispatch operation will be performed.
+     * If this method is called before the container-initiated dispatch
+     * that called <tt>startAsync</tt> has returned to the container, the
+     * dispatch operation will be delayed until after the container-initiated
+     * dispatch has returned to the container.
+     *
+     * <p>The dispatcher type of the request is set to
+     * <tt>DispatcherType.ASYNC</tt>. Unlike
+     * {@link RequestDispatcher#forward(ServletRequest, ServletResponse)
+     * forward dispatches}, the response buffer and
+     * headers will not be reset, and it is legal to dispatch even if the
+     * response has already been committed.
+     *
+     * <p>Control over the request and response is delegated
+     * to the dispatch target, and the response will be closed when the
+     * dispatch target has completed execution, unless
+     * {@link ServletRequest#startAsync()} or
+     * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}
+     * are called.
+     * 
+     * <p>Any errors or exceptions that may occur during the execution
+     * of this method must be caught and handled by the container, as
+     * follows:
+     * <ol>
+     * <li>Invoke, at their {@link AsyncListener#onError onError} method, all
+     * {@link AsyncListener} instances registered with the ServletRequest
+     * for which this AsyncContext was created, and make the caught 
+     * <tt>Throwable</tt> available via {@link AsyncEvent#getThrowable}.</li>
+     * <li>If none of the listeners called {@link #complete} or any of the
+     * {@link #dispatch} methods, perform an error dispatch with a status code
+     * equal to <tt>HttpServletResponse.SC_INTERNAL_SERVER_ERROR</tt>, and
+     * make the above <tt>Throwable</tt> available as the value of the
+     * <tt>RequestDispatcher.ERROR_EXCEPTION</tt> request attribute.</li>
+     * <li>If no matching error page was found, or the error page did not call
+     * {@link #complete} or any of the {@link #dispatch} methods, call
+     * {@link #complete}.</li>
+     * </ol>
+     *
+     * <p>There can be at most one asynchronous dispatch operation per
+     * asynchronous cycle, which is started by a call to one of the
+     * {@link ServletRequest#startAsync} methods. Any attempt to perform an
+     * additional asynchronous dispatch operation within the same
+     * asynchronous cycle will result in an IllegalStateException.
+     * If startAsync is subsequently called on the dispatched request,
+     * then any of the dispatch or {@link #complete} methods may be called.
+     *
+     * @throws IllegalStateException if one of the dispatch methods
+     * has been called and the startAsync method has not been
+     * called during the resulting dispatch, or if {@link #complete}
+     * was called
+     *
+     * @see ServletRequest#getDispatcherType
+     */
+    public void dispatch();
+
+
+    /**
+     * Dispatches the request and response objects of this AsyncContext
+     * to the given <tt>path</tt>.
+     *
+     * <p>The <tt>path</tt> parameter is interpreted in the same way 
+     * as in {@link ServletRequest#getRequestDispatcher(String)}, within
+     * the scope of the {@link ServletContext} from which this
+     * AsyncContext was initialized.
+     *
+     * <p>All path related query methods of the request must reflect the
+     * dispatch target, while the original request URI, context path,
+     * path info, servlet path, and query string may be recovered from
+     * the {@link #ASYNC_REQUEST_URI}, {@link #ASYNC_CONTEXT_PATH},
+     * {@link #ASYNC_PATH_INFO}, {@link #ASYNC_SERVLET_PATH}, and
+     * {@link #ASYNC_QUERY_STRING} attributes of the request. These
+     * attributes will always reflect the original path elements, even under
+     * repeated dispatches.
+     *
+     * <p>There can be at most one asynchronous dispatch operation per
+     * asynchronous cycle, which is started by a call to one of the
+     * {@link ServletRequest#startAsync} methods. Any attempt to perform an
+     * additional asynchronous dispatch operation within the same
+     * asynchronous cycle will result in an IllegalStateException.
+     * If startAsync is subsequently called on the dispatched request,
+     * then any of the dispatch or {@link #complete} methods may be called.
+     *
+     * <p>See {@link #dispatch()} for additional details, including error
+     * handling.
+     *
+     * @param path the path of the dispatch target, scoped to the
+     * ServletContext from which this AsyncContext was initialized
+     *
+     * @throws IllegalStateException if one of the dispatch methods
+     * has been called and the startAsync method has not been
+     * called during the resulting dispatch, or if {@link #complete}
+     * was called
+     *
+     * @see ServletRequest#getDispatcherType
+     */
+    public void dispatch(String path);
+
+
+    /**
+     * Dispatches the request and response objects of this AsyncContext
+     * to the given <tt>path</tt> scoped to the given <tt>context</tt>.
+     *
+     * <p>The <tt>path</tt> parameter is interpreted in the same way 
+     * as in {@link ServletRequest#getRequestDispatcher(String)}, except that
+     * it is scoped to the given <tt>context</tt>.
+     *
+     * <p>All path related query methods of the request must reflect the
+     * dispatch target, while the original request URI, context path,
+     * path info, servlet path, and query string may be recovered from
+     * the {@link #ASYNC_REQUEST_URI}, {@link #ASYNC_CONTEXT_PATH},
+     * {@link #ASYNC_PATH_INFO}, {@link #ASYNC_SERVLET_PATH}, and
+     * {@link #ASYNC_QUERY_STRING} attributes of the request. These
+     * attributes will always reflect the original path elements, even under
+     * repeated dispatches.
+     *
+     * <p>There can be at most one asynchronous dispatch operation per
+     * asynchronous cycle, which is started by a call to one of the
+     * {@link ServletRequest#startAsync} methods. Any attempt to perform an
+     * additional asynchronous dispatch operation within the same
+     * asynchronous cycle will result in an IllegalStateException.
+     * If startAsync is subsequently called on the dispatched request,
+     * then any of the dispatch or {@link #complete} methods may be called.
+     *
+     * <p>See {@link #dispatch()} for additional details, including error
+     * handling.
+     *
+     * @param context the ServletContext of the dispatch target
+     * @param path the path of the dispatch target, scoped to the given
+     * ServletContext
+     *
+     * @throws IllegalStateException if one of the dispatch methods
+     * has been called and the startAsync method has not been
+     * called during the resulting dispatch, or if {@link #complete}
+     * was called
+     *
+     * @see ServletRequest#getDispatcherType
+     */
+    public void dispatch(ServletContext context, String path);
+
+
+    /**
+     * Completes the asynchronous operation that was started on the request
+     * that was used to initialze this AsyncContext, closing the response
+     * that was used to initialize this AsyncContext.
+     *
+     * <p>Any listeners of type {@link AsyncListener} that were registered
+     * with the ServletRequest for which this AsyncContext was created will
+     * be invoked at their {@link AsyncListener#onComplete(AsyncEvent)
+     * onComplete} method.
+     *
+     * <p>It is legal to call this method any time after a call to
+     * {@link ServletRequest#startAsync()} or
+     * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)},
+     * and before a call to one of the <tt>dispatch</tt> methods
+     * of this class. 
+     * If this method is called before the container-initiated dispatch
+     * that called <tt>startAsync</tt> has returned to the container, then
+     * the call will not take effect (and any invocations of
+     * {@link AsyncListener#onComplete(AsyncEvent)} will be delayed) until
+     * after the container-initiated dispatch has returned to the container.
+     */
+    public void complete();
+
+
+    /**
+     * Causes the container to dispatch a thread, possibly from a managed
+     * thread pool, to run the specified <tt>Runnable</tt>. The container may
+     * propagate appropriate contextual information to the <tt>Runnable</tt>. 
+     *
+     * @param run the asynchronous handler
+     */
+    public void start(Runnable run);
+
+
+    /**
+     * Registers the given {@link AsyncListener} with the most recent
+     * asynchronous cycle that was started by a call to one of the
+     * {@link ServletRequest#startAsync} methods.
+     *
+     * <p>The given AsyncListener will receive an {@link AsyncEvent} when
+     * the asynchronous cycle completes successfully, times out, results
+     * in an error, or a new asynchronous cycle is being initiated via
+     * one of the {@link ServletRequest#startAsync} methods.
+     *
+     * <p>AsyncListener instances will be notified in the order in which
+     * they were added.
+     *
+     * <p>If {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}
+     * or {@link ServletRequest#startAsync} is called,
+     * the exact same request and response objects are available from the
+     * {@link AsyncEvent} when the {@link AsyncListener} is notified.
+     *
+     * @param listener the AsyncListener to be registered
+     * 
+     * @throws IllegalStateException if this method is called after
+     * the container-initiated dispatch, during which one of the
+     * {@link ServletRequest#startAsync} methods was called, has
+     * returned to the container
+     */
+    public void addListener(AsyncListener listener);
+
+
+    /**
+     * Registers the given {@link AsyncListener} with the most recent
+     * asynchronous cycle that was started by a call to one of the
+     * {@link ServletRequest#startAsync} methods.
+     *
+     * <p>The given AsyncListener will receive an {@link AsyncEvent} when
+     * the asynchronous cycle completes successfully, times out, results
+     * in an error, or a new asynchronous cycle is being initiated via
+     * one of the {@link ServletRequest#startAsync} methods.
+     *
+     * <p>AsyncListener instances will be notified in the order in which
+     * they were added.
+     *
+     * <p>The given ServletRequest and ServletResponse objects will
+     * be made available to the given AsyncListener via the
+     * {@link AsyncEvent#getSuppliedRequest getSuppliedRequest} and
+     * {@link AsyncEvent#getSuppliedResponse getSuppliedResponse} methods,
+     * respectively, of the {@link AsyncEvent} delivered to it. These objects
+     * should not be read from or written to, respectively, at the time the
+     * AsyncEvent is delivered, because additional wrapping may have
+     * occurred since the given AsyncListener was registered, but may be used
+     * in order to release any resources associated with them.
+     *
+     * @param listener the AsyncListener to be registered
+     * @param servletRequest the ServletRequest that will be included
+     * in the AsyncEvent
+     * @param servletResponse the ServletResponse that will be included
+     * in the AsyncEvent
+     *
+     * @throws IllegalStateException if this method is called after
+     * the container-initiated dispatch, during which one of the
+     * {@link ServletRequest#startAsync} methods was called, has
+     * returned to the container
+     */
+    public void addListener(AsyncListener listener,
+                            ServletRequest servletRequest,
+                            ServletResponse servletResponse);
+
+
+    /**
+     * Instantiates the given {@link AsyncListener} class.
+     *
+     * <p>The returned AsyncListener instance may be further customized
+     * before it is registered with this AsyncContext via a call to one of 
+     * the <code>addListener</code> methods.
+     *
+     * <p>The given AsyncListener class must define a zero argument
+     * constructor, which is used to instantiate it.
+     *
+     * <p>This method supports resource injection if the given
+     * <tt>clazz</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+
+     * <p>This method supports any annotations applicable to AsyncListener.
+     *
+     * @param <T> the class of the object to instantiate
+     * @param clazz the AsyncListener class to instantiate
+     *
+     * @return the new AsyncListener instance
+     *
+     * @throws ServletException if the given <tt>clazz</tt> fails to be
+     * instantiated
+     */
+    public <T extends AsyncListener> T createListener(Class<T> clazz)
+        throws ServletException; 
+
+
+    /**
+     * Sets the timeout (in milliseconds) for this AsyncContext.
+     *
+     * <p>The timeout applies to this AsyncContext once the
+     * container-initiated dispatch during which one of the
+     * {@link ServletRequest#startAsync} methods was called has
+     * returned to the container. 
+     *
+     * <p>The timeout will expire if neither the {@link #complete} method
+     * nor any of the dispatch methods are called. A timeout value of
+     * zero or less indicates no timeout. 
+     * 
+     * <p>If {@link #setTimeout} is not called, then the container's
+     * default timeout, which is available via a call to
+     * {@link #getTimeout}, will apply.
+     *
+     * <p>The default value is <code>30000</code> ms.
+     *
+     * @param timeout the timeout in milliseconds
+     *
+     * @throws IllegalStateException if this method is called after
+     * the container-initiated dispatch, during which one of the
+     * {@link ServletRequest#startAsync} methods was called, has
+     * returned to the container
+     */
+    public void setTimeout(long timeout);
+
+
+    /**
+     * Gets the timeout (in milliseconds) for this AsyncContext.
+     *
+     * <p>This method returns the container's default timeout for
+     * asynchronous operations, or the timeout value passed to the most
+     * recent invocation of {@link #setTimeout}.
+     *
+     * <p>A timeout value of zero or less indicates no timeout.
+     *
+     * @return the timeout in milliseconds
+     */
+    public long getTimeout();
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/AsyncEvent.java b/third_party/servlet-spec/src/main/java/javax/servlet/AsyncEvent.java
new file mode 100644
index 0000000..d1739ec
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/AsyncEvent.java
@@ -0,0 +1,166 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+/**
+ * Event that gets fired when the asynchronous operation initiated on a 
+ * ServletRequest (via a call to {@link ServletRequest#startAsync} or
+ * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)})
+ * has completed, timed out, or produced an error.
+ *
+ * @since Servlet 3.0
+ */
+public class AsyncEvent { 
+
+    private AsyncContext context;
+    private ServletRequest request;
+    private ServletResponse response;
+    private Throwable throwable;
+
+
+    /**
+     * Constructs an AsyncEvent from the given AsyncContext.
+     *
+     * @param context the AsyncContex to be delivered with this AsyncEvent
+     */
+    public AsyncEvent(AsyncContext context) {
+        this(context, context.getRequest(), context.getResponse(), null);
+    }
+
+    /**
+     * Constructs an AsyncEvent from the given AsyncContext, ServletRequest,
+     * and ServletResponse.
+     *
+     * @param context the AsyncContex to be delivered with this AsyncEvent
+     * @param request the ServletRequest to be delivered with this AsyncEvent
+     * @param response the ServletResponse to be delivered with this
+     * AsyncEvent
+     */
+    public AsyncEvent(AsyncContext context, ServletRequest request,
+            ServletResponse response) {
+        this(context, request, response, null);
+    }
+
+    /**
+     * Constructs an AsyncEvent from the given AsyncContext and Throwable.
+     *
+     * @param context the AsyncContex to be delivered with this AsyncEvent
+     * @param throwable the Throwable to be delivered with this AsyncEvent
+     */
+    public AsyncEvent(AsyncContext context, Throwable throwable) {
+        this(context, context.getRequest(), context.getResponse(), throwable);
+    }
+
+    /**
+     * Constructs an AsyncEvent from the given AsyncContext, ServletRequest,
+     * ServletResponse, and Throwable.
+     *
+     * @param context the AsyncContex to be delivered with this AsyncEvent
+     * @param request the ServletRequest to be delivered with this AsyncEvent
+     * @param response the ServletResponse to be delivered with this
+     * AsyncEvent
+     * @param throwable the Throwable to be delivered with this AsyncEvent
+     */
+    public AsyncEvent(AsyncContext context, ServletRequest request,
+            ServletResponse response, Throwable throwable) {
+        this.context = context;
+        this.request = request;
+        this.response = response;
+        this.throwable = throwable;
+    }
+
+    /**
+     * Gets the AsyncContext from this AsyncEvent.
+     *
+     * @return the AsyncContext that was used to initialize this AsyncEvent
+     */
+    public AsyncContext getAsyncContext() {
+        return context;
+    }
+
+    /**
+     * Gets the ServletRequest from this AsyncEvent.
+     *
+     * <p>If the AsyncListener to which this AsyncEvent is being delivered
+     * was added using {@link AsyncContext#addListener(AsyncListener,
+     * ServletRequest, ServletResponse)}, the returned ServletRequest
+     * will be the same as the one supplied to the above method.
+     * If the AsyncListener was added via
+     * {@link AsyncContext#addListener(AsyncListener)}, this method
+     * must return null.
+     *
+     * @return the ServletRequest that was used to initialize this AsyncEvent,
+     * or null if this AsyncEvent was initialized without any ServletRequest
+     */
+    public ServletRequest getSuppliedRequest() {
+        return request;
+    }
+
+    /**
+     * Gets the ServletResponse from this AsyncEvent.
+     *
+     * <p>If the AsyncListener to which this AsyncEvent is being delivered
+     * was added using {@link AsyncContext#addListener(AsyncListener,
+     * ServletRequest, ServletResponse)}, the returned ServletResponse
+     * will be the same as the one supplied to the above method.
+     * If the AsyncListener was added via
+     * {@link AsyncContext#addListener(AsyncListener)}, this method
+     * must return null.
+     *
+     * @return the ServletResponse that was used to initialize this AsyncEvent,
+     * or null if this AsyncEvent was initialized without any ServletResponse
+     */
+    public ServletResponse getSuppliedResponse() {
+        return response;
+    }
+
+    /**
+     * Gets the Throwable from this AsyncEvent.
+     *
+     * @return the Throwable that was used to initialize this AsyncEvent,
+     * or null if this AsyncEvent was initialized without any Throwable
+     */
+    public Throwable getThrowable() {
+        return throwable;
+    }
+
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/AsyncListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/AsyncListener.java
new file mode 100644
index 0000000..ebe6cb3
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/AsyncListener.java
@@ -0,0 +1,164 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.io.IOException;
+import java.util.EventListener;
+
+/**
+ * Listener that will be notified in the event that an asynchronous
+ * operation initiated on a ServletRequest to which the listener had been 
+ * added has completed, timed out, or resulted in an error.
+ *
+ * @since Servlet 3.0
+ */
+public interface AsyncListener extends EventListener {
+    
+    /**
+     * Notifies this AsyncListener that an asynchronous operation
+     * has been completed.
+     * 
+     * <p>The {@link AsyncContext} corresponding to the asynchronous
+     * operation that has been completed may be obtained by calling
+     * {@link AsyncEvent#getAsyncContext getAsyncContext} on the given
+     * <tt>event</tt>.
+     *
+     * <p>In addition, if this AsyncListener had been registered via a call
+     * to {@link AsyncContext#addListener(AsyncListener,
+     * ServletRequest, ServletResponse)}, the supplied ServletRequest and
+     * ServletResponse objects may be retrieved by calling
+     * {@link AsyncEvent#getSuppliedRequest getSuppliedRequest} and
+     * {@link AsyncEvent#getSuppliedResponse getSuppliedResponse},
+     * respectively, on the given <tt>event</tt>.
+     *
+     * @param event the AsyncEvent indicating that an asynchronous
+     * operation has been completed
+     *
+     * @throws IOException if an I/O related error has occurred during the
+     * processing of the given AsyncEvent
+     */
+    public void onComplete(AsyncEvent event) throws IOException;
+
+
+    /**
+     * Notifies this AsyncListener that an asynchronous operation
+     * has timed out.
+     * 
+     * <p>The {@link AsyncContext} corresponding to the asynchronous
+     * operation that has timed out may be obtained by calling
+     * {@link AsyncEvent#getAsyncContext getAsyncContext} on the given
+     * <tt>event</tt>.
+     *
+     * <p>In addition, if this AsyncListener had been registered via a call
+     * to {@link AsyncContext#addListener(AsyncListener,
+     * ServletRequest, ServletResponse)}, the supplied ServletRequest and
+     * ServletResponse objects may be retrieved by calling
+     * {@link AsyncEvent#getSuppliedRequest getSuppliedRequest} and
+     * {@link AsyncEvent#getSuppliedResponse getSuppliedResponse},
+     * respectively, on the given <tt>event</tt>.
+     *
+     * @param event the AsyncEvent indicating that an asynchronous
+     * operation has timed out
+     *
+     * @throws IOException if an I/O related error has occurred during the
+     * processing of the given AsyncEvent
+     */
+    public void onTimeout(AsyncEvent event) throws IOException;
+
+
+    /**
+     * Notifies this AsyncListener that an asynchronous operation 
+     * has failed to complete.
+     * 
+     * <p>The {@link AsyncContext} corresponding to the asynchronous
+     * operation that failed to complete may be obtained by calling
+     * {@link AsyncEvent#getAsyncContext getAsyncContext} on the given
+     * <tt>event</tt>.
+     * 
+     * <p>In addition, if this AsyncListener had been registered via a call
+     * to {@link AsyncContext#addListener(AsyncListener,
+     * ServletRequest, ServletResponse)}, the supplied ServletRequest and
+     * ServletResponse objects may be retrieved by calling
+     * {@link AsyncEvent#getSuppliedRequest getSuppliedRequest} and
+     * {@link AsyncEvent#getSuppliedResponse getSuppliedResponse},
+     * respectively, on the given <tt>event</tt>.
+     *
+     * @param event the AsyncEvent indicating that an asynchronous
+     * operation has failed to complete
+     *
+     * @throws IOException if an I/O related error has occurred during the
+     * processing of the given AsyncEvent
+     */
+    public void onError(AsyncEvent event) throws IOException;
+
+
+    /**
+     * Notifies this AsyncListener that a new asynchronous cycle is being
+     * initiated via a call to one of the {@link ServletRequest#startAsync}
+     * methods.
+     *
+     * <p>The {@link AsyncContext} corresponding to the asynchronous
+     * operation that is being reinitialized may be obtained by calling
+     * {@link AsyncEvent#getAsyncContext getAsyncContext} on the given
+     * <tt>event</tt>.
+     * 
+     * <p>In addition, if this AsyncListener had been registered via a call
+     * to {@link AsyncContext#addListener(AsyncListener,
+     * ServletRequest, ServletResponse)}, the supplied ServletRequest and
+     * ServletResponse objects may be retrieved by calling
+     * {@link AsyncEvent#getSuppliedRequest getSuppliedRequest} and
+     * {@link AsyncEvent#getSuppliedResponse getSuppliedResponse},
+     * respectively, on the given <tt>event</tt>.
+     *
+     * <p>This AsyncListener will not receive any events related to the
+     * new asynchronous cycle unless it registers itself (via a call
+     * to {@link AsyncContext#addListener}) with the AsyncContext that
+     * is delivered as part of the given AsyncEvent.
+     *
+     * @param event the AsyncEvent indicating that a new asynchronous
+     * cycle is being initiated
+     *
+     * @throws IOException if an I/O related error has occurred during the
+     * processing of the given AsyncEvent
+     */
+    public void onStartAsync(AsyncEvent event) throws IOException;     
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/DispatcherType.java b/third_party/servlet-spec/src/main/java/javax/servlet/DispatcherType.java
new file mode 100644
index 0000000..65d1b18
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/DispatcherType.java
@@ -0,0 +1,54 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+/**
+ * Enumeration of filter dispatcher types.
+ *
+ * @since Servlet 3.0
+ */
+public enum DispatcherType {
+    FORWARD,
+    INCLUDE,
+    REQUEST,
+    ASYNC,
+    ERROR
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/Filter.java b/third_party/servlet-spec/src/main/java/javax/servlet/Filter.java
new file mode 100644
index 0000000..7f67f46
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/Filter.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.IOException;
+
+/**
+ * <p>A filter is an object that performs 
+ * filtering tasks on either the request to a resource (a servlet or static content), or on the response
+ * from a resource, or both.</p>
+ * 
+ * <p>Filters perform filtering in the <code>doFilter</code> method.
+ * Every Filter has access to a FilterConfig object from which it can obtain
+ * its initialization parameters, and a reference to the ServletContext which
+ * it can use, for example, to load resources needed for filtering tasks.
+ *
+ * <p>Filters are configured in the deployment descriptor of a web
+ * application.
+ *
+ * <p>Examples that have been identified for this design are:
+ * <ol>
+ * <li>Authentication Filters
+ * <li>Logging and Auditing Filters
+ * <li>Image conversion Filters
+ * <li>Data compression Filters
+ * <li>Encryption Filters
+ * <li>Tokenizing Filters
+ * <li>Filters that trigger resource access events
+ * <li>XSL/T filters
+ * <li>Mime-type chain Filter
+ * </ol>
+ *
+ * @since Servlet 2.3
+ */
+
+public interface Filter {
+
+    /** 
+     * <p>Called by the web container
+     * to indicate to a filter that it is being placed into service.</p>
+     *
+     * <p>The servlet container calls the init
+     * method exactly once after instantiating the filter. The init
+     * method must complete successfully before the filter is asked to do any
+     * filtering work.</p>
+     * 
+     * <p>The web container cannot place the filter into service if the init
+     * method either</p>
+     * <ol>
+     * <li>Throws a ServletException
+     * <li>Does not return within a time period defined by the web container
+     * </ol>
+     * 
+     * @implSpec
+     * The default implementation takes no action.
+     *
+     * @param filterConfig a <code>FilterConfig</code> object containing the
+     *                     filter's configuration and initialization parameters 
+     * @throws ServletException if an exception has occurred that interferes with
+     *                          the filter's normal operation
+     */
+    default public void init(FilterConfig filterConfig) throws ServletException {}
+	
+	
+    /**
+     * The <code>doFilter</code> method of the Filter is called by the
+     * container each time a request/response pair is passed through the
+     * chain due to a client request for a resource at the end of the chain.
+     * The FilterChain passed in to this method allows the Filter to pass
+     * on the request and response to the next entity in the chain.
+     *
+     * <p>A typical implementation of this method would follow the following
+     * pattern:
+     * <ol>
+     * <li>Examine the request
+     * <li>Optionally wrap the request object with a custom implementation to
+     * filter content or headers for input filtering
+     * <li>Optionally wrap the response object with a custom implementation to
+     * filter content or headers for output filtering
+     * <li>
+     * <ul>
+     * <li><strong>Either</strong> invoke the next entity in the chain
+     * using the FilterChain object
+     * (<code>chain.doFilter()</code>),
+     * <li><strong>or</strong> not pass on the request/response pair to
+     * the next entity in the filter chain to
+     * block the request processing
+     * </ul>
+     * <li>Directly set headers on the response after invocation of the
+     * next entity in the filter chain.
+     * </ol>
+     *
+     * @param request the <code>ServletRequest</code> object contains the client's request
+     * @param response the <code>ServletResponse</code> object contains the filter's response
+     * @param chain the <code>FilterChain</code> for invoking the next filter or the resource
+     * @throws IOException if an I/O related error has occurred during the processing
+     * @throws ServletException if an exception occurs that interferes with the
+     *                          filter's normal operation
+     *
+     * @see UnavailableException
+     */
+    public void doFilter(ServletRequest request, ServletResponse response,
+                         FilterChain chain)
+            throws IOException, ServletException;
+
+
+    /**
+     * <p>Called by the web container 
+     * to indicate to a filter that it is being
+     * taken out of service.</p>
+     *
+     * <p>This method is only called once all threads within the filter's
+     * doFilter method have exited or after a timeout period has passed.
+     * After the web container calls this method, it will not call the
+     * doFilter method again on this instance of the filter.</p>
+     *
+     * <p>This method gives the filter an opportunity to clean up any
+     * resources that are being held (for example, memory, file handles,
+     * threads) and make sure that any persistent state is synchronized
+     * with the filter's current state in memory.</p>
+     * 
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void destroy() {}
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/FilterChain.java b/third_party/servlet-spec/src/main/java/javax/servlet/FilterChain.java
new file mode 100644
index 0000000..cefe387
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/FilterChain.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.IOException;
+
+    /**
+     * A FilterChain is an object provided by the servlet container to the developer
+     * giving a view into the invocation chain of a filtered request for a resource. Filters
+     * use the FilterChain to invoke the next filter in the chain, or if the calling filter
+     * is the last filter in the chain, to invoke the resource at the end of the chain.
+     *
+     * @see Filter
+     * @since Servlet 2.3
+     */
+
+public interface FilterChain {
+
+    /**
+     * Causes the next filter in the chain to be invoked, or if the calling filter is the last filter
+     * in the chain, causes the resource at the end of the chain to be invoked.
+     *
+     * @param request the request to pass along the chain.
+     * @param response the response to pass along the chain.
+     * @throws IOException if an I/O related error has occurred during the processing
+     * @throws ServletException if an exception has occurred that interferes with the
+     *                          filterChain's normal operation
+     */
+    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException;
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/FilterConfig.java b/third_party/servlet-spec/src/main/java/javax/servlet/FilterConfig.java
new file mode 100644
index 0000000..95ce0a1
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/FilterConfig.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.util.Enumeration;
+
+/** 
+ * A filter configuration object used by a servlet container
+ * to pass information to a filter during initialization.
+ *
+ * @see Filter 
+ * @since Servlet 2.3
+ */
+public interface FilterConfig {
+
+    /** 
+     * Returns the filter-name of this filter as defined in the deployment
+     * descriptor. 
+     *
+     * @return the filter name of this filter
+     */
+    public String getFilterName();
+
+
+    /**
+     * Returns a reference to the {@link ServletContext} in which the caller
+     * is executing.
+     *
+     * @return a {@link ServletContext} object, used by the caller to
+     * interact with its servlet container
+     * 
+     * @see ServletContext
+     */
+    public ServletContext getServletContext();
+    
+
+    /**
+     * Returns a <code>String</code> containing the value of the 
+     * named initialization parameter, or <code>null</code> if 
+     * the initialization parameter does not exist.
+     *
+     * @param name a <code>String</code> specifying the name of the
+     * initialization parameter
+     *
+     * @return a <code>String</code> containing the value of the
+     * initialization parameter, or <code>null</code> if 
+     * the initialization parameter does not exist
+     */
+    public String getInitParameter(String name);
+
+
+    /**
+     * Returns the names of the filter's initialization parameters
+     * as an <code>Enumeration</code> of <code>String</code> objects, 
+     * or an empty <code>Enumeration</code> if the filter has
+     * no initialization parameters.
+     *
+     * @return an <code>Enumeration</code> of <code>String</code> objects
+     * containing the names of the filter's initialization parameters
+     */
+    public Enumeration<String> getInitParameterNames();
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/FilterRegistration.java b/third_party/servlet-spec/src/main/java/javax/servlet/FilterRegistration.java
new file mode 100644
index 0000000..99c95b9
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/FilterRegistration.java
@@ -0,0 +1,150 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.util.*;
+
+/**
+ * Interface through which a {@link Filter} may be further configured.
+ *
+ * @since Servlet 3.0
+ */
+public interface FilterRegistration extends Registration {
+
+    /**
+     * Adds a filter mapping with the given servlet names and dispatcher
+     * types for the Filter represented by this FilterRegistration.
+     *
+     * <p>Filter mappings are matched in the order in which they were
+     * added.
+     * 
+     * <p>Depending on the value of the <tt>isMatchAfter</tt> parameter, the
+     * given filter mapping will be considered after or before any
+     * <i>declared</i> filter mappings of the ServletContext from which this
+     * FilterRegistration was obtained.
+     *
+     * <p>If this method is called multiple times, each successive call
+     * adds to the effects of the former.
+     *
+     * @param dispatcherTypes the dispatcher types of the filter mapping,
+     * or null if the default <tt>DispatcherType.REQUEST</tt> is to be used
+     * @param isMatchAfter true if the given filter mapping should be matched
+     * after any declared filter mappings, and false if it is supposed to
+     * be matched before any declared filter mappings of the ServletContext
+     * from which this FilterRegistration was obtained
+     * @param servletNames the servlet names of the filter mapping
+     *
+     * @throws IllegalArgumentException if <tt>servletNames</tt> is null or
+     * empty
+     * @throws IllegalStateException if the ServletContext from which this
+     * FilterRegistration was obtained has already been initialized
+     */
+    public void addMappingForServletNames(
+        EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter,
+        String... servletNames);
+
+    /**
+     * Gets the currently available servlet name mappings
+     * of the Filter represented by this <code>FilterRegistration</code>.
+     *
+     * <p>If permitted, any changes to the returned <code>Collection</code> must not 
+     * affect this <code>FilterRegistration</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the currently
+     * available servlet name mappings of the Filter represented by this
+     * <code>FilterRegistration</code>
+     */
+    public Collection<String> getServletNameMappings();
+
+    /**
+     * Adds a filter mapping with the given url patterns and dispatcher
+     * types for the Filter represented by this FilterRegistration.
+     *
+     * <p>Filter mappings are matched in the order in which they were
+     * added.
+     * 
+     * <p>Depending on the value of the <tt>isMatchAfter</tt> parameter, the
+     * given filter mapping will be considered after or before any
+     * <i>declared</i> filter mappings of the ServletContext from which
+     * this FilterRegistration was obtained.
+     *
+     * <p>If this method is called multiple times, each successive call
+     * adds to the effects of the former.
+     *
+     * @param dispatcherTypes the dispatcher types of the filter mapping,
+     * or null if the default <tt>DispatcherType.REQUEST</tt> is to be used
+     * @param isMatchAfter true if the given filter mapping should be matched
+     * after any declared filter mappings, and false if it is supposed to
+     * be matched before any declared filter mappings of the ServletContext
+     * from which this FilterRegistration was obtained
+     * @param urlPatterns the url patterns of the filter mapping
+     *
+     * @throws IllegalArgumentException if <tt>urlPatterns</tt> is null or
+     * empty
+     * @throws IllegalStateException if the ServletContext from which this
+     * FilterRegistration was obtained has already been initialized
+     */
+    public void addMappingForUrlPatterns(
+        EnumSet<DispatcherType> dispatcherTypes, boolean isMatchAfter,
+        String... urlPatterns);
+
+    /**
+     * Gets the currently available URL pattern mappings of the Filter
+     * represented by this <code>FilterRegistration</code>.
+     *
+     * <p>If permitted, any changes to the returned <code>Collection</code> must not 
+     * affect this <code>FilterRegistration</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the currently
+     * available URL pattern mappings of the Filter represented by this
+     * <code>FilterRegistration</code>
+     */
+    public Collection<String> getUrlPatternMappings();
+
+    /**
+     * Interface through which a {@link Filter} registered via one of the
+     * <tt>addFilter</tt> methods on {@link ServletContext} may be further
+     * configured.
+     */
+    interface Dynamic extends FilterRegistration, Registration.Dynamic {
+    }
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/GenericFilter.java b/third_party/servlet-spec/src/main/java/javax/servlet/GenericFilter.java
new file mode 100644
index 0000000..02e1e0f
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/GenericFilter.java
@@ -0,0 +1,254 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * <p>Defines a generic, protocol-independent
+ * filter. To write an HTTP filter for use on the
+ * Web, extend {@link javax.servlet.http.HttpFilter} instead.</p>
+ *
+ * <p><code>GenericFilter</code> implements the <code>Filter</code>
+ * and <code>FilterConfig</code> interfaces. <code>GenericFilter</code>
+ * may be directly extended by a filter, although it's more common to extend
+ * a protocol-specific subclass such as <code>HttpFilter</code>.
+ *
+ * <p><code>GenericFilter</code> makes writing filters
+ * easier. It provides simple versions of the lifecycle methods 
+ * <code>init</code> and <code>destroy</code> and of the methods 
+ * in the <code>FilterConfig</code> interface.
+ *
+ * <p>To write a generic filter, you need only
+ * override the abstract <code>doFilter</code> method. 
+ *
+ * @author 	Various
+ * 
+ * @since Servlet 4.0
+ */
+
+ 
+public abstract class GenericFilter 
+    implements Filter, FilterConfig, java.io.Serializable
+{
+    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
+    private static final ResourceBundle lStrings =
+        ResourceBundle.getBundle(LSTRING_FILE);
+
+    private transient FilterConfig config;
+    
+
+    /**
+     *
+     * <p>Does nothing. All of the filter initialization
+     * is done by one of the <code>init</code> methods.</p>
+     *
+     * @since Servlet 4.0
+     */
+    public GenericFilter() { }
+    
+    
+    /**
+     * <p>Returns a <code>String</code> containing the value of the named
+     * initialization parameter, or <code>null</code> if the parameter does
+     * not exist.  See {@link FilterConfig#getInitParameter}.</p>
+     *
+     * <p>This method is supplied for convenience. It gets the 
+     * value of the named parameter from the servlet's 
+     * <code>ServletConfig</code> object.
+     *
+     * @param name 		a <code>String</code> specifying the name 
+     *				of the initialization parameter
+     *
+     * @return String 		a <code>String</code> containing the value
+     *				of the initialization parameter
+     *
+     * @since Servlet 4.0
+     *
+     */ 
+    @Override
+    public String getInitParameter(String name) {
+        FilterConfig fc = getFilterConfig();
+        if (fc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.filter_config_not_initialized"));
+        }
+
+        return fc.getInitParameter(name);
+    }
+    
+    
+   /**
+    * <p>Returns the names of the filter's initialization parameters 
+    * as an <code>Enumeration</code> of <code>String</code> objects,
+    * or an empty <code>Enumeration</code> if the filter has no
+    * initialization parameters.  See {@link
+    * FilterConfig#getInitParameterNames}.</p>
+    *
+    * <p>This method is supplied for convenience. It gets the 
+    * parameter names from the filter's <code>FilterConfig</code> object. 
+    *
+    * @return Enumeration 	an enumeration of <code>String</code>
+    *				objects containing the names of 
+    *				the filter's initialization parameters
+    *
+    * @since Servlet 4.0
+    */
+    @Override
+    public Enumeration<String> getInitParameterNames() {
+        FilterConfig fc = getFilterConfig();
+        if (fc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.filter_config_not_initialized"));
+        }
+
+        return fc.getInitParameterNames();
+    }   
+     
+
+    /**
+     * <p>Returns this servlet's {@link ServletConfig} object.</p>
+     *
+     * @return FilterConfig 	the <code>FilterConfig</code> object
+     *				that initialized this filter
+     *
+     * @since Servlet 4.0
+     */    
+    public FilterConfig getFilterConfig() {
+	return config;
+    }
+ 
+    
+    /**
+     * <p>Returns a reference to the {@link ServletContext} in which this filter
+     * is running.  See {@link FilterConfig#getServletContext}.</p>
+     *
+     * <p>This method is supplied for convenience. It gets the 
+     * context from the filter's <code>FilterConfig</code> object.
+     *
+     * @return ServletContext 	the <code>ServletContext</code> object
+     *				passed to this filter by the <code>init</code>
+     *				method
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public ServletContext getServletContext() {
+        FilterConfig sc = getFilterConfig();
+        if (sc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.filter_config_not_initialized"));
+        }
+
+        return sc.getServletContext();
+    }
+
+
+    /**
+     * <p>Called by the servlet container to indicate to a filter that
+     * it is being placed into service.  See {@link Filter#init}.</p>
+     * 
+     * <p>This implementation stores the {@link FilterConfig}
+     * object it receives from the servlet container for later use.
+     * When overriding this form of the method, call 
+     * <code>super.init(config)</code>.
+     * 
+     * @param config 			the <code>FilterConfig</code> object
+     *					that contains configuration
+     *					information for this filter
+     *
+     * @exception ServletException 	if an exception occurs that
+     *					interrupts the servlet's normal
+     *					operation
+     * 
+     * @see 				UnavailableException
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public void init(FilterConfig config) throws ServletException {
+	this.config = config;
+	this.init();
+    }
+
+    /**
+     * <p>A convenience method which can be overridden so that there's no need
+     * to call <code>super.init(config)</code>.</p>
+     *
+     * <p>Instead of overriding {@link #init(FilterConfig)}, simply override
+     * this method and it will be called by
+     * <code>GenericFilter.init(FilterConfig config)</code>.
+     * The <code>FilterConfig</code> object can still be retrieved via {@link
+     * #getFilterConfig}. 
+     * 
+     * @exception ServletException 	if an exception occurs that
+     *					interrupts the servlet's
+     *					normal operation
+     *
+     * @since Servlet 4.0
+     */
+    public void init() throws ServletException {
+
+    }
+    
+
+    /**
+     * <p>Returns the name of this filter instance.
+     * See {@link FilterConfig#getFilterName}.</p>
+     *
+     * @return          the name of this filter instance
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public String getFilterName() {
+        FilterConfig sc = getFilterConfig();
+        if (sc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.servlet_config_not_initialized"));
+        }
+
+        return sc.getFilterName();
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/GenericServlet.java b/third_party/servlet-spec/src/main/java/javax/servlet/GenericServlet.java
new file mode 100644
index 0000000..4a51a5b
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/GenericServlet.java
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.IOException;
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * Defines a generic, protocol-independent
+ * servlet. To write an HTTP servlet for use on the
+ * Web, extend {@link javax.servlet.http.HttpServlet} instead.
+ *
+ * <p><code>GenericServlet</code> implements the <code>Servlet</code>
+ * and <code>ServletConfig</code> interfaces. <code>GenericServlet</code>
+ * may be directly extended by a servlet, although it's more common to extend
+ * a protocol-specific subclass such as <code>HttpServlet</code>.
+ *
+ * <p><code>GenericServlet</code> makes writing servlets
+ * easier. It provides simple versions of the lifecycle methods 
+ * <code>init</code> and <code>destroy</code> and of the methods 
+ * in the <code>ServletConfig</code> interface. <code>GenericServlet</code>
+ * also implements the <code>log</code> method, declared in the
+ * <code>ServletContext</code> interface. 
+ *
+ * <p>To write a generic servlet, you need only
+ * override the abstract <code>service</code> method. 
+ *
+ *
+ * @author 	Various
+ */
+
+ 
+public abstract class GenericServlet 
+    implements Servlet, ServletConfig, java.io.Serializable
+{
+    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
+    private static ResourceBundle lStrings =
+        ResourceBundle.getBundle(LSTRING_FILE);
+
+    private transient ServletConfig config;
+    
+
+    /**
+     *
+     * Does nothing. All of the servlet initialization
+     * is done by one of the <code>init</code> methods.
+     *
+     */
+    public GenericServlet() { }
+    
+    
+    /**
+     * Called by the servlet container to indicate to a servlet that the
+     * servlet is being taken out of service.  See {@link Servlet#destroy}.
+     *
+     * 
+     */
+    public void destroy() {
+    }
+    
+    
+    /**
+     * Returns a <code>String</code> containing the value of the named
+     * initialization parameter, or <code>null</code> if the parameter does
+     * not exist.  See {@link ServletConfig#getInitParameter}.
+     *
+     * <p>This method is supplied for convenience. It gets the 
+     * value of the named parameter from the servlet's 
+     * <code>ServletConfig</code> object.
+     *
+     * @param name 		a <code>String</code> specifying the name 
+     *				of the initialization parameter
+     *
+     * @return String 		a <code>String</code> containing the value
+     *				of the initialization parameter
+     *
+     */ 
+    public String getInitParameter(String name) {
+        ServletConfig sc = getServletConfig();
+        if (sc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.servlet_config_not_initialized"));
+        }
+
+        return sc.getInitParameter(name);
+    }
+    
+    
+   /**
+    * Returns the names of the servlet's initialization parameters 
+    * as an <code>Enumeration</code> of <code>String</code> objects,
+    * or an empty <code>Enumeration</code> if the servlet has no
+    * initialization parameters.  See {@link
+    * ServletConfig#getInitParameterNames}.
+    *
+    * <p>This method is supplied for convenience. It gets the 
+    * parameter names from the servlet's <code>ServletConfig</code> object. 
+    *
+    *
+    * @return Enumeration 	an enumeration of <code>String</code>
+    *				objects containing the names of 
+    *				the servlet's initialization parameters
+    */
+    public Enumeration<String> getInitParameterNames() {
+        ServletConfig sc = getServletConfig();
+        if (sc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.servlet_config_not_initialized"));
+        }
+
+        return sc.getInitParameterNames();
+    }   
+     
+
+    /**
+     * Returns this servlet's {@link ServletConfig} object.
+     *
+     * @return ServletConfig 	the <code>ServletConfig</code> object
+     *				that initialized this servlet
+     */    
+    public ServletConfig getServletConfig() {
+	return config;
+    }
+ 
+    
+    /**
+     * Returns a reference to the {@link ServletContext} in which this servlet
+     * is running.  See {@link ServletConfig#getServletContext}.
+     *
+     * <p>This method is supplied for convenience. It gets the 
+     * context from the servlet's <code>ServletConfig</code> object.
+     *
+     *
+     * @return ServletContext 	the <code>ServletContext</code> object
+     *				passed to this servlet by the <code>init</code>
+     *				method
+     */
+    public ServletContext getServletContext() {
+        ServletConfig sc = getServletConfig();
+        if (sc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.servlet_config_not_initialized"));
+        }
+
+        return sc.getServletContext();
+    }
+
+
+    /**
+     * Returns information about the servlet, such as 
+     * author, version, and copyright. 
+     * By default, this method returns an empty string.  Override this method
+     * to have it return a meaningful value.  See {@link
+     * Servlet#getServletInfo}.
+     *
+     *
+     * @return String 		information about this servlet, by default an
+     * 				empty string
+     */    
+    public String getServletInfo() {
+	return "";
+    }
+
+
+    /**
+     * Called by the servlet container to indicate to a servlet that the
+     * servlet is being placed into service.  See {@link Servlet#init}.
+     *
+     * <p>This implementation stores the {@link ServletConfig}
+     * object it receives from the servlet container for later use.
+     * When overriding this form of the method, call 
+     * <code>super.init(config)</code>.
+     *
+     * @param config 			the <code>ServletConfig</code> object
+     *					that contains configuration
+     *					information for this servlet
+     *
+     * @exception ServletException 	if an exception occurs that
+     *					interrupts the servlet's normal
+     *					operation
+     * 
+     * @see 				UnavailableException
+     */
+    public void init(ServletConfig config) throws ServletException {
+	this.config = config;
+	this.init();
+    }
+
+
+    /**
+     * A convenience method which can be overridden so that there's no need
+     * to call <code>super.init(config)</code>.
+     *
+     * <p>Instead of overriding {@link #init(ServletConfig)}, simply override
+     * this method and it will be called by
+     * <code>GenericServlet.init(ServletConfig config)</code>.
+     * The <code>ServletConfig</code> object can still be retrieved via {@link
+     * #getServletConfig}. 
+     *
+     * @exception ServletException 	if an exception occurs that
+     *					interrupts the servlet's
+     *					normal operation
+     */
+    public void init() throws ServletException {
+
+    }
+    
+
+    /**
+     * Writes the specified message to a servlet log file, prepended by the
+     * servlet's name.  See {@link ServletContext#log(String)}.
+     *
+     * @param msg 	a <code>String</code> specifying
+     *			the message to be written to the log file
+     */     
+    public void log(String msg) {
+	getServletContext().log(getServletName() + ": "+ msg);
+    }
+   
+   
+    /**
+     * Writes an explanatory message and a stack trace
+     * for a given <code>Throwable</code> exception
+     * to the servlet log file, prepended by the servlet's name.
+     * See {@link ServletContext#log(String, Throwable)}.
+     *
+     *
+     * @param message 		a <code>String</code> that describes
+     *				the error or exception
+     *
+     * @param t			the <code>java.lang.Throwable</code> error
+     * 				or exception
+     */   
+    public void log(String message, Throwable t) {
+	getServletContext().log(getServletName() + ": " + message, t);
+    }
+    
+    
+    /**
+     * Called by the servlet container to allow the servlet to respond to
+     * a request.  See {@link Servlet#service}.
+     * 
+     * <p>This method is declared abstract so subclasses, such as 
+     * <code>HttpServlet</code>, must override it.
+     *
+     * @param req 	the <code>ServletRequest</code> object
+     *			that contains the client's request
+     *
+     * @param res 	the <code>ServletResponse</code> object
+     *			that will contain the servlet's response
+     *
+     * @exception ServletException 	if an exception occurs that
+     *					interferes with the servlet's
+     *					normal operation occurred
+     *
+     * @exception IOException 		if an input or output
+     *					exception occurs
+     */
+
+    public abstract void service(ServletRequest req, ServletResponse res)
+	throws ServletException, IOException;
+    
+
+    /**
+     * Returns the name of this servlet instance.
+     * See {@link ServletConfig#getServletName}.
+     *
+     * @return          the name of this servlet instance
+     */
+    public String getServletName() {
+        ServletConfig sc = getServletConfig();
+        if (sc == null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.servlet_config_not_initialized"));
+        }
+
+        return sc.getServletName();
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/HttpConstraintElement.java b/third_party/servlet-spec/src/main/java/javax/servlet/HttpConstraintElement.java
new file mode 100644
index 0000000..47763a4
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/HttpConstraintElement.java
@@ -0,0 +1,172 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.util.*;
+import javax.servlet.annotation.HttpConstraint;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
+
+/**
+ * Java Class representation of an {@link HttpConstraint} annotation value.
+ *
+ * @since Servlet 3.0
+ */
+public class HttpConstraintElement {
+
+    private EmptyRoleSemantic emptyRoleSemantic;
+    private TransportGuarantee transportGuarantee;
+    private String[] rolesAllowed;
+
+    /**
+     * Constructs a default HTTP constraint element
+     */
+    public HttpConstraintElement() {
+        this(EmptyRoleSemantic.PERMIT);
+    }
+
+    /**
+     * Convenience constructor to establish <tt>EmptyRoleSemantic.DENY</tt>
+     *
+     * @param semantic should be EmptyRoleSemantic.DENY
+     */
+    public HttpConstraintElement(EmptyRoleSemantic semantic) {
+        this(semantic, TransportGuarantee.NONE, new String[0]);
+    }
+
+    /**
+     * Constructor to establish non-empty getRolesAllowed and/or
+     * <tt>TransportGuarantee.CONFIDENTIAL</tt>.
+     *
+     * @param guarantee <tt>TransportGuarantee.NONE</tt> or
+     * <tt>TransportGuarantee.CONFIDENTIAL</tt>
+     * @param roleNames the names of the roles that are to be
+     * allowed access
+     */
+    public HttpConstraintElement(TransportGuarantee guarantee,
+            String... roleNames) {
+        this(EmptyRoleSemantic.PERMIT, guarantee, roleNames);
+    }
+
+    /**
+     * Constructor to establish all of getEmptyRoleSemantic,
+     * getRolesAllowed, and getTransportGuarantee.
+     *
+     * @param semantic <tt>EmptyRoleSemantic.DENY</tt> or
+     * <tt>EmptyRoleSemantic.PERMIT</tt>
+     * @param guarantee <tt>TransportGuarantee.NONE</tt> or
+     * <tt>TransportGuarantee.CONFIDENTIAL</tt>
+     * @param roleNames the names of the roles that are to be allowed
+     * access, or missing if the semantic is <tt>EmptyRoleSemantic.DENY</tt>
+     */
+    public HttpConstraintElement(EmptyRoleSemantic semantic,
+            TransportGuarantee guarantee, String... roleNames) {
+        if (semantic == EmptyRoleSemantic.DENY && roleNames.length > 0) {
+            throw new IllegalArgumentException(
+                "Deny semantic with rolesAllowed");
+        }
+        this.emptyRoleSemantic = semantic;
+        this.transportGuarantee = guarantee;
+        this.rolesAllowed = copyStrings(roleNames);
+    }
+
+    /**
+     * Gets the default authorization semantic.
+     *
+     * <p>This value is insignificant when <code>getRolesAllowed</code>
+     * returns a non-empty array, and should not be specified when a
+     * non-empty array is specified for <tt>getRolesAllowed</tt>.
+     *
+     * @return the {@link EmptyRoleSemantic} to be applied when
+     * <code>getRolesAllowed</code> returns an empty (that is, zero-length)
+     * array
+     */
+    public EmptyRoleSemantic getEmptyRoleSemantic() {
+        return this.emptyRoleSemantic;
+    }
+
+    /**
+     * Gets the data protection requirement (i.e., whether or not SSL/TLS is
+     * required) that must be satisfied by the transport connection.
+     *
+     * @return the {@link TransportGuarantee} indicating the data
+     * protection that must be provided by the connection
+     */
+    public TransportGuarantee getTransportGuarantee() {
+        return this.transportGuarantee;
+    }
+
+    /**
+     * Gets the names of the authorized roles.
+     *
+     * <p>Duplicate role names appearing in getRolesAllowed are insignificant
+     * and may be discarded. The String <tt>"*"</tt> has no special meaning
+     * as a role name (should it occur in getRolesAllowed).
+     *
+     * @return a (possibly empty) array of role names. When the
+     * array is empty, its meaning depends on the value of
+     * {@link #getEmptyRoleSemantic}. If its value is <tt>DENY</tt>,
+     * and <code>getRolesAllowed</code> returns an empty array,
+     * access is to be denied independent of authentication state and
+     * identity. Conversely, if its value is <code>PERMIT</code>, it
+     * indicates that access is to be allowed independent of authentication
+     * state and identity. When the array contains the names of one or
+     * more roles, it indicates that access is contingent on membership in at
+     * least one of the named roles (independent of the value of
+     * {@link #getEmptyRoleSemantic}).
+     */
+    public String[] getRolesAllowed() {
+        return copyStrings(this.rolesAllowed);
+    }
+
+    private String[] copyStrings(String[] strings) {
+        String[] arr = null;
+        if (strings != null) {
+            int len = strings.length;
+            arr = new String[len];
+            if (len > 0) {
+                System.arraycopy(strings, 0, arr, 0, len);
+            }
+        }
+
+        return ((arr != null) ? arr : new String[0]);
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/HttpMethodConstraintElement.java b/third_party/servlet-spec/src/main/java/javax/servlet/HttpMethodConstraintElement.java
new file mode 100644
index 0000000..17bd88b
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/HttpMethodConstraintElement.java
@@ -0,0 +1,98 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import javax.servlet.annotation.HttpMethodConstraint;
+
+/**
+ * Java Class represntation of an {@link HttpMethodConstraint} annotation value.
+ *
+ * @since Servlet 3.0
+ */
+public class HttpMethodConstraintElement extends HttpConstraintElement {
+
+    private String methodName;
+
+    /**
+     * Constructs an instance with default {@link HttpConstraintElement}
+     * value.
+     *
+     * @param methodName the name of an HTTP protocol method. The name must
+     * not be null, or the empty string, and must be a legitimate HTTP
+     * Method name as defined by RFC 2616
+     */
+    public HttpMethodConstraintElement(String methodName) {
+        if (methodName == null || methodName.length() == 0) {
+            throw new IllegalArgumentException("invalid HTTP method name");
+        }
+        this.methodName = methodName;
+    }
+    /**
+     * Constructs an instance with specified {@link HttpConstraintElement}
+     * value.
+     *
+     * @param methodName the name of an HTTP protocol method. The name must
+     * not be null, or the empty string, and must be a legitimate HTTP
+     * Method name as defined by RFC 2616
+     *
+     * @param constraint the HTTPconstraintElement value to assign to the
+     * named HTTP method
+     */
+    public HttpMethodConstraintElement(String methodName,
+            HttpConstraintElement constraint) {
+        super(constraint.getEmptyRoleSemantic(),
+                constraint.getTransportGuarantee(),
+                constraint.getRolesAllowed());
+        if (methodName == null || methodName.length() == 0) {
+            throw new IllegalArgumentException("invalid HTTP method name");
+        }
+        this.methodName = methodName;
+    }
+
+    /**
+     * Gets the HTTP method name.
+     *
+     * @return the Http method name
+     */
+    public String getMethodName() {
+        return this.methodName;
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings.properties b/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings.properties
new file mode 100644
index 0000000..7a478e0
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings.properties
@@ -0,0 +1,24 @@
+#
+# Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright 2004 The Apache Software Foundation
+#
+# 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.
+#
+
+# Default localized string information
+# Localized for Locale en_US
+
+err.not_iso8859_1=Not an ISO 8859-1 character: {0}
+err.servlet_config_not_initialized=ServletConfig has not been initialized
+value.true=true
+value.false=false
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings_fr.properties b/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings_fr.properties
new file mode 100644
index 0000000..af9a2f0
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings_fr.properties
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright 2004 The Apache Software Foundation
+#
+# 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.
+#
+
+# Default localized string information
+# Localized for Locale fr_FR
+
+err.not_iso8859_1={0} n''est pas un caractère ISO 8859-1
+value.true=true
+value.false=false 
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings_ja.properties b/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings_ja.properties
new file mode 100644
index 0000000..7d55785
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/LocalStrings_ja.properties
@@ -0,0 +1,23 @@
+#
+# Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright 2004 The Apache Software Foundation
+#
+# 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.
+#
+
+# Default localized string information
+# Localized for Locale ja_JP
+
+err.not_iso8859_1=ISO 8859-1 \u306e\u6587\u5b57\u3067\u306f\u3042\u308a\u307e\u305b\u3093: {0}
+value.true=true
+value.false=false
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/MultipartConfigElement.java b/third_party/servlet-spec/src/main/java/javax/servlet/MultipartConfigElement.java
new file mode 100644
index 0000000..dd36f82
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/MultipartConfigElement.java
@@ -0,0 +1,142 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import javax.servlet.annotation.MultipartConfig;
+
+/**
+ * Java Class represntation of an {@link MultipartConfig} annotation value.
+ *
+ * @since Servlet 3.0
+ */
+public class MultipartConfigElement {
+
+    private String location;
+    private long maxFileSize;
+    private long maxRequestSize;
+    private int fileSizeThreshold;
+
+    /**
+     * Constructs an instance with defaults for all but location.
+     *
+     * @param location defualts to "" if values is null.
+     */
+    public MultipartConfigElement(String location) {
+        if (location == null) {
+            this.location = "";
+        } else {
+            this.location = location;
+        }
+        this.maxFileSize = -1L;
+        this.maxRequestSize = -1L;
+        this.fileSizeThreshold = 0;
+    }
+
+    /**
+     * Constructs an instance with all values specified.
+     *
+     * @param location the directory location where files will be stored
+     * @param maxFileSize the maximum size allowed for uploaded files
+     * @param maxRequestSize the maximum size allowed for
+     * multipart/form-data requests
+     * @param fileSizeThreshold the size threshold after which files will
+     * be written to disk
+     */
+    public MultipartConfigElement(String location, long maxFileSize,
+            long maxRequestSize, int fileSizeThreshold) {
+        if (location == null) {
+            this.location = "";
+        } else {
+            this.location = location;
+        }
+        this.maxFileSize = maxFileSize;
+        this.maxRequestSize = maxRequestSize;
+        this.fileSizeThreshold = fileSizeThreshold;
+    }
+
+    /**
+     * Constructs an instance from a {@link MultipartConfig} annotation value.
+     *
+     * @param annotation the annotation value
+     */
+    public MultipartConfigElement(MultipartConfig annotation) {
+        this.location = annotation.location();
+        this.fileSizeThreshold = annotation.fileSizeThreshold();
+        this.maxFileSize = annotation.maxFileSize();
+        this.maxRequestSize = annotation.maxRequestSize();
+    }
+
+    /**
+     * Gets the directory location where files will be stored.
+     *
+     * @return the directory location where files will be stored
+     */
+    public String getLocation() {
+        return this.location;
+    }
+
+    /**
+     * Gets the maximum size allowed for uploaded files.
+     *
+     * @return the maximum size allowed for uploaded files
+     */
+    public long getMaxFileSize() {
+        return this.maxFileSize;
+    }
+
+    /**
+     * Gets the maximum size allowed for multipart/form-data requests.
+     *
+     * @return the maximum size allowed for multipart/form-data requests
+     */
+    public long getMaxRequestSize() {
+        return this.maxRequestSize;
+    }
+
+    /**
+     * Gets the size threshold after which files will be written to disk.
+     *
+     * @return the size threshold after which files will be written to disk
+     */
+    public int getFileSizeThreshold() {
+        return this.fileSizeThreshold;
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ReadListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/ReadListener.java
new file mode 100644
index 0000000..82a5449
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ReadListener.java
@@ -0,0 +1,84 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.io.IOException;
+import java.util.EventListener;
+
+/**
+ * <p>
+ * This class represents a call-back mechanism that will notify implementations
+ * as HTTP request data becomes available to be read without blocking.
+ * </p>
+ *
+ * @since Servlet 3.1
+ */
+public interface ReadListener extends EventListener {
+
+    /**
+     * When an instance of the <code>ReadListener</code> is registered with a {@link ServletInputStream},
+     * this method will be invoked by the container the first time when it is possible
+     * to read data. Subsequently the container will invoke this method if and only
+     * if the {@link javax.servlet.ServletInputStream#isReady()} method
+     * has been called and has returned a value of <code>false</code> <em>and</em>
+     * data has subsequently become available to read.
+     *
+     * @throws IOException if an I/O related error has occurred during processing
+     */
+    public void onDataAvailable() throws IOException;
+
+    /**
+     * Invoked when all data for the current request has been read.
+     *
+     * @throws IOException if an I/O related error has occurred during processing
+     */
+
+    public void onAllDataRead() throws IOException;
+
+    /**
+     * Invoked when an error occurs processing the request.
+     *
+     * @param t the throwable to indicate why the read operation failed
+     */
+    public void onError(Throwable t);
+
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/Registration.java b/third_party/servlet-spec/src/main/java/javax/servlet/Registration.java
new file mode 100644
index 0000000..26df091
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/Registration.java
@@ -0,0 +1,187 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Interface through which a {@link Servlet} or {@link Filter} may be
+ * further configured.
+ *
+ * <p>A Registration object whose {@link #getClassName} method returns null
+ * is considered <i>preliminary</i>. Servlets and Filters whose implementation
+ * class is container implementation specific may be declared without
+ * any <tt>servlet-class</tt> or <tt>filter-class</tt> elements, respectively,
+ * and will be represented as preliminary Registration objects. 
+ * Preliminary registrations must be completed by calling one of the
+ * <tt>addServlet</tt> or <tt>addFilter</tt> methods on
+ * {@link ServletContext}, and passing in the Servlet or Filter name 
+ * (obtained via {@link #getName}) along with the supporting Servlet or Filter
+ * implementation class name, Class object, or instance, respectively.
+ * In most cases, preliminary registrations will be completed by an
+ * appropriate, container-provided {@link ServletContainerInitializer}.
+ *
+ * @since Servlet 3.0
+ */
+public interface Registration {
+
+    /**
+     * Gets the name of the Servlet or Filter that is represented by this
+     * Registration.
+     *
+     * @return the name of the Servlet or Filter that is represented by this
+     * Registration
+     */
+    public String getName();
+
+    /**
+     * Gets the fully qualified class name of the Servlet or Filter that
+     * is represented by this Registration.
+     *
+     * @return the fully qualified class name of the Servlet or Filter
+     * that is represented by this Registration, or null if this
+     * Registration is preliminary
+     */
+    public String getClassName();
+
+    /**
+     * Sets the initialization parameter with the given name and value
+     * on the Servlet or Filter that is represented by this Registration.
+     *
+     * @param name the initialization parameter name
+     * @param value the initialization parameter value
+     *
+     * @return true if the update was successful, i.e., an initialization
+     * parameter with the given name did not already exist for the Servlet
+     * or Filter represented by this Registration, and false otherwise
+     *
+     * @throws IllegalStateException if the ServletContext from which this
+     * Registration was obtained has already been initialized
+     * @throws IllegalArgumentException if the given name or value is
+     * <tt>null</tt>
+     */ 
+    public boolean setInitParameter(String name, String value);
+
+    /**
+     * Gets the value of the initialization parameter with the given name
+     * that will be used to initialize the Servlet or Filter represented
+     * by this Registration object.
+     *
+     * @param name the name of the initialization parameter whose value is
+     * requested
+     *
+     * @return the value of the initialization parameter with the given
+     * name, or <tt>null</tt> if no initialization parameter with the given
+     * name exists
+     */ 
+    public String getInitParameter(String name);
+
+    /**
+     * Sets the given initialization parameters on the Servlet or Filter
+     * that is represented by this Registration.
+     *
+     * <p>The given map of initialization parameters is processed
+     * <i>by-value</i>, i.e., for each initialization parameter contained
+     * in the map, this method calls {@link #setInitParameter(String,String)}.
+     * If that method would return false for any of the
+     * initialization parameters in the given map, no updates will be
+     * performed, and false will be returned. Likewise, if the map contains
+     * an initialization parameter with a <tt>null</tt> name or value, no
+     * updates will be performed, and an IllegalArgumentException will be
+     * thrown.
+     *
+     * <p>The returned set is not backed by the {@code Registration} object,
+     * so changes in the returned set are not reflected in the
+     * {@code Registration} object, and vice-versa.</p>
+     *
+     * @param initParameters the initialization parameters
+     *
+     * @return the (possibly empty) Set of initialization parameter names
+     * that are in conflict
+     *
+     * @throws IllegalStateException if the ServletContext from which this
+     * Registration was obtained has already been initialized
+     * @throws IllegalArgumentException if the given map contains an
+     * initialization parameter with a <tt>null</tt> name or value
+     */ 
+    public Set<String> setInitParameters(Map<String, String> initParameters);
+
+    /**
+     * Gets an immutable (and possibly empty) Map containing the
+     * currently available initialization parameters that will be used to
+     * initialize the Servlet or Filter represented by this Registration
+     * object.
+     *
+     * @return Map containing the currently available initialization
+     * parameters that will be used to initialize the Servlet or Filter
+     * represented by this Registration object
+     */ 
+    public Map<String, String> getInitParameters();
+
+    /**
+     * Interface through which a {@link Servlet} or {@link Filter} registered
+     * via one of the <tt>addServlet</tt> or <tt>addFilter</tt> methods,
+     * respectively, on {@link ServletContext} may be further configured.
+     */
+    interface Dynamic extends Registration {
+
+        /**
+         * Configures the Servlet or Filter represented by this dynamic
+         * Registration as supporting asynchronous operations or not.
+         *
+         * <p>By default, servlet and filters do not support asynchronous
+         * operations.
+         *
+         * <p>A call to this method overrides any previous setting.
+         *
+         * @param isAsyncSupported true if the Servlet or Filter represented
+         * by this dynamic Registration supports asynchronous operations,
+         * false otherwise
+         *
+         * @throws IllegalStateException if the ServletContext from which
+         * this dynamic Registration was obtained has already been
+         * initialized
+         */
+        public void setAsyncSupported(boolean isAsyncSupported);
+    }
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/RequestDispatcher.java b/third_party/servlet-spec/src/main/java/javax/servlet/RequestDispatcher.java
new file mode 100644
index 0000000..19cdacc
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/RequestDispatcher.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.IOException;
+
+/**
+ * Defines an object that receives requests from the client
+ * and sends them to any resource (such as a servlet, 
+ * HTML file, or JSP file) on the server. The servlet
+ * container creates the <code>RequestDispatcher</code> object,
+ * which is used as a wrapper around a server resource located
+ * at a particular path or given by a particular name.
+ *
+ * <p>This interface is intended to wrap servlets,
+ * but a servlet container can create <code>RequestDispatcher</code>
+ * objects to wrap any type of resource.
+ *
+ * @author Various
+ *
+ * @see ServletContext#getRequestDispatcher(java.lang.String)
+ * @see ServletContext#getNamedDispatcher(java.lang.String)
+ * @see ServletRequest#getRequestDispatcher(java.lang.String)
+ */
+ 
+public interface RequestDispatcher {
+
+    /**
+     * The name of the request attribute under which the original
+     * request URI is made available to the target of a 
+     * {@link #forward(ServletRequest,ServletResponse) forward}
+     */
+    static final String FORWARD_REQUEST_URI = "javax.servlet.forward.request_uri";
+
+    /**
+     * The name of the request attribute under which the original
+     * context path is made available to the target of a 
+     * {@link #forward(ServletRequest,ServletResponse) forward}
+     */
+    static final String FORWARD_CONTEXT_PATH = "javax.servlet.forward.context_path";
+
+    /**
+     * The name of the request attribute under which the original
+     * {@link javax.servlet.http.HttpServletMapping} is made available
+     * to the target of a 
+     * {@link #forward(ServletRequest,ServletResponse) forward}
+     * 
+     * @since 4.0
+     */
+    static final String FORWARD_MAPPING = "javax.servlet.forward.mapping";
+
+    /**
+     * The name of the request attribute under which the original
+     * path info is made available to the target of a 
+     * {@link #forward(ServletRequest,ServletResponse) forward}
+     */
+    static final String FORWARD_PATH_INFO = "javax.servlet.forward.path_info";
+
+    /**
+     * The name of the request attribute under which the original
+     * servlet path is made available to the target of a 
+     * {@link #forward(ServletRequest,ServletResponse) forward}
+     */
+    static final String FORWARD_SERVLET_PATH = "javax.servlet.forward.servlet_path";
+
+    /**
+     * The name of the request attribute under which the original
+     * query string is made available to the target of a 
+     * {@link #forward(ServletRequest,ServletResponse) forward}
+     */
+    static final String FORWARD_QUERY_STRING = "javax.servlet.forward.query_string";
+
+    /**
+     * The name of the request attribute under which the request URI
+     * of the target of an {@link #include(ServletRequest,ServletResponse)
+     * include} is stored
+     */
+    static final String INCLUDE_REQUEST_URI = "javax.servlet.include.request_uri";
+
+    /**
+     * The name of the request attribute under which the context path
+     * of the target of an {@link #include(ServletRequest,ServletResponse)
+     * include} is stored
+     */
+    static final String INCLUDE_CONTEXT_PATH = "javax.servlet.include.context_path";
+
+    /**
+     * The name of the request attribute under which the path info
+     * of the target of an {@link #include(ServletRequest,ServletResponse)
+     * include} is stored
+     */
+    static final String INCLUDE_PATH_INFO = "javax.servlet.include.path_info";
+
+    /**
+     * The name of the request attribute under which the
+     * {@link javax.servlet.http.HttpServletMapping}
+     * of the target of an {@link #include(ServletRequest,ServletResponse)
+     * include} is stored
+     */
+    static final String INCLUDE_MAPPING = "javax.servlet.include.mapping";
+
+    /**
+     * The name of the request attribute under which the servlet path
+     * of the target of an {@link #include(ServletRequest,ServletResponse)
+     * include} is stored
+     */
+    static final String INCLUDE_SERVLET_PATH = "javax.servlet.include.servlet_path";
+
+    /**
+     * The name of the request attribute under which the query string
+     * of the target of an {@link #include(ServletRequest,ServletResponse)
+     * include} is stored
+     */
+    static final String INCLUDE_QUERY_STRING = "javax.servlet.include.query_string";
+
+    /**
+     * The name of the request attribute under which the exception object
+     * is propagated during an error dispatch
+     */
+    public static final String ERROR_EXCEPTION = "javax.servlet.error.exception";
+
+    /**
+     * The name of the request attribute under which the type of the
+     * exception object is propagated during an error dispatch
+     */
+    public static final String ERROR_EXCEPTION_TYPE = "javax.servlet.error.exception_type";
+
+    /**
+     * The name of the request attribute under which the exception message
+     * is propagated during an error dispatch
+     */
+    public static final String ERROR_MESSAGE = "javax.servlet.error.message";
+
+    /**
+     * The name of the request attribute under which the request URI
+     * whose processing caused the error is propagated during an error
+     * dispatch
+     */
+    public static final String ERROR_REQUEST_URI = "javax.servlet.error.request_uri";
+
+    /**
+     * The name of the request attribute under which the name of the servlet
+     * in which the error occurred is propagated during an error dispatch
+     */
+    public static final String ERROR_SERVLET_NAME = "javax.servlet.error.servlet_name";
+
+    /**
+     * The name of the request attribute under which the response status
+     * is propagated during an error dispatch
+     */
+    public static final String ERROR_STATUS_CODE = "javax.servlet.error.status_code";
+
+
+    /**
+     * Forwards a request from
+     * a servlet to another resource (servlet, JSP file, or
+     * HTML file) on the server. This method allows
+     * one servlet to do preliminary processing of
+     * a request and another resource to generate
+     * the response.
+     *
+     * <p>For a <code>RequestDispatcher</code> obtained via 
+     * <code>getRequestDispatcher()</code>, the <code>ServletRequest</code> 
+     * object has its path elements and parameters adjusted to match
+     * the path of the target resource.
+     *
+     * <p><code>forward</code> should be called before the response has been 
+     * committed to the client (before response body output has been flushed). 
+     * If the response already has been committed, this method throws
+     * an <code>IllegalStateException</code>.
+     * Uncommitted output in the response buffer is automatically cleared 
+     * before the forward.
+     *
+     * <p>The request and response parameters must be either the same
+     * objects as were passed to the calling servlet's service method or be
+     * subclasses of the {@link ServletRequestWrapper} or
+     * {@link ServletResponseWrapper} classes
+     * that wrap them.
+     *
+     * <p>This method sets the dispatcher type of the given request to
+     * <code>DispatcherType.FORWARD</code>.
+     *
+     * @param request a {@link ServletRequest} object that represents the
+     * request the client makes of the servlet
+     *
+     * @param response a {@link ServletResponse} object that represents
+     * the response the servlet returns to the client
+     *
+     * @throws ServletException if the target resource throws this exception
+     *
+     * @throws IOException if the target resource throws this exception
+     *
+     * @throws IllegalStateException if the response was already committed
+     *
+     * @see ServletRequest#getDispatcherType
+     */
+    public void forward(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException;
+
+    /**
+     *
+     * Includes the content of a resource (servlet, JSP page,
+     * HTML file) in the response. In essence, this method enables 
+     * programmatic server-side includes.
+     *
+     * <p>The {@link ServletResponse} object has its path elements
+     * and parameters remain unchanged from the caller's. The included
+     * servlet cannot change the response status code or set headers;
+     * any attempt to make a change is ignored.
+     *
+     * <p>The request and response parameters must be either the same
+     * objects as were passed to the calling servlet's service method or be
+     * subclasses of the {@link ServletRequestWrapper} or
+     * {@link ServletResponseWrapper} classes that wrap them.
+     *
+     * <p>This method sets the dispatcher type of the given request to
+     * <code>DispatcherType.INCLUDE</code>.
+     *
+     * @param request a {@link ServletRequest} object that contains the
+     * client's request
+     *
+     * @param response a {@link ServletResponse} object that contains the
+     * servlet's response
+     *
+     * @throws ServletException if the included resource throws this
+     * exception
+     *
+     * @throws IOException if the included resource throws this exception
+     *
+     * @see ServletRequest#getDispatcherType
+     */
+    public void include(ServletRequest request, ServletResponse response)
+        throws ServletException, IOException;
+}
+
+
+
+
+
+
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/Servlet.java b/third_party/servlet-spec/src/main/java/javax/servlet/Servlet.java
new file mode 100644
index 0000000..abb0250
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/Servlet.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.IOException;
+
+
+/**
+ * Defines methods that all servlets must implement.
+ *
+ * <p>A servlet is a small Java program that runs within a Web server.
+ * Servlets receive and respond to requests from Web clients,
+ * usually across HTTP, the HyperText Transfer Protocol. 
+ *
+ * <p>To implement this interface, you can write a generic servlet
+ * that extends
+ * <code>javax.servlet.GenericServlet</code> or an HTTP servlet that
+ * extends <code>javax.servlet.http.HttpServlet</code>.
+ *
+ * <p>This interface defines methods to initialize a servlet,
+ * to service requests, and to remove a servlet from the server.
+ * These are known as life-cycle methods and are called in the
+ * following sequence:
+ * <ol>
+ * <li>The servlet is constructed, then initialized with the <code>init</code> method.
+ * <li>Any calls from clients to the <code>service</code> method are handled.
+ * <li>The servlet is taken out of service, then destroyed with the 
+ * <code>destroy</code> method, then garbage collected and finalized.
+ * </ol>
+ *
+ * <p>In addition to the life-cycle methods, this interface
+ * provides the <code>getServletConfig</code> method, which the servlet 
+ * can use to get any startup information, and the <code>getServletInfo</code>
+ * method, which allows the servlet to return basic information about itself,
+ * such as author, version, and copyright.
+ *
+ * @author 	Various
+ *
+ * @see 	GenericServlet
+ * @see 	javax.servlet.http.HttpServlet
+ *
+ */
+
+
+public interface Servlet {
+
+    /**
+     * Called by the servlet container to indicate to a servlet that the 
+     * servlet is being placed into service.
+     *
+     * <p>The servlet container calls the <code>init</code>
+     * method exactly once after instantiating the servlet.
+     * The <code>init</code> method must complete successfully
+     * before the servlet can receive any requests.
+     *
+     * <p>The servlet container cannot place the servlet into service
+     * if the <code>init</code> method
+     * <ol>
+     * <li>Throws a <code>ServletException</code>
+     * <li>Does not return within a time period defined by the Web server
+     * </ol>
+     *
+     *
+     * @param config			a <code>ServletConfig</code> object 
+     *					containing the servlet's
+     * 					configuration and initialization parameters
+     *
+     * @exception ServletException 	if an exception has occurred that
+     *					interferes with the servlet's normal
+     *					operation
+     *
+     * @see 				UnavailableException
+     * @see 				#getServletConfig
+     *
+     */
+
+    public void init(ServletConfig config) throws ServletException;
+    
+    
+
+    /**
+     *
+     * Returns a {@link ServletConfig} object, which contains
+     * initialization and startup parameters for this servlet.
+     * The <code>ServletConfig</code> object returned is the one 
+     * passed to the <code>init</code> method. 
+     *
+     * <p>Implementations of this interface are responsible for storing the 
+     * <code>ServletConfig</code> object so that this 
+     * method can return it. The {@link GenericServlet}
+     * class, which implements this interface, already does this.
+     *
+     * @return		the <code>ServletConfig</code> object
+     *			that initializes this servlet
+     *
+     * @see 		#init
+     *
+     */
+
+    public ServletConfig getServletConfig();
+    
+    
+
+    /**
+     * Called by the servlet container to allow the servlet to respond to 
+     * a request.
+     *
+     * <p>This method is only called after the servlet's <code>init()</code>
+     * method has completed successfully.
+     * 
+     * <p>  The status code of the response always should be set for a servlet 
+     * that throws or sends an error.
+     *
+     * 
+     * <p>Servlets typically run inside multithreaded servlet containers
+     * that can handle multiple requests concurrently. Developers must 
+     * be aware to synchronize access to any shared resources such as files,
+     * network connections, and as well as the servlet's class and instance 
+     * variables. 
+     * More information on multithreaded programming in Java is available in 
+     * <a href="http://java.sun.com/Series/Tutorial/java/threads/multithreaded.html">
+     * the Java tutorial on multi-threaded programming</a>.
+     *
+     *
+     * @param req 	the <code>ServletRequest</code> object that contains
+     *			the client's request
+     *
+     * @param res 	the <code>ServletResponse</code> object that contains
+     *			the servlet's response
+     *
+     * @exception ServletException 	if an exception occurs that interferes
+     *					with the servlet's normal operation 
+     *
+     * @exception IOException 		if an input or output exception occurs
+     *
+     */
+
+    public void service(ServletRequest req, ServletResponse res)
+	throws ServletException, IOException;
+	
+	
+
+    /**
+     * Returns information about the servlet, such
+     * as author, version, and copyright.
+     * 
+     * <p>The string that this method returns should
+     * be plain text and not markup of any kind (such as HTML, XML,
+     * etc.).
+     *
+     * @return 		a <code>String</code> containing servlet information
+     *
+     */
+
+    public String getServletInfo();
+    
+    
+
+    /**
+     *
+     * Called by the servlet container to indicate to a servlet that the
+     * servlet is being taken out of service.  This method is
+     * only called once all threads within the servlet's
+     * <code>service</code> method have exited or after a timeout
+     * period has passed. After the servlet container calls this 
+     * method, it will not call the <code>service</code> method again
+     * on this servlet.
+     *
+     * <p>This method gives the servlet an opportunity 
+     * to clean up any resources that are being held (for example, memory,
+     * file handles, threads) and make sure that any persistent state is
+     * synchronized with the servlet's current state in memory.
+     *
+     */
+
+    public void destroy();
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletConfig.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletConfig.java
new file mode 100644
index 0000000..2140916
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletConfig.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.util.Enumeration;
+
+/**
+ * A servlet configuration object used by a servlet container
+ * to pass information to a servlet during initialization. 
+ */
+ public interface ServletConfig {
+    
+    /**
+     * Returns the name of this servlet instance.
+     * The name may be provided via server administration, assigned in the 
+     * web application deployment descriptor, or for an unregistered (and thus
+     * unnamed) servlet instance it will be the servlet's class name.
+     *
+     * @return	the name of the servlet instance
+     */
+    public String getServletName();
+
+
+    /**
+     * Returns a reference to the {@link ServletContext} in which the caller
+     * is executing.
+     *
+     * @return	a {@link ServletContext} object, used
+     * by the caller to interact with its servlet container
+     * 
+     * @see ServletContext
+     */
+    public ServletContext getServletContext();
+
+    
+    /**
+     * Gets the value of the initialization parameter with the given name.
+     *
+     * @param name the name of the initialization parameter whose value to
+     * get
+     *
+     * @return a <code>String</code> containing the value 
+     * of the initialization parameter, or <code>null</code> if 
+     * the initialization parameter does not exist
+     */
+    public String getInitParameter(String name);
+
+
+    /**
+     * Returns the names of the servlet's initialization parameters
+     * as an <code>Enumeration</code> of <code>String</code> objects, 
+     * or an empty <code>Enumeration</code> if the servlet has
+     * no initialization parameters.
+     *
+     * @return an <code>Enumeration</code> of <code>String</code> 
+     * objects containing the names of the servlet's 
+     * initialization parameters
+     */
+    public Enumeration<String> getInitParameterNames();
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletContainerInitializer.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContainerInitializer.java
new file mode 100644
index 0000000..a7e873e
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContainerInitializer.java
@@ -0,0 +1,115 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.util.Set;
+
+/**
+ * Interface which allows a library/runtime to be notified of a web
+ * application's startup phase and perform any required programmatic
+ * registration of servlets, filters, and listeners in response to it.
+ *
+ * <p>Implementations of this interface may be annotated with
+ * {@link javax.servlet.annotation.HandlesTypes HandlesTypes}, in order to
+ * receive (at their {@link #onStartup} method) the Set of application
+ * classes that implement, extend, or have been annotated with the class
+ * types specified by the annotation.
+ * 
+ * <p>If an implementation of this interface does not use <tt>HandlesTypes</tt>
+ * annotation, or none of the application classes match the ones specified
+ * by the annotation, the container must pass a <tt>null</tt> Set of classes
+ * to {@link #onStartup}.
+ *
+ * <p>When examining the classes of an application to see if they match
+ * any of the criteria specified by the <tt>HandlesTypes</tt> annotation
+ * of a <tt>ServletContainerInitializer</tt>, the container may run into
+ * classloading problems if any of the application's optional JAR
+ * files are missing. Because the container is not in a position to decide
+ * whether these types of classloading failures will prevent
+ * the application from working correctly, it must ignore them,
+ * while at the same time providing a configuration option that would
+ * log them. 
+ *
+ * <p>Implementations of this interface must be declared by a JAR file
+ * resource located inside the <tt>META-INF/services</tt> directory and
+ * named for the fully qualified class name of this interface, and will be 
+ * discovered using the runtime's service provider lookup mechanism
+ * or a container specific mechanism that is semantically equivalent to
+ * it. In either case, <tt>ServletContainerInitializer</tt> services from web
+ * fragment JAR files excluded from an absolute ordering must be ignored,
+ * and the order in which these services are discovered must follow the
+ * application's classloading delegation model.
+ *
+ * @see javax.servlet.annotation.HandlesTypes
+ *
+ * @since Servlet 3.0
+ */
+public interface ServletContainerInitializer {
+
+    /**
+     * Notifies this <tt>ServletContainerInitializer</tt> of the startup
+     * of the application represented by the given <tt>ServletContext</tt>.
+     *
+     * <p>If this <tt>ServletContainerInitializer</tt> is bundled in a JAR
+     * file inside the <tt>WEB-INF/lib</tt> directory of an application,
+     * its <tt>onStartup</tt> method will be invoked only once during the
+     * startup of the bundling application. If this
+     * <tt>ServletContainerInitializer</tt> is bundled inside a JAR file
+     * outside of any <tt>WEB-INF/lib</tt> directory, but still
+     * discoverable as described above, its <tt>onStartup</tt> method
+     * will be invoked every time an application is started.
+     *
+     * @param c the Set of application classes that extend, implement, or
+     * have been annotated with the class types specified by the 
+     * {@link javax.servlet.annotation.HandlesTypes HandlesTypes} annotation,
+     * or <tt>null</tt> if there are no matches, or this
+     * <tt>ServletContainerInitializer</tt> has not been annotated with
+     * <tt>HandlesTypes</tt>
+     *
+     * @param ctx the <tt>ServletContext</tt> of the web application that
+     * is being started and in which the classes contained in <tt>c</tt>
+     * were found
+     *
+     * @throws ServletException if an error has occurred
+     */
+    public void onStartup(Set<Class<?>> c, ServletContext ctx)
+        throws ServletException; 
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletContext.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContext.java
new file mode 100644
index 0000000..3bd5431
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContext.java
@@ -0,0 +1,1757 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.EnumSet;
+import java.util.EventListener;
+import java.util.Map;
+import java.util.Set;
+import javax.servlet.descriptor.JspConfigDescriptor;
+
+/**
+ * Defines a set of methods that a servlet uses to communicate with its
+ * servlet container, for example, to get the MIME type of a file,
+ * dispatch requests, or write to a log file.
+ *
+ * <p>There is one context per "web application" per Java Virtual Machine.  (A
+ * "web application" is a collection of servlets and content installed under a
+ * specific subset of the server's URL namespace such as <code>/catalog</code>
+ * and possibly installed via a <code>.war</code> file.)
+ *
+ * <p>In the case of a web
+ * application marked "distributed" in its deployment descriptor, there will
+ * be one context instance for each virtual machine.  In this situation, the
+ * context cannot be used as a location to share global information (because
+ * the information won't be truly global).  Use an external resource like
+ * a database instead.
+ *
+ * <p>The <code>ServletContext</code> object is contained within
+ * the {@link ServletConfig} object, which the Web server provides the
+ * servlet when the servlet is initialized.
+ *
+ * @author 	Various
+ *
+ * @see 	Servlet#getServletConfig
+ * @see 	ServletConfig#getServletContext
+ */
+
+public interface ServletContext {
+
+    /**
+     * The name of the <tt>ServletContext</tt> attribute which stores
+     * the private temporary directory (of type <tt>java.io.File</tt>)
+     * provided by the servlet container for the <tt>ServletContext</tt>
+     */
+    public static final String TEMPDIR = "javax.servlet.context.tempdir";
+
+
+    /**
+     * The name of the <code>ServletContext</code> attribute whose value
+     * (of type <code>java.util.List&lt;java.lang.String&gt;</code>) contains
+     * the list of names of JAR files in <code>WEB-INF/lib</code> ordered by
+     * their web fragment names (with possible exclusions if
+     * <code>&lt;absolute-ordering&gt;</code> without any
+     * <code>&lt;others/&gt;</code> is being used), or null if no
+     * absolute or relative ordering has been specified
+     */
+    public static final String ORDERED_LIBS =
+        "javax.servlet.context.orderedLibs";
+
+
+    /**
+     * Returns the context path of the web application.
+     *
+     * <p>The context path is the portion of the request URI that is used
+     * to select the context of the request. The context path always comes
+     * first in a request URI. If this context is the "root" context
+     * rooted at the base of the Web server's URL name space, this path
+     * will be an empty string. Otherwise, if the context is not rooted at
+     * the root of the server's name space, the path starts with a /
+     * character but does not end with a / character.
+     *
+     * <p>It is possible that a servlet container may match a context by
+     * more than one context path. In such cases the
+     * {@link javax.servlet.http.HttpServletRequest#getContextPath()}
+     * will return the actual context path used by the request and it may
+     * differ from the path returned by this method.
+     * The context path returned by this method should be considered as the
+     * prime or preferred context path of the application.
+     *
+     * @return The context path of the web application, or "" for the
+     * root context
+     *
+     * @see javax.servlet.http.HttpServletRequest#getContextPath()
+     *
+     * @since Servlet 2.5
+     */
+    public String getContextPath();
+
+
+    /**
+     * Returns a <code>ServletContext</code> object that
+     * corresponds to a specified URL on the server.
+     *
+     * <p>This method allows servlets to gain
+     * access to the context for various parts of the server, and as
+     * needed obtain {@link RequestDispatcher} objects from the context.
+     * The given path must be begin with <tt>/</tt>, is interpreted relative
+     * to the server's document root and is matched against the context
+     * roots of other web applications hosted on this container.
+     *
+     * <p>In a security conscious environment, the servlet container may
+     * return <code>null</code> for a given URL.
+     *
+     * @param uripath 	a <code>String</code> specifying the context path of
+     *			another web application in the container.
+     * @return		the <code>ServletContext</code> object that
+     *			corresponds to the named URL, or null if either
+			none exists or the container wishes to restrict
+     * 			this access.
+     *
+     * @see 		RequestDispatcher
+     */
+    public ServletContext getContext(String uripath);
+
+
+    /**
+     * Returns the major version of the Servlet API that this
+     * servlet container supports. All implementations that comply
+     * with Version 4.0 must have this method return the integer 4.
+     *
+     * @return 4
+     */
+    public int getMajorVersion();
+
+
+    /**
+     * Returns the minor version of the Servlet API that this
+     * servlet container supports. All implementations that comply
+     * with Version 4.0 must have this method return the integer 0.
+     *
+     * @return 0
+     */
+    public int getMinorVersion();
+
+
+    /**
+     * Gets the major version of the Servlet specification that the
+     * application represented by this ServletContext is based on.
+     *
+     * <p>The value returned may be different from {@link #getMajorVersion},
+     * which returns the major version of the Servlet specification
+     * supported by the Servlet container.
+     *
+     * @return the major version of the Servlet specification that the
+     * application represented by this ServletContext is based on
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public int getEffectiveMajorVersion();
+
+
+    /**
+     * Gets the minor version of the Servlet specification that the
+     * application represented by this ServletContext is based on.
+     *
+     * <p>The value returned may be different from {@link #getMinorVersion},
+     * which returns the minor version of the Servlet specification
+     * supported by the Servlet container.
+     *
+     * @return the minor version of the Servlet specification that the
+     * application represented by this ServletContext is based on
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public int getEffectiveMinorVersion();
+
+
+    /**
+     * Returns the MIME type of the specified file, or <code>null</code> if
+     * the MIME type is not known. The MIME type is determined
+     * by the configuration of the servlet container, and may be specified
+     * in a web application deployment descriptor. Common MIME
+     * types include <code>text/html</code> and <code>image/gif</code>.
+     *
+     * @param file a <code>String</code> specifying the name of a file
+     *
+     * @return a <code>String</code> specifying the file's MIME type
+     */
+    public String getMimeType(String file);
+
+
+    /**
+     * Returns a directory-like listing of all the paths to resources
+     * within the web application whose longest sub-path matches the
+     * supplied path argument.
+     *
+     * <p>Paths indicating subdirectory paths end with a <tt>/</tt>.
+     *
+     * <p>The returned paths are all relative to the root of the web
+     * application, or relative to the <tt>/META-INF/resources</tt>
+     * directory of a JAR file inside the web application's
+     * <tt>/WEB-INF/lib</tt> directory, and have a leading <tt>/</tt>.
+     *
+     * <p>The returned set is not backed by the {@code ServletContext} object,
+     * so changes in the returned set are not reflected in the
+     * {@code ServletContext} object, and vice-versa.</p>
+     *
+     * <p>For example, for a web application containing:
+     *
+     * <pre>{@code
+     *   /welcome.html
+     *   /catalog/index.html
+     *   /catalog/products.html
+     *   /catalog/offers/books.html
+     *   /catalog/offers/music.html
+     *   /customer/login.jsp
+     *   /WEB-INF/web.xml
+     *   /WEB-INF/classes/com.acme.OrderServlet.class
+     *   /WEB-INF/lib/catalog.jar!/META-INF/resources/catalog/moreOffers/books.html
+     * }</pre>
+     *
+     * <tt>getResourcePaths("/")</tt> would return
+     * <tt>{"/welcome.html", "/catalog/", "/customer/", "/WEB-INF/"}</tt>,
+     * and <tt>getResourcePaths("/catalog/")</tt> would return
+     * <tt>{"/catalog/index.html", "/catalog/products.html",
+     * "/catalog/offers/", "/catalog/moreOffers/"}</tt>.
+     *
+     * @param path the partial path used to match the resources,
+     * which must start with a <tt>/</tt>
+     * @return a Set containing the directory listing, or null if there
+     * are no resources in the web application whose path
+     * begins with the supplied path.
+     *
+     * @since Servlet 2.3
+     */
+    public Set<String> getResourcePaths(String path);
+
+
+    /**
+     * Returns a URL to the resource that is mapped to the given path.
+     *
+     * <p>The path must begin with a <tt>/</tt> and is interpreted
+     * as relative to the current context root,
+     * or relative to the <tt>/META-INF/resources</tt> directory
+     * of a JAR file inside the web application's <tt>/WEB-INF/lib</tt>
+     * directory.
+     * This method will first search the document root of the
+     * web application for the requested resource, before searching
+     * any of the JAR files inside <tt>/WEB-INF/lib</tt>.
+     * The order in which the JAR files inside <tt>/WEB-INF/lib</tt>
+     * are searched is undefined.
+     *
+     * <p>This method allows the servlet container to make a resource
+     * available to servlets from any source. Resources
+     * can be located on a local or remote
+     * file system, in a database, or in a <code>.war</code> file.
+     *
+     * <p>The servlet container must implement the URL handlers
+     * and <code>URLConnection</code> objects that are necessary
+     * to access the resource.
+     *
+     * <p>This method returns <code>null</code>
+     * if no resource is mapped to the pathname.
+     *
+     * <p>Some containers may allow writing to the URL returned by
+     * this method using the methods of the URL class.
+     *
+     * <p>The resource content is returned directly, so be aware that
+     * requesting a <code>.jsp</code> page returns the JSP source code.
+     * Use a <code>RequestDispatcher</code> instead to include results of
+     * an execution.
+     *
+     * <p>This method has a different purpose than
+     * <code>java.lang.Class.getResource</code>,
+     * which looks up resources based on a class loader. This
+     * method does not use class loaders.
+     *
+     * @param path a <code>String</code> specifying
+     * the path to the resource
+     *
+     * @return the resource located at the named path,
+     * or <code>null</code> if there is no resource at that path
+     *
+     * @exception MalformedURLException if the pathname is not given in
+     * the correct form
+     */
+    public URL getResource(String path) throws MalformedURLException;
+
+
+    /**
+     * Returns the resource located at the named path as
+     * an <code>InputStream</code> object.
+     *
+     * <p>The data in the <code>InputStream</code> can be
+     * of any type or length. The path must be specified according
+     * to the rules given in <code>getResource</code>.
+     * This method returns <code>null</code> if no resource exists at
+     * the specified path.
+     *
+     * <p>Meta-information such as content length and content type
+     * that is available via <code>getResource</code>
+     * method is lost when using this method.
+     *
+     * <p>The servlet container must implement the URL handlers
+     * and <code>URLConnection</code> objects necessary to access
+     * the resource.
+     *
+     * <p>This method is different from
+     * <code>java.lang.Class.getResourceAsStream</code>,
+     * which uses a class loader. This method allows servlet containers
+     * to make a resource available
+     * to a servlet from any location, without using a class loader.
+     *
+     *
+     * @param path 	a <code>String</code> specifying the path
+     *			to the resource
+     *
+     * @return 		the <code>InputStream</code> returned to the
+     *			servlet, or <code>null</code> if no resource
+     *			exists at the specified path
+     */
+    public InputStream getResourceAsStream(String path);
+
+
+    /**
+     *
+     * Returns a {@link RequestDispatcher} object that acts
+     * as a wrapper for the resource located at the given path.
+     * A <code>RequestDispatcher</code> object can be used to forward
+     * a request to the resource or to include the resource in a response.
+     * The resource can be dynamic or static.
+     *
+     * <p>The pathname must begin with a <tt>/</tt> and is interpreted as
+     * relative to the current context root.  Use <code>getContext</code>
+     * to obtain a <code>RequestDispatcher</code> for resources in foreign
+     * contexts.
+     *
+     * <p>This method returns <code>null</code> if the
+     * <code>ServletContext</code> cannot return a
+     * <code>RequestDispatcher</code>.
+     *
+     * @param path 	a <code>String</code> specifying the pathname
+     *			to the resource
+     *
+     * @return 		a <code>RequestDispatcher</code> object
+     *			that acts as a wrapper for the resource
+     *			at the specified path, or <code>null</code> if
+     *			the <code>ServletContext</code> cannot return
+     *			a <code>RequestDispatcher</code>
+     *
+     * @see 		RequestDispatcher
+     * @see 		ServletContext#getContext
+     */
+    public RequestDispatcher getRequestDispatcher(String path);
+
+
+    /**
+     * Returns a {@link RequestDispatcher} object that acts
+     * as a wrapper for the named servlet.
+     *
+     * <p>Servlets (and JSP pages also) may be given names via server
+     * administration or via a web application deployment descriptor.
+     * A servlet instance can determine its name using
+     * {@link ServletConfig#getServletName}.
+     *
+     * <p>This method returns <code>null</code> if the
+     * <code>ServletContext</code>
+     * cannot return a <code>RequestDispatcher</code> for any reason.
+     *
+     * @param name 	a <code>String</code> specifying the name
+     *			of a servlet to wrap
+     *
+     * @return 		a <code>RequestDispatcher</code> object
+     *			that acts as a wrapper for the named servlet,
+     *			or <code>null</code> if the <code>ServletContext</code>
+     *			cannot return a <code>RequestDispatcher</code>
+     *
+     * @see 		RequestDispatcher
+     * @see 		ServletContext#getContext
+     * @see 		ServletConfig#getServletName
+     */
+    public RequestDispatcher getNamedDispatcher(String name);
+
+
+    /**
+     * @deprecated	As of Java Servlet API 2.1, with no direct replacement.
+     *
+     * <p>This method was originally defined to retrieve a servlet
+     * from a <code>ServletContext</code>. In this version, this method
+     * always returns <code>null</code> and remains only to preserve
+     * binary compatibility. This method will be permanently removed
+     * in a future version of the Java Servlet API.
+     *
+     * <p>In lieu of this method, servlets can share information using the
+     * <code>ServletContext</code> class and can perform shared business logic
+     * by invoking methods on common non-servlet classes.
+     *
+     * @param name the servlet name
+     * @return the {@code javax.servlet.Servlet Servlet} with the given name
+     * @throws ServletException if an exception has occurred that interfaces
+     *                          with servlet's normal operation
+     */
+    @Deprecated
+    public Servlet getServlet(String name) throws ServletException;
+
+
+    /**
+     * @deprecated	As of Java Servlet API 2.0, with no replacement.
+     *
+     * <p>This method was originally defined to return an
+     * <code>Enumeration</code> of all the servlets known to this servlet
+     * context.
+     * In this version, this method always returns an empty enumeration and
+     * remains only to preserve binary compatibility. This method
+     * will be permanently removed in a future version of the Java
+     * Servlet API.
+     *
+     * @return an <code>Enumeration</code> of {@code javax.servlet.Servlet Servlet}
+     */
+    @Deprecated
+    public Enumeration<Servlet> getServlets();
+
+
+    /**
+     * @deprecated	As of Java Servlet API 2.1, with no replacement.
+     *
+     * <p>This method was originally defined to return an
+     * <code>Enumeration</code>
+     * of all the servlet names known to this context. In this version,
+     * this method always returns an empty <code>Enumeration</code> and
+     * remains only to preserve binary compatibility. This method will
+     * be permanently removed in a future version of the Java Servlet API.
+     *
+     * @return an <code>Enumeration</code> of {@code javax.servlet.Servlet Servlet} names
+     */
+    @Deprecated
+    public Enumeration<String> getServletNames();
+
+
+    /**
+     *
+     * Writes the specified message to a servlet log file, usually
+     * an event log. The name and type of the servlet log file is
+     * specific to the servlet container.
+     *
+     * @param msg 	a <code>String</code> specifying the
+     *			message to be written to the log file
+     */
+    public void log(String msg);
+
+
+    /**
+     * @deprecated	As of Java Servlet API 2.1, use
+     * 			{@link #log(String message, Throwable throwable)}
+     *			instead.
+     *
+     * <p>This method was originally defined to write an
+     * exception's stack trace and an explanatory error message
+     * to the servlet log file.
+     *
+     * @param exception the <code>Exception</code> error
+     * @param msg a <code>String</code> that describes the exception
+     */
+    @Deprecated
+    public void log(Exception exception, String msg);
+
+
+    /**
+     * Writes an explanatory message and a stack trace
+     * for a given <code>Throwable</code> exception
+     * to the servlet log file. The name and type of the servlet log
+     * file is specific to the servlet container, usually an event log.
+     *
+     * @param message 		a <code>String</code> that
+     *				describes the error or exception
+     *
+     * @param throwable 	the <code>Throwable</code> error
+     *				or exception
+     */
+    public void log(String message, Throwable throwable);
+
+
+    /**
+     * Gets the <i>real</i> path corresponding to the given
+     * <i>virtual</i> path.
+     *
+     * <p>For example, if <tt>path</tt> is equal to <tt>/index.html</tt>,
+     * this method will return the absolute file path on the server's
+     * filesystem to which a request of the form
+     * <tt>http://&lt;host&gt;:&lt;port&gt;/&lt;contextPath&gt;/index.html</tt>
+     * would be mapped, where <tt>&lt;contextPath&gt;</tt> corresponds to the
+     * context path of this ServletContext.
+     *
+     * <p>The real path returned will be in a form
+     * appropriate to the computer and operating system on
+     * which the servlet container is running, including the
+     * proper path separators.
+     *
+     * <p>Resources inside the <tt>/META-INF/resources</tt>
+     * directories of JAR files bundled in the application's
+     * <tt>/WEB-INF/lib</tt> directory must be considered only if the
+     * container has unpacked them from their containing JAR file, in
+     * which case the path to the unpacked location must be returned.
+     *
+     * <p>This method returns <code>null</code> if the servlet container
+     * is unable to translate the given <i>virtual</i> path to a
+     * <i>real</i> path.
+     *
+     * @param path the <i>virtual</i> path to be translated to a
+     * <i>real</i> path
+     *
+     * @return the <i>real</i> path, or <tt>null</tt> if the
+     * translation cannot be performed
+     */
+    public String getRealPath(String path);
+
+
+    /**
+     * Returns the name and version of the servlet container on which
+     * the servlet is running.
+     *
+     * <p>The form of the returned string is
+     * <i>servername</i>/<i>versionnumber</i>.
+     * For example, the JavaServer Web Development Kit may return the string
+     * <code>JavaServer Web Dev Kit/1.0</code>.
+     *
+     * <p>The servlet container may return other optional information
+     * after the primary string in parentheses, for example,
+     * <code>JavaServer Web Dev Kit/1.0 (JDK 1.1.6; Windows NT 4.0 x86)</code>.
+     *
+     *
+     * @return 		a <code>String</code> containing at least the
+     *			servlet container name and version number
+     */
+    public String getServerInfo();
+
+
+    /**
+     * Returns a <code>String</code> containing the value of the named
+     * context-wide initialization parameter, or <code>null</code> if
+     * the parameter does not exist.
+     *
+     * <p>This method can make available configuration information useful
+     * to an entire web application.  For example, it can provide a
+     * webmaster's email address or the name of a system that holds
+     * critical data.
+     *
+     * @param	name	a <code>String</code> containing the name of the
+     *                  parameter whose value is requested
+     *
+     * @return a <code>String</code> containing the value of the
+     * context's initialization parameter, or <code>null</code> if the
+     * context's initialization parameter does not exist.
+     *
+     * @throws NullPointerException if the argument {@code name} is
+     * {@code null}
+     *
+     * @see ServletConfig#getInitParameter
+     */
+    public String getInitParameter(String name);
+
+
+    /**
+     * Returns the names of the context's initialization parameters as an
+     * <code>Enumeration</code> of <code>String</code> objects, or an
+     * empty <code>Enumeration</code> if the context has no initialization
+     * parameters.
+     *
+     * @return 		an <code>Enumeration</code> of <code>String</code>
+     *                  objects containing the names of the context's
+     *                  initialization parameters
+     *
+     * @see ServletConfig#getInitParameter
+     */
+    public Enumeration<String> getInitParameterNames();
+
+
+    /**
+     * Sets the context initialization parameter with the given name and
+     * value on this ServletContext.
+     *
+     * @param name the name of the context initialization parameter to set
+     * @param value the value of the context initialization parameter to set
+     *
+     * @return true if the context initialization parameter with the given
+     * name and value was set successfully on this ServletContext, and false
+     * if it was not set because this ServletContext already contains a
+     * context initialization parameter with a matching name
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws NullPointerException if the name parameter is {@code null}
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public boolean setInitParameter(String name, String value);
+
+
+    /**
+     * Returns the servlet container attribute with the given name, or
+     * <code>null</code> if there is no attribute by that name.
+     *
+     * <p>An attribute allows a servlet container to give the
+     * servlet additional information not
+     * already provided by this interface. See your
+     * server documentation for information about its attributes.
+     * A list of supported attributes can be retrieved using
+     * <code>getAttributeNames</code>.
+     *
+     * <p>The attribute is returned as a <code>java.lang.Object</code>
+     * or some subclass.
+     *
+     * <p>Attribute names should follow the same convention as package
+     * names. The Java Servlet API specification reserves names
+     * matching <code>java.*</code>, <code>javax.*</code>,
+     * and <code>sun.*</code>.
+     *
+     * @param name 	a <code>String</code> specifying the name
+     *			of the attribute
+     *
+     * @return an <code>Object</code> containing the value of the
+     *			attribute, or <code>null</code> if no attribute
+     *			exists matching the given name.
+     *
+     * @see 		ServletContext#getAttributeNames
+     *
+     * @throws NullPointerException if the argument {@code name} is
+     * {@code null}
+     *
+     */
+    public Object getAttribute(String name);
+
+
+    /**
+     * Returns an <code>Enumeration</code> containing the
+     * attribute names available within this ServletContext.
+     *
+     * <p>Use the {@link #getAttribute} method with an attribute name
+     * to get the value of an attribute.
+     *
+     * @return 		an <code>Enumeration</code> of attribute
+     *			names
+     *
+     * @see		#getAttribute
+     */
+    public Enumeration<String> getAttributeNames();
+
+
+    /**
+     * Binds an object to a given attribute name in this ServletContext. If
+     * the name specified is already used for an attribute, this
+     * method will replace the attribute with the new to the new attribute.
+     * <p>If listeners are configured on the <code>ServletContext</code> the
+     * container notifies them accordingly.
+     * <p>
+     * If a null value is passed, the effect is the same as calling
+     * <code>removeAttribute()</code>.
+     *
+     * <p>Attribute names should follow the same convention as package
+     * names. The Java Servlet API specification reserves names
+     * matching <code>java.*</code>, <code>javax.*</code>, and
+     * <code>sun.*</code>.
+     *
+     * @param name 	a <code>String</code> specifying the name
+     *			of the attribute
+     *
+     * @param object 	an <code>Object</code> representing the
+     *			attribute to be bound
+     *
+     * @throws NullPointerException if the name parameter is {@code null}
+     *
+     */
+    public void setAttribute(String name, Object object);
+
+
+    /**
+     * Removes the attribute with the given name from
+     * this ServletContext. After removal, subsequent calls to
+     * {@link #getAttribute} to retrieve the attribute's value
+     * will return <code>null</code>.
+     *
+     * <p>If listeners are configured on the <code>ServletContext</code> the
+     * container notifies them accordingly.
+     *
+     * @param name	a <code>String</code> specifying the name
+     * 			of the attribute to be removed
+     */
+    public void removeAttribute(String name);
+
+
+    /**
+     * Returns the name of this web application corresponding to this
+     * ServletContext as specified in the deployment descriptor for this
+     * web application by the display-name element.
+     *
+     * @return The name of the web application or null if no name has been
+     * declared in the deployment descriptor.
+     *
+     * @since Servlet 2.3
+     */
+    public String getServletContextName();
+
+
+    /**
+     * Adds the servlet with the given name and class name to this servlet
+     * context.
+     *
+     * <p>The registered servlet may be further configured via the returned
+     * {@link ServletRegistration} object.
+     *
+     * <p>The specified <tt>className</tt> will be loaded using the
+     * classloader associated with the application represented by this
+     * ServletContext.
+     *
+     * <p>If this ServletContext already contains a preliminary
+     * ServletRegistration for a servlet with the given <tt>servletName</tt>,
+     * it will be completed (by assigning the given <tt>className</tt> to it)
+     * and returned.
+     *
+     * <p>This method introspects the class with the given <tt>className</tt>
+     * for the {@link javax.servlet.annotation.ServletSecurity},
+     * {@link javax.servlet.annotation.MultipartConfig},
+     * <tt>javax.annotation.security.RunAs</tt>, and
+     * <tt>javax.annotation.security.DeclareRoles</tt> annotations.
+     * In addition, this method supports resource injection if the
+     * class with the given <tt>className</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param servletName the name of the servlet
+     * @param className the fully qualified class name of the servlet
+     *
+     * @return a ServletRegistration object that may be used to further
+     * configure the registered servlet, or <tt>null</tt> if this
+     * ServletContext already contains a complete ServletRegistration for
+     * a servlet with the given <tt>servletName</tt>
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws IllegalArgumentException if <code>servletName</code> is null
+     * or an empty String
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public ServletRegistration.Dynamic addServlet(
+        String servletName, String className);
+
+
+    /**
+     * Registers the given servlet instance with this ServletContext
+     * under the given <tt>servletName</tt>.
+     *
+     * <p>The registered servlet may be further configured via the returned
+     * {@link ServletRegistration} object.
+     *
+     * <p>If this ServletContext already contains a preliminary
+     * ServletRegistration for a servlet with the given <tt>servletName</tt>,
+     * it will be completed (by assigning the class name of the given servlet
+     * instance to it) and returned.
+     *
+     * @param servletName the name of the servlet
+     * @param servlet the servlet instance to register
+     *
+     * @return a ServletRegistration object that may be used to further
+     * configure the given servlet, or <tt>null</tt> if this
+     * ServletContext already contains a complete ServletRegistration for a
+     * servlet with the given <tt>servletName</tt> or if the same servlet
+     * instance has already been registered with this or another
+     * ServletContext in the same container
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @throws IllegalArgumentException if the given servlet instance
+     * implements {@link SingleThreadModel}, or <code>servletName</code> is null
+     * or an empty String
+     *
+     * @since Servlet 3.0
+     */
+    public ServletRegistration.Dynamic addServlet(
+        String servletName, Servlet servlet);
+
+
+    /**
+     * Adds the servlet with the given name and class type to this servlet
+     * context.
+     *
+     * <p>The registered servlet may be further configured via the returned
+     * {@link ServletRegistration} object.
+     *
+     * <p>If this ServletContext already contains a preliminary
+     * ServletRegistration for a servlet with the given <tt>servletName</tt>,
+     * it will be completed (by assigning the name of the given
+     * <tt>servletClass</tt> to it) and returned.
+     *
+     * <p>This method introspects the given <tt>servletClass</tt> for
+     * the {@link javax.servlet.annotation.ServletSecurity},
+     * {@link javax.servlet.annotation.MultipartConfig},
+     * <tt>javax.annotation.security.RunAs</tt>, and
+     * <tt>javax.annotation.security.DeclareRoles</tt> annotations.
+     * In addition, this method supports resource injection if the
+     * given <tt>servletClass</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param servletName the name of the servlet
+     * @param servletClass the class object from which the servlet will be
+     * instantiated
+     *
+     * @return a ServletRegistration object that may be used to further
+     * configure the registered servlet, or <tt>null</tt> if this
+     * ServletContext already contains a complete ServletRegistration for
+     * the given <tt>servletName</tt>
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws IllegalArgumentException if <code>servletName</code> is null
+     * or an empty String
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public ServletRegistration.Dynamic addServlet(String servletName,
+        Class <? extends Servlet> servletClass);
+
+
+    /**
+     * Adds the servlet with the given jsp file to this servlet context.
+     *
+     * <p>The registered servlet may be further configured via the returned
+     * {@link ServletRegistration} object.
+     *
+     * <p>If this ServletContext already contains a preliminary
+     * ServletRegistration for a servlet with the given <tt>servletName</tt>,
+     * it will be completed (by assigning the given <tt>jspFile</tt> to it)
+     * and returned.
+     *
+     * @param servletName the name of the servlet
+     * @param jspFile the full path to a JSP file within the web application
+     *                beginning with a `/'.
+     *
+     * @return a ServletRegistration object that may be used to further
+     * configure the registered servlet, or <tt>null</tt> if this
+     * ServletContext already contains a complete ServletRegistration for
+     * a servlet with the given <tt>servletName</tt>
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws IllegalArgumentException if <code>servletName</code> is null
+     * or an empty String
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 4.0
+     */
+    public ServletRegistration.Dynamic addJspFile(
+        String servletName, String jspFile);
+
+
+    /**
+     * Instantiates the given Servlet class.
+     *
+     * <p>The returned Servlet instance may be further customized before it
+     * is registered with this ServletContext via a call to
+     * {@link #addServlet(String,Servlet)}.
+     *
+     * <p>The given Servlet class must define a zero argument constructor,
+     * which is used to instantiate it.
+     *
+     * <p>This method introspects the given <tt>clazz</tt> for
+     * the following annotations:
+     * {@link javax.servlet.annotation.ServletSecurity},
+     * {@link javax.servlet.annotation.MultipartConfig},
+     * <tt>javax.annotation.security.RunAs</tt>, and
+     * <tt>javax.annotation.security.DeclareRoles</tt>.
+     * In addition, this method supports resource injection if the
+     * given <tt>clazz</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param <T> the class of the Servlet to create
+     * @param clazz the Servlet class to instantiate
+     *
+     * @return the new Servlet instance
+     *
+     * @throws ServletException if the given <tt>clazz</tt> fails to be
+     * instantiated
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public <T extends Servlet> T createServlet(Class<T> clazz)
+        throws ServletException;
+
+
+    /**
+     * Gets the ServletRegistration corresponding to the servlet with the
+     * given <tt>servletName</tt>.
+     *
+     * @return the (complete or preliminary) ServletRegistration for the
+     * servlet with the given <tt>servletName</tt>, or null if no
+     * ServletRegistration exists under that name
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @param servletName the name of a servlet
+     * @since Servlet 3.0
+     */
+    public ServletRegistration getServletRegistration(String servletName);
+
+
+    /**
+     * Gets a (possibly empty) Map of the ServletRegistration
+     * objects (keyed by servlet name) corresponding to all servlets
+     * registered with this ServletContext.
+     *
+     * <p>The returned Map includes the ServletRegistration objects
+     * corresponding to all declared and annotated servlets, as well as the
+     * ServletRegistration objects corresponding to all servlets that have
+     * been added via one of the <tt>addServlet</tt> and <tt>addJspFile</tt>
+     * methods.
+     *
+     * <p>If permitted, any changes to the returned Map must not affect this
+     * ServletContext.
+     *
+     * @return Map of the (complete and preliminary) ServletRegistration
+     * objects corresponding to all servlets currently registered with this
+     * ServletContext
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public Map<String, ? extends ServletRegistration> getServletRegistrations();
+
+
+    /**
+     * Adds the filter with the given name and class name to this servlet
+     * context.
+     *
+     * <p>The registered filter may be further configured via the returned
+     * {@link FilterRegistration} object.
+     *
+     * <p>The specified <tt>className</tt> will be loaded using the
+     * classloader associated with the application represented by this
+     * ServletContext.
+     *
+     * <p>If this ServletContext already contains a preliminary
+     * FilterRegistration for a filter with the given <tt>filterName</tt>,
+     * it will be completed (by assigning the given <tt>className</tt> to it)
+     * and returned.
+     *
+     * <p>This method supports resource injection if the class with the
+     * given <tt>className</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param filterName the name of the filter
+     * @param className the fully qualified class name of the filter
+     *
+     * @return a FilterRegistration object that may be used to further
+     * configure the registered filter, or <tt>null</tt> if this
+     * ServletContext already contains a complete FilterRegistration for
+     * a filter with the given <tt>filterName</tt>
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws IllegalArgumentException if <code>filterName</code> is null or
+     * an empty String
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public FilterRegistration.Dynamic addFilter(
+        String filterName, String className);
+
+
+    /**
+     * Registers the given filter instance with this ServletContext
+     * under the given <tt>filterName</tt>.
+     *
+     * <p>The registered filter may be further configured via the returned
+     * {@link FilterRegistration} object.
+     *
+     * <p>If this ServletContext already contains a preliminary
+     * FilterRegistration for a filter with the given <tt>filterName</tt>,
+     * it will be completed (by assigning the class name of the given filter
+     * instance to it) and returned.
+     *
+     * @param filterName the name of the filter
+     * @param filter the filter instance to register
+     *
+     * @return a FilterRegistration object that may be used to further
+     * configure the given filter, or <tt>null</tt> if this
+     * ServletContext already contains a complete FilterRegistration for a
+     * filter with the given <tt>filterName</tt> or if the same filter
+     * instance has already been registered with this or another
+     * ServletContext in the same container
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws IllegalArgumentException if <code>filterName</code> is null or
+     * an empty String
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public FilterRegistration.Dynamic addFilter(
+        String filterName, Filter filter);
+
+
+    /**
+     * Adds the filter with the given name and class type to this servlet
+     * context.
+     *
+     * <p>The registered filter may be further configured via the returned
+     * {@link FilterRegistration} object.
+     *
+     * <p>If this ServletContext already contains a preliminary
+     * FilterRegistration for a filter with the given <tt>filterName</tt>,
+     * it will be completed (by assigning the name of the given
+     * <tt>filterClass</tt> to it) and returned.
+     *
+     * <p>This method supports resource injection if the given
+     * <tt>filterClass</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param filterName the name of the filter
+     * @param filterClass the class object from which the filter will be
+     * instantiated
+     *
+     * @return a FilterRegistration object that may be used to further
+     * configure the registered filter, or <tt>null</tt> if this
+     * ServletContext already contains a complete FilterRegistration for a
+     * filter with the given <tt>filterName</tt>
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws IllegalArgumentException if <code>filterName</code> is null or
+     * an empty String
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public FilterRegistration.Dynamic addFilter(String filterName,
+        Class <? extends Filter> filterClass);
+
+
+    /**
+     * Instantiates the given Filter class.
+     *
+     * <p>The returned Filter instance may be further customized before it
+     * is registered with this ServletContext via a call to
+     * {@link #addFilter(String,Filter)}.
+     *
+     * <p>The given Filter class must define a zero argument constructor,
+     * which is used to instantiate it.
+     *
+     * <p>This method supports resource injection if the given
+     * <tt>clazz</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param <T> the class of the Filter to create
+     * @param clazz the Filter class to instantiate
+     *
+     * @return the new Filter instance
+     *
+     * @throws ServletException if the given <tt>clazz</tt> fails to be
+     * instantiated
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public <T extends Filter> T createFilter(Class<T> clazz)
+        throws ServletException;
+
+
+    /**
+     * Gets the FilterRegistration corresponding to the filter with the
+     * given <tt>filterName</tt>.
+     *
+     * @param filterName the name of a filter
+     * @return the (complete or preliminary) FilterRegistration for the
+     * filter with the given <tt>filterName</tt>, or null if no
+     * FilterRegistration exists under that name
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public FilterRegistration getFilterRegistration(String filterName);
+
+
+    /**
+     * Gets a (possibly empty) Map of the FilterRegistration
+     * objects (keyed by filter name) corresponding to all filters
+     * registered with this ServletContext.
+     *
+     * <p>The returned Map includes the FilterRegistration objects
+     * corresponding to all declared and annotated filters, as well as the
+     * FilterRegistration objects corresponding to all filters that have
+     * been added via one of the <tt>addFilter</tt> methods.
+     *
+     * <p>Any changes to the returned Map must not affect this
+     * ServletContext.
+     *
+     * @return Map of the (complete and preliminary) FilterRegistration
+     * objects corresponding to all filters currently registered with this
+     * ServletContext
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public Map<String, ? extends FilterRegistration> getFilterRegistrations();
+
+
+    /**
+     * Gets the {@link SessionCookieConfig} object through which various
+     * properties of the session tracking cookies created on behalf of this
+     * <tt>ServletContext</tt> may be configured.
+     *
+     * <p>Repeated invocations of this method will return the same
+     * <tt>SessionCookieConfig</tt> instance.
+     *
+     * @return the <tt>SessionCookieConfig</tt> object through which
+     * various properties of the session tracking cookies created on
+     * behalf of this <tt>ServletContext</tt> may be configured
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public SessionCookieConfig getSessionCookieConfig();
+
+
+    /**
+     * Sets the session tracking modes that are to become effective for this
+     * <tt>ServletContext</tt>.
+     *
+     * <p>The given <tt>sessionTrackingModes</tt> replaces any
+     * session tracking modes set by a previous invocation of this
+     * method on this <tt>ServletContext</tt>.
+     *
+     * @param sessionTrackingModes the set of session tracking modes to
+     * become effective for this <tt>ServletContext</tt>
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @throws IllegalArgumentException if <tt>sessionTrackingModes</tt>
+     * specifies a combination of <tt>SessionTrackingMode.SSL</tt> with a
+     * session tracking mode other than <tt>SessionTrackingMode.SSL</tt>,
+     * or if <tt>sessionTrackingModes</tt> specifies a session tracking mode
+     * that is not supported by the servlet container
+     *
+     * @since Servlet 3.0
+     */
+    public void setSessionTrackingModes(Set<SessionTrackingMode> sessionTrackingModes);
+
+
+    /**
+     * Gets the session tracking modes that are supported by default for this
+     * <tt>ServletContext</tt>.
+     *
+     * <p>The returned set is not backed by the {@code ServletContext} object,
+     * so changes in the returned set are not reflected in the
+     * {@code ServletContext} object, and vice-versa.</p>
+     *
+     * @return set of the session tracking modes supported by default for
+     * this <tt>ServletContext</tt>
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public Set<SessionTrackingMode> getDefaultSessionTrackingModes();
+
+
+    /**
+     * Gets the session tracking modes that are in effect for this
+     * <tt>ServletContext</tt>.
+     *
+     * <p>The session tracking modes in effect are those provided to
+     * {@link #setSessionTrackingModes setSessionTrackingModes}.
+     *
+     * <p>The returned set is not backed by the {@code ServletContext} object,
+     * so changes in the returned set are not reflected in the
+     * {@code ServletContext} object, and vice-versa.</p>
+     *
+     * @return set of the session tracking modes in effect for this
+     * <tt>ServletContext</tt>
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public Set<SessionTrackingMode> getEffectiveSessionTrackingModes();
+
+
+    /**
+     * Adds the listener with the given class name to this ServletContext.
+     *
+     * <p>The class with the given name will be loaded using the
+     * classloader associated with the application represented by this
+     * ServletContext, and must implement one or more of the following
+     * interfaces:
+     * <ul>
+     * <li>{@link ServletContextAttributeListener}
+     * <li>{@link ServletRequestListener}
+     * <li>{@link ServletRequestAttributeListener}
+     * <li>{@link javax.servlet.http.HttpSessionAttributeListener}
+     * <li>{@link javax.servlet.http.HttpSessionIdListener}
+     * <li>{@link javax.servlet.http.HttpSessionListener}
+     * </ul>
+     *
+     * <p>If this ServletContext was passed to
+     * {@link ServletContainerInitializer#onStartup}, then the class with
+     * the given name may also implement {@link ServletContextListener},
+     * in addition to the interfaces listed above.
+     *
+     * <p>As part of this method call, the container must load the class
+     * with the specified class name to ensure that it implements one of
+     * the required interfaces.
+     *
+     * <p>If the class with the given name implements a listener interface
+     * whose invocation order corresponds to the declaration order (i.e.,
+     * if it implements {@link ServletRequestListener},
+     * {@link ServletContextListener}, or
+     * {@link javax.servlet.http.HttpSessionListener}),
+     * then the new listener will be added to the end of the ordered list of
+     * listeners of that interface.
+     *
+     * <p>This method supports resource injection if the class with the
+     * given <tt>className</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param className the fully qualified class name of the listener
+     *
+     * @throws IllegalArgumentException if the class with the given name
+     * does not implement any of the above interfaces, or if it implements
+     * {@link ServletContextListener} and this ServletContext was not
+     * passed to {@link ServletContainerInitializer#onStartup}
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public void addListener(String className);
+
+
+    /**
+     * Adds the given listener to this ServletContext.
+     *
+     * <p>The given listener must be an instance of one or more of the
+     * following interfaces:
+     * <ul>
+     * <li>{@link ServletContextAttributeListener}
+     * <li>{@link ServletRequestListener}
+     * <li>{@link ServletRequestAttributeListener}
+     * <li>{@link javax.servlet.http.HttpSessionAttributeListener}
+     * <li>{@link javax.servlet.http.HttpSessionIdListener}
+     * <li>{@link javax.servlet.http.HttpSessionListener}
+     * </ul>
+     *
+     * <p>If this ServletContext was passed to
+     * {@link ServletContainerInitializer#onStartup}, then the given
+     * listener may also be an instance of {@link ServletContextListener},
+     * in addition to the interfaces listed above.
+     *
+     * <p>If the given listener is an instance of a listener interface whose
+     * invocation order corresponds to the declaration order (i.e., if it
+     * is an instance of {@link ServletRequestListener},
+     * {@link ServletContextListener}, or
+     * {@link javax.servlet.http.HttpSessionListener}),
+     * then the listener will be added to the end of the ordered list of
+     * listeners of that interface.
+     *
+     * @param <T> the class of the EventListener to add
+     * @param t the listener to be added
+     *
+     * @throws IllegalArgumentException if the given listener is not
+     * an instance of any of the above interfaces, or if it is an instance
+     * of {@link ServletContextListener} and this ServletContext was not
+     * passed to {@link ServletContainerInitializer#onStartup}
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public <T extends EventListener> void addListener(T t);
+
+
+    /**
+     * Adds a listener of the given class type to this ServletContext.
+     *
+     * <p>The given <tt>listenerClass</tt> must implement one or more of the
+     * following interfaces:
+     * <ul>
+     * <li>{@link ServletContextAttributeListener}
+     * <li>{@link ServletRequestListener}
+     * <li>{@link ServletRequestAttributeListener}
+     * <li>{@link javax.servlet.http.HttpSessionAttributeListener}
+     * <li>{@link javax.servlet.http.HttpSessionIdListener}
+     * <li>{@link javax.servlet.http.HttpSessionListener}
+     * </ul>
+     *
+     * <p>If this ServletContext was passed to
+     * {@link ServletContainerInitializer#onStartup}, then the given
+     * <tt>listenerClass</tt> may also implement
+     * {@link ServletContextListener}, in addition to the interfaces listed
+     * above.
+     *
+     * <p>If the given <tt>listenerClass</tt> implements a listener
+     * interface whose invocation order corresponds to the declaration order
+     * (i.e., if it implements {@link ServletRequestListener},
+     * {@link ServletContextListener}, or
+     * {@link javax.servlet.http.HttpSessionListener}),
+     * then the new listener will be added to the end of the ordered list
+     * of listeners of that interface.
+     *
+     * <p>This method supports resource injection if the given
+     * <tt>listenerClass</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param listenerClass the listener class to be instantiated
+     *
+     * @throws IllegalArgumentException if the given <tt>listenerClass</tt>
+     * does not implement any of the above interfaces, or if it implements
+     * {@link ServletContextListener} and this ServletContext was not passed
+     * to {@link ServletContainerInitializer#onStartup}
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.0
+     */
+    public void addListener(Class <? extends EventListener> listenerClass);
+
+
+    /**
+     * Instantiates the given EventListener class.
+     *
+     * <p>The specified EventListener class must implement at least one of
+     * the {@link ServletContextListener},
+     * {@link ServletContextAttributeListener},
+     * {@link ServletRequestListener},
+     * {@link ServletRequestAttributeListener},
+     * {@link javax.servlet.http.HttpSessionAttributeListener},
+     * {@link javax.servlet.http.HttpSessionIdListener}, or
+     * {@link javax.servlet.http.HttpSessionListener}
+     * interfaces.
+     *
+     * <p>The returned EventListener instance may be further customized
+     * before it is registered with this ServletContext via a call to
+     * {@link #addListener(EventListener)}.
+     *
+     * <p>The given EventListener class must define a zero argument
+     * constructor, which is used to instantiate it.
+     *
+     * <p>This method supports resource injection if the given
+     * <tt>clazz</tt> represents a Managed Bean.
+     * See the Java EE platform and JSR 299 specifications for additional
+     * details about Managed Beans and resource injection.
+     *
+     * @param <T> the class of the EventListener to create
+     * @param clazz the EventListener class to instantiate
+     *
+     * @return the new EventListener instance
+     *
+     * @throws ServletException if the given <tt>clazz</tt> fails to be
+     * instantiated
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @throws IllegalArgumentException if the specified EventListener class
+     * does not implement any of the
+     * {@link ServletContextListener},
+     * {@link ServletContextAttributeListener},
+     * {@link ServletRequestListener},
+     * {@link ServletRequestAttributeListener},
+     * {@link javax.servlet.http.HttpSessionAttributeListener},
+     * {@link javax.servlet.http.HttpSessionIdListener}, or
+     * {@link javax.servlet.http.HttpSessionListener}
+     * interfaces.
+     *
+     * @since Servlet 3.0
+     */
+    public <T extends EventListener> T createListener(Class<T> clazz)
+        throws ServletException;
+
+
+    /**
+     * Gets the <code>&lt;jsp-config&gt;</code> related configuration
+     * that was aggregated from the <code>web.xml</code> and
+     * <code>web-fragment.xml</code> descriptor files of the web application
+     * represented by this ServletContext.
+     *
+     * @return the <code>&lt;jsp-config&gt;</code> related configuration
+     * that was aggregated from the <code>web.xml</code> and
+     * <code>web-fragment.xml</code> descriptor files of the web application
+     * represented by this ServletContext, or null if no such configuration
+     * exists
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @see javax.servlet.descriptor.JspConfigDescriptor
+     *
+     * @since Servlet 3.0
+     */
+    public JspConfigDescriptor getJspConfigDescriptor();
+
+
+    /**
+     * Gets the class loader of the web application represented by this
+     * ServletContext.
+     *
+     * <p>If a security manager exists, and the caller's class loader
+     * is not the same as, or an ancestor of the requested class loader,
+     * then the security manager's <code>checkPermission</code> method is
+     * called with a <code>RuntimePermission("getClassLoader")</code>
+     * permission to check whether access to the requested class loader
+     * should be granted.
+     *
+     * @return the class loader of the web application represented by this
+     * ServletContext
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @throws SecurityException if a security manager denies access to
+     * the requested class loader
+     *
+     * @since Servlet 3.0
+     */
+    public ClassLoader getClassLoader();
+
+
+    /**
+     * Declares role names that are tested using <code>isUserInRole</code>.
+     *
+     * <p>Roles that are implicitly declared as a result of their use within
+     * the {@link ServletRegistration.Dynamic#setServletSecurity
+     * setServletSecurity} or {@link ServletRegistration.Dynamic#setRunAsRole
+     * setRunAsRole} methods of the {@link ServletRegistration} interface need
+     * not be declared.
+     *
+     * @param roleNames the role names being declared
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @throws IllegalArgumentException if any of the argument roleNames is
+     * null or the empty string
+     *
+     * @throws IllegalStateException if the ServletContext has already
+     * been initialized
+     *
+     * @since Servlet 3.0
+     */
+    public void declareRoles(String... roleNames);
+
+
+    /**
+     * Returns the configuration name of the logical host on which the
+     * ServletContext is deployed.
+     *
+     * Servlet containers may support multiple logical hosts. This method must
+     * return the same name for all the servlet contexts deployed on a logical
+     * host, and the name returned by this method must be distinct, stable per
+     * logical host, and suitable for use in associating server configuration
+     * information with the logical host. The returned value is NOT expected
+     * or required to be equivalent to a network address or hostname of the
+     * logical host.
+     *
+     * @return a <code>String</code> containing the configuration name of the
+     * logical host on which the servlet context is deployed.
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 3.1
+     */
+    public String getVirtualServerName();
+
+
+    /**
+     * Gets the session timeout in minutes that are supported by default for
+     * this <tt>ServletContext</tt>.
+     *
+     * @return the session timeout in minutes that are supported by default for
+     * this <tt>ServletContext</tt>
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 4.0
+     */
+    public int getSessionTimeout();
+
+
+    /**
+     * Sets the session timeout in minutes for this ServletContext.
+     *
+     * @param sessionTimeout session timeout in minutes
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 4.0
+     */
+    public void setSessionTimeout(int sessionTimeout);
+
+
+    /**
+     * Gets the request character encoding that are supported by default for
+     * this <tt>ServletContext</tt>. This method returns null if no request
+     * encoding character encoding has been specified in deployment descriptor
+     * or container specific configuration (for all web applications in the
+     * container).
+     *
+     * @return the request character encoding that are supported by default for
+     * this <tt>ServletContext</tt>
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 4.0
+     */
+    public String getRequestCharacterEncoding();
+
+
+    /**
+     * Sets the request character encoding for this ServletContext.
+     *
+     * @param encoding request character encoding
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 4.0
+     */
+    public void setRequestCharacterEncoding(String encoding);
+
+
+    /**
+     * Gets the response character encoding that are supported by default for
+     * this <tt>ServletContext</tt>. This method returns null if no response
+     * encoding character encoding has been specified in deployment descriptor
+     * or container specific configuration (for all web applications in the
+     * container).
+     *
+     * @return the request character encoding that are supported by default for
+     * this <tt>ServletContext</tt>
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 4.0
+     */
+    public String getResponseCharacterEncoding();
+
+
+    /**
+     * Sets the response character encoding for this ServletContext.
+     *
+     * @param encoding response character encoding
+     *
+     * @throws IllegalStateException if this ServletContext has already
+     * been initialized
+     *
+     * @throws UnsupportedOperationException if this ServletContext was
+     * passed to the {@link ServletContextListener#contextInitialized} method
+     * of a {@link ServletContextListener} that was neither declared in
+     * <code>web.xml</code> or <code>web-fragment.xml</code>, nor annotated
+     * with {@link javax.servlet.annotation.WebListener}
+     *
+     * @since Servlet 4.0
+     */
+    public void setResponseCharacterEncoding(String encoding);
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextAttributeEvent.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextAttributeEvent.java
new file mode 100644
index 0000000..8ebc5fd
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextAttributeEvent.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+/** 
+ * Event class for notifications about changes to the attributes of
+ * the ServletContext of a web application.
+ *
+ * @see ServletContextAttributeListener
+ *
+ * @since Servlet 2.3
+ */
+
+public class ServletContextAttributeEvent extends ServletContextEvent { 
+
+    private static final long serialVersionUID = -5804680734245618303L;
+
+    private String name;
+    private Object value;
+
+    /**
+     * Constructs a ServletContextAttributeEvent from the given 
+     * ServletContext, attribute name, and attribute value.
+     *
+     * @param source the ServletContext whose attribute changed
+     * @param name the name of the ServletContext attribute that changed
+     * @param value the value of the ServletContext attribute that changed
+     */
+    public ServletContextAttributeEvent(ServletContext source,
+            String name, Object value) {
+        super(source);
+        this.name = name;
+        this.value = value;
+    }
+	
+    /**
+     * Gets the name of the ServletContext attribute that changed.
+     *
+     * @return the name of the ServletContext attribute that changed
+     */
+    public String getName() {
+        return this.name;
+    }
+	
+    /**
+     * Gets the value of the ServletContext attribute that changed.
+     *
+     * <p>If the attribute was added, this is the value of the attribute.
+     * If the attribute was removed, this is the value of the removed
+     * attribute. If the attribute was replaced, this is the old value of
+     * the attribute.
+     *
+     * @return the value of the ServletContext attribute that changed
+     */
+    public Object getValue() {
+        return this.value;   
+    }
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextAttributeListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextAttributeListener.java
new file mode 100644
index 0000000..2e10f8e
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextAttributeListener.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.util.EventListener;
+
+/**
+ * Interface for receiving notification events about ServletContext
+ * attribute changes.
+ *
+ * <p>In order to receive these notification events, the implementation
+ * class must be either declared in the deployment descriptor of the web
+ * application, annotated with {@link javax.servlet.annotation.WebListener},
+ * or registered via one of the addListener methods defined on
+ * {@link ServletContext}.
+ *
+ * <p>The order in which implementations of this interface are invoked is
+ * unspecified.
+ *
+ * @see ServletContextAttributeEvent
+ *
+ * @since Servlet 2.3
+ */
+
+public interface ServletContextAttributeListener extends EventListener {
+
+    /**
+     * Receives notification that an attribute has been added to the
+     * ServletContext.
+     *
+     * @param event the ServletContextAttributeEvent containing the
+     * ServletContext to which the attribute was added, along with the
+     * attribute name and value
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void attributeAdded(ServletContextAttributeEvent event) {}
+
+    /**
+     * Receives notification that an attribute has been removed
+     * from the ServletContext.
+     *
+     * @param event the ServletContextAttributeEvent containing the
+     * ServletContext from which the attribute was removed, along with
+     * the attribute name and value
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void attributeRemoved(ServletContextAttributeEvent event) {}
+
+    /*
+     * Receives notification that an attribute has been replaced
+     * in the ServletContext.
+     *
+     * @param event the ServletContextAttributeEvent containing the
+     * ServletContext in which the attribute was replaced, along with
+     * the attribute name and its old value
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void attributeReplaced(ServletContextAttributeEvent event) {}
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextEvent.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextEvent.java
new file mode 100644
index 0000000..8e3eca2
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextEvent.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+/** 
+ * This is the event class for notifications about changes to
+ * the servlet context of a web application.
+ * @see ServletContextListener
+ *
+ * @since Servlet 2.3
+ */
+
+public class ServletContextEvent extends java.util.EventObject { 
+
+    private static final long serialVersionUID = -7501701636134222423L;
+
+    /** Construct a ServletContextEvent from the given context.
+     *
+     * @param source - the ServletContext that is sending the event.
+     */
+    public ServletContextEvent(ServletContext source) {
+        super(source);
+    }
+    
+    /**
+     * Return the ServletContext that changed.
+     *
+     * @return the ServletContext that sent the event.
+     */
+    public ServletContext getServletContext () { 
+        return (ServletContext) super.getSource();
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextListener.java
new file mode 100644
index 0000000..d37e58d
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletContextListener.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.util.EventListener;
+
+/** 
+ * Interface for receiving notification events about ServletContext
+ * lifecycle changes.
+ *
+ * <p>In order to receive these notification events, the implementation
+ * class must be either declared in the deployment descriptor of the web
+ * application, annotated with {@link javax.servlet.annotation.WebListener},
+ * or registered via one of the addListener methods defined on
+ * {@link ServletContext}.
+ *
+ * <p>Implementations of this interface are invoked at their
+ * {@link #contextInitialized} method in the order in which they have been
+ * declared, and at their {@link #contextDestroyed} method in reverse
+ * order.
+ *
+ * @see ServletContextEvent
+ *
+ * @since Servlet 2.3
+ */
+public interface ServletContextListener extends EventListener {
+
+    /**
+     * Receives notification that the web application initialization
+     * process is starting.
+     *
+     * <p>All ServletContextListeners are notified of context
+     * initialization before any filters or servlets in the web
+     * application are initialized.
+     *
+     * @param sce the ServletContextEvent containing the ServletContext
+     * that is being initialized
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void contextInitialized(ServletContextEvent sce) {}
+
+    /**
+     * Receives notification that the ServletContext is about to be
+     * shut down.
+     *
+     * <p>All servlets and filters will have been destroyed before any
+     * ServletContextListeners are notified of context
+     * destruction.
+     *
+     * @param sce the ServletContextEvent containing the ServletContext
+     * that is being destroyed
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void contextDestroyed(ServletContextEvent sce) {}
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletException.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletException.java
new file mode 100644
index 0000000..375bb29
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletException.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+
+/**
+ * Defines a general exception a servlet can throw when it
+ * encounters difficulty.
+ *
+ * @author 	Various
+ */
+
+
+public class ServletException extends Exception {
+
+    private Throwable rootCause;
+
+
+
+
+
+    /**
+     * Constructs a new servlet exception.
+     *
+     */
+
+    public ServletException() {
+	super();
+    }
+    
+   
+
+    
+
+    /**
+     * Constructs a new servlet exception with the
+     * specified message. The message can be written 
+     * to the server log and/or displayed for the user. 
+     *
+     * @param message 		a <code>String</code> 
+     *				specifying the text of 
+     *				the exception message
+     *
+     */
+
+    public ServletException(String message) {
+	super(message);
+    }
+    
+   
+   
+    
+
+    /**
+     * Constructs a new servlet exception when the servlet 
+     * needs to throw an exception and include a message 
+     * about the "root cause" exception that interfered with its 
+     * normal operation, including a description message.
+     *
+     *
+     * @param message 		a <code>String</code> containing 
+     *				the text of the exception message
+     *
+     * @param rootCause		the <code>Throwable</code> exception 
+     *				that interfered with the servlet's
+     *				normal operation, making this servlet
+     *				exception necessary
+     *
+     */
+    
+    public ServletException(String message, Throwable rootCause) {
+	super(message, rootCause);
+	this.rootCause = rootCause;
+    }
+
+
+
+
+
+    /**
+     * Constructs a new servlet exception when the servlet 
+     * needs to throw an exception and include a message
+     * about the "root cause" exception that interfered with its
+     * normal operation.  The exception's message is based on the localized
+     * message of the underlying exception.
+     *
+     * <p>This method calls the <code>getLocalizedMessage</code> method
+     * on the <code>Throwable</code> exception to get a localized exception
+     * message. When subclassing <code>ServletException</code>, 
+     * this method can be overridden to create an exception message 
+     * designed for a specific locale.
+     *
+     * @param rootCause 	the <code>Throwable</code> exception
+     * 				that interfered with the servlet's
+     *				normal operation, making the servlet exception
+     *				necessary
+     *
+     */
+
+    public ServletException(Throwable rootCause) {
+	super(rootCause);
+	this.rootCause = rootCause;
+    }
+  
+  
+ 
+ 
+    
+    /**
+     * Returns the exception that caused this servlet exception.
+     *
+     *
+     * @return			the <code>Throwable</code> 
+     *				that caused this servlet exception
+     *
+     */
+    
+    public Throwable getRootCause() {
+	return rootCause;
+    }
+}
+
+
+
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletInputStream.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletInputStream.java
new file mode 100644
index 0000000..a0369ab
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletInputStream.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.InputStream;
+import java.io.IOException;
+
+/**
+ * 
+ * Provides an input stream for reading binary data from a client
+ * request, including an efficient <code>readLine</code> method
+ * for reading data one line at a time. With some protocols, such
+ * as HTTP POST and PUT, a <code>ServletInputStream</code>
+ * object can be used to read data sent from the client.
+ *
+ * <p>A <code>ServletInputStream</code> object is normally retrieved via
+ * the {@link ServletRequest#getInputStream} method.
+ *
+ *
+ * <p>This is an abstract class that a servlet container implements.
+ * Subclasses of this class
+ * must implement the <code>java.io.InputStream.read()</code> method.
+ *
+ *
+ * @author 	Various
+ *
+ * @see		ServletRequest 
+ *
+ */
+
+public abstract class ServletInputStream extends InputStream {
+
+
+
+    /**
+     * Does nothing, because this is an abstract class.
+     *
+     */
+
+    protected ServletInputStream() { }
+
+  
+  
+    
+    /**
+     *
+     * Reads the input stream, one line at a time. Starting at an
+     * offset, reads bytes into an array, until it reads a certain number
+     * of bytes or reaches a newline character, which it reads into the
+     * array as well.
+     *
+     * <p>This method returns -1 if it reaches the end of the input
+     * stream before reading the maximum number of bytes.
+     *
+     *
+     *
+     * @param b 		an array of bytes into which data is read
+     *
+     * @param off 		an integer specifying the character at which
+     *				this method begins reading
+     *
+     * @param len		an integer specifying the maximum number of 
+     *				bytes to read
+     *
+     * @return			an integer specifying the actual number of bytes 
+     *				read, or -1 if the end of the stream is reached
+     *
+     * @exception IOException	if an input or output exception has occurred
+     *
+     */
+    public int readLine(byte[] b, int off, int len) throws IOException {
+
+	if (len <= 0) {
+	    return 0;
+	}
+	int count = 0, c;
+
+	while ((c = read()) != -1) {
+	    b[off++] = (byte)c;
+	    count++;
+	    if (c == '\n' || count == len) {
+		break;
+	    }
+	}
+	return count > 0 ? count : -1;
+    }
+
+
+    /**
+     * Returns true when all the data from the stream has been read else
+     * it returns false.
+     *
+     * @return <code>true</code> when all data for this particular request
+     *  has been read, otherwise returns <code>false</code>.
+     *
+     * @since Servlet 3.1
+     */
+    public abstract boolean isFinished();
+
+    /**
+     * Returns true if data can be read without blocking else returns
+     * false.
+     *
+     * @return <code>true</code> if data can be obtained without blocking,
+     *  otherwise returns <code>false</code>.
+     *
+     * @since Servlet 3.1
+     */
+    public abstract boolean isReady();
+
+    /**
+     * Instructs the <code>ServletInputStream</code> to invoke the provided
+     * {@link ReadListener} when it is possible to read
+     *
+     * @param readListener the {@link ReadListener} that should be notified
+     *  when it's possible to read.
+     *
+     * @exception IllegalStateException if one of the following conditions is true
+     * <ul>
+     * <li>the associated request is neither upgraded nor the async started
+     * <li>setReadListener is called more than once within the scope of the same request.
+     * </ul>
+     *
+     * @throws NullPointerException if readListener is null
+     *
+     * @since Servlet 3.1
+
+     */
+    public abstract void setReadListener(ReadListener readListener);
+}
+
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletOutputStream.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletOutputStream.java
new file mode 100644
index 0000000..efcd1e5
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletOutputStream.java
@@ -0,0 +1,395 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.OutputStream;
+import java.io.IOException;
+import java.io.CharConversionException;
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+/**
+ * Provides an output stream for sending binary data to the
+ * client. A <code>ServletOutputStream</code> object is normally retrieved 
+ * via the {@link ServletResponse#getOutputStream} method.
+ *
+ * <p>This is an abstract class that the servlet container implements.
+ * Subclasses of this class
+ * must implement the <code>java.io.OutputStream.write(int)</code>
+ * method.
+ *
+ * 
+ * @author         Various
+ *
+ * @see         ServletResponse
+ *
+ */
+
+public abstract class ServletOutputStream extends OutputStream  {
+
+    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
+    private static ResourceBundle lStrings =
+        ResourceBundle.getBundle(LSTRING_FILE);
+
+
+    
+    /**
+     *
+     * Does nothing, because this is an abstract class.
+     *
+     */
+
+    protected ServletOutputStream() { }
+
+
+    /**
+     * Writes a <code>String</code> to the client, 
+     * without a carriage return-line feed (CRLF) 
+     * character at the end.
+     *
+     *
+     * @param s                       the <code>String</code> to send to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void print(String s) throws IOException {
+        if (s==null) s="null";
+        int len = s.length();
+        for (int i = 0; i < len; i++) {
+            char c = s.charAt (i);
+
+            //
+            // XXX NOTE:  This is clearly incorrect for many strings,
+            // but is the only consistent approach within the current
+            // servlet framework.  It must suffice until servlet output
+            // streams properly encode their output.
+            //
+            if ((c & 0xff00) != 0) {        // high order byte must be zero
+                String errMsg = lStrings.getString("err.not_iso8859_1");
+                Object[] errArgs = new Object[1];
+                errArgs[0] = Character.valueOf(c);
+                errMsg = MessageFormat.format(errMsg, errArgs);
+                throw new CharConversionException(errMsg);
+            }
+            write (c);
+        }
+    }
+
+
+
+    /**
+     * Writes a <code>boolean</code> value to the client,
+     * with no carriage return-line feed (CRLF) 
+     * character at the end.
+     *
+     * @param b                       the <code>boolean</code> value 
+     *                                to send to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void print(boolean b) throws IOException {
+        String msg;
+        if (b) {
+            msg = lStrings.getString("value.true");
+        } else {
+            msg = lStrings.getString("value.false");
+        }
+        print(msg);
+    }
+
+
+
+    /**
+     * Writes a character to the client,
+     * with no carriage return-line feed (CRLF) 
+     * at the end.
+     *
+     * @param c                       the character to send to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void print(char c) throws IOException {
+        print(String.valueOf(c));
+    }
+
+
+
+
+    /**
+     *
+     * Writes an int to the client,
+     * with no carriage return-line feed (CRLF) 
+     * at the end.
+     *
+     * @param i                       the int to send to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */  
+
+    public void print(int i) throws IOException {
+        print(String.valueOf(i));
+    }
+
+
+
+ 
+    /**
+     * 
+     * Writes a <code>long</code> value to the client,
+     * with no carriage return-line feed (CRLF) at the end.
+     *
+     * @param l                       the <code>long</code> value 
+     *                                to send to the client
+     *
+     * @exception IOException         if an input or output exception 
+     *                                occurred
+     * 
+     */
+
+    public void print(long l) throws IOException {
+        print(String.valueOf(l));
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>float</code> value to the client,
+     * with no carriage return-line feed (CRLF) at the end.
+     *
+     * @param f                       the <code>float</code> value
+     *                                to send to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     *
+     */
+
+    public void print(float f) throws IOException {
+        print(String.valueOf(f));
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>double</code> value to the client,
+     * with no carriage return-line feed (CRLF) at the end.
+     * 
+     * @param d                       the <code>double</code> value
+     *                                to send to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void print(double d) throws IOException {
+        print(String.valueOf(d));
+    }
+
+
+
+    /**
+     * Writes a carriage return-line feed (CRLF)
+     * to the client.
+     *
+     *
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void println() throws IOException {
+        print("\r\n");
+    }
+
+
+
+    /**
+     * Writes a <code>String</code> to the client, 
+     * followed by a carriage return-line feed (CRLF).
+     *
+     *
+     * @param s                       the <code>String</code> to write to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void println(String s) throws IOException {
+        print(s);
+        println();
+    }
+
+
+
+
+    /**
+     *
+     * Writes a <code>boolean</code> value to the client, 
+     * followed by a 
+     * carriage return-line feed (CRLF).
+     *
+     *
+     * @param b                       the <code>boolean</code> value 
+     *                                to write to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void println(boolean b) throws IOException {
+        print(b);
+        println();
+    }
+
+
+
+    /**
+     *
+     * Writes a character to the client, followed by a carriage
+     * return-line feed (CRLF).
+     *
+     * @param c                       the character to write to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void println(char c) throws IOException {
+        print(c);
+        println();
+    }
+
+
+
+    /**
+     *
+     * Writes an int to the client, followed by a 
+     * carriage return-line feed (CRLF) character.
+     *
+     *
+     * @param i                       the int to write to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void println(int i) throws IOException {
+        print(i);
+        println();
+    }
+
+
+
+    /**  
+     *
+     * Writes a <code>long</code> value to the client, followed by a 
+     * carriage return-line feed (CRLF).
+     *
+     *
+     * @param l                       the <code>long</code> value to write to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */  
+
+    public void println(long l) throws IOException {
+        print(l);
+        println();
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>float</code> value to the client, 
+     * followed by a carriage return-line feed (CRLF).
+     *
+     * @param f                       the <code>float</code> value 
+     *                                to write to the client
+     *
+     *
+     * @exception IOException         if an input or output exception 
+     *                                occurred
+     *
+     */
+
+    public void println(float f) throws IOException {
+        print(f);
+        println();
+    }
+
+
+
+    /**
+     *
+     * Writes a <code>double</code> value to the client, 
+     * followed by a carriage return-line feed (CRLF).
+     *
+     *
+     * @param d                       the <code>double</code> value
+     *                                to write to the client
+     *
+     * @exception IOException         if an input or output exception occurred
+     *
+     */
+
+    public void println(double d) throws IOException {
+        print(d);
+        println();
+    }
+
+    /**
+     * This method can be used to determine if data can be written without blocking.
+     *
+     * @return <code>true</code> if a write to this <code>ServletOutputStream</code>
+     *  will succeed, otherwise returns <code>false</code>.
+     *
+     *  @since Servlet 3.1
+     */
+    public abstract boolean isReady();
+
+    /**
+     * Instructs the <code>ServletOutputStream</code> to invoke the provided
+     * {@link WriteListener} when it is possible to write
+     *
+     *
+     * @param writeListener the {@link WriteListener} that should be notified
+     *  when it's possible to write
+     *
+     * @exception IllegalStateException if one of the following conditions is true
+     * <ul>
+     * <li>the associated request is neither upgraded nor the async started
+     * <li>setWriteListener is called more than once within the scope of the same request.
+     * </ul>
+     *
+     * @throws NullPointerException if writeListener is null
+     *
+     * @since Servlet 3.1
+     */
+    public abstract void setWriteListener(WriteListener writeListener);
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletRegistration.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRegistration.java
new file mode 100644
index 0000000..26037e3
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRegistration.java
@@ -0,0 +1,220 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.util.*;
+
+/**
+ * Interface through which a {@link Servlet} may be further configured.
+ *
+ * @since Servlet 3.0
+ */
+public interface ServletRegistration extends Registration {
+
+    /**
+     * Adds a servlet mapping with the given URL patterns for the Servlet
+     * represented by this ServletRegistration.
+     *
+     * <p>If any of the specified URL patterns are already mapped to a 
+     * different Servlet, no updates will be performed.
+     *
+     * <p>If this method is called multiple times, each successive call
+     * adds to the effects of the former.
+     *
+     * <p>The returned set is not backed by the {@code ServletRegistration}
+     * object, so changes in the returned set are not reflected in the
+     * {@code ServletRegistration} object, and vice-versa.</p>
+     *
+     * @param urlPatterns the URL patterns of the servlet mapping
+     *
+     * @return the (possibly empty) Set of URL patterns that are already
+     * mapped to a different Servlet
+     *
+     * @throws IllegalArgumentException if <tt>urlPatterns</tt> is null
+     * or empty
+     * @throws IllegalStateException if the ServletContext from which this
+     * ServletRegistration was obtained has already been initialized
+     */
+    public Set<String> addMapping(String... urlPatterns);
+
+    /**
+     * Gets the currently available mappings of the
+     * Servlet represented by this <code>ServletRegistration</code>.
+     *
+     * <p>If permitted, any changes to the returned <code>Collection</code> must not 
+     * affect this <code>ServletRegistration</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the currently
+     * available mappings of the Servlet represented by this
+     * <code>ServletRegistration</code>
+     */
+    public Collection<String> getMappings();
+
+    /**
+     * Gets the name of the runAs role of the Servlet represented by this
+     * <code>ServletRegistration</code>.
+     * 
+     * @return the name of the runAs role, or null if the Servlet is
+     * configured to run as its caller
+     */
+    public String getRunAsRole();
+
+    /**
+     * Interface through which a {@link Servlet} registered via one of the
+     * <tt>addServlet</tt> methods on {@link ServletContext} may be further
+     * configured.
+     */
+    interface Dynamic extends ServletRegistration, Registration.Dynamic {
+
+        /**
+         * Sets the <code>loadOnStartup</code> priority on the Servlet
+         * represented by this dynamic ServletRegistration.
+         *
+         * <p>A <tt>loadOnStartup</tt> value of greater than or equal to
+         * zero indicates to the container the initialization priority of
+         * the Servlet. In this case, the container must instantiate and
+         * initialize the Servlet during the initialization phase of the
+         * ServletContext, that is, after it has invoked all of the
+         * ServletContextListener objects configured for the ServletContext
+         * at their {@link ServletContextListener#contextInitialized}
+         * method.
+         *
+         * <p>If <tt>loadOnStartup</tt> is a negative integer, the container
+         * is free to instantiate and initialize the Servlet lazily.
+         *
+         * <p>The default value for <tt>loadOnStartup</tt> is <code>-1</code>.
+         *
+         * <p>A call to this method overrides any previous setting.
+         *
+         * @param loadOnStartup the initialization priority of the Servlet
+         *
+         * @throws IllegalStateException if the ServletContext from which
+         * this ServletRegistration was obtained has already been initialized
+         */
+        public void setLoadOnStartup(int loadOnStartup);
+
+        /**
+         * Sets the {@link ServletSecurityElement} to be applied to the
+         * mappings defined for this <code>ServletRegistration</code>.
+         *
+         * <p>This method applies to all mappings added to this
+         * <code>ServletRegistration</code> up until the point that the
+         * <code>ServletContext</code> from which it was obtained has been
+         * initialized.
+         * 
+         * <p>If a URL pattern of this ServletRegistration is an exact target
+         * of a <code>security-constraint</code> that was established via
+         * the portable deployment descriptor, then this method does not
+         * change the <code>security-constraint</code> for that pattern,
+         * and the pattern will be included in the return value.
+         * 
+         * <p>If a URL pattern of this ServletRegistration is an exact
+         * target of a security constraint that was established via the
+         * {@link javax.servlet.annotation.ServletSecurity} annotation
+         * or a previous call to this method, then this method replaces
+         * the security constraint for that pattern.
+         * 
+         * <p>If a URL pattern of this ServletRegistration is neither the
+         * exact target of a security constraint that was established via
+         * the {@link javax.servlet.annotation.ServletSecurity} annotation
+         * or a previous call to this method, nor the exact target of a
+         * <code>security-constraint</code> in the portable deployment
+         * descriptor, then this method establishes the security constraint
+         * for that pattern from the argument
+         * <code>ServletSecurityElement</code>.
+         *
+         * <p>The returned set is not backed by the {@code Dynamic} object,
+         * so changes in the returned set are not reflected in the
+         * {@code Dynamic} object, and vice-versa.</p>
+         * 
+         * @param constraint the {@link ServletSecurityElement} to be applied
+         * to the patterns mapped to this ServletRegistration
+         * 
+         * @return the (possibly empty) Set of URL patterns that were already
+         * the exact target of a <code>security-constraint</code> that was
+         * established via the portable deployment descriptor. This method
+         * has no effect on the patterns included in the returned set
+         * 
+         * @throws IllegalArgumentException if <tt>constraint</tt> is null
+         * 
+         * @throws IllegalStateException if the {@link ServletContext} from
+         * which this <code>ServletRegistration</code> was obtained has
+         * already been initialized 
+         */
+        public Set<String> setServletSecurity(ServletSecurityElement constraint);
+
+        /**
+         * Sets the {@link MultipartConfigElement} to be applied to the
+         * mappings defined for this <code>ServletRegistration</code>. If this
+         * method is called multiple times, each successive call overrides the
+         * effects of the former.
+         *
+         * @param multipartConfig the {@link MultipartConfigElement} to be
+         * applied to the patterns mapped to the registration
+         *
+         * @throws IllegalArgumentException if <tt>multipartConfig</tt> is
+         * null
+         *
+         * @throws IllegalStateException if the {@link ServletContext} from
+         * which this ServletRegistration was obtained has already been
+         * initialized
+         */
+        public void setMultipartConfig(
+            MultipartConfigElement multipartConfig);
+
+        /**
+         * Sets the name of the <code>runAs</code> role for this
+         * <code>ServletRegistration</code>.
+         *
+         * @param roleName the name of the <code>runAs</code> role
+         *
+         * @throws IllegalArgumentException if <tt>roleName</tt> is null
+         *
+         * @throws IllegalStateException if the {@link ServletContext} from
+         * which this ServletRegistration was obtained has already been
+         * initialized
+         */
+        public void setRunAsRole(String roleName);
+
+    }
+
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequest.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequest.java
new file mode 100644
index 0000000..979898e
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequest.java
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * Defines an object to provide client request information to a servlet.  The
+ * servlet container creates a <code>ServletRequest</code> object and passes
+ * it as an argument to the servlet's <code>service</code> method.
+ *
+ * <p>A <code>ServletRequest</code> object provides data including
+ * parameter name and values, attributes, and an input stream.
+ * Interfaces that extend <code>ServletRequest</code> can provide
+ * additional protocol-specific data (for example, HTTP data is
+ * provided by {@link javax.servlet.http.HttpServletRequest}.
+ * 
+ * @author Various
+ *
+ * @see javax.servlet.http.HttpServletRequest
+ *
+ */
+public interface ServletRequest {
+
+    /**
+     * Returns the value of the named attribute as an <code>Object</code>,
+     * or <code>null</code> if no attribute of the given name exists. 
+     *
+     * <p> Attributes can be set two ways.  The servlet container may set
+     * attributes to make available custom information about a request.
+     * For example, for requests made using HTTPS, the attribute
+     * <code>javax.servlet.request.X509Certificate</code> can be used to
+     * retrieve information on the certificate of the client.  Attributes
+     * can also be set programatically using 
+     * {@link ServletRequest#setAttribute}.  This allows information to be
+     * embedded into a request before a {@link RequestDispatcher} call.
+     *
+     * <p>Attribute names should follow the same conventions as package
+     * names. This specification reserves names matching <code>java.*</code>,
+     * <code>javax.*</code>, and <code>sun.*</code>. 
+     *
+     * @param name a <code>String</code> specifying the name of the attribute
+     *
+     * @return an <code>Object</code> containing the value of the attribute,
+     * or <code>null</code> if the attribute does not exist
+     */
+    public Object getAttribute(String name);
+    
+    /**
+     * Returns an <code>Enumeration</code> containing the
+     * names of the attributes available to this request. 
+     * This method returns an empty <code>Enumeration</code>
+     * if the request has no attributes available to it.
+     * 
+     * @return an <code>Enumeration</code> of strings containing the names 
+     * of the request's attributes
+     */
+    public Enumeration<String> getAttributeNames();
+    
+    /**
+     * Returns the name of the character encoding used in the body of this
+     * request. This method returns <code>null</code> if no request encoding
+     * character encoding has been specified. The following methods for
+     * specifying the request character encoding are consulted, in decreasing
+     * order of priority: per request, per web app (using
+     * {@link ServletContext#setRequestCharacterEncoding}, deployment
+     * descriptor), and per container (for all web applications deployed in 
+     * that container, using vendor specific configuration).
+     * 
+     * @return a <code>String</code> containing the name of the character
+     * encoding, or <code>null</code> if the request does not specify a
+     * character encoding
+     */
+    public String getCharacterEncoding();
+
+    /**
+     * Overrides the name of the character encoding used in the body of this
+     * request. This method must be called prior to reading request parameters
+     * or reading input using getReader(). Otherwise, it has no effect.
+     * 
+     * @param env <code>String</code> containing the name of
+     * the character encoding.
+     *
+     * @throws UnsupportedEncodingException if this ServletRequest is still
+     * in a state where a character encoding may be set,
+     * but the specified encoding is invalid
+     */
+    public void setCharacterEncoding(String env) throws UnsupportedEncodingException;
+
+    /**
+     * Returns the length, in bytes, of the request body and made available by
+     * the input stream, or -1 if the length is not known ir is greater than
+     * Integer.MAX_VALUE. For HTTP servlets,
+     * same as the value of the CGI variable CONTENT_LENGTH.
+     *
+     * @return an integer containing the length of the request body or -1 if
+     * the length is not known or is greater than Integer.MAX_VALUE.
+     */
+    public int getContentLength();
+    
+    /**
+     * Returns the length, in bytes, of the request body and made available by
+     * the input stream, or -1 if the length is not known. For HTTP servlets,
+     * same as the value of the CGI variable CONTENT_LENGTH.
+     *
+     * @return a long containing the length of the request body or -1L if
+     * the length is not known
+     *
+     * @since Servlet 3.1
+     */
+    public long getContentLengthLong();
+    
+    /**
+     * Returns the MIME type of the body of the request, or 
+     * <code>null</code> if the type is not known. For HTTP servlets, 
+     * same as the value of the CGI variable CONTENT_TYPE.
+     *
+     * @return a <code>String</code> containing the name of the MIME type
+     * of the request, or null if the type is not known
+     */
+    public String getContentType();
+    
+    /**
+     * Retrieves the body of the request as binary data using
+     * a {@link ServletInputStream}.  Either this method or 
+     * {@link #getReader} may be called to read the body, not both.
+     *
+     * @return a {@link ServletInputStream} object containing
+     * the body of the request
+     *
+     * @exception IllegalStateException if the {@link #getReader} method
+     * has already been called for this request
+     *
+     * @exception IOException if an input or output exception occurred
+     */
+    public ServletInputStream getInputStream() throws IOException; 
+     
+    /**
+     * Returns the value of a request parameter as a <code>String</code>,
+     * or <code>null</code> if the parameter does not exist. Request parameters
+     * are extra information sent with the request.  For HTTP servlets,
+     * parameters are contained in the query string or posted form data.
+     *
+     * <p>You should only use this method when you are sure the
+     * parameter has only one value. If the parameter might have
+     * more than one value, use {@link #getParameterValues}.
+     *
+     * <p>If you use this method with a multivalued
+     * parameter, the value returned is equal to the first value
+     * in the array returned by <code>getParameterValues</code>.
+     *
+     * <p>If the parameter data was sent in the request body, such as occurs
+     * with an HTTP POST request, then reading the body directly via {@link
+     * #getInputStream} or {@link #getReader} can interfere
+     * with the execution of this method.
+     *
+     * @param name a <code>String</code> specifying the name of the parameter
+     *
+     * @return a <code>String</code> representing the single value of
+     * the parameter
+     *
+     * @see #getParameterValues
+     */
+    public String getParameter(String name);
+    
+    /**
+     *
+     * Returns an <code>Enumeration</code> of <code>String</code>
+     * objects containing the names of the parameters contained
+     * in this request. If the request has 
+     * no parameters, the method returns an empty <code>Enumeration</code>. 
+     *
+     * @return an <code>Enumeration</code> of <code>String</code>
+     * objects, each <code>String</code> containing the name of
+     * a request parameter; or an empty <code>Enumeration</code>
+     * if the request has no parameters
+     */
+    public Enumeration<String> getParameterNames();
+        
+    /**
+     * Returns an array of <code>String</code> objects containing 
+     * all of the values the given request parameter has, or 
+     * <code>null</code> if the parameter does not exist.
+     *
+     * <p>If the parameter has a single value, the array has a length
+     * of 1.
+     *
+     * @param name a <code>String</code> containing the name of 
+     * the parameter whose value is requested
+     *
+     * @return an array of <code>String</code> objects 
+     * containing the parameter's values
+     *
+     * @see #getParameter
+     */
+    public String[] getParameterValues(String name);
+ 
+    /**
+     * Returns a java.util.Map of the parameters of this request.
+     * 
+     * <p>Request parameters are extra information sent with the request.
+     * For HTTP servlets, parameters are contained in the query string or
+     * posted form data.
+     *
+     * @return an immutable java.util.Map containing parameter names as 
+     * keys and parameter values as map values. The keys in the parameter
+     * map are of type String. The values in the parameter map are of type
+     * String array.
+     */
+    public Map<String, String[]> getParameterMap();
+    
+    /**
+     * Returns the name and version of the protocol the request uses
+     * in the form <i>protocol/majorVersion.minorVersion</i>, for 
+     * example, HTTP/1.1. For HTTP servlets, the value
+     * returned is the same as the value of the CGI variable 
+     * <code>SERVER_PROTOCOL</code>.
+     *
+     * @return a <code>String</code> containing the protocol 
+     * name and version number
+     */    
+    public String getProtocol();
+    
+    /**
+     * Returns the name of the scheme used to make this request, 
+     * for example,
+     * <code>http</code>, <code>https</code>, or <code>ftp</code>.
+     * Different schemes have different rules for constructing URLs,
+     * as noted in RFC 1738.
+     *
+     * @return a <code>String</code> containing the name 
+     * of the scheme used to make this request
+     */
+    public String getScheme();
+    
+    /**
+     * Returns the host name of the server to which the request was sent.
+     * It is the value of the part before ":" in the <code>Host</code>
+     * header value, if any, or the resolved server name, or the server IP
+     * address.
+     *
+     * @return a <code>String</code> containing the name of the server
+     */
+    public String getServerName();
+    
+    /**
+     * Returns the port number to which the request was sent.
+     * It is the value of the part after ":" in the <code>Host</code>
+     * header value, if any, or the server port where the client connection
+     * was accepted on.
+     *
+     * @return an integer specifying the port number
+     */
+    public int getServerPort();
+    
+    /**
+     * Retrieves the body of the request as character data using
+     * a <code>BufferedReader</code>.  The reader translates the character
+     * data according to the character encoding used on the body.
+     * Either this method or {@link #getInputStream} may be called to read the
+     * body, not both.
+     * 
+     * @return a <code>BufferedReader</code> containing the body of the request 
+     *
+     * @exception UnsupportedEncodingException  if the character set encoding
+     * used is not supported and the text cannot be decoded
+     *
+     * @exception IllegalStateException if {@link #getInputStream} method
+     * has been called on this request
+     *
+     * @exception IOException if an input or output exception occurred
+     *
+     * @see #getInputStream
+     */
+    public BufferedReader getReader() throws IOException;
+    
+    /**
+     * Returns the Internet Protocol (IP) address of the client 
+     * or last proxy that sent the request.
+     * For HTTP servlets, same as the value of the 
+     * CGI variable <code>REMOTE_ADDR</code>.
+     *
+     * @return a <code>String</code> containing the 
+     * IP address of the client that sent the request
+     */
+    public String getRemoteAddr();
+    
+    /**
+     * Returns the fully qualified name of the client
+     * or the last proxy that sent the request.
+     * If the engine cannot or chooses not to resolve the hostname 
+     * (to improve performance), this method returns the dotted-string form of 
+     * the IP address. For HTTP servlets, same as the value of the CGI variable 
+     * <code>REMOTE_HOST</code>.
+     *
+     * @return a <code>String</code> containing the fully 
+     * qualified name of the client
+     */
+    public String getRemoteHost();
+    
+    /**
+     * Stores an attribute in this request.
+     * Attributes are reset between requests.  This method is most
+     * often used in conjunction with {@link RequestDispatcher}.
+     *
+     * <p>Attribute names should follow the same conventions as
+     * package names. Names beginning with <code>java.*</code>,
+     * <code>javax.*</code>, and <code>com.sun.*</code>, are
+     * reserved for use by Sun Microsystems.
+     *<br> If the object passed in is null, the effect is the same as
+     * calling {@link #removeAttribute}.
+     * <br> It is warned that when the request is dispatched from the
+     * servlet resides in a different web application by
+     * <code>RequestDispatcher</code>, the object set by this method
+     * may not be correctly retrieved in the caller servlet.
+     *
+     * @param name a <code>String</code> specifying 
+     * the name of the attribute
+     *
+     * @param o the <code>Object</code> to be stored
+     *
+     */
+    public void setAttribute(String name, Object o);
+    
+    /**
+     *
+     * Removes an attribute from this request.  This method is not
+     * generally needed as attributes only persist as long as the request
+     * is being handled.
+     *
+     * <p>Attribute names should follow the same conventions as
+     * package names. Names beginning with <code>java.*</code>,
+     * <code>javax.*</code>, and <code>com.sun.*</code>, are
+     * reserved for use by Sun Microsystems.
+     *
+     * @param name a <code>String</code> specifying 
+     * the name of the attribute to remove
+     */
+    public void removeAttribute(String name);
+    
+    /**
+     * Returns the preferred <code>Locale</code> that the client will 
+     * accept content in, based on the Accept-Language header.
+     * If the client request doesn't provide an Accept-Language header,
+     * this method returns the default locale for the server.
+     *
+     * @return the preferred <code>Locale</code> for the client
+     */
+    public Locale getLocale();
+    
+    /**
+     * Returns an <code>Enumeration</code> of <code>Locale</code> objects
+     * indicating, in decreasing order starting with the preferred locale, the
+     * locales that are acceptable to the client based on the Accept-Language
+     * header.
+     * If the client request doesn't provide an Accept-Language header,
+     * this method returns an <code>Enumeration</code> containing one 
+     * <code>Locale</code>, the default locale for the server.
+     *
+     * @return an <code>Enumeration</code> of preferred 
+     * <code>Locale</code> objects for the client
+     */
+    public Enumeration<Locale> getLocales();
+    
+    /**
+     *
+     * Returns a boolean indicating whether this request was made using a
+     * secure channel, such as HTTPS.
+     *
+     * @return a boolean indicating if the request was made using a
+     * secure channel
+     */
+    public boolean isSecure();
+    
+    /**
+     *
+     * Returns a {@link RequestDispatcher} object that acts as a wrapper for
+     * the resource located at the given path.  
+     * A <code>RequestDispatcher</code> object can be used to forward
+     * a request to the resource or to include the resource in a response.
+     * The resource can be dynamic or static.
+     *
+     * <p>The pathname specified may be relative, although it cannot extend
+     * outside the current servlet context.  If the path begins with 
+     * a "/" it is interpreted as relative to the current context root.  
+     * This method returns <code>null</code> if the servlet container
+     * cannot return a <code>RequestDispatcher</code>.
+     *
+     * <p>The difference between this method and {@link
+     * ServletContext#getRequestDispatcher} is that this method can take a
+     * relative path.
+     *
+     * @param path a <code>String</code> specifying the pathname
+     * to the resource. If it is relative, it must be
+     * relative against the current servlet.
+     *
+     * @return a <code>RequestDispatcher</code> object that acts as a
+     * wrapper for the resource at the specified path,
+     * or <code>null</code> if the servlet container cannot
+     * return a <code>RequestDispatcher</code>
+     *
+     * @see RequestDispatcher
+     * @see ServletContext#getRequestDispatcher
+     */
+    public RequestDispatcher getRequestDispatcher(String path);
+    
+    /**
+     * @param path the path for which the real path is to be returned.
+
+     * @return the <i>real</i> path, or <tt>null</tt> if the
+     * translation cannot be performed.
+
+     * @deprecated  As of Version 2.1 of the Java Servlet API,
+     *    use {@link ServletContext#getRealPath} instead.
+     */
+    public String getRealPath(String path);
+    
+    /**
+     * Returns the Internet Protocol (IP) source port of the client
+     * or last proxy that sent the request.
+     *
+     * @return an integer specifying the port number
+     *
+     * @since Servlet 2.4
+     */    
+    public int getRemotePort();
+
+    /**
+     * Returns the host name of the Internet Protocol (IP) interface on
+     * which the request was received.
+     *
+     * @return a <code>String</code> containing the host
+     *         name of the IP on which the request was received.
+     *
+     * @since Servlet 2.4
+     */
+    public String getLocalName();
+
+    /**
+     * Returns the Internet Protocol (IP) address of the interface on
+     * which the request  was received.
+     *
+     * @return a <code>String</code> containing the
+     * IP address on which the request was received. 
+     *
+     * @since Servlet 2.4
+     */       
+    public String getLocalAddr();
+
+    /**
+     * Returns the Internet Protocol (IP) port number of the interface
+     * on which the request was received.
+     *
+     * @return an integer specifying the port number
+     *
+     * @since Servlet 2.4
+     */
+    public int getLocalPort();
+
+    /**
+     * Gets the servlet context to which this ServletRequest was last
+     * dispatched.
+     *
+     * @return the servlet context to which this ServletRequest was last
+     * dispatched
+     *
+     * @since Servlet 3.0
+     */
+    public ServletContext getServletContext();
+
+    /**
+     * Puts this request into asynchronous mode, and initializes its
+     * {@link AsyncContext} with the original (unwrapped) ServletRequest
+     * and ServletResponse objects.
+     *
+     * <p>Calling this method will cause committal of the associated
+     * response to be delayed until {@link AsyncContext#complete} is
+     * called on the returned {@link AsyncContext}, or the asynchronous
+     * operation has timed out.
+     *
+     * <p>Calling {@link AsyncContext#hasOriginalRequestAndResponse()} on
+     * the returned AsyncContext will return <code>true</code>. Any filters
+     * invoked in the <i>outbound</i> direction after this request was put
+     * into asynchronous mode may use this as an indication that any request
+     * and/or response wrappers that they added during their <i>inbound</i>
+     * invocation need not stay around for the duration of the asynchronous
+     * operation, and therefore any of their associated resources may be
+     * released.
+     *
+     * <p>This method clears the list of {@link AsyncListener} instances
+     * (if any) that were registered with the AsyncContext returned by the
+     * previous call to one of the startAsync methods, after calling each
+     * AsyncListener at its {@link AsyncListener#onStartAsync onStartAsync}
+     * method.
+     *
+     * <p>Subsequent invocations of this method, or its overloaded 
+     * variant, will return the same AsyncContext instance, reinitialized
+     * as appropriate.
+     *
+     * @return the (re)initialized AsyncContext
+     * 
+     * @throws IllegalStateException if this request is within the scope of
+     * a filter or servlet that does not support asynchronous operations
+     * (that is, {@link #isAsyncSupported} returns false),
+     * or if this method is called again without any asynchronous dispatch
+     * (resulting from one of the {@link AsyncContext#dispatch} methods),
+     * is called outside the scope of any such dispatch, or is called again
+     * within the scope of the same dispatch, or if the response has
+     * already been closed
+     *
+     * @see AsyncContext#dispatch()
+     * @since Servlet 3.0
+     */
+    public AsyncContext startAsync() throws IllegalStateException;
+ 
+    /**
+     * Puts this request into asynchronous mode, and initializes its
+     * {@link AsyncContext} with the given request and response objects.
+     *
+     * <p>The ServletRequest and ServletResponse arguments must be
+     * the same instances, or instances of {@link ServletRequestWrapper} and
+     * {@link ServletResponseWrapper} that wrap them, that were passed to the
+     * {@link Servlet#service service} method of the Servlet or the
+     * {@link Filter#doFilter doFilter} method of the Filter, respectively,
+     * in whose scope this method is being called.
+     *
+     * <p>Calling this method will cause committal of the associated
+     * response to be delayed until {@link AsyncContext#complete} is
+     * called on the returned {@link AsyncContext}, or the asynchronous
+     * operation has timed out.
+     *
+     * <p>Calling {@link AsyncContext#hasOriginalRequestAndResponse()} on
+     * the returned AsyncContext will return <code>false</code>,
+     * unless the passed in ServletRequest and ServletResponse arguments
+     * are the original ones or do not carry any application-provided wrappers.
+     * Any filters invoked in the <i>outbound</i> direction after this
+     * request was put into asynchronous mode may use this as an indication
+     * that some of the request and/or response wrappers that they added
+     * during their <i>inbound</i> invocation may need to stay in place for
+     * the duration of the asynchronous operation, and their associated
+     * resources may not be released.
+     * A ServletRequestWrapper applied during the <i>inbound</i>
+     * invocation of a filter may be released by the <i>outbound</i>
+     * invocation of the filter only if the given <code>servletRequest</code>,
+     * which is used to initialize the AsyncContext and will be returned by
+     * a call to {@link AsyncContext#getRequest()}, does not contain said
+     * ServletRequestWrapper. The same holds true for ServletResponseWrapper
+     * instances. 
+     *
+     * <p>This method clears the list of {@link AsyncListener} instances
+     * (if any) that were registered with the AsyncContext returned by the
+     * previous call to one of the startAsync methods, after calling each
+     * AsyncListener at its {@link AsyncListener#onStartAsync onStartAsync}
+     * method.
+     *
+     * <p>Subsequent invocations of this method, or its zero-argument
+     * variant, will return the same AsyncContext instance, reinitialized
+     * as appropriate. If a call to this method is followed by a call to its
+     * zero-argument variant, the specified (and possibly wrapped) request
+     * and response objects will remain <i>locked in</i> on the returned
+     * AsyncContext.
+     *
+     * @param servletRequest the ServletRequest used to initialize the
+     * AsyncContext
+     * @param servletResponse the ServletResponse used to initialize the
+     * AsyncContext
+     *
+     * @return the (re)initialized AsyncContext
+     * 
+     * @throws IllegalStateException if this request is within the scope of
+     * a filter or servlet that does not support asynchronous operations
+     * (that is, {@link #isAsyncSupported} returns false),
+     * or if this method is called again without any asynchronous dispatch
+     * (resulting from one of the {@link AsyncContext#dispatch} methods),
+     * is called outside the scope of any such dispatch, or is called again
+     * within the scope of the same dispatch, or if the response has
+     * already been closed
+     *
+     * @since Servlet 3.0
+     */
+    public AsyncContext startAsync(ServletRequest servletRequest,
+                                   ServletResponse servletResponse)
+            throws IllegalStateException;
+   
+    /**
+     * Checks if this request has been put into asynchronous mode.
+     *
+     * <p>A ServletRequest is put into asynchronous mode by calling
+     * {@link #startAsync} or
+     * {@link #startAsync(ServletRequest,ServletResponse)} on it.
+     * 
+     * <p>This method returns <tt>false</tt> if this request was
+     * put into asynchronous mode, but has since been dispatched using
+     * one of the {@link AsyncContext#dispatch} methods or released
+     * from asynchronous mode via a call to {@link AsyncContext#complete}.
+     *
+     * @return true if this request has been put into asynchronous mode,
+     * false otherwise
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isAsyncStarted();
+
+    /**
+     * Checks if this request supports asynchronous operation.
+     *
+     * <p>Asynchronous operation is disabled for this request if this request
+     * is within the scope of a filter or servlet that has not been annotated
+     * or flagged in the deployment descriptor as being able to support
+     * asynchronous handling.
+     *
+     * @return true if this request supports asynchronous operation, false
+     * otherwise
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isAsyncSupported();
+
+    /**
+     * Gets the AsyncContext that was created or reinitialized by the
+     * most recent invocation of {@link #startAsync} or
+     * {@link #startAsync(ServletRequest,ServletResponse)} on this request.
+     *
+     * @return the AsyncContext that was created or reinitialized by the
+     * most recent invocation of {@link #startAsync} or
+     * {@link #startAsync(ServletRequest,ServletResponse)} on
+     * this request 
+     *
+     * @throws IllegalStateException if this request has not been put 
+     * into asynchronous mode, i.e., if neither {@link #startAsync} nor
+     * {@link #startAsync(ServletRequest,ServletResponse)} has been called
+     *
+     * @since Servlet 3.0
+     */
+    public AsyncContext getAsyncContext();
+
+    /**
+     * Gets the dispatcher type of this request.
+     *
+     * <p>The dispatcher type of a request is used by the container
+     * to select the filters that need to be applied to the request:
+     * Only filters with matching dispatcher type and url patterns will
+     * be applied.
+     * 
+     * <p>Allowing a filter that has been configured for multiple 
+     * dispatcher types to query a request for its dispatcher type
+     * allows the filter to process the request differently depending on
+     * its dispatcher type.
+     *
+     * <p>The initial dispatcher type of a request is defined as
+     * <code>DispatcherType.REQUEST</code>. The dispatcher type of a request
+     * dispatched via {@link RequestDispatcher#forward(ServletRequest,
+     * ServletResponse)} or {@link RequestDispatcher#include(ServletRequest,
+     * ServletResponse)} is given as <code>DispatcherType.FORWARD</code> or
+     * <code>DispatcherType.INCLUDE</code>, respectively, while the
+     * dispatcher type of an asynchronous request dispatched via
+     * one of the {@link AsyncContext#dispatch} methods is given as
+     * <code>DispatcherType.ASYNC</code>. Finally, the dispatcher type of a
+     * request dispatched to an error page by the container's error handling
+     * mechanism is given as <code>DispatcherType.ERROR</code>.
+     *
+     * @return the dispatcher type of this request
+     * 
+     * @see DispatcherType
+     *
+     * @since Servlet 3.0
+     */
+    public DispatcherType getDispatcherType();
+
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestAttributeEvent.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestAttributeEvent.java
new file mode 100644
index 0000000..1f59887
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestAttributeEvent.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+
+    /** 
+      * This is the event class for notifications of changes to the 
+      * attributes of the servlet request in an application.
+      * @see ServletRequestAttributeListener
+      * @since Servlet 2.4
+      */
+
+public class ServletRequestAttributeEvent extends ServletRequestEvent { 
+
+    private static final long serialVersionUID = -1466635426192317793L;
+
+    private String name;
+    private Object value;
+
+     /** Construct a ServletRequestAttributeEvent giving the servlet context
+      * of this web application, the ServletRequest whose attributes are
+      * changing and the name and value of the attribute.
+      *
+      * @param sc		the ServletContext that is sending the event.
+      * @param request		the ServletRequest that is sending the event.
+      * @param name		the name of the request attribute.
+      * @param value		the value of the request attribute.
+      */
+    public ServletRequestAttributeEvent(ServletContext sc, ServletRequest request, String name, Object value) {
+        super(sc, request);
+        this.name = name;
+        this.value = value;
+    }
+
+    /**
+      * Return the name of the attribute that changed on the ServletRequest.
+      *
+      * @return		the name of the changed request attribute
+      */
+    public String getName() {
+        return this.name;
+    }
+
+    /**
+      * Returns the value of the attribute that has been added, removed or 
+      * replaced. If the attribute was added, this is the value of the 
+      * attribute. If the attribute was removed, this is the value of the 
+      * removed attribute. If the attribute was replaced, this is the old 
+      * value of the attribute.
+      *
+      * @return		the value of the changed request attribute
+      */
+    public Object getValue() {
+        return this.value;   
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestAttributeListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestAttributeListener.java
new file mode 100644
index 0000000..f17ab03
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestAttributeListener.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.util.EventListener;
+
+/**
+ * Interface for receiving notification events about ServletRequest
+ * attribute changes.
+ *
+ * <p>Notifications will be generated while the request
+ * is within the scope of the web application. A ServletRequest
+ * is defined as coming into scope of a web application when it
+ * is about to enter the first servlet or filter of the web
+ * application, and as going out of scope when it exits the last
+ * servlet or the first filter in the chain.
+ *
+ * <p>In order to receive these notification events, the implementation
+ * class must be either declared in the deployment descriptor of the web
+ * application, annotated with {@link javax.servlet.annotation.WebListener},
+ * or registered via one of the addListener methods defined on
+ * {@link ServletContext}.
+ *
+ * <p>The order in which implementations of this interface are invoked is
+ * unspecified.
+ *
+ * @since Servlet 2.4
+ */
+
+public interface ServletRequestAttributeListener extends EventListener {
+
+    /**
+     * Receives notification that an attribute has been added to the
+     * ServletRequest.
+     *
+     * @param srae the ServletRequestAttributeEvent containing the 
+     * ServletRequest and the name and value of the attribute that was
+     * added
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void attributeAdded(ServletRequestAttributeEvent srae) {}
+
+    /**
+     * Receives notification that an attribute has been removed from the
+     * ServletRequest.
+     *
+     * @param srae the ServletRequestAttributeEvent containing the 
+     * ServletRequest and the name and value of the attribute that was
+     * removed
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void attributeRemoved(ServletRequestAttributeEvent srae) {}
+
+    /**
+     * Receives notification that an attribute has been replaced on the
+     * ServletRequest.
+     *
+     * @param srae the ServletRequestAttributeEvent containing the 
+     * ServletRequest and the name and (old) value of the attribute
+     * that was replaced
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void attributeReplaced(ServletRequestAttributeEvent srae) {}
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestEvent.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestEvent.java
new file mode 100644
index 0000000..c4db8fa
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestEvent.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+/** 
+ * Events of this kind indicate lifecycle events for a ServletRequest.
+ * The source of the event is the ServletContext of this web application.
+ *
+ * @see ServletRequestListener
+ * @since Servlet 2.4
+ */
+public class ServletRequestEvent extends java.util.EventObject { 
+
+    private static final long serialVersionUID = -7467864054698729101L;
+
+    private final transient ServletRequest request;
+
+    /** Construct a ServletRequestEvent for the given ServletContext
+      * and ServletRequest.
+      *
+      * @param sc       the ServletContext of the web application.
+      * @param request  the ServletRequest that is sending the event.
+      */
+    public ServletRequestEvent(ServletContext sc, ServletRequest request) {
+        super(sc);
+        this.request = request;
+    }
+
+    /**
+      * Returns the ServletRequest that is changing.
+
+      * @return the {@link ServletRequest} corresponding to this event.
+      */
+    public ServletRequest getServletRequest () { 
+        return this.request;
+    }
+
+    /**
+      * Returns the ServletContext of this web application.
+      *
+      * @return the {@link ServletContext} for this web application.
+      */
+    public ServletContext getServletContext () { 
+        return (ServletContext) super.getSource();
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestListener.java
new file mode 100644
index 0000000..d65edf9
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestListener.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.util.EventListener;
+
+/**
+ * Interface for receiving notification events about requests coming
+ * into and going out of scope of a web application.
+ *
+ * <p>A ServletRequest is defined as coming into scope of a web
+ * application when it is about to enter the first servlet or filter
+ * of the web application, and as going out of scope as it exits
+ * the last servlet or the first filter in the chain.
+ *
+ * <p>In order to receive these notification events, the implementation
+ * class must be either declared in the deployment descriptor of the web
+ * application, annotated with {@link javax.servlet.annotation.WebListener}, 
+ * or registered via one of the addListener methods defined on
+ * {@link ServletContext}.
+ *
+ * <p>Implementations of this interface are invoked at their
+ * {@link #requestInitialized} method in the order in which they have been
+ * declared, and at their {@link #requestDestroyed} method in reverse
+ * order.
+ *
+ * @since Servlet 2.4
+ */
+
+public interface ServletRequestListener extends EventListener {
+
+    /**
+     * Receives notification that a ServletRequest is about to go out
+     * of scope of the web application.
+     *
+     * @param sre the ServletRequestEvent containing the ServletRequest
+     * and the ServletContext representing the web application
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void requestDestroyed(ServletRequestEvent sre) {}
+
+    /**
+     * Receives notification that a ServletRequest is about to come
+     * into scope of the web application.
+     *
+     * @param sre the ServletRequestEvent containing the ServletRequest
+     * and the ServletContext representing the web application
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     */
+    default public void requestInitialized(ServletRequestEvent sre) {}
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestWrapper.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestWrapper.java
new file mode 100644
index 0000000..bf8c95b
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletRequestWrapper.java
@@ -0,0 +1,558 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * Provides a convenient implementation of the ServletRequest interface that
+ * can be subclassed by developers wishing to adapt the request to a Servlet.
+ * This class implements the Wrapper or Decorator pattern. Methods default to
+ * calling through to the wrapped request object.
+ *
+ * @see javax.servlet.ServletRequest
+ *
+ * @since Servlet 2.3
+ */
+
+public class ServletRequestWrapper implements ServletRequest {
+
+    private ServletRequest request;
+
+    /**
+     * Creates a ServletRequest adaptor wrapping the given request object. 
+     * @throws java.lang.IllegalArgumentException if the request is null
+     *
+     * @param request the {@link ServletRequest} to be wrapped
+     */
+    public ServletRequestWrapper(ServletRequest request) {
+        if (request == null) {
+            throw new IllegalArgumentException("Request cannot be null");   
+        }
+        this.request = request;
+    }
+
+
+    /**
+     * Return the wrapped request object.
+     *
+     * @return the wrapped {@link ServletRequest}
+     */
+    public ServletRequest getRequest() {
+        return this.request;
+    }
+
+
+    /**
+     * Sets the request object being wrapped. 
+     *
+     * @param request the {@link ServletRequest} to be installed
+     *
+     * @throws java.lang.IllegalArgumentException if the request is null.
+     * 
+     */
+    public void setRequest(ServletRequest request) {
+        if (request == null) {
+            throw new IllegalArgumentException("Request cannot be null");
+        }
+        this.request = request;
+    }
+
+
+    /**
+     * The default behavior of this method is to call getAttribute(String name)
+     * on the wrapped request object.
+     */
+    public Object getAttribute(String name) {
+        return this.request.getAttribute(name);
+    }
+
+
+    /**
+     * The default behavior of this method is to return getAttributeNames()
+     * on the wrapped request object.
+     */
+    public Enumeration<String> getAttributeNames() {
+        return this.request.getAttributeNames();
+    }    
+
+
+    /**
+     * The default behavior of this method is to return getCharacterEncoding()
+     * on the wrapped request object.
+     */
+    public String getCharacterEncoding() {
+        return this.request.getCharacterEncoding();
+    }
+
+
+    /**
+     * The default behavior of this method is to set the character encoding
+     * on the wrapped request object.
+     */
+    public void setCharacterEncoding(String enc)
+            throws UnsupportedEncodingException {
+        this.request.setCharacterEncoding(enc);
+    }
+
+
+    /**
+     * The default behavior of this method is to return getContentLength()
+     * on the wrapped request object.
+     */
+    public int getContentLength() {
+        return this.request.getContentLength();
+    }
+
+    /**
+     * The default behavior of this method is to return getContentLengthLong()
+     * on the wrapped request object.
+     *
+     * @since Servlet 3.1
+     */
+    public long getContentLengthLong() {
+        return this.request.getContentLengthLong();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getContentType()
+     * on the wrapped request object.
+     */
+    public String getContentType() {
+        return this.request.getContentType();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getInputStream()
+     * on the wrapped request object.
+     */
+    public ServletInputStream getInputStream() throws IOException {
+        return this.request.getInputStream();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getParameter(String name) on the wrapped request object.
+     */
+    public String getParameter(String name) {
+        return this.request.getParameter(name);
+    }
+
+
+    /**
+     * The default behavior of this method is to return getParameterMap()
+     * on the wrapped request object.
+     */
+    public Map<String, String[]> getParameterMap() {
+        return this.request.getParameterMap();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getParameterNames()
+     * on the wrapped request object.
+     */
+    public Enumeration<String> getParameterNames() {
+        return this.request.getParameterNames();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getParameterValues(String name) on the wrapped request object.
+     */
+    public String[] getParameterValues(String name) {
+        return this.request.getParameterValues(name);
+    }
+
+
+    /**
+     * The default behavior of this method is to return getProtocol()
+     * on the wrapped request object.
+     */
+    public String getProtocol() {
+        return this.request.getProtocol();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getScheme()
+     * on the wrapped request object.
+     */
+    public String getScheme() {
+        return this.request.getScheme();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getServerName()
+     * on the wrapped request object.
+     */
+    public String getServerName() {
+        return this.request.getServerName();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getServerPort()
+     * on the wrapped request object.
+     */
+    public int getServerPort() {
+        return this.request.getServerPort();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getReader()
+     * on the wrapped request object.
+     */
+    public BufferedReader getReader() throws IOException {
+        return this.request.getReader();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getRemoteAddr()
+     * on the wrapped request object.
+     */
+    public String getRemoteAddr() {
+        return this.request.getRemoteAddr();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getRemoteHost()
+     * on the wrapped request object.
+     */
+    public String getRemoteHost() {
+        return this.request.getRemoteHost();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * setAttribute(String name, Object o) on the wrapped request object.
+     */
+    public void setAttribute(String name, Object o) {
+        this.request.setAttribute(name, o);
+    }
+
+
+    /**
+     * The default behavior of this method is to call
+     * removeAttribute(String name) on the wrapped request object.
+     */
+    public void removeAttribute(String name) {
+        this.request.removeAttribute(name);
+    }
+
+
+    /**
+     * The default behavior of this method is to return getLocale()
+     * on the wrapped request object.
+     */
+    public Locale getLocale() {
+        return this.request.getLocale();
+    }
+
+
+    /**
+     * The default behavior of this method is to return getLocales()
+     * on the wrapped request object.
+     */
+    public Enumeration<Locale> getLocales() {
+        return this.request.getLocales();
+    }
+
+
+    /**
+     * The default behavior of this method is to return isSecure()
+     * on the wrapped request object.
+     */
+    public boolean isSecure() {
+        return this.request.isSecure();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getRequestDispatcher(String path) on the wrapped request object.
+     */
+    public RequestDispatcher getRequestDispatcher(String path) {
+        return this.request.getRequestDispatcher(path);
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getRealPath(String path) on the wrapped request object.
+     *
+     * @deprecated As of Version 2.1 of the Java Servlet API,
+     * use {@link ServletContext#getRealPath} instead
+     */
+    @Deprecated
+    public String getRealPath(String path) {
+        return this.request.getRealPath(path);
+    }
+
+    
+    /**
+     * The default behavior of this method is to return
+     * getRemotePort() on the wrapped request object.
+     *
+     * @since Servlet 2.4
+     */    
+    public int getRemotePort(){
+        return this.request.getRemotePort();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getLocalName() on the wrapped request object.
+     *
+     * @since Servlet 2.4
+     */
+    public String getLocalName(){
+        return this.request.getLocalName();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getLocalAddr() on the wrapped request object.
+     *
+     * @since Servlet 2.4
+     */       
+    public String getLocalAddr(){
+        return this.request.getLocalAddr();
+    }
+
+
+    /**
+     * The default behavior of this method is to return
+     * getLocalPort() on the wrapped request object.
+     *
+     * @since Servlet 2.4
+     */
+    public int getLocalPort(){
+        return this.request.getLocalPort();
+    }
+
+
+    /**
+     * Gets the servlet context to which the wrapped servlet request was last
+     * dispatched.
+     *
+     * @return the servlet context to which the wrapped servlet request was
+     * last dispatched
+     *
+     * @since Servlet 3.0
+     */
+    public ServletContext getServletContext() {
+        return request.getServletContext();
+    }
+
+
+    /**
+     * The default behavior of this method is to invoke
+     * {@link ServletRequest#startAsync} on the wrapped request object.
+     *
+     * @return the (re)initialized AsyncContext
+     * 
+     * @throws IllegalStateException if the request is within the scope of
+     * a filter or servlet that does not support asynchronous operations
+     * (that is, {@link #isAsyncSupported} returns false),
+     * or if this method is called again without any asynchronous dispatch
+     * (resulting from one of the {@link AsyncContext#dispatch} methods),
+     * is called outside the scope of any such dispatch, or is called again
+     * within the scope of the same dispatch, or if the response has
+     * already been closed
+     *
+     * @see ServletRequest#startAsync
+     *
+     * @since Servlet 3.0
+     */
+    public AsyncContext startAsync() throws IllegalStateException {
+        return request.startAsync();
+    }
+    
+
+    /**
+     * The default behavior of this method is to invoke
+     * {@link ServletRequest#startAsync(ServletRequest, ServletResponse)}
+     * on the wrapped request object.
+     *
+     * @param servletRequest the ServletRequest used to initialize the
+     * AsyncContext
+     * @param servletResponse the ServletResponse used to initialize the
+     * AsyncContext
+     *
+     * @return the (re)initialized AsyncContext
+     *
+     * @throws IllegalStateException if the request is within the scope of
+     * a filter or servlet that does not support asynchronous operations
+     * (that is, {@link #isAsyncSupported} returns false),
+     * or if this method is called again without any asynchronous dispatch
+     * (resulting from one of the {@link AsyncContext#dispatch} methods),
+     * is called outside the scope of any such dispatch, or is called again
+     * within the scope of the same dispatch, or if the response has
+     * already been closed
+     *
+     * @see ServletRequest#startAsync(ServletRequest, ServletResponse)
+     *
+     * @since Servlet 3.0
+     */
+    public AsyncContext startAsync(ServletRequest servletRequest,
+                                   ServletResponse servletResponse)
+            throws IllegalStateException {
+        return request.startAsync(servletRequest, servletResponse);
+    }
+
+
+    /**
+     * Checks if the wrapped request has been put into asynchronous mode.
+     *
+     * @return true if this request has been put into asynchronous mode,
+     * false otherwise
+     *
+     * @see ServletRequest#isAsyncStarted
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isAsyncStarted() {
+        return request.isAsyncStarted();
+    }
+
+
+    /**
+     * Checks if the wrapped request supports asynchronous operation.
+     *
+     * @return true if this request supports asynchronous operation, false
+     * otherwise
+     *
+     * @see ServletRequest#isAsyncSupported
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isAsyncSupported() {
+        return request.isAsyncSupported();
+    }
+
+
+    /**
+     * Gets the AsyncContext that was created or reinitialized by the
+     * most recent invocation of {@link #startAsync} or
+     * {@link #startAsync(ServletRequest,ServletResponse)} on the wrapped
+     * request.
+     *
+     * @return the AsyncContext that was created or reinitialized by the
+     * most recent invocation of {@link #startAsync} or
+     * {@link #startAsync(ServletRequest,ServletResponse)} on
+     * the wrapped request 
+     *
+     * @throws IllegalStateException if this request has not been put 
+     * into asynchronous mode, i.e., if neither {@link #startAsync} nor
+     * {@link #startAsync(ServletRequest,ServletResponse)} has been called
+     *
+     * @see ServletRequest#getAsyncContext
+     *
+     * @since Servlet 3.0
+     */
+    public AsyncContext getAsyncContext() {
+        return request.getAsyncContext();
+    }
+
+
+    /**
+     * Checks (recursively) if this ServletRequestWrapper wraps the given
+     * {@link ServletRequest} instance.
+     *
+     * @param wrapped the ServletRequest instance to search for
+     *
+     * @return true if this ServletRequestWrapper wraps the
+     * given ServletRequest instance, false otherwise
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isWrapperFor(ServletRequest wrapped) {
+        if (request == wrapped) {
+            return true;
+        } else if (request instanceof ServletRequestWrapper) {
+            return ((ServletRequestWrapper) request).isWrapperFor(wrapped);
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Checks (recursively) if this ServletRequestWrapper wraps a
+     * {@link ServletRequest} of the given class type.
+     *
+     * @param wrappedType the ServletRequest class type to
+     * search for
+     *
+     * @return true if this ServletRequestWrapper wraps a
+     * ServletRequest of the given class type, false otherwise
+     *
+     * @throws IllegalArgumentException if the given class does not
+     * implement {@link ServletRequest}
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isWrapperFor(Class<?> wrappedType) {
+        if (!ServletRequest.class.isAssignableFrom(wrappedType)) {
+            throw new IllegalArgumentException("Given class " +
+                wrappedType.getName() + " not a subinterface of " +
+                ServletRequest.class.getName());
+        }
+        if (wrappedType.isAssignableFrom(request.getClass())) {
+            return true;
+        } else if (request instanceof ServletRequestWrapper) {
+            return ((ServletRequestWrapper) request).isWrapperFor(wrappedType);
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Gets the dispatcher type of the wrapped request.
+     *
+     * @return the dispatcher type of the wrapped request
+     * 
+     * @see ServletRequest#getDispatcherType
+     *
+     * @since Servlet 3.0
+     */
+    public DispatcherType getDispatcherType() {
+        return request.getDispatcherType();
+    }
+
+
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletResponse.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletResponse.java
new file mode 100644
index 0000000..7b1c38d
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletResponse.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+
+/**
+ * Defines an object to assist a servlet in sending a response to the client.
+ * The servlet container creates a <code>ServletResponse</code> object and
+ * passes it as an argument to the servlet's <code>service</code> method.
+ *
+ * <p>To send binary data in a MIME body response, use
+ * the {@link ServletOutputStream} returned by {@link #getOutputStream}.
+ * To send character data, use the <code>PrintWriter</code> object 
+ * returned by {@link #getWriter}. To mix binary and text data,
+ * for example, to create a multipart response, use a
+ * <code>ServletOutputStream</code> and manage the character sections
+ * manually.
+ *
+ * <p>The charset for the MIME body response can be specified explicitly
+ * using any of the following techniques: per request, per web-app (using
+ * {@link ServletContext#setRequestCharacterEncoding}, deployment descriptor),
+ * and per container (for all web applications deployed in that container, 
+ * using vendor specific configuration).
+ * If multiple of the preceding techniques have been employed, the priority is
+ * the order listed.
+ * For per request, the charset for the response can be specified explicitly
+ * using the {@link #setCharacterEncoding} and {@link #setContentType} methods,
+ * or implicitly using the {@link #setLocale} method.
+ * Explicit specifications take precedence over implicit specifications.
+ * If no charset is explicitly specified, ISO-8859-1 will be used.
+ * The <code>setCharacterEncoding</code>,
+ * <code>setContentType</code>, or <code>setLocale</code> method must
+ * be called before <code>getWriter</code> and before committing
+ * the response for the character encoding to be used.
+ * 
+ * <p>See the Internet RFCs such as 
+ * <a href="http://www.ietf.org/rfc/rfc2045.txt">
+ * RFC 2045</a> for more information on MIME. Protocols such as SMTP
+ * and HTTP define profiles of MIME, and those standards
+ * are still evolving.
+ *
+ * @author Various
+ *
+ * @see ServletOutputStream
+ */
+ 
+public interface ServletResponse {
+    
+    /**
+     * Returns the name of the character encoding (MIME charset)
+     * used for the body sent in this response.
+     * The following methods for specifying the response character encoding are
+     * consulted, in decreasing order of priority: per request, perweb-app
+     * (using {@link ServletContext#setResponseCharacterEncoding}, deployment
+     * descriptor), and per container (for all web applications deployed in
+     * that container, using vendor specific configuration).
+     * The first one of these methods that yields a result is returned.
+     * Per-request, the charset for the response can be specified explicitly
+     * using the {@link setCharacterEncoding} and {@link setContentType}
+     * methods, or implicitly using the setLocale(java.util.Locale) method.
+     * Explicit specifications take precedence over implicit specifications.
+     * Calls made to these methods after <code>getWriter</code> has been
+     * called or after the response has been committed have no
+     * effect on the character encoding. If no character encoding
+     * has been specified, <code>ISO-8859-1</code> is returned.
+     * <p>See RFC 2047 (http://www.ietf.org/rfc/rfc2047.txt)
+     * for more information about character encoding and MIME.
+     *
+     * @return a <code>String</code> specifying the name of
+     * the character encoding, for example, <code>UTF-8</code>
+     */
+    public String getCharacterEncoding();
+    
+    /**
+     * Returns the content type used for the MIME body
+     * sent in this response. The content type proper must
+     * have been specified using {@link #setContentType}
+     * before the response is committed. If no content type
+     * has been specified, this method returns null.
+     * If a content type has been specified, and a
+     * character encoding has been explicitly or implicitly
+     * specified as described in {@link #getCharacterEncoding}
+     * or {@link #getWriter} has been called,
+     * the charset parameter is included in the string returned.
+     * If no character encoding has been specified, the
+     * charset parameter is omitted.
+     *
+     * @return a <code>String</code> specifying the content type,
+     * for example, <code>text/html; charset=UTF-8</code>, or null
+     *
+     * @since Servlet 2.4
+     */
+    public String getContentType();
+    
+    
+
+    /**
+     * Returns a {@link ServletOutputStream} suitable for writing binary 
+     * data in the response. The servlet container does not encode the
+     * binary data.  
+     *
+     * <p> Calling flush() on the ServletOutputStream commits the response.
+     *
+     * Either this method or {@link #getWriter} may 
+     * be called to write the body, not both, except when {@link #reset}
+     * has been called.
+     *
+     * @return a {@link ServletOutputStream} for writing binary data 
+     *
+     * @exception IllegalStateException if the <code>getWriter</code> method
+     * has been called on this response
+     *
+     * @exception IOException if an input or output exception occurred
+     *
+     * @see #getWriter
+     * @see #reset
+     */
+    public ServletOutputStream getOutputStream() throws IOException;
+    
+    /**
+     * Returns a <code>PrintWriter</code> object that
+     * can send character text to the client.
+     * The <code>PrintWriter</code> uses the character
+     * encoding returned by {@link #getCharacterEncoding}.
+     * If the response's character encoding has not been
+     * specified as described in <code>getCharacterEncoding</code>
+     * (i.e., the method just returns the default value 
+     * <code>ISO-8859-1</code>), <code>getWriter</code>
+     * updates it to <code>ISO-8859-1</code>.
+     * <p>Calling flush() on the <code>PrintWriter</code>
+     * commits the response.
+     * <p>Either this method or {@link #getOutputStream} may be called
+     * to write the body, not both, except when {@link #reset}
+     * has been called.
+     * 
+     * @return a <code>PrintWriter</code> object that 
+     * can return character data to the client 
+     *
+     * @exception java.io.UnsupportedEncodingException
+     * if the character encoding returned
+     * by <code>getCharacterEncoding</code> cannot be used
+     *
+     * @exception IllegalStateException
+     * if the <code>getOutputStream</code>
+     * method has already been called for this response object
+     *
+     * @exception IOException
+     * if an input or output exception occurred
+     *
+     * @see #getOutputStream
+     * @see #setCharacterEncoding
+     * @see #reset
+     */
+    public PrintWriter getWriter() throws IOException;
+    
+    /**
+     * Sets the character encoding (MIME charset) of the response
+     * being sent to the client, for example, to UTF-8.
+     * If the response character encoding has already been set by the
+     * {@link ServletContext#setResponseCharacterEncoding},
+     * deployment descriptor, or using the setContentType() or setLocale()
+     * methods, the value set in this method overrides any of those values.
+     * Calling {@link #setContentType} with the <code>String</code>
+     * of <code>text/html</code> and calling
+     * this method with the <code>String</code> of <code>UTF-8</code>
+     * is equivalent with calling
+     * <code>setContentType</code> with the <code>String</code> of
+     * <code>text/html; charset=UTF-8</code>.
+     * <p>This method can be called repeatedly to change the character
+     * encoding.
+     * This method has no effect if it is called after
+     * <code>getWriter</code> has been
+     * called or after the response has been committed.
+     * <p>Containers must communicate the character encoding used for
+     * the servlet response's writer to the client if the protocol
+     * provides a way for doing so. In the case of HTTP, the character
+     * encoding is communicated as part of the <code>Content-Type</code>
+     * header for text media types. Note that the character encoding
+     * cannot be communicated via HTTP headers if the servlet does not
+     * specify a content type; however, it is still used to encode text
+     * written via the servlet response's writer.
+     *
+     * @param charset a String specifying only the character set
+     * defined by IANA Character Sets
+     * (http://www.iana.org/assignments/character-sets)
+     *
+     * @see #setContentType
+     * @see #setLocale
+     *
+     * @since Servlet 2.4
+     */
+    public void setCharacterEncoding(String charset);
+    
+    /**
+     * Sets the length of the content body in the response
+     * In HTTP servlets, this method sets the HTTP Content-Length header.
+     *
+     * @param len an integer specifying the length of the 
+     * content being returned to the client; sets the Content-Length header
+     */
+    public void setContentLength(int len);
+    
+    /**
+     * Sets the length of the content body in the response
+     * In HTTP servlets, this method sets the HTTP Content-Length header.
+     *
+     * @param len a long specifying the length of the 
+     * content being returned to the client; sets the Content-Length header
+     *
+     * @since Servlet 3.1
+     */
+    public void setContentLengthLong(long len);
+
+    /**
+     * Sets the content type of the response being sent to
+     * the client, if the response has not been committed yet.
+     * The given content type may include a character encoding
+     * specification, for example, <code>text/html;charset=UTF-8</code>.
+     * The response's character encoding is only set from the given
+     * content type if this method is called before <code>getWriter</code>
+     * is called.
+     * <p>This method may be called repeatedly to change content type and
+     * character encoding.
+     * This method has no effect if called after the response
+     * has been committed. It does not set the response's character
+     * encoding if it is called after <code>getWriter</code>
+     * has been called or after the response has been committed.
+     * <p>Containers must communicate the content type and the character
+     * encoding used for the servlet response's writer to the client if
+     * the protocol provides a way for doing so. In the case of HTTP,
+     * the <code>Content-Type</code> header is used.
+     *
+     * @param type a <code>String</code> specifying the MIME 
+     * type of the content
+     *
+     * @see #setLocale
+     * @see #setCharacterEncoding
+     * @see #getOutputStream
+     * @see #getWriter
+     *
+     */
+
+    public void setContentType(String type);
+    
+
+    /**
+     * Sets the preferred buffer size for the body of the response.  
+     * The servlet container will use a buffer at least as large as 
+     * the size requested.  The actual buffer size used can be found
+     * using <code>getBufferSize</code>.
+     *
+     * <p>A larger buffer allows more content to be written before anything is
+     * actually sent, thus providing the servlet with more time to set
+     * appropriate status codes and headers.  A smaller buffer decreases 
+     * server memory load and allows the client to start receiving data more
+     * quickly.
+     *
+     * <p>This method must be called before any response body content is
+     * written; if content has been written or the response object has
+     * been committed, this method throws an 
+     * <code>IllegalStateException</code>.
+     *
+     * @param size the preferred buffer size
+     *
+     * @exception IllegalStateException if this method is called after
+     * content has been written
+     *
+     * @see 		#getBufferSize
+     * @see 		#flushBuffer
+     * @see 		#isCommitted
+     * @see 		#reset
+     */
+    public void setBufferSize(int size);
+   
+    /**
+     * Returns the actual buffer size used for the response.  If no buffering
+     * is used, this method returns 0.
+     *
+     * @return the actual buffer size used
+     *
+     * @see #setBufferSize
+     * @see #flushBuffer
+     * @see #isCommitted
+     * @see #reset
+     */
+    public int getBufferSize();
+    
+    /**
+     * Forces any content in the buffer to be written to the client.  A call
+     * to this method automatically commits the response, meaning the status 
+     * code and headers will be written.
+     *
+     * @see #setBufferSize
+     * @see #getBufferSize
+     * @see #isCommitted
+     * @see #reset
+
+     * @throws IOException if the act of flushing the buffer cannot be
+     * completed.
+     *
+     */
+    public void flushBuffer() throws IOException;
+    
+    /**
+     * Clears the content of the underlying buffer in the response without
+     * clearing headers or status code. If the 
+     * response has been committed, this method throws an 
+     * <code>IllegalStateException</code>.
+     *
+     * @see #setBufferSize
+     * @see #getBufferSize
+     * @see #isCommitted
+     * @see #reset
+     *
+     * @since Servlet 2.3
+     */
+
+    public void resetBuffer();
+    
+    /**
+     * Returns a boolean indicating if the response has been
+     * committed.  A committed response has already had its status 
+     * code and headers written.
+     *
+     * @return  a boolean indicating if the response has been
+     * committed
+     *
+     * @see #setBufferSize
+     * @see #getBufferSize
+     * @see #flushBuffer
+     * @see #reset
+     *
+     */
+    public boolean isCommitted();
+    
+    /**
+     * Clears any data that exists in the buffer as well as the status code,
+     * headers.  The state of calling {@link #getWriter} or
+     * {@link #getOutputStream} is also cleared.  It is legal, for instance,
+     * to call {@link #getWriter}, {@link #reset} and then
+     * {@link #getOutputStream}.  If {@link #getWriter} or
+     * {@link #getOutputStream} have been called before this method,
+     * then the corrresponding returned Writer or OutputStream will be
+     * staled and the behavior of using the stale object is undefined.
+     * If the response has been committed, this method throws an 
+     * <code>IllegalStateException</code>.
+     *
+     * @exception IllegalStateException  if the response has already been
+     * committed
+     *
+     * @see #setBufferSize
+     * @see #getBufferSize
+     * @see #flushBuffer
+     * @see #isCommitted
+     */
+    public void reset();
+    
+    /**
+     * Sets the locale of the response, if the response has not been
+     * committed yet. It also sets the response's character encoding
+     * appropriately for the locale, if the character encoding has not
+     * been explicitly set using {@link #setContentType} or
+     * {@link #setCharacterEncoding}, <code>getWriter</code> hasn't
+     * been called yet, and the response hasn't been committed yet.
+     * If the deployment descriptor contains a 
+     * <code>locale-encoding-mapping-list</code> element, and that
+     * element provides a mapping for the given locale, that mapping
+     * is used. Otherwise, the mapping from locale to character
+     * encoding is container dependent.
+     * <p>This method may be called repeatedly to change locale and
+     * character encoding. The method has no effect if called after the
+     * response has been committed. It does not set the response's
+     * character encoding if it is called after {@link #setContentType}
+     * has been called with a charset specification, after
+     * {@link #setCharacterEncoding} has been called, after
+     * <code>getWriter</code> has been called, or after the response
+     * has been committed.
+     * <p>Containers must communicate the locale and the character encoding
+     * used for the servlet response's writer to the client if the protocol
+     * provides a way for doing so. In the case of HTTP, the locale is
+     * communicated via the <code>Content-Language</code> header,
+     * the character encoding as part of the <code>Content-Type</code>
+     * header for text media types. Note that the character encoding
+     * cannot be communicated via HTTP headers if the servlet does not
+     * specify a content type; however, it is still used to encode text
+     * written via the servlet response's writer.
+     * 
+     * @param loc the locale of the response
+     *
+     * @see #getLocale
+     * @see #setContentType
+     * @see #setCharacterEncoding
+     */
+    public void setLocale(Locale loc);
+    
+    /**
+     * Returns the locale specified for this response
+     * using the {@link #setLocale} method. Calls made to
+     * <code>setLocale</code> after the response is committed
+     * have no effect. If no locale has been specified,
+     * the container's default locale is returned.
+     *
+     * @return the Locale for this response.
+     * 
+     * @see #setLocale
+     */
+    public Locale getLocale();
+
+}
+
+
+
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletResponseWrapper.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletResponseWrapper.java
new file mode 100644
index 0000000..b861f84
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletResponseWrapper.java
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+/**
+ * 
+ * Provides a convenient implementation of the ServletResponse interface that
+ * can be subclassed by developers wishing to adapt the response from a Servlet.
+ * This class implements the Wrapper or Decorator pattern. Methods default to
+ * calling through to the wrapped response object.
+ * 
+ * @author Various
+ * @since Servlet 2.3
+ *
+ * @see javax.servlet.ServletResponse
+ */
+
+ 
+public class ServletResponseWrapper implements ServletResponse {
+	private ServletResponse response;
+	/**
+	* Creates a ServletResponse adaptor wrapping the given response object.
+	* @throws java.lang.IllegalArgumentException if the response is null.
+        * @param response the {@link ServletResponse} to be wrapped
+        *
+	*/
+
+
+	public ServletResponseWrapper(ServletResponse response) {
+	    if (response == null) {
+		throw new IllegalArgumentException("Response cannot be null");
+	    }
+	    this.response = response;
+	}
+
+	/**
+	* Return the wrapped ServletResponse object.
+        *
+        * @return the wrapped {@link ServletResponse}
+	*/
+
+	public ServletResponse getResponse() {
+		return this.response;
+	}	
+	
+	
+	/**
+	* Sets the response being wrapped. 
+	* @throws java.lang.IllegalArgumentException if the response is null.
+        *
+        * @param response the {@link ServletResponse} to be installed 
+	*/
+	
+	public void setResponse(ServletResponse response) {
+	    if (response == null) {
+		throw new IllegalArgumentException("Response cannot be null");
+	    }
+	    this.response = response;
+	}
+
+    /**
+     * The default behavior of this method is to call setCharacterEncoding(String charset)
+     * on the wrapped response object.
+     *
+     * @since Servlet 2.4
+     */
+
+    public void setCharacterEncoding(String charset) {
+	this.response.setCharacterEncoding(charset);
+    }
+
+    /**
+     * The default behavior of this method is to return getCharacterEncoding()
+     * on the wrapped response object.
+     */
+
+    public String getCharacterEncoding() {
+	return this.response.getCharacterEncoding();
+	}
+    
+    
+	  /**
+     * The default behavior of this method is to return getOutputStream()
+     * on the wrapped response object.
+     */
+
+    public ServletOutputStream getOutputStream() throws IOException {
+	return this.response.getOutputStream();
+    }  
+      
+     /**
+     * The default behavior of this method is to return getWriter()
+     * on the wrapped response object.
+     */
+
+
+    public PrintWriter getWriter() throws IOException {
+	return this.response.getWriter();
+	}
+    
+    /**
+     * The default behavior of this method is to call setContentLength(int len)
+     * on the wrapped response object.
+     */
+
+    public void setContentLength(int len) {
+	this.response.setContentLength(len);
+    }
+
+    /**
+     * The default behavior of this method is to call setContentLengthLong(long len)
+     * on the wrapped response object.
+     */
+
+    public void setContentLengthLong(long len) {
+        this.response.setContentLengthLong(len);
+    }
+
+    /**
+     * The default behavior of this method is to call setContentType(String type)
+     * on the wrapped response object.
+     */
+
+    public void setContentType(String type) {
+	this.response.setContentType(type);
+    }
+
+    /**
+     * The default behavior of this method is to return getContentType()
+     * on the wrapped response object.
+     *
+     * @since Servlet 2.4
+     */
+
+    public String getContentType() {
+	return this.response.getContentType();
+    }
+    
+    /**
+     * The default behavior of this method is to call setBufferSize(int size)
+     * on the wrapped response object.
+     */
+    public void setBufferSize(int size) {
+	this.response.setBufferSize(size);
+    }
+    
+    /**
+     * The default behavior of this method is to return getBufferSize()
+     * on the wrapped response object.
+     */
+    public int getBufferSize() {
+	return this.response.getBufferSize();
+    }
+
+    /**
+     * The default behavior of this method is to call flushBuffer()
+     * on the wrapped response object.
+     */
+
+    public void flushBuffer() throws IOException {
+	this.response.flushBuffer();
+    }
+    
+    /**
+     * The default behavior of this method is to return isCommitted()
+     * on the wrapped response object.
+     */
+    public boolean isCommitted() {
+	return this.response.isCommitted();
+    }
+
+    /**
+     * The default behavior of this method is to call reset()
+     * on the wrapped response object.
+     */
+
+    public void reset() {
+	this.response.reset();
+    }
+    
+    /**
+     * The default behavior of this method is to call resetBuffer()
+     * on the wrapped response object.
+     */
+     
+    public void resetBuffer() {
+	this.response.resetBuffer();
+    }
+    
+    /**
+     * The default behavior of this method is to call setLocale(Locale loc)
+     * on the wrapped response object.
+     */
+
+    public void setLocale(Locale loc) {
+	this.response.setLocale(loc);
+    }
+    
+    /**
+     * The default behavior of this method is to return getLocale()
+     * on the wrapped response object.
+     */
+    public Locale getLocale() {
+	return this.response.getLocale();
+    }
+
+
+    /**
+     * Checks (recursively) if this ServletResponseWrapper wraps the given
+     * {@link ServletResponse} instance.
+     *
+     * @param wrapped the ServletResponse instance to search for
+     *
+     * @return true if this ServletResponseWrapper wraps the
+     * given ServletResponse instance, false otherwise
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isWrapperFor(ServletResponse wrapped) {
+        if (response == wrapped) {
+            return true;
+        } else if (response instanceof ServletResponseWrapper) {
+            return ((ServletResponseWrapper) response).isWrapperFor(wrapped);
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Checks (recursively) if this ServletResponseWrapper wraps a
+     * {@link ServletResponse} of the given class type.
+     *
+     * @param wrappedType the ServletResponse class type to
+     * search for
+     *
+     * @return true if this ServletResponseWrapper wraps a
+     * ServletResponse of the given class type, false otherwise
+     *
+     * @throws IllegalArgumentException if the given class does not
+     * implement {@link ServletResponse}
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isWrapperFor(Class<?> wrappedType) {
+        if (!ServletResponse.class.isAssignableFrom(wrappedType)) {
+            throw new IllegalArgumentException("Given class " +
+                wrappedType.getName() + " not a subinterface of " +
+                ServletResponse.class.getName());
+        }
+        if (wrappedType.isAssignableFrom(response.getClass())) {
+            return true;
+        } else if (response instanceof ServletResponseWrapper) {
+            return ((ServletResponseWrapper) response).isWrapperFor(wrappedType);
+        } else {
+            return false;
+        }
+    }
+
+}
+
+
+
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/ServletSecurityElement.java b/third_party/servlet-spec/src/main/java/javax/servlet/ServletSecurityElement.java
new file mode 100644
index 0000000..13950ef
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/ServletSecurityElement.java
@@ -0,0 +1,202 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.util.*;
+import javax.servlet.annotation.HttpMethodConstraint;
+import javax.servlet.annotation.ServletSecurity;
+
+/**
+ * Java Class representation of a {@link ServletSecurity} annotation value.
+ *
+ * @since Servlet 3.0
+ */
+public class ServletSecurityElement extends HttpConstraintElement {
+
+    private Collection<String> methodNames;
+    private Collection<HttpMethodConstraintElement> methodConstraints;
+
+    /**
+     * Constructs an instance using the default
+     * <code>HttpConstraintElement</code> value as the default Constraint
+     * element and with no HTTP Method specific constraint elements.
+     */
+    public ServletSecurityElement() {
+        methodConstraints = new HashSet<HttpMethodConstraintElement>();
+        methodNames = Collections.emptySet();
+    }
+
+    /**
+     * Constructs an instance with a default Constraint element
+     * and with no HTTP Method specific constraint elements.
+     *
+     * @param constraint the HttpConstraintElement to be
+     * applied to all HTTP methods other than those represented in the
+     * <tt>methodConstraints</tt>
+     */
+    public ServletSecurityElement(HttpConstraintElement constraint) {
+        super(constraint.getEmptyRoleSemantic(),
+                constraint.getTransportGuarantee(),
+                constraint.getRolesAllowed());
+        methodConstraints = new HashSet<HttpMethodConstraintElement>();
+        methodNames = Collections.emptySet();
+    }
+
+    /**
+     * Constructs an instance using the default
+     * <code>HttpConstraintElement</code> value as the default Constraint
+     * element and with a collection of HTTP Method specific constraint
+     * elements.
+     *
+     * @param methodConstraints the collection of HTTP method specific
+     * constraint elements
+     *
+     * @throws IllegalArgumentException if duplicate method names are
+     * detected
+     */
+    public ServletSecurityElement(
+            Collection<HttpMethodConstraintElement> methodConstraints) {
+        this.methodConstraints = (methodConstraints == null ?
+            new HashSet<HttpMethodConstraintElement>() : methodConstraints);
+        methodNames = checkMethodNames(this.methodConstraints);
+    }
+
+    /**
+     * Constructs an instance with a default Constraint element
+     * and with a collection of HTTP Method specific constraint elements.
+     *
+     * @param constraint the HttpConstraintElement to be
+     * applied to all HTTP methods other than those represented in the
+     * <tt>methodConstraints</tt>
+     * @param methodConstraints the collection of HTTP method specific
+     * constraint elements.
+     *
+     * @throws IllegalArgumentException if duplicate method names are
+     * detected
+     */
+    public ServletSecurityElement(HttpConstraintElement constraint,
+            Collection<HttpMethodConstraintElement> methodConstraints) {
+        super(constraint.getEmptyRoleSemantic(),
+                constraint.getTransportGuarantee(),
+                constraint.getRolesAllowed());
+        this.methodConstraints = (methodConstraints == null ?
+            new HashSet<HttpMethodConstraintElement>() : methodConstraints);
+        methodNames = checkMethodNames(this.methodConstraints);
+    }
+
+    /**
+     * Constructs an instance from a {@link ServletSecurity} annotation value.
+     *
+     * @param annotation the annotation value
+     *
+     * @throws IllegalArgumentException if duplicate method names are
+     * detected
+     */
+    public ServletSecurityElement(ServletSecurity annotation) {
+        super(annotation.value().value(),
+                annotation.value().transportGuarantee(),
+                annotation.value().rolesAllowed());
+        this.methodConstraints = new HashSet<HttpMethodConstraintElement>();
+        for (HttpMethodConstraint constraint :
+                annotation.httpMethodConstraints()) {
+            this.methodConstraints.add(
+                new HttpMethodConstraintElement(
+                    constraint.value(),
+                    new HttpConstraintElement(constraint.emptyRoleSemantic(),
+                        constraint.transportGuarantee(),
+                        constraint.rolesAllowed())));
+        }
+        methodNames = checkMethodNames(this.methodConstraints);
+    }
+
+    /**
+     * Gets the (possibly empty) collection of HTTP Method specific
+     * constraint elements.
+     *
+     * <p>If permitted, any changes to the returned <code>Collection</code> must not
+     * affect this <code>ServletSecurityElement</code>.
+     *
+     *
+     * @return the (possibly empty) collection of HttpMethodConstraintElement
+     * objects
+     */
+    public Collection<HttpMethodConstraintElement> getHttpMethodConstraints() {
+        return Collections.unmodifiableCollection(methodConstraints);
+    }
+
+    /**
+     * Gets the set of HTTP method names named by the HttpMethodConstraints.
+     *
+     *  <p>If permitted, any changes to the returned <code>Collection</code> must not
+     * affect this <code>ServletSecurityElement</code>.
+     *
+
+     *
+     * @return the collection String method names
+     */
+    public Collection<String> getMethodNames() {
+        return Collections.unmodifiableCollection(methodNames);
+    }
+
+    /**
+     * Checks for duplicate method names in methodConstraints.
+     *
+     * @param methodConstraints
+     *
+     * @retrun Set of method names
+     *
+     * @throws IllegalArgumentException if duplicate method names are
+     * detected
+     */
+    private Collection<String> checkMethodNames(
+            Collection<HttpMethodConstraintElement> methodConstraints) {
+        Collection<String> methodNames = new HashSet<String>();
+        for (HttpMethodConstraintElement methodConstraint :
+                        methodConstraints) {
+            String methodName = methodConstraint.getMethodName();
+            if (!methodNames.add(methodName)) {
+                throw new IllegalArgumentException(
+                    "Duplicate HTTP method name: " + methodName);
+            }
+        }
+        return methodNames;
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/SessionCookieConfig.java b/third_party/servlet-spec/src/main/java/javax/servlet/SessionCookieConfig.java
new file mode 100644
index 0000000..2dd82f3
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/SessionCookieConfig.java
@@ -0,0 +1,322 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+/**
+ * Class that may be used to configure various properties of cookies 
+ * used for session tracking purposes.
+ *
+ * <p>An instance of this class is acquired by a call to
+ * {@link ServletContext#getSessionCookieConfig}.
+ *
+ * @since Servlet 3.0
+ */
+public interface SessionCookieConfig {
+
+    /**
+     * Sets the name that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * <p>NOTE: Changing the name of session tracking cookies may break
+     * other tiers (for example, a load balancing frontend) that assume
+     * the cookie name to be equal to the default <tt>JSESSIONID</tt>,
+     * and therefore should only be done cautiously.
+     *
+     * @param name the cookie name to use
+     *
+     * @throws IllegalStateException if the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired has
+     * already been initialized
+     */
+    public void setName(String name);
+
+
+    /**
+     * Gets the name that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * <p>By default, <tt>JSESSIONID</tt> will be used as the cookie name.
+     *
+     * @return the cookie name set via {@link #setName}, or
+     * <tt>null</tt> if {@link #setName} was never called
+     *
+     * @see javax.servlet.http.Cookie#getName()
+     */
+    public String getName();
+
+
+    /**
+     * Sets the domain name that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * @param domain the cookie domain to use
+     *
+     * @throws IllegalStateException if the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired has
+     * already been initialized
+     *
+     * @see javax.servlet.http.Cookie#setDomain(String)
+     */
+    public void setDomain(String domain);
+
+
+    /**
+     * Gets the domain name that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * @return the cookie domain set via {@link #setDomain}, or
+     * <tt>null</tt> if {@link #setDomain} was never called
+     *
+     * @see javax.servlet.http.Cookie#getDomain()
+     */
+    public String getDomain();
+
+
+    /**
+     * Sets the path that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * @param path the cookie path to use
+     *
+     * @throws IllegalStateException if the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired has
+     * already been initialized
+     *
+     * @see javax.servlet.http.Cookie#setPath(String)
+     */
+    public void setPath(String path);
+
+
+    /**
+     * Gets the path that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * <p>By default, the context path of the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired will
+     * be used.
+     *
+     * @return the cookie path set via {@link #setPath}, or <tt>null</tt>
+     * if {@link #setPath} was never called
+     *
+     * @see javax.servlet.http.Cookie#getPath()
+     */
+    public String getPath();
+
+
+    /**
+     * Sets the comment that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * <p>As a side effect of this call, the session tracking cookies
+     * will be marked with a <code>Version</code> attribute equal to
+     * <code>1</code>.
+     * 
+     * @param comment the cookie comment to use
+     *
+     * @throws IllegalStateException if the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired has
+     * already been initialized
+     *
+     * @see javax.servlet.http.Cookie#setComment(String)
+     * @see javax.servlet.http.Cookie#getVersion
+     */
+    public void setComment(String comment);
+
+
+    /**
+     * Gets the comment that will be assigned to any session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * @return the cookie comment set via {@link #setComment}, or
+     * <tt>null</tt> if {@link #setComment} was never called
+     *
+     * @see javax.servlet.http.Cookie#getComment()
+     */
+    public String getComment();
+
+
+    /**
+     * Marks or unmarks the session tracking cookies created on behalf
+     * of the application represented by the <tt>ServletContext</tt> from
+     * which this <tt>SessionCookieConfig</tt> was acquired as
+     * <i>HttpOnly</i>.
+     *
+     * <p>A cookie is marked as <tt>HttpOnly</tt> by adding the
+     * <tt>HttpOnly</tt> attribute to it. <i>HttpOnly</i> cookies are
+     * not supposed to be exposed to client-side scripting code, and may
+     * therefore help mitigate certain kinds of cross-site scripting
+     * attacks.
+     *
+     * @param httpOnly true if the session tracking cookies created
+     * on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired shall be marked as <i>HttpOnly</i>, false otherwise
+     *
+     * @throws IllegalStateException if the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired has
+     * already been initialized
+     *
+     * @see javax.servlet.http.Cookie#setHttpOnly(boolean)
+     */
+    public void setHttpOnly(boolean httpOnly);
+
+
+    /**
+     * Checks if the session tracking cookies created on behalf of the
+     * application represented by the <tt>ServletContext</tt> from which
+     * this <tt>SessionCookieConfig</tt> was acquired will be marked as
+     * <i>HttpOnly</i>.
+     *
+     * @return true if the session tracking cookies created on behalf of
+     * the application represented by the <tt>ServletContext</tt> from
+     * which this <tt>SessionCookieConfig</tt> was acquired will be marked
+     * as <i>HttpOnly</i>, false otherwise
+     *
+     * @see javax.servlet.http.Cookie#isHttpOnly()
+     */
+    public boolean isHttpOnly();
+
+
+    /**
+     * Marks or unmarks the session tracking cookies created on behalf of
+     * the application represented by the <tt>ServletContext</tt> from which
+     * this <tt>SessionCookieConfig</tt> was acquired as <i>secure</i>.
+     *
+     * <p>One use case for marking a session tracking cookie as
+     * <tt>secure</tt>, even though the request that initiated the session
+     * came over HTTP, is to support a topology where the web container is
+     * front-ended by an SSL offloading load balancer.
+     * In this case, the traffic between the client and the load balancer
+     * will be over HTTPS, whereas the traffic between the load balancer
+     * and the web container will be over HTTP.  
+     *
+     * @param secure true if the session tracking cookies created on
+     * behalf of the application represented by the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired shall be
+     * marked as <i>secure</i> even if the request that initiated the
+     * corresponding session is using plain HTTP instead of HTTPS, and false
+     * if they shall be marked as <i>secure</i> only if the request that
+     * initiated the corresponding session was also secure
+     *
+     * @throws IllegalStateException if the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired has
+     * already been initialized
+     *
+     * @see javax.servlet.http.Cookie#setSecure(boolean)
+     * @see ServletRequest#isSecure()
+     */
+    public void setSecure(boolean secure);
+
+
+    /**
+     * Checks if the session tracking cookies created on behalf of the
+     * application represented by the <tt>ServletContext</tt> from which
+     * this <tt>SessionCookieConfig</tt> was acquired will be marked as
+     * <i>secure</i> even if the request that initiated the corresponding
+     * session is using plain HTTP instead of HTTPS.
+     *
+     * @return true if the session tracking cookies created on behalf of the
+     * application represented by the <tt>ServletContext</tt> from which
+     * this <tt>SessionCookieConfig</tt> was acquired will be marked as
+     * <i>secure</i> even if the request that initiated the corresponding
+     * session is using plain HTTP instead of HTTPS, and false if they will
+     * be marked as <i>secure</i> only if the request that initiated the
+     * corresponding session was also secure
+     *
+     * @see javax.servlet.http.Cookie#getSecure()
+     * @see ServletRequest#isSecure()
+     */
+    public boolean isSecure();
+
+
+    /**
+     * Sets the lifetime (in seconds) for the session tracking cookies
+     * created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * @param maxAge the lifetime (in seconds) of the session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * @throws IllegalStateException if the <tt>ServletContext</tt>
+     * from which this <tt>SessionCookieConfig</tt> was acquired has
+     * already been initialized
+     *
+     * @see javax.servlet.http.Cookie#setMaxAge
+     */
+    public void setMaxAge(int maxAge);
+
+
+    /**
+     * Gets the lifetime (in seconds) of the session tracking cookies
+     * created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired.
+     *
+     * <p>By default, <tt>-1</tt> is returned.
+     *
+     * @return the lifetime (in seconds) of the session tracking
+     * cookies created on behalf of the application represented by the
+     * <tt>ServletContext</tt> from which this <tt>SessionCookieConfig</tt>
+     * was acquired, or <tt>-1</tt> (the default)
+     *
+     * @see javax.servlet.http.Cookie#getMaxAge
+     */
+    public int getMaxAge();
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/SessionTrackingMode.java b/third_party/servlet-spec/src/main/java/javax/servlet/SessionTrackingMode.java
new file mode 100644
index 0000000..9c3a855
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/SessionTrackingMode.java
@@ -0,0 +1,52 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+/**
+ * Enumeration of session tracking modes.
+ *
+ * @since Servlet 3.0
+ */
+public enum SessionTrackingMode {
+    COOKIE,
+    URL,
+    SSL
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/SingleThreadModel.java b/third_party/servlet-spec/src/main/java/javax/servlet/SingleThreadModel.java
new file mode 100644
index 0000000..2572d3f
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/SingleThreadModel.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+/**
+ * Ensures that servlets handle
+ * only one request at a time. This interface has no methods.
+ *
+ * <p>If a servlet implements this interface, you are <i>guaranteed</i>
+ * that no two threads will execute concurrently in the
+ * servlet's <code>service</code> method. The servlet container
+ * can make this guarantee by synchronizing access to a single
+ * instance of the servlet, or by maintaining a pool of servlet
+ * instances and dispatching each new request to a free servlet.
+ *
+ * <p>Note that SingleThreadModel does not solve all thread safety
+ * issues.  For example, session attributes and static variables can
+ * still be accessed by multiple requests on multiple threads
+ * at the same time, even when SingleThreadModel servlets are used.
+ * It is recommended that a developer take other means to resolve
+ * those issues instead of implementing this interface, such as
+ * avoiding the usage of an instance variable or synchronizing
+ * the block of the code accessing those resources.
+ * This interface is deprecated in Servlet API version 2.4.
+ *
+ *
+ * @author	Various
+ *
+ * @deprecated	As of Java Servlet API 2.4, with no direct
+ *	replacement.
+ */
+@Deprecated
+public interface SingleThreadModel {
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/UnavailableException.java b/third_party/servlet-spec/src/main/java/javax/servlet/UnavailableException.java
new file mode 100644
index 0000000..f529aaf
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/UnavailableException.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet;
+
+
+/**
+ * Defines an exception that a servlet or filter throws to indicate
+ * that it is permanently or temporarily unavailable. 
+ *
+ * <p>When a servlet or filter is permanently unavailable, something is wrong
+ * with it, and it cannot handle
+ * requests until some action is taken. For example, a servlet
+ * might be configured incorrectly, or a filter's state may be corrupted.
+ * The component should log both the error and the corrective action
+ * that is needed.
+ *
+ * <p>A servlet or filter is temporarily unavailable if it cannot handle
+ * requests momentarily due to some system-wide problem. For example,
+ * a third-tier server might not be accessible, or there may be 
+ * insufficient memory or disk storage to handle requests. A system
+ * administrator may need to take corrective action.
+ *
+ * <p>Servlet containers can safely treat both types of unavailable
+ * exceptions in the same way. However, treating temporary unavailability
+ * effectively makes the servlet container more robust. Specifically,
+ * the servlet container might block requests to the servlet or filter for a period
+ * of time suggested by the exception, rather than rejecting them until
+ * the servlet container restarts.
+ *
+ *
+ * @author 	Various
+ *
+ */
+
+public class UnavailableException
+extends ServletException {
+
+    private Servlet     servlet;           // what's unavailable
+    private boolean     permanent;         // needs admin action?
+    private int         seconds;           // unavailability estimate
+
+    /**
+     * 
+     * @deprecated	As of Java Servlet API 2.2, use {@link
+     * 			#UnavailableException(String)} instead.
+     *
+     * @param servlet 	the <code>Servlet</code> instance that is
+     *                  unavailable
+     *
+     * @param msg 	a <code>String</code> specifying the
+     *                  descriptive message
+     *
+     */
+    @Deprecated
+    public UnavailableException(Servlet servlet, String msg) {
+	super(msg);
+	this.servlet = servlet;
+	permanent = true;
+    }
+ 
+    /**
+     * @deprecated	As of Java Servlet API 2.2, use {@link
+     *			#UnavailableException(String, int)} instead.
+     *
+     * @param seconds	an integer specifying the number of seconds
+     * 			the servlet expects to be unavailable; if
+     *			zero or negative, indicates that the servlet
+     *			can't make an estimate
+     *
+     * @param servlet	the <code>Servlet</code> that is unavailable
+     * 
+     * @param msg	a <code>String</code> specifying the descriptive 
+     *			message, which can be written to a log file or 
+     *			displayed for the user.
+     *
+     */
+    @Deprecated
+    public UnavailableException(int seconds, Servlet servlet, String msg) {
+	super(msg);
+	this.servlet = servlet;
+	if (seconds <= 0)
+	    this.seconds = -1;
+	else
+	    this.seconds = seconds;
+	permanent = false;
+    }
+
+    /**
+     * 
+     * Constructs a new exception with a descriptive
+     * message indicating that the servlet is permanently
+     * unavailable.
+     *
+     * @param msg 	a <code>String</code> specifying the
+     *                  descriptive message
+     *
+     */
+
+    public UnavailableException(String msg) {
+	super(msg);
+
+	permanent = true;
+    }
+
+    /**
+     * Constructs a new exception with a descriptive message
+     * indicating that the servlet is temporarily unavailable
+     * and giving an estimate of how long it will be unavailable.
+     * 
+     * <p>In some cases, the servlet cannot make an estimate. For
+     * example, the servlet might know that a server it needs is
+     * not running, but not be able to report how long it will take
+     * to be restored to functionality. This can be indicated with
+     * a negative or zero value for the <code>seconds</code> argument.
+     *
+     * @param msg	a <code>String</code> specifying the
+     *                  descriptive message, which can be written
+     *                  to a log file or displayed for the user.
+     *
+     * @param seconds	an integer specifying the number of seconds
+     * 			the servlet expects to be unavailable; if
+     *			zero or negative, indicates that the servlet
+     *			can't make an estimate
+     *
+     */
+    
+    public UnavailableException(String msg, int seconds) {
+	super(msg);
+
+	if (seconds <= 0)
+	    this.seconds = -1;
+	else
+	    this.seconds = seconds;
+
+	permanent = false;
+    }
+
+    /**
+     *
+     * Returns a <code>boolean</code> indicating
+     * whether the servlet is permanently unavailable.
+     * If so, something is wrong with the servlet, and the
+     * system administrator must take some corrective action.
+     *
+     * @return		<code>true</code> if the servlet is
+     *			permanently unavailable; <code>false</code>
+     *			if the servlet is available or temporarily
+     *			unavailable
+     *
+     */
+     
+    public boolean isPermanent() {
+	return permanent;
+    }
+  
+    /**
+     * @deprecated	As of Java Servlet API 2.2, with no replacement.
+     *
+     * Returns the servlet that is reporting its unavailability.
+     * 
+     * @return		the <code>Servlet</code> object that is 
+     *			throwing the <code>UnavailableException</code>
+     *
+     */
+    @Deprecated
+    public Servlet getServlet() {
+	return servlet;
+    }
+
+    /**
+     * Returns the number of seconds the servlet expects to 
+     * be temporarily unavailable.  
+     *
+     * <p>If this method returns a negative number, the servlet
+     * is permanently unavailable or cannot provide an estimate of
+     * how long it will be unavailable. No effort is
+     * made to correct for the time elapsed since the exception was
+     * first reported.
+     *
+     * @return		an integer specifying the number of seconds
+     *			the servlet will be temporarily unavailable,
+     *			or a negative number if the servlet is permanently
+     *			unavailable or cannot make an estimate
+     *
+     */
+     
+    public int getUnavailableSeconds() {
+	return permanent ? -1 : seconds;
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/WriteListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/WriteListener.java
new file mode 100644
index 0000000..6d50ecf
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/WriteListener.java
@@ -0,0 +1,74 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet;
+
+import java.io.IOException;
+import java.util.EventListener;
+
+/**
+ *
+ * Callback notification mechanism that signals to the developer it's possible
+ * to write content without blocking.
+ *
+ * @since Servlet 3.1
+ */
+public interface WriteListener extends EventListener {
+
+    /**
+     * When an instance of the WriteListener is registered with a {@link ServletOutputStream},
+     * this method will be invoked by the container the first time when it is possible
+     * to write data. Subsequently the container will invoke this method if and only
+     * if the {@link javax.servlet.ServletOutputStream#isReady()} method
+     * has been called and has returned a value of <code>false</code> and a write
+     * operation has subsequently become possible.
+     *
+     * @throws IOException if an I/O related error has occurred during processing
+     */
+    public void onWritePossible() throws IOException;
+
+    /**
+     * Invoked when an error occurs writing data using the non-blocking APIs.
+     *
+     * @param t the throwable to indicate why the write operation failed
+     */
+    public void onError(final Throwable t);
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HandlesTypes.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HandlesTypes.java
new file mode 100644
index 0000000..2be3cdb
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HandlesTypes.java
@@ -0,0 +1,77 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This annotation is used to declare the class types that a
+ * {@link javax.servlet.ServletContainerInitializer
+ * ServletContainerInitializer} can handle.
+ *
+ * @see javax.servlet.ServletContainerInitializer
+ *
+ * @since Servlet 3.0
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HandlesTypes {
+
+    /**
+     * The classes in which a {@link javax.servlet.ServletContainerInitializer
+     * ServletContainerInitializer} has expressed interest.
+     *
+     * <p>If an implementation of <tt>ServletContainerInitializer</tt> 
+     * specifies this annotation, the Servlet container must pass the
+     * <tt>Set</tt> of application classes that extend, implement, or have
+     * been annotated with the class types listed by this annotation to
+     * the {@link javax.servlet.ServletContainerInitializer#onStartup}
+     * method of the ServletContainerInitializer (if no matching classes
+     * are found, <tt>null</tt> must be passed instead)
+     * 
+     * @return the classes in which {@link javax.servlet.ServletContainerInitializer
+     *         ServletContainerInitializer} has expressed interest
+     */
+    Class<?>[] value();
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HttpConstraint.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HttpConstraint.java
new file mode 100644
index 0000000..093090f
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HttpConstraint.java
@@ -0,0 +1,113 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
+
+/**
+ * This annotation is used within the {@link ServletSecurity} annotation to
+ * represent the security constraints to be applied to all HTTP protocol
+ * methods for which a corresponding {@link HttpMethodConstraint} element does
+ * NOT occur within the {@link ServletSecurity} annotation.
+ *
+ * <p>For the special case where an <code>@HttpConstraint</code> that returns
+ * all default values occurs in combination with at least one
+ * {@link HttpMethodConstraint} that returns other than all default values, the
+ * <code>@HttpConstraint</code> represents that no security constraint is to be
+ * applied to any of the HTTP protocol methods to which a security constraint
+ * would otherwise apply. This exception is made to ensure that such
+ * potentially non-specific uses of <code>@HttpConstraint</code> do not yield
+ * constraints that will explicitly establish unprotected access for such
+ * methods; given that they would not otherwise be covered by a constraint.
+ *
+ * @since Servlet 3.0
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HttpConstraint {
+
+    /**
+     * The default authorization semantic.
+     * This value is insignificant when <code>rolesAllowed</code> returns a
+     * non-empty array, and should not be specified when a non-empty
+     * array is specified for <tt>rolesAllowed</tt>.
+     *
+     * @return the {@link EmptyRoleSemantic} to be applied when
+     * <code>rolesAllowed</code> returns an empty (that is, zero-length) array.
+     */
+    EmptyRoleSemantic value() default EmptyRoleSemantic.PERMIT;
+
+    /**
+     * The data protection requirements (i.e., whether or not SSL/TLS is
+     * required) that must be satisfied by the connections on which requests
+     * arrive.
+     * 
+     * @return the {@link TransportGuarantee}
+     * indicating the data protection that must be provided by the connection.
+     */
+    TransportGuarantee transportGuarantee() default TransportGuarantee.NONE;
+
+    /**
+     * The names of the authorized roles.
+     *
+     * Duplicate role names appearing in rolesAllowed are insignificant and
+     * may be discarded during runtime processing of the annotation. The String
+     * <tt>"*"</tt> has no special meaning as a role name (should it occur in
+     * rolesAllowed).
+     *
+     * @return an array of zero or more role names. When the array contains
+     * zero elements, its meaning depends on the <code>EmptyRoleSemantic</code>
+     * returned by the <code>value</code> method. If <code>value</code> returns
+     * <tt>DENY</tt>, and <code>rolesAllowed</code> returns a zero length array,
+     * access is to be denied independent of authentication state and identity.
+     * Conversely, if <code>value</code> returns <code>PERMIT</code>, it
+     * indicates that access is to be allowed independent of authentication
+     * state and identity. When the array contains the names of one or more
+     * roles, it indicates that access is contingent on membership in at
+     * least one of the named roles (independent of the
+     * <code>EmptyRoleSemantic</code> returned by the <code>value</code> method).
+     */
+    String[] rolesAllowed() default {};
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HttpMethodConstraint.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HttpMethodConstraint.java
new file mode 100644
index 0000000..e221835
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/HttpMethodConstraint.java
@@ -0,0 +1,110 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import javax.servlet.annotation.ServletSecurity.EmptyRoleSemantic;
+import javax.servlet.annotation.ServletSecurity.TransportGuarantee;
+
+/**
+ * This annotation is used within the {@link ServletSecurity} annotation to
+ * represent security constraints on specific HTTP protocol messages.
+ *
+ * @since Servlet 3.0
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HttpMethodConstraint {
+
+    /**
+     * Http protocol method name
+     *
+     * @return the name of an HTTP protocol method. <code>value</code>
+     * may not be null, or the empty string, and must be a
+     * legitimate HTTP Method name as defined by RFC 2616.
+     */
+    String value();
+
+    /**
+     * The default authorization semantic.
+     * This value is insignificant when <code>rolesAllowed</code> returns a
+     * non-empty array, and should not be specified when a non-empty
+     * array is specified for <tt>rolesAllowed</tt>.
+     *
+     * @return the {@link EmptyRoleSemantic} to be applied when
+     * <code>rolesAllowed</code> returns an empty (that is, zero-length) array.
+     */
+    EmptyRoleSemantic emptyRoleSemantic() default EmptyRoleSemantic.PERMIT;
+
+    /**
+     * The data protection requirements (i.e., whether or not SSL/TLS is
+     * required) that must be satisfied by the connections on which requests
+     * arrive.
+     *
+     * @return the {@link TransportGuarantee}
+     * indicating the data protection that must be provided by the connection.
+     */
+    TransportGuarantee transportGuarantee() default TransportGuarantee.NONE;
+
+    /**
+     * The names of the authorized roles.
+     *
+     * Duplicate role names appearing in rolesAllowed are insignificant and
+     * may be discarded during runtime processing of the annotation. The String
+     * <tt>"*"</tt> has no special meaning as a role name (should it occur in
+     * rolesAllowed).
+     *
+     * @return an array of zero or more role names. When the array contains
+     * zero elements, its meaning depends on the value returned by
+     * <code>emptyRoleSemantic</code>. If <code>emptyRoleSemantic</code> returns
+     * <tt>DENY</tt>, and <code>rolesAllowed</code> returns a zero length array,
+     * access is to be denied independent of authentication state and identity.
+     * Conversely, if <code>emptyRoleSemantic</code> returns
+     * <code>PERMIT</code>, it indicates that access is to be allowed
+     * independent of authentication state and identity. When the array
+     * contains the names of one or more roles, it indicates that access is
+     * contingent on membership in at least one of the named roles (independent
+     * of the value returned by <code>emptyRoleSemantic</code>).
+     */
+    String[] rolesAllowed() default {};
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/MultipartConfig.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/MultipartConfig.java
new file mode 100644
index 0000000..c3287b5
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/MultipartConfig.java
@@ -0,0 +1,96 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.Target;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Annotation that may be specified on a {@link javax.servlet.Servlet}
+ * class, indicating that instances of the <tt>Servlet</tt> expect requests
+ * that conform to the <tt>multipart/form-data</tt> MIME type.
+ *
+ * <p>Servlets annotated with <tt>MultipartConfig</tt> may retrieve the
+ * {@link javax.servlet.http.Part} components of a given
+ * <tt>multipart/form-data</tt> request by calling 
+ * {@link javax.servlet.http.HttpServletRequest#getPart getPart} or
+ * {@link javax.servlet.http.HttpServletRequest#getParts getParts}.
+ */
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface MultipartConfig {
+
+    /**
+     * The directory location where files will be stored
+     *
+     * @return the directory location where files will be stored
+     */
+    String location() default "";
+
+    /**
+     * The maximum size allowed for uploaded files.
+     * 
+     * <p>The default is <tt>-1L</tt>, which means unlimited.
+     *
+     * @return the maximum size allowed for uploaded files
+     */
+    long maxFileSize() default -1L;
+
+    /**
+     * The maximum size allowed for <tt>multipart/form-data</tt>
+     * requests
+     * 
+     * <p>The default is <tt>-1L</tt>, which means unlimited.
+     *
+     * @return the maximum size allowed for <tt>multipart/form-data</tt> requests
+     */
+    long maxRequestSize() default -1L;
+
+    /**
+     * The size threshold after which the file will be written to disk
+     *
+     * @return the size threshold after which the file will be written to disk
+     */
+    int fileSizeThreshold() default 0;
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/ServletSecurity.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/ServletSecurity.java
new file mode 100644
index 0000000..bbdf529
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/ServletSecurity.java
@@ -0,0 +1,121 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Target;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * This annotation is used on a Servlet implementation class to specify security
+ * constraints to be enforced by a Servlet container on HTTP protocol messages.
+ * The Servlet container will enforce these constraints on the url-patterns
+ * mapped to the servlets mapped to the annotated class.
+ *
+ * @since Servlet 3.0
+ */
+
+@Inherited
+@Documented
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface ServletSecurity {
+
+    /**
+     * Defines the access semantic to be applied to an empty rolesAllowed array.
+     */
+    enum EmptyRoleSemantic {
+        /**
+         * access is to be permitted independent of authentication state and
+         * identity.
+         */
+        PERMIT,
+        /**
+         * access is to be denied independent of authentication state and
+         * identity.
+         */
+        DENY
+    }
+
+    /**
+     * Defines the data protection requirements that must be satisfied by
+     * the transport
+     */
+    enum TransportGuarantee {
+        /**
+         * no protection of user data must be performed by the transport.
+         */
+        NONE,
+        /**
+         * All user data must be encrypted by the transport (typically
+         * using SSL/TLS).
+         */
+        CONFIDENTIAL
+    }
+
+    /**
+     * Get the {@link HttpConstraint} that defines the protection
+     * that is to be applied to all HTTP methods that are NOT represented in
+     * the array returned by <tt>httpMethodConstraints</tt>.
+     *
+     * @return a <code>HttpConstraint</code> object.
+     */
+    HttpConstraint value() default @HttpConstraint;
+
+    /**
+     * Get the HTTP method specific constraints. Each
+     * {@link HttpMethodConstraint} names an HTTP protocol method
+     * and defines the protection to be applied to it.
+     *
+     * @return an array of {@link HttpMethodConstraint} elements each
+     * defining the protection to be applied to one HTTP protocol method. For
+     * any HTTP method name, there must be at most one corresponding element in
+     * the returned array. If the returned array is of zero length, it indicates
+     * that no HTTP method specific constraints are defined.
+     */
+
+  
+    HttpMethodConstraint[] httpMethodConstraints() default {};
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebFilter.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebFilter.java
new file mode 100644
index 0000000..46c4d3e
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebFilter.java
@@ -0,0 +1,147 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.servlet.DispatcherType;
+
+/**
+ * Annotation used to declare a servlet filter.
+ *
+ * <p>This annotation is processed by the container at deployment time,
+ * and the corresponding filter applied to the specified URL patterns,
+ * servlets, and dispatcher types.
+ * 
+ * @see javax.servlet.Filter
+ *
+ * @since Servlet 3.0
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebFilter {
+
+    /**
+     * The description of the filter
+     * 
+     * @return the description of the filter
+     */
+    String description() default "";
+    
+    /**
+     * The display name of the filter
+     *
+     * @return the display name of the filter
+     */
+    String displayName() default "";
+    
+    /**
+     * The init parameters of the filter
+     *
+     * @return the init parameters of the filter
+     */
+    WebInitParam[] initParams() default {};
+    
+    /**
+     * The name of the filter
+     *
+     * @return the name of the filter
+     */
+    String filterName() default "";
+    
+    /**
+     * The small-icon of the filter
+     *
+     * @return the small-icon of the filter
+     */
+    String smallIcon() default "";
+
+    /**
+     * The large-icon of the filter
+     *
+     * @return the large-icon of the filter
+     */
+    String largeIcon() default "";
+
+    /**
+     * The names of the servlets to which the filter applies.
+     *
+     * @return the names of the servlets to which the filter applies
+     */
+    String[] servletNames() default {};
+    
+    /**
+     * The URL patterns to which the filter applies
+     * The default value is an empty array.
+     *
+     * @return the URL patterns to which the filter applies
+     */
+    String[] value() default {};
+
+    /**
+     * The URL patterns to which the filter applies
+     *
+     * @return the URL patterns to which the filter applies
+     */
+    String[] urlPatterns() default {};
+
+    /**
+     * The dispatcher types to which the filter applies
+     *
+     * @return the dispatcher types to which the filter applies
+     */
+    DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};
+    
+    /**
+     * Declares whether the filter supports asynchronous operation mode.
+     *
+     * @return {@code true} if the filter supports asynchronous operation mode
+     * @see javax.servlet.ServletRequest#startAsync
+     * @see javax.servlet.ServletRequest#startAsync(ServletRequest,
+     * ServletResponse)
+     */
+    boolean asyncSupported() default false;
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebInitParam.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebInitParam.java
new file mode 100644
index 0000000..50586a1
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebInitParam.java
@@ -0,0 +1,80 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.annotation.Documented;
+
+/**
+ * This annotation is used on a Servlet or Filter implementation class
+ * to specify an initialization parameter.
+ * 
+ * @since Servlet 3.0
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebInitParam {
+
+    /**
+     * Name of the initialization parameter
+     *
+     * @return name of the initialization parameter
+     */
+    String name();
+    
+    /**
+     * Value of the initialization parameter
+     *
+     * @return value of the initialization parameter
+     */    
+    String value();
+    
+    /**
+     * Description of the initialization parameter
+     *
+     * @return description of the initialization parameter
+     */
+    String description() default "";
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebListener.java
new file mode 100644
index 0000000..49acb19
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebListener.java
@@ -0,0 +1,73 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation is used to declare a WebListener.
+ *
+ * Any class annotated with WebListener must implement one or more of
+ * the {@link javax.servlet.ServletContextListener}, 
+ * {@link javax.servlet.ServletContextAttributeListener},
+ * {@link javax.servlet.ServletRequestListener},
+ * {@link javax.servlet.ServletRequestAttributeListener}, 
+ * {@link javax.servlet.http.HttpSessionListener}, or
+ * {@link javax.servlet.http.HttpSessionAttributeListener}, or
+ * {@link javax.servlet.http.HttpSessionIdListener} interfaces.
+ * 
+ * @since Servlet 3.0
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebListener {
+    /**
+     * Description of the listener
+     *
+     * @return description of the listener
+     */
+    String value() default "";
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebServlet.java b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebServlet.java
new file mode 100644
index 0000000..aa32498
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/WebServlet.java
@@ -0,0 +1,138 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Target;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Documented;
+
+/**
+ * Annotation used to declare a servlet.
+ *
+ * <p>This annotation is processed by the container at deployment time,
+ * and the corresponding servlet made available at the specified URL
+ * patterns.
+ * 
+ * @see javax.servlet.Servlet
+ *
+ * @since Servlet 3.0
+ */
+@Target({ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface WebServlet {
+    
+    /**
+     * The name of the servlet
+     *
+     * @return the name of the servlet
+     */
+    String name() default "";
+    
+    /**
+     * The URL patterns of the servlet
+     *
+     * @return the URL patterns of the servlet
+     */
+    String[] value() default {};
+
+    /**
+     * The URL patterns of the servlet
+     *
+     * @return the URL patterns of the servlet
+     */
+    String[] urlPatterns() default {};
+    
+    /**
+     * The load-on-startup order of the servlet 
+     *
+     * @return the load-on-startup order of the servlet
+     */
+    int loadOnStartup() default -1;
+    
+    /**
+     * The init parameters of the servlet
+     *
+     * @return the init parameters of the servlet
+     */
+    WebInitParam [] initParams() default {};
+    
+    /**
+     * Declares whether the servlet supports asynchronous operation mode.
+     *
+     * @return {@code true} if the servlet supports asynchronous operation mode
+     * @see javax.servlet.ServletRequest#startAsync
+     * @see javax.servlet.ServletRequest#startAsync(ServletRequest,
+     * ServletResponse)
+     */
+    boolean asyncSupported() default false;
+    
+    /**
+     * The small-icon of the servlet
+     *
+     * @return the small-icon of the servlet
+     */
+    String smallIcon() default "";
+
+    /**
+     * The large-icon of the servlet
+     *
+     * @return the large-icon of the servlet
+     */
+    String largeIcon() default "";
+
+    /**
+     * The description of the servlet
+     *
+     * @return the description of the servlet
+     */
+    String description() default "";
+
+    /**
+     * The display name of the servlet
+     *
+     * @return the display name of the servlet
+     */
+    String displayName() default "";
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/annotation/package.html b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/package.html
new file mode 100644
index 0000000..11b7bb2
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/annotation/package.html
@@ -0,0 +1,57 @@
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 2008-2017 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+
+
+</HEAD>
+<BODY BGCOLOR="white">
+
+The javax.servlet.annotation package contains a number of annotations 
+that allow users to use annotations to declare servlets, filters,
+listeners and specify the metadata for the declared component.
+
+@since Servlet 3.0
+</BODY>
+</HTML>
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/JspConfigDescriptor.java b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/JspConfigDescriptor.java
new file mode 100644
index 0000000..ac8281c
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/JspConfigDescriptor.java
@@ -0,0 +1,85 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.descriptor;
+
+import java.util.Collection;
+
+/**
+ * This interface provides access to the <code>&lt;jsp-config&gt;</code>
+ * related configuration of a web application.
+ *
+ * <p>The configuration is aggregated from the <code>web.xml</code> and
+ * <code>web-fragment.xml</code> descriptor files of the web application.
+ *
+ * @since Servlet 3.0
+ */
+public interface JspConfigDescriptor {
+
+    /**
+     * Gets the <code>&lt;taglib&gt;</code> child elements of the
+     * <code>&lt;jsp-config&gt;</code> element represented by this
+     * <code>JspConfigDescriptor</code>.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>JspConfigDescriptor</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the
+     * <code>&lt;taglib&gt;</code> child elements of the
+     * <code>&lt;jsp-config&gt;</code> element represented by this
+     * <code>JspConfigDescriptor</code>
+     */
+    public Collection<TaglibDescriptor> getTaglibs();
+
+    /**
+     * Gets the <code>&lt;jsp-property-group&gt;</code> child elements
+     * of the <code>&lt;jsp-config&gt;</code> element represented by this
+     * <code>JspConfigDescriptor</code>.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>JspConfigDescriptor</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the
+     * <code>&lt;jsp-property-group&gt;</code> child elements of the
+     * <code>&lt;jsp-config&gt;</code> element represented by this
+     * <code>JspConfigDescriptor</code>
+     */
+    public Collection<JspPropertyGroupDescriptor> getJspPropertyGroups();
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/JspPropertyGroupDescriptor.java b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/JspPropertyGroupDescriptor.java
new file mode 100644
index 0000000..b088cfa
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/JspPropertyGroupDescriptor.java
@@ -0,0 +1,204 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.descriptor;
+
+import java.util.Collection;
+
+/**
+ * This interface provides access to the
+ * <code>&lt;jsp-property-group&gt;</code>
+ * related configuration of a web application.
+ *
+ * <p>The configuration is aggregated from the <code>web.xml</code> and
+ * <code>web-fragment.xml</code> descriptor files of the web application.
+ *
+ * @since Servlet 3.0
+ */
+public interface JspPropertyGroupDescriptor {
+    
+    /**
+     * Gets the URL patterns of the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the URL
+     * patterns of the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>
+     */
+    public Collection<String> getUrlPatterns();
+
+    /**
+     * Gets the value of the <code>el-ignored</code> configuration, which
+     * specifies whether Expression Language (EL) evaluation is enabled for
+     * any JSP pages mapped to the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the <code>el-ignored</code> configuration, or
+     * null if unspecified
+     */
+    public String getElIgnored();
+
+    /**
+     * Gets the value of the <code>page-encoding</code> configuration,
+     * which specifies the default page encoding for any JSP pages mapped
+     * to the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the <code>page-encoding</code> configuration, or
+     * null if unspecified
+     */
+    public String getPageEncoding();
+
+    /**
+     * Gets the value of the <code>scripting-invalid</code> configuration,
+     * which specifies whether scripting is enabled for any JSP pages mapped
+     * to the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the <code>scripting-invalid</code> configuration,
+     * or null if unspecified
+     */
+    public String getScriptingInvalid();
+
+    /**
+     * Gets the value of the <code>is-xml</code> configuration, which 
+     * specifies whether any JSP pages mapped to the JSP property group
+     * represented by this <code>JspPropertyGroupDescriptor</code> will
+     * be treated as JSP documents (XML syntax).
+     *
+     * @return the value of the <code>is-xml</code> configuration, or
+     * null if unspecified
+     */
+    public String getIsXml();
+
+    /**
+     * Gets the <code>include-prelude</code> configuration
+     * of the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the
+     * <code>include-prelude</code> configuration of
+     * the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>
+     */
+    public Collection<String> getIncludePreludes();
+
+    /**
+     * Gets the <code>include-coda</code> configuration
+     * of the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the
+     * <code>include-coda</code> configuration of
+     * the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>
+     */
+    public Collection<String> getIncludeCodas();
+
+    /**
+     * Gets the value of the
+     * <code>deferred-syntax-allowed-as-literal</code> configuration, which
+     * specifies whether the character sequence <code>&quot;#{&quot;</code>,
+     * which is normally reserved for Expression Language (EL) expressions,
+     * will cause a translation error if it appears as a String literal
+     * in any JSP pages mapped to the JSP property group represented by
+     * this <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the
+     * <code>deferred-syntax-allowed-as-literal</code> configuration, or
+     * null if unspecified
+     */
+    public String getDeferredSyntaxAllowedAsLiteral();
+
+    /**
+     * Gets the value of the <code>trim-directive-whitespaces</code>
+     * configuration, which specifies whether template text containing only
+     * whitespaces must be removed from the response output of any JSP
+     * pages mapped to the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the <code>trim-directive-whitespaces</code>
+     * configuration, or null if unspecified
+     */
+    public String getTrimDirectiveWhitespaces();
+
+    /**
+     * Gets the value of the <code>default-content-type</code> configuration,
+     * which specifies the default response content type for any JSP pages
+     * mapped to the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the <code>default-content-type</code>
+     * configuration, or null if unspecified
+     */
+    public String getDefaultContentType();
+
+    /**
+     * Gets the value of the <code>buffer</code> configuration, which
+     * specifies the default size of the response buffer for any JSP pages
+     * mapped to the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the <code>buffer</code> configuration, or
+     * null if unspecified
+     */
+    public String getBuffer();
+
+    /**
+     * Gets the value of the <code>error-on-undeclared-namespace</code>
+     * configuration, which specifies whether an error will be raised at
+     * translation time if tag with an undeclared namespace is used in
+     * any JSP pages mapped to the JSP property group represented by this
+     * <code>JspPropertyGroupDescriptor</code>.
+     *
+     * @return the value of the <code>error-on-undeclared-namespace</code>
+     * configuration, or null if unspecified
+     */
+    public String getErrorOnUndeclaredNamespace();
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/TaglibDescriptor.java b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/TaglibDescriptor.java
new file mode 100644
index 0000000..19ee530
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/TaglibDescriptor.java
@@ -0,0 +1,71 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.descriptor;
+
+/**
+ * This interface provides access to the <code>&lt;taglib&gt;</code>
+ * related configuration of a web application.
+ *
+ * <p>The configuration is aggregated from the <code>web.xml</code> and
+ * <code>web-fragment.xml</code> descriptor files of the web application.
+ *
+ * @since Servlet 3.0
+ */
+public interface TaglibDescriptor {
+  
+    /**
+     * Gets the unique identifier of the tag library represented by this
+     * TaglibDescriptor.
+     *  
+     * @return the unique identifier of the tag library represented by this
+     * TaglibDescriptor
+     */
+    public String getTaglibURI();
+
+    /**
+     * Gets the location of the tag library represented by this
+     * TaglibDescriptor.
+     *  
+     * @return the location of the tag library represented by this
+     * TaglibDescriptor
+     */    
+    public String getTaglibLocation();    
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/package.html b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/package.html
new file mode 100644
index 0000000..d25c845
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/descriptor/package.html
@@ -0,0 +1,53 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<html>
+<head>
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 2009-2017 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+</head>
+<body bgcolor="white">
+
+Provides programmatic access to a web application's configuration information that was aggregated from the <code>web.xml</code> and <code>web-fragment.xml</code> descriptors.
+
+@since Servlet 3.0
+</body>
+</html>
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/Cookie.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/Cookie.java
new file mode 100644
index 0000000..cfd8582
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/Cookie.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.io.Serializable;
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ *
+ * Creates a cookie, a small amount of information sent by a servlet to 
+ * a Web browser, saved by the browser, and later sent back to the server.
+ * A cookie's value can uniquely 
+ * identify a client, so cookies are commonly used for session management.
+ * 
+ * <p>A cookie has a name, a single value, and optional attributes
+ * such as a comment, path and domain qualifiers, a maximum age, and a
+ * version number. Some Web browsers have bugs in how they handle the 
+ * optional attributes, so use them sparingly to improve the interoperability 
+ * of your servlets.
+ *
+ * <p>The servlet sends cookies to the browser by using the
+ * {@link HttpServletResponse#addCookie} method, which adds
+ * fields to HTTP response headers to send cookies to the 
+ * browser, one at a time. The browser is expected to 
+ * support 20 cookies for each Web server, 300 cookies total, and
+ * may limit cookie size to 4 KB each.
+ * 
+ * <p>The browser returns cookies to the servlet by adding 
+ * fields to HTTP request headers. Cookies can be retrieved
+ * from a request by using the {@link HttpServletRequest#getCookies} method.
+ * Several cookies might have the same name but different path attributes.
+ * 
+ * <p>Cookies affect the caching of the Web pages that use them. 
+ * HTTP 1.0 does not cache pages that use cookies created with
+ * this class. This class does not support the cache control
+ * defined with HTTP 1.1.
+ *
+ * <p>This class supports both the Version 0 (by Netscape) and Version 1 
+ * (by RFC 2109) cookie specifications. By default, cookies are
+ * created using Version 0 to ensure the best interoperability.
+ *
+ * @author	Various
+ */
+public class Cookie implements Cloneable, Serializable {
+
+    private static final long serialVersionUID = -6454587001725327448L;
+
+    private static final String TSPECIALS;
+
+    private static final String LSTRING_FILE =
+        "javax.servlet.http.LocalStrings";
+
+    private static ResourceBundle lStrings =
+        ResourceBundle.getBundle(LSTRING_FILE);
+
+    static {
+        if (Boolean.valueOf(System.getProperty("org.glassfish.web.rfc2109_cookie_names_enforced", "true"))) {
+            TSPECIALS = "/()<>@,;:\\\"[]?={} \t";
+        } else {
+            TSPECIALS = ",; ";
+        }
+    }
+    
+    //
+    // The value of the cookie itself.
+    //
+    
+    private String name;	// NAME= ... "$Name" style is reserved
+    private String value;	// value of NAME
+
+    //
+    // Attributes encoded in the header's cookie fields.
+    //
+    
+    private String comment;	// ;Comment=VALUE ... describes cookie's use
+				// ;Discard ... implied by maxAge < 0
+    private String domain;	// ;Domain=VALUE ... domain that sees cookie
+    private int maxAge = -1;	// ;Max-Age=VALUE ... cookies auto-expire
+    private String path;	// ;Path=VALUE ... URLs that see the cookie
+    private boolean secure;	// ;Secure ... e.g. use SSL
+    private int version = 0;	// ;Version=1 ... means RFC 2109++ style
+    private boolean isHttpOnly = false;
+
+    /**
+     * Constructs a cookie with the specified name and value.
+     *
+     * <p>The name must conform to RFC 2109. However, vendors may
+     * provide a configuration option that allows cookie names conforming
+     * to the original Netscape Cookie Specification to be accepted.
+     *
+     * <p>The name of a cookie cannot be changed once the cookie has
+     * been created.
+     *
+     * <p>The value can be anything the server chooses to send. Its
+     * value is probably of interest only to the server. The cookie's
+     * value can be changed after creation with the
+     * <code>setValue</code> method.
+     *
+     * <p>By default, cookies are created according to the Netscape
+     * cookie specification. The version can be changed with the 
+     * <code>setVersion</code> method.
+     *
+     * @param name the name of the cookie
+     *
+     * @param value the value of the cookie
+     *
+     * @throws IllegalArgumentException	if the cookie name is null or
+     * empty or contains any illegal characters (for example, a comma,
+     * space, or semicolon) or matches a token reserved for use by the
+     * cookie protocol
+     *
+     * @see #setValue
+     * @see #setVersion
+     */
+    public Cookie(String name, String value) {
+        if (name == null || name.length() == 0) {
+            throw new IllegalArgumentException(
+                    lStrings.getString("err.cookie_name_blank"));
+        }
+        if (!isToken(name) ||
+                name.equalsIgnoreCase("Comment") || // rfc2019
+                name.equalsIgnoreCase("Discard") || // 2019++
+                name.equalsIgnoreCase("Domain") ||
+                name.equalsIgnoreCase("Expires") || // (old cookies)
+                name.equalsIgnoreCase("Max-Age") || // rfc2019
+                name.equalsIgnoreCase("Path") ||
+                name.equalsIgnoreCase("Secure") ||
+                name.equalsIgnoreCase("Version") ||
+                name.startsWith("$")) {
+            String errMsg = lStrings.getString("err.cookie_name_is_token");
+            Object[] errArgs = new Object[1];
+            errArgs[0] = name;
+            errMsg = MessageFormat.format(errMsg, errArgs);
+            throw new IllegalArgumentException(errMsg);
+        }
+
+        this.name = name;
+        this.value = value;
+    }
+
+    /**
+     * Specifies a comment that describes a cookie's purpose.
+     * The comment is useful if the browser presents the cookie 
+     * to the user. Comments
+     * are not supported by Netscape Version 0 cookies.
+     *
+     * @param purpose		a <code>String</code> specifying the comment 
+     *				to display to the user
+     *
+     * @see #getComment
+     */
+    public void setComment(String purpose) {
+        comment = purpose;
+    }
+
+    /**
+     * Returns the comment describing the purpose of this cookie, or
+     * <code>null</code> if the cookie has no comment.
+     *
+     * @return the comment of the cookie, or <code>null</code> if unspecified
+     *
+     * @see #setComment
+     */ 
+    public String getComment() {
+        return comment;
+    }
+    
+    /**
+     *
+     * Specifies the domain within which this cookie should be presented.
+     *
+     * <p>The form of the domain name is specified by RFC 2109. A domain
+     * name begins with a dot (<code>.foo.com</code>) and means that
+     * the cookie is visible to servers in a specified Domain Name System
+     * (DNS) zone (for example, <code>www.foo.com</code>, but not 
+     * <code>a.b.foo.com</code>). By default, cookies are only returned
+     * to the server that sent them.
+     *
+     * @param domain the domain name within which this cookie is visible;
+     * form is according to RFC 2109
+     *
+     * @see #getDomain
+     */
+    public void setDomain(String domain) {
+        this.domain = domain.toLowerCase(Locale.ENGLISH); // IE allegedly needs this
+    }
+
+    /**
+     * Gets the domain name of this Cookie.
+     *
+     * <p>Domain names are formatted according to RFC 2109.
+     *
+     * @return the domain name of this Cookie
+     *
+     * @see #setDomain
+     */ 
+    public String getDomain() {
+        return domain;
+    }
+
+    /**
+     * Sets the maximum age in seconds for this Cookie.
+     *
+     * <p>A positive value indicates that the cookie will expire
+     * after that many seconds have passed. Note that the value is
+     * the <i>maximum</i> age when the cookie will expire, not the cookie's
+     * current age.
+     *
+     * <p>A negative value means
+     * that the cookie is not stored persistently and will be deleted
+     * when the Web browser exits. A zero value causes the cookie
+     * to be deleted.
+     *
+     * @param expiry		an integer specifying the maximum age of the
+     * 				cookie in seconds; if negative, means
+     *				the cookie is not stored; if zero, deletes
+     *				the cookie
+     *
+     * @see #getMaxAge
+     */
+    public void setMaxAge(int expiry) {
+        maxAge = expiry;
+    }
+
+    /**
+     * Gets the maximum age in seconds of this Cookie.
+     *
+     * <p>By default, <code>-1</code> is returned, which indicates that
+     * the cookie will persist until browser shutdown.
+     *
+     * @return			an integer specifying the maximum age of the
+     *				cookie in seconds; if negative, means
+     *				the cookie persists until browser shutdown
+     *
+     * @see #setMaxAge
+     */
+    public int getMaxAge() {
+        return maxAge;
+    }
+    
+    /**
+     * Specifies a path for the cookie
+     * to which the client should return the cookie.
+     *
+     * <p>The cookie is visible to all the pages in the directory
+     * you specify, and all the pages in that directory's subdirectories. 
+     * A cookie's path must include the servlet that set the cookie,
+     * for example, <i>/catalog</i>, which makes the cookie
+     * visible to all directories on the server under <i>/catalog</i>.
+     *
+     * <p>Consult RFC 2109 (available on the Internet) for more
+     * information on setting path names for cookies.
+     *
+     *
+     * @param uri		a <code>String</code> specifying a path
+     *
+     * @see #getPath
+     */
+    public void setPath(String uri) {
+        path = uri;
+    }
+
+    /**
+     * Returns the path on the server 
+     * to which the browser returns this cookie. The
+     * cookie is visible to all subpaths on the server.
+     *
+     * @return		a <code>String</code> specifying a path that contains
+     *			a servlet name, for example, <i>/catalog</i>
+     *
+     * @see #setPath
+     */ 
+    public String getPath() {
+        return path;
+    }
+
+    /**
+     * Indicates to the browser whether the cookie should only be sent
+     * using a secure protocol, such as HTTPS or SSL.
+     *
+     * <p>The default value is <code>false</code>.
+     *
+     * @param flag if <code>true</code>, sends the cookie from the browser
+     * to the server only when using a secure protocol; if <code>false</code>,
+     * sent on any protocol
+     *
+     * @see #getSecure
+     */
+    public void setSecure(boolean flag) {
+        secure = flag;
+    }
+
+    /**
+     * Returns <code>true</code> if the browser is sending cookies
+     * only over a secure protocol, or <code>false</code> if the
+     * browser can send cookies using any protocol.
+     *
+     * @return <code>true</code> if the browser uses a secure protocol,
+     * <code>false</code> otherwise
+     *
+     * @see #setSecure
+     */
+    public boolean getSecure() {
+        return secure;
+    }
+
+    /**
+     * Returns the name of the cookie. The name cannot be changed after
+     * creation.
+     *
+     * @return the name of the cookie
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Assigns a new value to this Cookie.
+     * 
+     * <p>If you use a binary value, you may want to use BASE64 encoding.
+     *
+     * <p>With Version 0 cookies, values should not contain white 
+     * space, brackets, parentheses, equals signs, commas,
+     * double quotes, slashes, question marks, at signs, colons,
+     * and semicolons. Empty values may not behave the same way
+     * on all browsers.
+     *
+     * @param newValue the new value of the cookie
+     *
+     * @see #getValue
+     */
+    public void setValue(String newValue) {
+        value = newValue;
+    }
+
+    /**
+     * Gets the current value of this Cookie.
+     *
+     * @return the current value of this Cookie
+     *
+     * @see #setValue
+     */
+    public String getValue() {
+        return value;
+    }
+
+    /**
+     * Returns the version of the protocol this cookie complies 
+     * with. Version 1 complies with RFC 2109, 
+     * and version 0 complies with the original
+     * cookie specification drafted by Netscape. Cookies provided
+     * by a browser use and identify the browser's cookie version.
+     * 
+     * @return			0 if the cookie complies with the
+     *				original Netscape specification; 1
+     *				if the cookie complies with RFC 2109
+     *
+     * @see #setVersion
+     */
+    public int getVersion() {
+        return version;
+    }
+
+    /**
+     * Sets the version of the cookie protocol that this Cookie complies
+     * with.
+     *
+     * <p>Version 0 complies with the original Netscape cookie
+     * specification. Version 1 complies with RFC 2109.
+     *
+     * <p>Since RFC 2109 is still somewhat new, consider
+     * version 1 as experimental; do not use it yet on production sites.
+     *
+     * @param v	0 if the cookie should comply with the original Netscape
+     * specification; 1 if the cookie should comply with RFC 2109
+     *
+     * @see #getVersion
+     */
+    public void setVersion(int v) {
+        version = v;
+    }
+
+    /*
+     * Tests a string and returns true if the string counts as a 
+     * reserved token in the Java language.
+     * 
+     * @param value the <code>String</code> to be tested
+     *
+     * @return <code>true</code> if the <code>String</code> is a reserved
+     * token; <code>false</code> otherwise
+     */
+    private boolean isToken(String value) {
+        int len = value.length();
+        for (int i = 0; i < len; i++) {
+            char c = value.charAt(i);
+            if (c < 0x20 || c >= 0x7f || TSPECIALS.indexOf(c) != -1) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * Overrides the standard <code>java.lang.Object.clone</code> 
+     * method to return a copy of this Cookie.
+     */
+    public Object clone() {
+        try {
+            return super.clone();
+        } catch (CloneNotSupportedException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * Marks or unmarks this Cookie as <i>HttpOnly</i>.
+     *
+     * <p>If <tt>isHttpOnly</tt> is set to <tt>true</tt>, this cookie is
+     * marked as <i>HttpOnly</i>, by adding the <tt>HttpOnly</tt> attribute
+     * to it.
+     *
+     * <p><i>HttpOnly</i> cookies are not supposed to be exposed to
+     * client-side scripting code, and may therefore help mitigate certain
+     * kinds of cross-site scripting attacks.
+     *
+     * @param isHttpOnly true if this cookie is to be marked as
+     * <i>HttpOnly</i>, false otherwise
+     *
+     * @since Servlet 3.0
+     */
+    public void setHttpOnly(boolean isHttpOnly) {
+        this.isHttpOnly = isHttpOnly;
+    }
+ 
+    /**
+     * Checks whether this Cookie has been marked as <i>HttpOnly</i>.
+     *
+     * @return true if this Cookie has been marked as <i>HttpOnly</i>,
+     * false otherwise
+     *
+     * @since Servlet 3.0
+     */
+    public boolean isHttpOnly() {
+        return isHttpOnly;
+    }
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpFilter.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpFilter.java
new file mode 100644
index 0000000..5b3635d
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpFilter.java
@@ -0,0 +1,164 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.GenericFilter;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+
+
+/**
+ *
+ * <p>Provides an abstract class to be subclassed to create
+ * an HTTP filter suitable for a Web site. A subclass of
+ * <code>HttpFilter</code> should override {@link #doFilter(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain) }.</p>
+ *
+ * <p>Filters typically run on multithreaded servers,
+ * so be aware that a filter must handle concurrent
+ * requests and be careful to synchronize access to shared resources.
+ * Shared resources include in-memory data such as
+ * instance or class variables and external objects
+ * such as files, database connections, and network 
+ * connections.
+ * See the
+ * <a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/">
+ * Java Tutorial on Multithreaded Programming</a> for more
+ * information on handling multiple threads in a Java program.
+ *
+ * @author  Various
+ *
+ * @since Servlet 4.0
+ */
+
+public abstract class HttpFilter extends GenericFilter
+{
+    
+    /**
+     * <p>Does nothing, because this is an abstract class.</p>
+     * 
+     * @since 4.0
+     */
+
+    public HttpFilter() { }
+
+    /**
+     *
+     * <p>The <code>doFilter</code> method of the Filter is called by the
+     * container each time a request/response pair is passed through the
+     * chain due to a client request for a resource at the end of the chain.
+     * The FilterChain passed in to this method allows the Filter to pass
+     * on the request and response to the next entity in the chain.  There's no need to
+     * override this method.</p>
+     * 
+     * <p>The default implementation inspects the incoming {@code req} and {@code res}
+     * objects to determine if they are instances of {@link HttpServletRequest}
+     * and {@link HttpServletResponse}, respectively.  If not, a {@link ServletException} is thrown.
+     * Otherwise, the protected {@link #doFilter(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, javax.servlet.FilterChain)}
+     * method is called.</p>
+     *
+     * @param req   a {@link ServletRequest} object that
+     *                  contains the request the client has made
+     *                  of the filter
+     *
+     * @param res  a {@link ServletResponse} object that
+     *                  contains the response the filter sends
+     *                  to the client
+     * 
+     * @param chain     the <code>FilterChain</code> for invoking the next filter or the resource
+     * 
+     * @throws IOException   if an input or output error is 
+     *                              detected when the filter handles
+     *                              the request
+     *
+     * @throws ServletException  if the request for the could not be handled or 
+     * either parameter is not an instance of the respective {@link HttpServletRequest}
+     * or {@link HttpServletResponse}.
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
+        if (!(req instanceof HttpServletRequest &&
+                res instanceof HttpServletResponse)) {
+            throw new ServletException("non-HTTP request or response");
+        }
+
+        this.doFilter((HttpServletRequest)req, (HttpServletResponse)res, chain);
+    }
+    
+    /**
+     *
+     * <p>The <code>doFilter</code> method of the Filter is called by the
+     * container each time a request/response pair is passed through the
+     * chain due to a client request for a resource at the end of the chain.
+     * The FilterChain passed in to this method allows the Filter to pass
+     * on the request and response to the next entity in the chain.</p>
+     * 
+     * <p>The default implementation simply calls {@link FilterChain#doFilter}</p>
+     *
+     * @param req   a {@link HttpServletRequest} object that
+     *                  contains the request the client has made
+     *                  of the filter
+     *
+     * @param res  a {@link HttpServletResponse} object that
+     *                  contains the response the filter sends
+     *                  to the client
+     * 
+     * @param chain     the <code>FilterChain</code> for invoking the next filter or the resource
+     * 
+     * @throws IOException   if an input or output error is 
+     *                              detected when the filter handles
+     *                              the request
+     *
+     * @throws ServletException  if the request for the could not be handled
+     *
+     * @since Servlet 4.0
+     */
+    protected void doFilter(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
+        chain.doFilter(req, res);
+    }
+    
+}
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServlet.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServlet.java
new file mode 100644
index 0000000..46f16f0
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServlet.java
@@ -0,0 +1,917 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Method;
+import java.text.MessageFormat;
+import java.util.Enumeration;
+import java.util.ResourceBundle;
+
+import javax.servlet.*;
+
+
+/**
+ *
+ * Provides an abstract class to be subclassed to create
+ * an HTTP servlet suitable for a Web site. A subclass of
+ * <code>HttpServlet</code> must override at least 
+ * one method, usually one of these:
+ *
+ * <ul>
+ * <li> <code>doGet</code>, if the servlet supports HTTP GET requests
+ * <li> <code>doPost</code>, for HTTP POST requests
+ * <li> <code>doPut</code>, for HTTP PUT requests
+ * <li> <code>doDelete</code>, for HTTP DELETE requests
+ * <li> <code>init</code> and <code>destroy</code>, 
+ * to manage resources that are held for the life of the servlet
+ * <li> <code>getServletInfo</code>, which the servlet uses to
+ * provide information about itself 
+ * </ul>
+ *
+ * <p>There's almost no reason to override the <code>service</code>
+ * method. <code>service</code> handles standard HTTP
+ * requests by dispatching them to the handler methods
+ * for each HTTP request type (the <code>do</code><i>XXX</i>
+ * methods listed above).
+ *
+ * <p>Likewise, there's almost no reason to override the 
+ * <code>doOptions</code> and <code>doTrace</code> methods.
+ * 
+ * <p>Servlets typically run on multithreaded servers,
+ * so be aware that a servlet must handle concurrent
+ * requests and be careful to synchronize access to shared resources.
+ * Shared resources include in-memory data such as
+ * instance or class variables and external objects
+ * such as files, database connections, and network 
+ * connections.
+ * See the
+ * <a href="https://docs.oracle.com/javase/tutorial/essential/concurrency/">
+ * Java Tutorial on Multithreaded Programming</a> for more
+ * information on handling multiple threads in a Java program.
+ *
+ * @author  Various
+ */
+
+public abstract class HttpServlet extends GenericServlet
+{
+    private static final String METHOD_DELETE = "DELETE";
+    private static final String METHOD_HEAD = "HEAD";
+    private static final String METHOD_GET = "GET";
+    private static final String METHOD_OPTIONS = "OPTIONS";
+    private static final String METHOD_POST = "POST";
+    private static final String METHOD_PUT = "PUT";
+    private static final String METHOD_TRACE = "TRACE";
+
+    private static final String HEADER_IFMODSINCE = "If-Modified-Since";
+    private static final String HEADER_LASTMOD = "Last-Modified";
+    
+    private static final String LSTRING_FILE =
+        "javax.servlet.http.LocalStrings";
+    private static ResourceBundle lStrings =
+        ResourceBundle.getBundle(LSTRING_FILE);
+   
+    
+    /**
+     * Does nothing, because this is an abstract class.
+     * 
+     */
+
+    public HttpServlet() { }
+    
+
+    /**
+     *
+     * Called by the server (via the <code>service</code> method) to
+     * allow a servlet to handle a GET request. 
+     *
+     * <p>Overriding this method to support a GET request also
+     * automatically supports an HTTP HEAD request. A HEAD
+     * request is a GET request that returns no body in the
+     * response, only the request header fields.
+     *
+     * <p>When overriding this method, read the request data,
+     * write the response headers, get the response's writer or 
+     * output stream object, and finally, write the response data.
+     * It's best to include content type and encoding. When using
+     * a <code>PrintWriter</code> object to return the response,
+     * set the content type before accessing the
+     * <code>PrintWriter</code> object.
+     *
+     * <p>The servlet container must write the headers before
+     * committing the response, because in HTTP the headers must be sent
+     * before the response body.
+     *
+     * <p>Where possible, set the Content-Length header (with the
+     * {@link javax.servlet.ServletResponse#setContentLength} method),
+     * to allow the servlet container to use a persistent connection 
+     * to return its response to the client, improving performance.
+     * The content length is automatically set if the entire response fits
+     * inside the response buffer.
+     *
+     * <p>When using HTTP 1.1 chunked encoding (which means that the response
+     * has a Transfer-Encoding header), do not set the Content-Length header.
+     *
+     * <p>The GET method should be safe, that is, without
+     * any side effects for which users are held responsible.
+     * For example, most form queries have no side effects.
+     * If a client request is intended to change stored data,
+     * the request should use some other HTTP method.
+     *
+     * <p>The GET method should also be idempotent, meaning
+     * that it can be safely repeated. Sometimes making a
+     * method safe also makes it idempotent. For example, 
+     * repeating queries is both safe and idempotent, but
+     * buying a product online or modifying data is neither
+     * safe nor idempotent. 
+     *
+     * <p>If the request is incorrectly formatted, <code>doGet</code>
+     * returns an HTTP "Bad Request" message.
+     * 
+     * @param req   an {@link HttpServletRequest} object that
+     *                  contains the request the client has made
+     *                  of the servlet
+     *
+     * @param resp  an {@link HttpServletResponse} object that
+     *                  contains the response the servlet sends
+     *                  to the client
+     * 
+     * @throws IOException   if an input or output error is 
+     *                              detected when the servlet handles
+     *                              the GET request
+     *
+     * @throws ServletException  if the request for the GET
+     *                                  could not be handled
+     *
+     * @see javax.servlet.ServletResponse#setContentType
+     */
+
+    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        String protocol = req.getProtocol();
+        String msg = lStrings.getString("http.method_get_not_supported");
+        if (protocol.endsWith("1.1")) {
+            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+        } else {
+            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+        }
+    }
+
+
+    /**
+     *
+     * Returns the time the <code>HttpServletRequest</code>
+     * object was last modified,
+     * in milliseconds since midnight January 1, 1970 GMT.
+     * If the time is unknown, this method returns a negative
+     * number (the default).
+     *
+     * <p>Servlets that support HTTP GET requests and can quickly determine
+     * their last modification time should override this method.
+     * This makes browser and proxy caches work more effectively,
+     * reducing the load on server and network resources.
+     *
+     * @param req   the <code>HttpServletRequest</code> 
+     *                  object that is sent to the servlet
+     *
+     * @return  a   <code>long</code> integer specifying
+     *                  the time the <code>HttpServletRequest</code>
+     *                  object was last modified, in milliseconds
+     *                  since midnight, January 1, 1970 GMT, or
+     *                  -1 if the time is not known
+     */
+
+    protected long getLastModified(HttpServletRequest req) {
+        return -1;
+    }
+
+
+    /**
+     * 
+     *
+     * <p>Receives an HTTP HEAD request from the protected
+     * <code>service</code> method and handles the
+     * request.
+     * The client sends a HEAD request when it wants
+     * to see only the headers of a response, such as
+     * Content-Type or Content-Length. The HTTP HEAD
+     * method counts the output bytes in the response
+     * to set the Content-Length header accurately.
+     *
+     * <p>If you override this method, you can avoid computing
+     * the response body and just set the response headers
+     * directly to improve performance. Make sure that the
+     * <code>doHead</code> method you write is both safe
+     * and idempotent (that is, protects itself from being
+     * called multiple times for one HTTP HEAD request).
+     *
+     * <p>If the HTTP HEAD request is incorrectly formatted,
+     * <code>doHead</code> returns an HTTP "Bad Request"
+     * message.
+     *
+     * @param req   the request object that is passed to the servlet
+     *                        
+     * @param resp  the response object that the servlet
+     *                  uses to return the headers to the clien
+     *
+     * @throws IOException   if an input or output error occurs
+     *
+     * @throws ServletException  if the request for the HEAD
+     *                                  could not be handled
+     */
+    protected void doHead(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        NoBodyResponse response = new NoBodyResponse(resp);
+        
+        doGet(req, response);
+        response.setContentLength();
+    }
+
+
+    /**
+     *
+     * Called by the server (via the <code>service</code> method)
+     * to allow a servlet to handle a POST request.
+     *
+     * The HTTP POST method allows the client to send
+     * data of unlimited length to the Web server a single time
+     * and is useful when posting information such as
+     * credit card numbers.
+     *
+     * <p>When overriding this method, read the request data,
+     * write the response headers, get the response's writer or output
+     * stream object, and finally, write the response data. It's best 
+     * to include content type and encoding. When using a
+     * <code>PrintWriter</code> object to return the response, set the 
+     * content type before accessing the <code>PrintWriter</code> object. 
+     *
+     * <p>The servlet container must write the headers before committing the
+     * response, because in HTTP the headers must be sent before the 
+     * response body.
+     *
+     * <p>Where possible, set the Content-Length header (with the
+     * {@link javax.servlet.ServletResponse#setContentLength} method),
+     * to allow the servlet container to use a persistent connection 
+     * to return its response to the client, improving performance.
+     * The content length is automatically set if the entire response fits
+     * inside the response buffer.  
+     *
+     * <p>When using HTTP 1.1 chunked encoding (which means that the response
+     * has a Transfer-Encoding header), do not set the Content-Length header. 
+     *
+     * <p>This method does not need to be either safe or idempotent.
+     * Operations requested through POST can have side effects for
+     * which the user can be held accountable, for example, 
+     * updating stored data or buying items online.
+     *
+     * <p>If the HTTP POST request is incorrectly formatted,
+     * <code>doPost</code> returns an HTTP "Bad Request" message.
+     *
+     *
+     * @param req   an {@link HttpServletRequest} object that
+     *                  contains the request the client has made
+     *                  of the servlet
+     *
+     * @param resp  an {@link HttpServletResponse} object that
+     *                  contains the response the servlet sends
+     *                  to the client
+     * 
+     * @throws IOException   if an input or output error is 
+     *                              detected when the servlet handles
+     *                              the request
+     *
+     * @throws ServletException  if the request for the POST
+     *                                  could not be handled
+     *
+     * @see javax.servlet.ServletOutputStream
+     * @see javax.servlet.ServletResponse#setContentType
+     */
+    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        String protocol = req.getProtocol();
+        String msg = lStrings.getString("http.method_post_not_supported");
+        if (protocol.endsWith("1.1")) {
+            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+        } else {
+            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+        }
+    }
+
+
+    /**
+     * Called by the server (via the <code>service</code> method)
+     * to allow a servlet to handle a PUT request.
+     *
+     * The PUT operation allows a client to 
+     * place a file on the server and is similar to 
+     * sending a file by FTP.
+     *
+     * <p>When overriding this method, leave intact
+     * any content headers sent with the request (including
+     * Content-Length, Content-Type, Content-Transfer-Encoding,
+     * Content-Encoding, Content-Base, Content-Language, Content-Location,
+     * Content-MD5, and Content-Range). If your method cannot
+     * handle a content header, it must issue an error message
+     * (HTTP 501 - Not Implemented) and discard the request.
+     * For more information on HTTP 1.1, see RFC 2616
+     * <a href="http://www.ietf.org/rfc/rfc2616.txt"></a>.
+     *
+     * <p>This method does not need to be either safe or idempotent.
+     * Operations that <code>doPut</code> performs can have side
+     * effects for which the user can be held accountable. When using
+     * this method, it may be useful to save a copy of the
+     * affected URL in temporary storage.
+     *
+     * <p>If the HTTP PUT request is incorrectly formatted,
+     * <code>doPut</code> returns an HTTP "Bad Request" message.
+     *
+     * @param req   the {@link HttpServletRequest} object that
+     *                  contains the request the client made of
+     *                  the servlet
+     *
+     * @param resp  the {@link HttpServletResponse} object that
+     *                  contains the response the servlet returns
+     *                  to the client
+     *
+     * @throws IOException   if an input or output error occurs
+     *                              while the servlet is handling the
+     *                              PUT request
+     *
+     * @throws ServletException  if the request for the PUT
+     *                                  cannot be handled
+     */
+    protected void doPut(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        String protocol = req.getProtocol();
+        String msg = lStrings.getString("http.method_put_not_supported");
+        if (protocol.endsWith("1.1")) {
+            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+        } else {
+            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+        }
+    }
+
+
+    /**
+     * Called by the server (via the <code>service</code> method)
+     * to allow a servlet to handle a DELETE request.
+     *
+     * The DELETE operation allows a client to remove a document
+     * or Web page from the server.
+     * 
+     * <p>This method does not need to be either safe
+     * or idempotent. Operations requested through
+     * DELETE can have side effects for which users
+     * can be held accountable. When using
+     * this method, it may be useful to save a copy of the
+     * affected URL in temporary storage.
+     *
+     * <p>If the HTTP DELETE request is incorrectly formatted,
+     * <code>doDelete</code> returns an HTTP "Bad Request"
+     * message.
+     *
+     * @param req   the {@link HttpServletRequest} object that
+     *                  contains the request the client made of
+     *                  the servlet
+     *
+     * @param resp  the {@link HttpServletResponse} object that
+     *                  contains the response the servlet returns
+     *                  to the client                                
+     *
+     * @throws IOException   if an input or output error occurs
+     *                              while the servlet is handling the
+     *                              DELETE request
+     *
+     * @throws ServletException  if the request for the
+     *                                  DELETE cannot be handled
+     */
+    protected void doDelete(HttpServletRequest req,
+                            HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        String protocol = req.getProtocol();
+        String msg = lStrings.getString("http.method_delete_not_supported");
+        if (protocol.endsWith("1.1")) {
+            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
+        } else {
+            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
+        }
+    }
+    
+
+    private Method[] getAllDeclaredMethods(Class<? extends HttpServlet> c) {
+
+        Class<?> clazz = c;
+        Method[] allMethods = null;
+
+        while (!clazz.equals(HttpServlet.class)) {
+            Method[] thisMethods = clazz.getDeclaredMethods();
+            if (allMethods != null && allMethods.length > 0) {
+                Method[] subClassMethods = allMethods;
+                allMethods =
+                    new Method[thisMethods.length + subClassMethods.length];
+                System.arraycopy(thisMethods, 0, allMethods, 0,
+                                 thisMethods.length);
+                System.arraycopy(subClassMethods, 0, allMethods, thisMethods.length,
+                                 subClassMethods.length);
+            } else {
+                allMethods = thisMethods;
+            }
+
+            clazz = clazz.getSuperclass();
+        }
+
+        return ((allMethods != null) ? allMethods : new Method[0]);
+    }
+
+
+    /**
+     * Called by the server (via the <code>service</code> method)
+     * to allow a servlet to handle a OPTIONS request.
+     *
+     * The OPTIONS request determines which HTTP methods 
+     * the server supports and
+     * returns an appropriate header. For example, if a servlet
+     * overrides <code>doGet</code>, this method returns the
+     * following header:
+     *
+     * <p><code>Allow: GET, HEAD, TRACE, OPTIONS</code>
+     *
+     * <p>There's no need to override this method unless the
+     * servlet implements new HTTP methods, beyond those 
+     * implemented by HTTP 1.1.
+     *
+     * @param req   the {@link HttpServletRequest} object that
+     *                  contains the request the client made of
+     *                  the servlet
+     *
+     * @param resp  the {@link HttpServletResponse} object that
+     *                  contains the response the servlet returns
+     *                  to the client                                
+     *
+     * @throws IOException   if an input or output error occurs
+     *                              while the servlet is handling the
+     *                              OPTIONS request
+     *
+     * @throws ServletException  if the request for the
+     *                                  OPTIONS cannot be handled
+     */
+    protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        Method[] methods = getAllDeclaredMethods(this.getClass());
+        
+        boolean ALLOW_GET = false;
+        boolean ALLOW_HEAD = false;
+        boolean ALLOW_POST = false;
+        boolean ALLOW_PUT = false;
+        boolean ALLOW_DELETE = false;
+        boolean ALLOW_TRACE = true;
+        boolean ALLOW_OPTIONS = true;
+        
+        for (int i=0; i<methods.length; i++) {
+            String methodName = methods[i].getName();
+            
+            if (methodName.equals("doGet")) {
+                ALLOW_GET = true;
+                ALLOW_HEAD = true;
+            } else if (methodName.equals("doPost")) {
+                ALLOW_POST = true;
+            } else if (methodName.equals("doPut")) {
+                ALLOW_PUT = true;
+            } else if (methodName.equals("doDelete")) {
+                ALLOW_DELETE = true;
+            }
+            
+        }
+        
+        // we know "allow" is not null as ALLOW_OPTIONS = true
+        // when this method is invoked
+        StringBuilder allow = new StringBuilder();
+        if (ALLOW_GET) {
+            allow.append(METHOD_GET);
+        }
+        if (ALLOW_HEAD) {
+            if (allow.length() > 0) {
+                allow.append(", ");
+            }
+            allow.append(METHOD_HEAD);
+        }
+        if (ALLOW_POST) {
+            if (allow.length() > 0) {
+                allow.append(", ");
+            }
+            allow.append(METHOD_POST);
+        }
+        if (ALLOW_PUT) {
+            if (allow.length() > 0) {
+                allow.append(", ");
+            }
+            allow.append(METHOD_PUT);
+        }
+        if (ALLOW_DELETE) {
+            if (allow.length() > 0) {
+                allow.append(", ");
+            }
+            allow.append(METHOD_DELETE);
+        }
+        if (ALLOW_TRACE) {
+            if (allow.length() > 0) {
+                allow.append(", ");
+            }
+            allow.append(METHOD_TRACE);
+        }
+        if (ALLOW_OPTIONS) {
+            if (allow.length() > 0) {
+                allow.append(", ");
+            }
+            allow.append(METHOD_OPTIONS);
+        }
+        
+        resp.setHeader("Allow", allow.toString());
+    }
+    
+    
+    /**
+     * Called by the server (via the <code>service</code> method)
+     * to allow a servlet to handle a TRACE request.
+     *
+     * A TRACE returns the headers sent with the TRACE
+     * request to the client, so that they can be used in
+     * debugging. There's no need to override this method. 
+     *
+     * @param req   the {@link HttpServletRequest} object that
+     *                  contains the request the client made of
+     *                  the servlet
+     *
+     *
+     * @param resp  the {@link HttpServletResponse} object that
+     *                  contains the response the servlet returns
+     *                  to the client                                
+     *
+     * @throws IOException   if an input or output error occurs
+     *                              while the servlet is handling the
+     *                              TRACE request
+     *
+     * @throws ServletException  if the request for the
+     *                                  TRACE cannot be handled
+     */
+    protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 
+        throws ServletException, IOException
+    {
+        
+        int responseLength;
+
+        String CRLF = "\r\n";
+        StringBuilder buffer = new StringBuilder("TRACE ").append(req.getRequestURI())
+            .append(" ").append(req.getProtocol());
+
+        Enumeration<String> reqHeaderEnum = req.getHeaderNames();
+
+        while( reqHeaderEnum.hasMoreElements() ) {
+            String headerName = reqHeaderEnum.nextElement();
+            buffer.append(CRLF).append(headerName).append(": ")
+                .append(req.getHeader(headerName));
+        }
+
+        buffer.append(CRLF);
+
+        responseLength = buffer.length();
+
+        resp.setContentType("message/http");
+        resp.setContentLength(responseLength);
+        ServletOutputStream out = resp.getOutputStream();
+        out.print(buffer.toString());
+    }
+
+
+    /**
+     * Receives standard HTTP requests from the public
+     * <code>service</code> method and dispatches
+     * them to the <code>do</code><i>XXX</i> methods defined in 
+     * this class. This method is an HTTP-specific version of the 
+     * {@link javax.servlet.Servlet#service} method. There's no
+     * need to override this method.
+     *
+     * @param req   the {@link HttpServletRequest} object that
+     *                  contains the request the client made of
+     *                  the servlet
+     *
+     * @param resp  the {@link HttpServletResponse} object that
+     *                  contains the response the servlet returns
+     *                  to the client                                
+     *
+     * @throws IOException   if an input or output error occurs
+     *                              while the servlet is handling the
+     *                              HTTP request
+     *
+     * @throws ServletException  if the HTTP request
+     *                                  cannot be handled
+     * 
+     * @see javax.servlet.Servlet#service
+     */
+    protected void service(HttpServletRequest req, HttpServletResponse resp)
+        throws ServletException, IOException
+    {
+        String method = req.getMethod();
+
+        if (method.equals(METHOD_GET)) {
+            long lastModified = getLastModified(req);
+            if (lastModified == -1) {
+                // servlet doesn't support if-modified-since, no reason
+                // to go through further expensive logic
+                doGet(req, resp);
+            } else {
+                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
+                if (ifModifiedSince < lastModified) {
+                    // If the servlet mod time is later, call doGet()
+                    // Round down to the nearest second for a proper compare
+                    // A ifModifiedSince of -1 will always be less
+                    maybeSetLastModified(resp, lastModified);
+                    doGet(req, resp);
+                } else {
+                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+                }
+            }
+
+        } else if (method.equals(METHOD_HEAD)) {
+            long lastModified = getLastModified(req);
+            maybeSetLastModified(resp, lastModified);
+            doHead(req, resp);
+
+        } else if (method.equals(METHOD_POST)) {
+            doPost(req, resp);
+            
+        } else if (method.equals(METHOD_PUT)) {
+            doPut(req, resp);
+            
+        } else if (method.equals(METHOD_DELETE)) {
+            doDelete(req, resp);
+            
+        } else if (method.equals(METHOD_OPTIONS)) {
+            doOptions(req,resp);
+            
+        } else if (method.equals(METHOD_TRACE)) {
+            doTrace(req,resp);
+            
+        } else {
+            //
+            // Note that this means NO servlet supports whatever
+            // method was requested, anywhere on this server.
+            //
+
+            String errMsg = lStrings.getString("http.method_not_implemented");
+            Object[] errArgs = new Object[1];
+            errArgs[0] = method;
+            errMsg = MessageFormat.format(errMsg, errArgs);
+            
+            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
+        }
+    }
+    
+
+    /*
+     * Sets the Last-Modified entity header field, if it has not
+     * already been set and if the value is meaningful.  Called before
+     * doGet, to ensure that headers are set before response data is
+     * written.  A subclass might have set this header already, so we
+     * check.
+     */
+    private void maybeSetLastModified(HttpServletResponse resp,
+                                      long lastModified) {
+        if (resp.containsHeader(HEADER_LASTMOD))
+            return;
+        if (lastModified >= 0)
+            resp.setDateHeader(HEADER_LASTMOD, lastModified);
+    }
+   
+    
+    /**
+     * Dispatches client requests to the protected
+     * <code>service</code> method. There's no need to
+     * override this method.
+     * 
+     * @param req   the {@link HttpServletRequest} object that
+     *                  contains the request the client made of
+     *                  the servlet
+     *
+     * @param res   the {@link HttpServletResponse} object that
+     *                  contains the response the servlet returns
+     *                  to the client                                
+     *
+     * @throws IOException   if an input or output error occurs
+     *                              while the servlet is handling the
+     *                              HTTP request
+     *
+     * @throws ServletException  if the HTTP request cannot
+     *                                  be handled or if either parameter is not
+     *                           an instance of its respective {@link HttpServletRequest}
+     *                           or {@link HttpServletResponse} counterparts.
+     * 
+     * @see javax.servlet.Servlet#service
+     */
+    @Override
+    public void service(ServletRequest req, ServletResponse res)
+        throws ServletException, IOException
+    {
+        HttpServletRequest  request;
+        HttpServletResponse response;
+        
+        if (!(req instanceof HttpServletRequest &&
+                res instanceof HttpServletResponse)) {
+            throw new ServletException("non-HTTP request or response");
+        }
+
+        request = (HttpServletRequest) req;
+        response = (HttpServletResponse) res;
+
+        service(request, response);
+    }
+}
+
+
+/*
+ * A response that includes no body, for use in (dumb) "HEAD" support.
+ * This just swallows that body, counting the bytes in order to set
+ * the content length appropriately.  All other methods delegate directly
+ * to the wrapped HTTP Servlet Response object.
+ */
+// file private
+class NoBodyResponse extends HttpServletResponseWrapper {
+
+    private static final ResourceBundle lStrings
+        = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");
+
+    private NoBodyOutputStream noBody;
+    private PrintWriter writer;
+    private boolean didSetContentLength;
+    private boolean usingOutputStream;
+
+    // file private
+    NoBodyResponse(HttpServletResponse r) {
+        super(r);
+        noBody = new NoBodyOutputStream();
+    }
+
+    // file private
+    void setContentLength() {
+        if (!didSetContentLength) {
+            if (writer != null) {
+                writer.flush();
+            }
+            setContentLength(noBody.getContentLength());
+        }
+    }
+
+    @Override
+    public void setContentLength(int len) {
+        super.setContentLength(len);
+        didSetContentLength = true;
+    }
+
+    @Override
+    public void setContentLengthLong(long len) {
+        super.setContentLengthLong(len);
+        didSetContentLength = true;
+    }
+
+    @Override
+    public void setHeader(String name, String value) {
+        super.setHeader(name, value);
+        checkHeader(name);
+    }
+
+    @Override
+    public void addHeader(String name, String value) {
+        super.addHeader(name, value);
+        checkHeader(name);
+    }
+
+    @Override
+    public void setIntHeader(String name, int value) {
+        super.setIntHeader(name, value);
+        checkHeader(name);
+    }
+
+    @Override
+    public void addIntHeader(String name, int value) {
+        super.addIntHeader(name, value);
+        checkHeader(name);
+    }
+
+    private void checkHeader(String name) {
+        if ("content-length".equalsIgnoreCase(name)) {
+            didSetContentLength = true;
+        }
+    }
+
+    @Override
+    public ServletOutputStream getOutputStream() throws IOException {
+
+        if (writer != null) {
+            throw new IllegalStateException(
+                lStrings.getString("err.ise.getOutputStream"));
+        }
+        usingOutputStream = true;
+
+        return noBody;
+    }
+
+    @Override
+    public PrintWriter getWriter() throws UnsupportedEncodingException {
+
+        if (usingOutputStream) {
+            throw new IllegalStateException(
+                lStrings.getString("err.ise.getWriter"));
+        }
+
+        if (writer == null) {
+            OutputStreamWriter w = new OutputStreamWriter(
+                noBody, getCharacterEncoding());
+            writer = new PrintWriter(w);
+        }
+
+        return writer;
+    }
+}
+
+
+/*
+ * Servlet output stream that gobbles up all its data.
+ */
+// file private
+class NoBodyOutputStream extends ServletOutputStream {
+
+    private static final String LSTRING_FILE =
+        "javax.servlet.http.LocalStrings";
+    private static ResourceBundle lStrings =
+        ResourceBundle.getBundle(LSTRING_FILE);
+
+    private int contentLength = 0;
+
+    // file private
+    NoBodyOutputStream() {}
+
+    // file private
+    int getContentLength() {
+        return contentLength;
+    }
+
+    @Override
+    public void write(int b) {
+        contentLength++;
+    }
+
+    @Override
+    public void write(byte buf[], int offset, int len)
+        throws IOException
+    {
+        if (buf == null) {
+            throw new NullPointerException(
+                    lStrings.getString("err.io.nullArray"));
+        }
+
+        if (offset < 0 || len < 0 || offset+len > buf.length) {
+            String msg = lStrings.getString("err.io.indexOutOfBounds");
+            Object[] msgArgs = new Object[3];
+            msgArgs[0] = Integer.valueOf(offset);
+            msgArgs[1] = Integer.valueOf(len);
+            msgArgs[2] = Integer.valueOf(buf.length);
+            msg = MessageFormat.format(msg, msgArgs);
+            throw new IndexOutOfBoundsException(msg);
+        }
+
+        contentLength += len;
+    }
+
+
+    public boolean isReady() {
+        return false;
+    }
+
+    public void setWriteListener(WriteListener writeListener) {
+
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletMapping.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletMapping.java
new file mode 100644
index 0000000..3e057e2
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletMapping.java
@@ -0,0 +1,174 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+/**
+ * <p>Allows runtime discovery of the manner in which the {@link
+ * HttpServlet} for the current {@link HttpServletRequest} was invoked.
+ * Invoking any of the methods must not block the caller.  The
+ * implementation must be thread safe.  Instances are immutable and are
+ * returned from {@link HttpServletRequest#getHttpServletMapping}.</p>
+ *
+ * <p>Following are some illustrative examples for various combinations
+ * of mappings.  Consider the following Servlet declaration:</p>
+ *
+ * <pre><code>
+ * &lt;servlet&gt;
+ *     &lt;servlet-name&gt;MyServlet&lt;/servlet-name&gt;
+ *     &lt;servlet-class&gt;MyServlet&lt;/servlet-class&gt;
+ * &lt;/servlet&gt;
+ * &lt;servlet-mapping&gt;
+ *     &lt;servlet-name&gt;MyServlet&lt;/servlet-name&gt;
+ *     &lt;url-pattern&gt;/MyServlet&lt;/url-pattern&gt;
+ *     &lt;url-pattern&gt;""&lt;/url-pattern&gt;
+ *     &lt;url-pattern&gt;*.extension&lt;/url-pattern&gt;
+ *     &lt;url-pattern&gt;/path/*&lt;/url-pattern&gt;
+ * &lt;/servlet-mapping&gt;
+ * </code></pre>
+ *
+ * <p>The expected values of the properties for various incoming URI
+ * path values are as shown in this table.  The {@code servletName}
+ * column is omitted as its value is always {@code MyServlet}.</p>
+ * 
+ * <table border="1">
+ *   <caption>Expected values of properties for various URI paths</caption>
+ *   <tr>
+ *     <th>URI Path (in quotes)</th>
+ *     <th>matchValue</th>
+ *     <th>pattern</th>
+ *     <th>mappingMatch</th>
+ *   </tr>
+ *   <tr>
+ *     <td>""</td>
+ *     <td>""</td>
+ *     <td>""</td>
+ *     <td>CONTEXT_ROOT</td>
+ *   </tr>
+ *   <tr>
+ *     <td>"/index.html"</td>
+ *     <td>""</td>
+ *     <td>/</td>
+ *     <td>DEFAULT</td>
+ *   </tr>
+ *   <tr>
+ *     <td>"/MyServlet"</td>
+ *     <td>MyServlet</td>
+ *     <td>/MyServlet</td>
+ *     <td>EXACT</td>
+ *   </tr>
+ *   <tr>
+ *     <td>"/foo.extension"</td>
+ *     <td>foo</td>
+ *     <td>*.extension</td>
+ *     <td>EXTENSION</td>
+ *   </tr>
+ *   <tr>
+ *     <td>"/path/foo"</td>
+ *     <td>foo</td>
+ *     <td>/path/*</td>
+ *     <td>PATH</td>
+ *   </tr>  
+ *   
+ * </table>
+ * 
+ * @since 4.0
+ */
+public interface HttpServletMapping {
+
+
+    
+    /**
+     * <p>Return the portion of the URI path that caused this request to
+     * be matched.  If the {@link getMappingMatch} value is {@code
+     * CONTEXT_ROOT} or {@code DEFAULT}, this method must return the
+     * empty string.  If the {@link getMappingMatch} value is {@code
+     * EXACT}, this method must return the portion of the path that
+     * matched the servlet, omitting any leading slash.  If the {@link
+     * getMappingMatch} value is {@code EXTENSION} or {@code PATH}, this
+     * method must return the value that matched the '*'.  See the class
+     * javadoc for examples. </p>
+     * 
+     * @return the match.
+     * 
+     * @since 4.0
+     */
+    public String getMatchValue();
+
+    /**
+     * <p>Return the String representation for the {@code url-pattern}
+     * for this mapping.  If the {@link getMappingMatch} value is {@code
+     * CONTEXT_ROOT} or {@code DEFAULT}, this method must return the
+     * empty string. If the {@link getMappingMatch} value is {@code
+     * EXTENSION}, this method must return the pattern, without any
+     * leading slash.  Otherwise, this method returns the pattern
+     * exactly as specified in the descriptor or Java configuration.</p>
+     * 
+     * @return the String representation for the
+     * {@code url-pattern} for this mapping. 
+     * 
+     * @since 4.0
+     */
+    public String getPattern();
+    
+    /**
+     * <p>Return the String representation for the {@code servlet-name}
+     * for this mapping.  If the Servlet providing the response is the
+     * default servlet, the return from this method is the name of the
+     * defautl servlet, which is container specific.</p>
+     * 
+     * @return the String representation for the {@code servlet-name}
+     * for this mapping.
+     * 
+     * @since 4.0
+     */
+    public String getServletName();
+
+    /**
+     * <p>Return the {@link MappingMatch} for this 
+     * instance</p> 
+     * 
+     * @return the {@code MappingMatch} for this instance.
+     * 
+     * @since 4.0
+     */
+    public MappingMatch getMappingMatch();
+    
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletRequest.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletRequest.java
new file mode 100644
index 0000000..3f0a0d0
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletRequest.java
@@ -0,0 +1,871 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.io.IOException;
+import java.util.*;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+
+/**
+ *
+ * Extends the {@link javax.servlet.ServletRequest} interface to provide
+ * request information for HTTP servlets.
+ *
+ * <p>The servlet container creates an <code>HttpServletRequest</code>
+ * object and passes it as an argument to the servlet's service
+ * methods (<code>doGet</code>, <code>doPost</code>, etc).
+ *
+ *
+ * @author 	Various
+ */
+
+public interface HttpServletRequest extends ServletRequest {
+
+    /**
+     * String identifier for Basic authentication. Value "BASIC"
+     */
+    public static final String BASIC_AUTH = "BASIC";
+
+    /**
+     * String identifier for Form authentication. Value "FORM"
+     */
+    public static final String FORM_AUTH = "FORM";
+
+    /**
+     * String identifier for Client Certificate authentication. Value "CLIENT_CERT"
+     */
+    public static final String CLIENT_CERT_AUTH = "CLIENT_CERT";
+
+    /**
+     * String identifier for Digest authentication. Value "DIGEST"
+     */
+    public static final String DIGEST_AUTH = "DIGEST";
+
+    /**
+     * Returns the name of the authentication scheme used to protect
+     * the servlet. All servlet containers support basic, form and client
+     * certificate authentication, and may additionally support digest
+     * authentication.
+     * If the servlet is not authenticated <code>null</code> is returned.
+     *
+     * <p>Same as the value of the CGI variable AUTH_TYPE.
+     *
+     * @return		one of the static members BASIC_AUTH,
+     *			FORM_AUTH, CLIENT_CERT_AUTH, DIGEST_AUTH
+     *			(suitable for == comparison) or
+     *			the container-specific string indicating
+     *			the authentication scheme, or
+     *			<code>null</code> if the request was
+     *			not authenticated.
+     */
+    public String getAuthType();
+
+    /**
+     * Returns an array containing all of the <code>Cookie</code>
+     * objects the client sent with this request.
+     * This method returns <code>null</code> if no cookies were sent.
+     *
+     * @return		an array of all the <code>Cookies</code>
+     *			included with this request, or <code>null</code>
+     *			if the request has no cookies
+     */
+    public Cookie[] getCookies();
+
+    /**
+     * Returns the value of the specified request header
+     * as a <code>long</code> value that represents a
+     * <code>Date</code> object. Use this method with
+     * headers that contain dates, such as
+     * <code>If-Modified-Since</code>.
+     *
+     * <p>The date is returned as
+     * the number of milliseconds since January 1, 1970 GMT.
+     * The header name is case insensitive.
+     *
+     * <p>If the request did not have a header of the
+     * specified name, this method returns -1. If the header
+     * can't be converted to a date, the method throws
+     * an <code>IllegalArgumentException</code>.
+     *
+     * @param name		a <code>String</code> specifying the
+     *				name of the header
+     *
+     * @return			a <code>long</code> value
+     *				representing the date specified
+     *				in the header expressed as
+     *				the number of milliseconds
+     *				since January 1, 1970 GMT,
+     *				or -1 if the named header
+     *				was not included with the
+     *				request
+     *
+     * @exception	IllegalArgumentException	If the header value
+     *							can't be converted
+     *							to a date
+     */
+    public long getDateHeader(String name);
+
+    /**
+     * Returns the value of the specified request header
+     * as a <code>String</code>. If the request did not include a header
+     * of the specified name, this method returns <code>null</code>.
+     * If there are multiple headers with the same name, this method
+     * returns the first head in the request.
+     * The header name is case insensitive. You can use
+     * this method with any request header.
+     *
+     * @param name		a <code>String</code> specifying the
+     *				header name
+     *
+     * @return			a <code>String</code> containing the
+     *				value of the requested
+     *				header, or <code>null</code>
+     *				if the request does not
+     *				have a header of that name
+     */
+    public String getHeader(String name);
+
+    /**
+     * Returns all the values of the specified request header
+     * as an <code>Enumeration</code> of <code>String</code> objects.
+     *
+     * <p>Some headers, such as <code>Accept-Language</code> can be sent
+     * by clients as several headers each with a different value rather than
+     * sending the header as a comma separated list.
+     *
+     * <p>If the request did not include any headers
+     * of the specified name, this method returns an empty
+     * <code>Enumeration</code>.
+     * The header name is case insensitive. You can use
+     * this method with any request header.
+     *
+     * @param name		a <code>String</code> specifying the
+     *				header name
+     *
+     * @return			an <code>Enumeration</code> containing
+     *                  	the values of the requested header. If
+     *                  	the request does not have any headers of
+     *                  	that name return an empty
+     *                  	enumeration. If
+     *                  	the container does not allow access to
+     *                  	header information, return null
+     */
+    public Enumeration<String> getHeaders(String name);
+
+    /**
+     * Returns an enumeration of all the header names
+     * this request contains. If the request has no
+     * headers, this method returns an empty enumeration.
+     *
+     * <p>Some servlet containers do not allow
+     * servlets to access headers using this method, in
+     * which case this method returns <code>null</code>
+     *
+     * @return			an enumeration of all the
+     *				header names sent with this
+     *				request; if the request has
+     *				no headers, an empty enumeration;
+     *				if the servlet container does not
+     *				allow servlets to use this method,
+     *				<code>null</code>
+     */
+    public Enumeration<String> getHeaderNames();
+
+    /**
+     * Returns the value of the specified request header
+     * as an <code>int</code>. If the request does not have a header
+     * of the specified name, this method returns -1. If the
+     * header cannot be converted to an integer, this method
+     * throws a <code>NumberFormatException</code>.
+     *
+     * <p>The header name is case insensitive.
+     *
+     * @param name		a <code>String</code> specifying the name
+     *				of a request header
+     *
+     * @return			an integer expressing the value
+     * 				of the request header or -1
+     *				if the request doesn't have a
+     *				header of this name
+     *
+     * @exception	NumberFormatException		If the header value
+     *							can't be converted
+     *							to an <code>int</code>
+     */
+    public int getIntHeader(String name);
+
+    /**
+     * <p>Return the {@link HttpServletMapping} by which the {@link
+     * HttpServlet} for this {@code HttpServletRequest} was invoked.
+     * The mappings for any applicable {@link javax.servlet.Filter}s are
+     * not indicated in the result.  If the currently active {@link
+     * javax.servlet.Servlet} invocation was obtained by a call to
+     * {@link ServletRequest#getRequestDispatcher} followed by a call to
+     * {@link RequestDispatcher#forward}, the returned {@code
+     * HttpServletMapping} is the one corresponding to the path used to
+     * obtain the {@link RequestDispatcher}.  If the currently active
+     * {@code Servlet} invocation was obtained by a call to {@link
+     * ServletRequest#getRequestDispatcher} followed by a call to {@link
+     * RequestDispatcher#include}, the returned {@code
+     * HttpServletMapping} is the one corresponding to the path that
+     * caused the first {@code Servlet} in the invocation sequence to be
+     * invoked.  If the currently active {@code Servlet} invocation was
+     * obtained by a call to {@link
+     * javax.servlet.AsyncContext#dispatch}, the returned {@code
+     * HttpServletMapping} is the one corresponding to the path that
+     * caused the first {@code Servlet} in the invocation sequence to be
+     * invoked.  See {@link
+     * javax.servlet.RequestDispatcher#FORWARD_MAPPING}, {@link
+     * javax.servlet.RequestDispatcher#INCLUDE_MAPPING} and {@link
+     * javax.servlet.AsyncContext#ASYNC_MAPPING} for additional request
+     * attributes related to {@code HttpServletMapping}. If the
+     * currently active {@code Servlet} invocation was obtained by a
+     * call to {@link javax.servlet.ServletContext#getNamedDispatcher},
+     * the returned {@code HttpServletMapping} is the one corresponding
+     * to the path for the mapping last applied to this request.</p>
+     * 
+     * <p>The returned object is immutable.  Servlet 4.0 compliant
+     * implementations must override this method.</p>
+     * 
+     * @implSpec The default implementation returns a {@code
+     * HttpServletMapping} that returns the empty string for the match
+     * value, pattern and servlet name and {@code null} for the match
+     * type.
+     *
+     * @return An instance of {@code HttpServletMapping} describing the manner in which
+     * the current request was invoked.
+     * 
+     * @since 4.0
+     */
+    
+    default public HttpServletMapping getHttpServletMapping() {
+        return new HttpServletMapping() {
+            @Override
+            public String getMatchValue() {
+                return "";
+            }
+
+            @Override
+            public String getPattern() {
+                return "";
+            }
+
+            @Override
+            public String getServletName() {
+                return "";
+            }
+
+            @Override
+            public MappingMatch getMappingMatch() {
+               return null;
+            }
+
+            @Override
+            public String toString() {
+                return "MappingImpl{" + "matchValue=" + getMatchValue()
+                        + ", pattern=" + getPattern() + ", servletName=" 
+                        + getServletName() + ", mappingMatch=" + getMappingMatch() 
+                        + "} HttpServletRequest {" + HttpServletRequest.this.toString()
+                        + '}';
+            }
+            
+            
+            
+        };
+    }
+    
+    /**
+     * Returns the name of the HTTP method with which this
+     * request was made, for example, GET, POST, or PUT.
+     * Same as the value of the CGI variable REQUEST_METHOD.
+     *
+     * @return			a <code>String</code>
+     *				specifying the name
+     *				of the method with which
+     *				this request was made
+     */
+    public String getMethod();
+
+    /**
+     * Returns any extra path information associated with
+     * the URL the client sent when it made this request.
+     * The extra path information follows the servlet path
+     * but precedes the query string and will start with
+     * a "/" character.
+     *
+     * <p>This method returns <code>null</code> if there
+     * was no extra path information.
+     *
+     * <p>Same as the value of the CGI variable PATH_INFO.
+     *
+     * @return		a <code>String</code>, decoded by the
+     *			web container, specifying
+     *			extra path information that comes
+     *			after the servlet path but before
+     *			the query string in the request URL;
+     *			or <code>null</code> if the URL does not have
+     *			any extra path information
+     */
+    public String getPathInfo();
+
+    /**
+     * Returns any extra path information after the servlet name
+     * but before the query string, and translates it to a real
+     * path. Same as the value of the CGI variable PATH_TRANSLATED.
+     *
+     * <p>If the URL does not have any extra path information,
+     * this method returns <code>null</code> or the servlet container
+     * cannot translate the virtual path to a real path for any reason
+     * (such as when the web application is executed from an archive).
+     *
+     * The web container does not decode this string.
+     *
+     * @return		a <code>String</code> specifying the
+     *			real path, or <code>null</code> if
+     *			the URL does not have any extra path
+     *			information
+     */
+    public String getPathTranslated();
+
+    /**
+     * Instantiates a new instance of {@link PushBuilder} for issuing server
+     * push responses from the current request. This method returns null
+     * if the current connection does not support server push, or server
+     * push has been disabled by the client via a
+     * {@code SETTINGS_ENABLE_PUSH} settings frame value of {@code 0} (zero).
+     *
+     * @implSpec
+     * The default implementation returns null.
+     *
+     * @return a {@link PushBuilder} for issuing server push responses
+     * from the current request, or null if push is not supported
+     *
+     * @since Servlet 4.0
+     */
+     default public PushBuilder newPushBuilder() {
+         return null;
+     }
+
+    /**
+     * Returns the portion of the request URI that indicates the context
+     * of the request. The context path always comes first in a request
+     * URI. The path starts with a "/" character but does not end with a "/"
+     * character. For servlets in the default (root) context, this method
+     * returns "". The container does not decode this string.
+     *
+     * <p>It is possible that a servlet container may match a context by
+     * more than one context path. In such cases this method will return the
+     * actual context path used by the request and it may differ from the
+     * path returned by the
+     * {@link javax.servlet.ServletContext#getContextPath()} method.
+     * The context path returned by
+     * {@link javax.servlet.ServletContext#getContextPath()}
+     * should be considered as the prime or preferred context path of the
+     * application.
+     *
+     * @return		a <code>String</code> specifying the
+     *			portion of the request URI that indicates the context
+     *			of the request
+     *
+     * @see javax.servlet.ServletContext#getContextPath()
+     */
+    public String getContextPath();
+
+    /**
+     * Returns the query string that is contained in the request
+     * URL after the path. This method returns <code>null</code>
+     * if the URL does not have a query string. Same as the value
+     * of the CGI variable QUERY_STRING.
+     *
+     * @return		a <code>String</code> containing the query
+     *			string or <code>null</code> if the URL
+     *			contains no query string. The value is not
+     *			decoded by the container.
+     */
+    public String getQueryString();
+
+    /**
+     * Returns the login of the user making this request, if the
+     * user has been authenticated, or <code>null</code> if the user
+     * has not been authenticated.
+     * Whether the user name is sent with each subsequent request
+     * depends on the browser and type of authentication. Same as the
+     * value of the CGI variable REMOTE_USER.
+     *
+     * @return		a <code>String</code> specifying the login
+     *			of the user making this request, or <code>null</code>
+     *			if the user login is not known
+     */
+    public String getRemoteUser();
+
+    /**
+     * Returns a boolean indicating whether the authenticated user is included
+     * in the specified logical "role".  Roles and role membership can be
+     * defined using deployment descriptors.  If the user has not been
+     * authenticated, the method returns <code>false</code>.
+     *
+     * <p>The role name "*" should never be used as an argument in calling
+     * <code>isUserInRole</code>. Any call to <code>isUserInRole</code> with
+     * "*" must return false.
+     * If the role-name of the security-role to be tested is "**", and
+     * the application has NOT declared an application security-role with
+     * role-name "**", <code>isUserInRole</code> must only return true if
+     * the user has been authenticated; that is, only when
+     * {@link #getRemoteUser} and {@link #getUserPrincipal} would both return
+     * a non-null value. Otherwise, the container must check
+     * the user for membership in the application role.
+     *
+     * @param role		a <code>String</code> specifying the name
+     *				of the role
+     *
+     * @return		a <code>boolean</code> indicating whether
+     *			the user making this request belongs to a given role;
+     *			<code>false</code> if the user has not been
+     *			authenticated
+     */
+    public boolean isUserInRole(String role);
+
+    /**
+     * Returns a <code>java.security.Principal</code> object containing
+     * the name of the current authenticated user. If the user has not been
+     * authenticated, the method returns <code>null</code>.
+     *
+     * @return		a <code>java.security.Principal</code> containing
+     *			the name of the user making this request;
+     *			<code>null</code> if the user has not been
+     *			authenticated
+     */
+    public java.security.Principal getUserPrincipal();
+
+    /**
+     * Returns the session ID specified by the client. This may
+     * not be the same as the ID of the current valid session
+     * for this request.
+     * If the client did not specify a session ID, this method returns
+     * <code>null</code>.
+     *
+     * @return		a <code>String</code> specifying the session
+     *			ID, or <code>null</code> if the request did
+     *			not specify a session ID
+     *
+     * @see     #isRequestedSessionIdValid
+     */
+    public String getRequestedSessionId();
+
+    /**
+     * Returns the part of this request's URL from the protocol
+     * name up to the query string in the first line of the HTTP request.
+     * The web container does not decode this String.
+     * For example:
+     *
+     * <table summary="Examples of Returned Values">
+     * <tr align=left><th>First line of HTTP request      </th>
+     * <th>     Returned Value</th>
+     * <tr><td>POST /some/path.html HTTP/1.1<td><td>/some/path.html
+     * <tr><td>GET http://foo.bar/a.html HTTP/1.0
+     * <td><td>/a.html
+     * <tr><td>HEAD /xyz?a=b HTTP/1.1<td><td>/xyz
+     * </table>
+     *
+     * <p>To reconstruct an URL with a scheme and host, use
+     * {@link HttpUtils#getRequestURL}.
+     *
+     * @return		a <code>String</code> containing
+     *			the part of the URL from the
+     *			protocol name up to the query string
+     *
+     * @see     HttpUtils#getRequestURL
+     */
+    public String getRequestURI();
+
+    /**
+     * Reconstructs the URL the client used to make the request.
+     * The returned URL contains a protocol, server name, port
+     * number, and server path, but it does not include query
+     * string parameters.
+     *
+     * <p>If this request has been forwarded using
+     * {@link javax.servlet.RequestDispatcher#forward}, the server path in the
+     * reconstructed URL must reflect the path used to obtain the
+     * RequestDispatcher, and not the server path specified by the client.
+     *
+     * <p>Because this method returns a <code>StringBuffer</code>,
+     * not a string, you can modify the URL easily, for example,
+     * to append query parameters.
+     *
+     * <p>This method is useful for creating redirect messages
+     * and for reporting errors.
+     *
+     * @return		a <code>StringBuffer</code> object containing
+     *			the reconstructed URL
+     */
+    public StringBuffer getRequestURL();
+
+    /**
+     * Returns the part of this request's URL that calls
+     * the servlet. This path starts with a "/" character
+     * and includes either the servlet name or a path to
+     * the servlet, but does not include any extra path
+     * information or a query string. Same as the value of
+     * the CGI variable SCRIPT_NAME.
+     *
+     * <p>This method will return an empty string ("") if the
+     * servlet used to process this request was matched using
+     * the "/*" pattern.
+     *
+     * @return		a <code>String</code> containing
+     *			the name or path of the servlet being
+     *			called, as specified in the request URL,
+     *			decoded, or an empty string if the servlet
+     *			used to process the request is matched
+     *			using the "/*" pattern.
+     */
+    public String getServletPath();
+
+    /**
+     * Returns the current <code>HttpSession</code>
+     * associated with this request or, if there is no
+     * current session and <code>create</code> is true, returns
+     * a new session.
+     *
+     * <p>If <code>create</code> is <code>false</code>
+     * and the request has no valid <code>HttpSession</code>,
+     * this method returns <code>null</code>.
+     *
+     * <p>To make sure the session is properly maintained,
+     * you must call this method before
+     * the response is committed. If the container is using cookies
+     * to maintain session integrity and is asked to create a new session
+     * when the response is committed, an IllegalStateException is thrown.
+     *
+     * @param create	<code>true</code> to create
+     *			a new session for this request if necessary;
+     *			<code>false</code> to return <code>null</code>
+     *			if there's no current session
+     *
+     * @return 		the <code>HttpSession</code> associated
+     *			with this request or <code>null</code> if
+     * 			<code>create</code> is <code>false</code>
+     *			and the request has no valid session
+     *
+     * @see #getSession()
+     */
+    public HttpSession getSession(boolean create);
+
+    /**
+     * Returns the current session associated with this request,
+     * or if the request does not have a session, creates one.
+     *
+     * @return		the <code>HttpSession</code> associated
+     *			with this request
+     *
+     * @see	#getSession(boolean)
+     */
+    public HttpSession getSession();
+
+    /**
+     * Change the session id of the current session associated with this
+     * request and return the new session id.
+     *
+     * @return the new session id
+     *
+     * @throws IllegalStateException if there is no session associated
+     * with the request
+     *
+     * @since Servlet 3.1
+     */
+    public String changeSessionId();
+
+    /**
+     * Checks whether the requested session ID is still valid.
+     *
+     * <p>If the client did not specify any session ID, this method returns
+     * <code>false</code>.
+     *
+     * @return			<code>true</code> if this
+     *				request has an id for a valid session
+     *				in the current session context;
+     *				<code>false</code> otherwise
+     *
+     * @see			#getRequestedSessionId
+     * @see			#getSession
+     * @see			HttpSessionContext
+     */
+    public boolean isRequestedSessionIdValid();
+
+    /**
+     * <p>Checks whether the requested session ID was conveyed to the
+     * server as an HTTP cookie.</p>
+     *
+     * @return			<code>true</code> if the session ID
+     *				was conveyed to the server an an HTTP
+     *				cookie; otherwise, <code>false</code>
+     *
+     * @see         #getSession
+     */
+    public boolean isRequestedSessionIdFromCookie();
+
+    /**
+     * <p>Checks whether the requested session ID was conveyed to the
+     * server as part of the request URL.</p>
+     *
+     * @return <code>true</code> if the session ID was conveyed to the
+     *				server as part of a URL; otherwise,
+     *				<code>false</code>
+     *
+     * @see         #getSession
+     */
+    public boolean isRequestedSessionIdFromURL();
+
+    /**
+     * @deprecated		As of Version 2.1 of the Java Servlet
+     *				API, use {@link #isRequestedSessionIdFromURL}
+     *				instead.
+     *
+     * @return <code>true</code> if the session ID was conveyed to the
+     *				server as part of a URL; otherwise,
+     *				<code>false</code>
+     */
+    @Deprecated
+    public boolean isRequestedSessionIdFromUrl();
+
+    /**
+     * Use the container login mechanism configured for the
+     * <code>ServletContext</code> to authenticate the user making
+     * this request.
+     *
+     * <p>This method may modify and commit the argument
+     * <code>HttpServletResponse</code>.
+     *
+     * @param response The <code>HttpServletResponse</code>
+     * associated with this <code>HttpServletRequest</code>
+     *
+     * @return <code>true</code> when non-null values were or have been
+     * established as the values returned by <code>getUserPrincipal</code>,
+     * <code>getRemoteUser</code>, and <code>getAuthType</code>. Return
+     * <code>false</code> if authentication is incomplete and the underlying
+     * login mechanism has committed, in the response, the message (e.g.,
+     * challenge) and HTTP status code to be returned to the user.
+     *
+     * @throws IOException if an input or output error occurred while
+     * reading from this request or writing to the given response
+     *
+     * @throws IllegalStateException if the login mechanism attempted to
+     * modify the response and it was already committed
+     *
+     * @throws ServletException if the authentication failed and
+     * the caller is responsible for handling the error (i.e., the
+     * underlying login mechanism did NOT establish the message and
+     * HTTP status code to be returned to the user)
+     *
+     * @since Servlet 3.0
+     */
+    public boolean authenticate(HttpServletResponse response)
+	throws IOException,ServletException;
+
+    /**
+     * Validate the provided username and password in the password validation
+     * realm used by the web container login mechanism configured for the
+     * <code>ServletContext</code>.
+     *
+     * <p>This method returns without throwing a <code>ServletException</code>
+     * when the login mechanism configured for the <code>ServletContext</code>
+     * supports username password validation, and when, at the time of the
+     * call to login, the identity of the caller of the request had
+     * not been established (i.e, all of <code>getUserPrincipal</code>,
+     * <code>getRemoteUser</code>, and <code>getAuthType</code> return null),
+     * and when validation of the provided credentials is successful.
+     * Otherwise, this method throws a <code>ServletException</code> as
+     * described below.
+     *
+     * <p>When this method returns without throwing an exception, it must
+     * have established non-null values as the values returned by
+     * <code>getUserPrincipal</code>, <code>getRemoteUser</code>, and
+     * <code>getAuthType</code>.
+     *
+     * @param username The <code>String</code> value corresponding to
+     * the login identifier of the user.
+     *
+     * @param password The password <code>String</code> corresponding
+     * to the identified user.
+     *
+     * @exception	ServletException    if the configured login mechanism
+     *                                      does not support username
+     *                                      password authentication, or if a
+     *                                      non-null caller identity had
+     *                                      already been established (prior
+     *                                      to the call to login), or if
+     *                                      validation of the provided
+     *                                      username and password fails.
+     *
+     * @since Servlet 3.0
+     */
+    public void login(String username, String password)
+	throws ServletException;
+
+    /**
+     * Establish <code>null</code> as the value returned when
+     * <code>getUserPrincipal</code>, <code>getRemoteUser</code>,
+     * and <code>getAuthType</code> is called on the request.
+     *
+     * @exception ServletException if logout fails
+     *
+     * @since Servlet 3.0
+     */
+    public void logout() throws ServletException;
+
+    /**
+     * Gets all the {@link Part} components of this request, provided
+     * that it is of type <code>multipart/form-data</code>.
+     *
+     * <p>If this request is of type <code>multipart/form-data</code>, but
+     * does not contain any <code>Part</code> components, the returned
+     * <code>Collection</code> will be empty.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not
+     * affect this <code>HttpServletRequest</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the
+     * <code>Part</code> components of this request
+     *
+     * @throws IOException if an I/O error occurred during the retrieval
+     * of the {@link Part} components of this request
+     *
+     * @throws ServletException if this request is not of type
+     * <code>multipart/form-data</code>
+     *
+     * @throws IllegalStateException if the request body is larger than
+     * <code>maxRequestSize</code>, or any <code>Part</code> in the
+     * request is larger than <code>maxFileSize</code>, or there is no
+     * <code>@MultipartConfig</code> or <code>multipart-config</code> in
+     * deployment descriptors
+     *
+     * @see javax.servlet.annotation.MultipartConfig#maxFileSize
+     * @see javax.servlet.annotation.MultipartConfig#maxRequestSize
+     *
+     * @since Servlet 3.0
+     */
+    public Collection<Part> getParts() throws IOException, ServletException;
+
+    /**
+     * Gets the {@link Part} with the given name.
+     *
+     * @param name the name of the requested <code>Part</code>
+     *
+     * @return The <code>Part</code> with the given name, or
+     * <code>null</code> if this request is of type
+     * <code>multipart/form-data</code>, but does not
+     * contain the requested <code>Part</code>
+     *
+     * @throws IOException if an I/O error occurred during the retrieval
+     * of the requested <code>Part</code>
+     * @throws ServletException if this request is not of type
+     * <code>multipart/form-data</code>
+     * @throws IllegalStateException if the request body is larger than
+     * <code>maxRequestSize</code>, or any <code>Part</code> in the
+     * request is larger than <code>maxFileSize</code>, or there is no
+     * <code>@MultipartConfig</code> or <code>multipart-config</code> in
+     * deployment descriptors
+     *
+     * @see javax.servlet.annotation.MultipartConfig#maxFileSize
+     * @see javax.servlet.annotation.MultipartConfig#maxRequestSize
+     *
+     * @since Servlet 3.0
+     */
+    public Part getPart(String name) throws IOException, ServletException;
+
+    /**
+     * Creates an instance of <code>HttpUpgradeHandler</code> for a given
+     * class and uses it for the http protocol upgrade processing.
+     *
+     * @param <T> The {@code Class}, which extends {@link
+     * HttpUpgradeHandler}, of the {@code handlerClass}.
+
+     * @param handlerClass The <code>HttpUpgradeHandler</code> class used for the upgrade.
+     *
+     * @return an instance of the <code>HttpUpgradeHandler</code>
+     *
+     * @exception IOException if an I/O error occurred during the upgrade
+     * @exception ServletException if the given <code>handlerClass</code> fails to
+     * be instantiated
+     *
+     * @see javax.servlet.http.HttpUpgradeHandler
+     * @see javax.servlet.http.WebConnection
+     *
+     * @since Servlet 3.1
+     */
+    public <T extends HttpUpgradeHandler> T  upgrade(Class<T> handlerClass)
+        throws IOException, ServletException;
+
+    /**
+     * Get the request trailer fields.
+     *
+     * <p>The returned map is not backed by the {@code HttpServletRequest} object,
+     * so changes in the returned map are not reflected in the
+     * {@code HttpServletRequest} object, and vice-versa.</p>
+     * 
+     * <p>{@link #isTrailerFieldsReady()} should be called first to determine
+     * if it is safe to call this method without causing an exception.</p>
+     *
+     * @implSpec
+     * The default implementation returns an empty map.
+     * 
+     * @return A map of trailer fields in which all the keys are in lowercase,
+     * regardless of the case they had at the protocol level. If there are no
+     * trailer fields, yet {@link #isTrailerFieldsReady} is returning true,
+     * the empty map is returned.
+     *
+     * @throws IllegalStateException if {@link #isTrailerFieldsReady()} is false
+     *
+     * @since Servlet 4.0
+     */
+    default public Map<String, String> getTrailerFields() {
+        return Collections.emptyMap();
+    }
+
+    /**
+     * Return a boolean indicating whether trailer fields are ready to read
+     * using {@link #getTrailerFields}.
+     *
+     * This methods returns true immediately if it is known that there is no
+     * trailer in the request, for instance, the underlying protocol (such
+     * as HTTP 1.0) does not supports the trailer fields, or the request is
+     * not in chunked encoding in HTTP 1.1.
+     * And the method also returns true if both of the following conditions
+     * are satisfied:
+     * <ol type="a">
+     *   <li> the application has read all the request data and an EOF
+     *        indication has been returned from the {@link #getReader}
+     *        or {@link #getInputStream}.
+     *   <li> all the trailer fields sent by the client have been received.
+     *        Note that it is possible that the client has sent no trailer fields.
+     * </ol>
+     *
+     * @implSpec
+     * The default implementation returns false.
+     *
+     * @return a boolean whether trailer fields are ready to read
+     *
+     * @since Servlet 4.0
+     */
+    default public boolean isTrailerFieldsReady() {
+        return true;
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletRequestWrapper.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletRequestWrapper.java
new file mode 100644
index 0000000..cb2393e
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletRequestWrapper.java
@@ -0,0 +1,408 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.io.IOException;
+import java.util.*;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequestWrapper;
+
+/**
+ * Provides a convenient implementation of the HttpServletRequest interface
+ * that can be subclassed by developers wishing to adapt the request to a
+ * Servlet.
+ *
+ * <p>This class implements the Wrapper or Decorator pattern. Methods default
+ * to calling through to the wrapped request object.
+ * 
+ * @see javax.servlet.http.HttpServletRequest
+ * @since Servlet 2.3
+ */
+
+
+public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest {
+
+    /** 
+     * Constructs a request object wrapping the given request.
+     * @throws java.lang.IllegalArgumentException if the request is null
+     
+     * @param request the {@link HttpServletRequest} to be wrapped.
+     */
+    public HttpServletRequestWrapper(HttpServletRequest request) {
+        super(request);
+    }
+    
+    private HttpServletRequest _getHttpServletRequest() {
+        return (HttpServletRequest) super.getRequest();
+    }
+
+    /**
+     * The default behavior of this method is to return getAuthType()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getAuthType() {
+        return this._getHttpServletRequest().getAuthType();
+    }
+   
+    /**
+     * The default behavior of this method is to return getCookies()
+     * on the wrapped request object.
+     */
+    @Override
+    public Cookie[] getCookies() {
+        return this._getHttpServletRequest().getCookies();
+    }
+
+    /**
+     * The default behavior of this method is to return getDateHeader(String name)
+     * on the wrapped request object.
+     */
+    @Override
+    public long getDateHeader(String name) {
+        return this._getHttpServletRequest().getDateHeader(name);
+    }
+                
+    /**
+     * The default behavior of this method is to return getHeader(String name)
+     * on the wrapped request object.
+     */
+    @Override
+    public String getHeader(String name) {
+        return this._getHttpServletRequest().getHeader(name);
+    }
+    
+    /**
+     * The default behavior of this method is to return getHeaders(String name)
+     * on the wrapped request object.
+     */
+    @Override
+    public Enumeration<String> getHeaders(String name) {
+        return this._getHttpServletRequest().getHeaders(name);
+    }  
+
+    /**
+     * The default behavior of this method is to return getHeaderNames()
+     * on the wrapped request object.
+     */
+    @Override
+    public Enumeration<String> getHeaderNames() {
+        return this._getHttpServletRequest().getHeaderNames();
+    }
+    
+    /**
+     * The default behavior of this method is to return
+     * getIntHeader(String name) on the wrapped request object.
+     */
+    @Override
+     public int getIntHeader(String name) {
+        return this._getHttpServletRequest().getIntHeader(name);
+    }
+
+    /**
+     * <p>The default behavior of this method is to
+     * return getServletMapping() on the wrapped request object.</p>
+     */
+     @Override
+     public HttpServletMapping getHttpServletMapping() {
+        return this._getHttpServletRequest().getHttpServletMapping();
+    }
+
+    /**
+     * The default behavior of this method is to return getMethod()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getMethod() {
+        return this._getHttpServletRequest().getMethod();
+    }
+    
+    /**
+     * The default behavior of this method is to return getPathInfo()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getPathInfo() {
+        return this._getHttpServletRequest().getPathInfo();
+    }
+
+    /**
+     * The default behavior of this method is to return getPathTranslated()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getPathTranslated() {
+        return this._getHttpServletRequest().getPathTranslated();
+    }
+
+    /**
+     * The default behavior of this method is to return getContextPath()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getContextPath() {
+        return this._getHttpServletRequest().getContextPath();
+    }
+    
+    /**
+     * The default behavior of this method is to return getQueryString()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getQueryString() {
+        return this._getHttpServletRequest().getQueryString();
+    }
+    
+    /**
+     * The default behavior of this method is to return getRemoteUser()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getRemoteUser() {
+        return this._getHttpServletRequest().getRemoteUser();
+    }
+    
+    /**
+     * The default behavior of this method is to return isUserInRole(String role)
+     * on the wrapped request object.
+     */
+    @Override
+    public boolean isUserInRole(String role) {
+        return this._getHttpServletRequest().isUserInRole(role);
+    }
+    
+    /**
+     * The default behavior of this method is to return getUserPrincipal()
+     * on the wrapped request object.
+     */
+    @Override
+    public java.security.Principal getUserPrincipal() {
+        return this._getHttpServletRequest().getUserPrincipal();
+    }
+    
+    /**
+     * The default behavior of this method is to return getRequestedSessionId()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getRequestedSessionId() {
+        return this._getHttpServletRequest().getRequestedSessionId();
+    }
+    
+    /**
+     * The default behavior of this method is to return getRequestURI()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getRequestURI() {
+        return this._getHttpServletRequest().getRequestURI();
+    }
+
+    /**
+     * The default behavior of this method is to return getRequestURL()
+     * on the wrapped request object.
+     */
+    @Override
+    public StringBuffer getRequestURL() {
+        return this._getHttpServletRequest().getRequestURL();
+    }
+        
+    /**
+     * The default behavior of this method is to return getServletPath()
+     * on the wrapped request object.
+     */
+    @Override
+    public String getServletPath() {
+        return this._getHttpServletRequest().getServletPath();
+    }
+    
+    /**
+     * The default behavior of this method is to return getSession(boolean create)
+     * on the wrapped request object.
+     */
+    @Override
+    public HttpSession getSession(boolean create) {
+        return this._getHttpServletRequest().getSession(create);
+    }
+    
+    /**
+     * The default behavior of this method is to return getSession()
+     * on the wrapped request object.
+     */
+    @Override
+    public HttpSession getSession() {
+        return this._getHttpServletRequest().getSession();
+    }
+    
+    /**
+     * The default behavior of this method is to return changeSessionId()
+     * on the wrapped request object.
+     *
+     * @since Servlet 3.1
+     */
+    @Override
+    public String changeSessionId() {
+        return this._getHttpServletRequest().changeSessionId();
+    }
+    
+    /**
+     * The default behavior of this method is to return isRequestedSessionIdValid()
+     * on the wrapped request object.
+     */ 
+    @Override
+    public boolean isRequestedSessionIdValid() {
+        return this._getHttpServletRequest().isRequestedSessionIdValid();
+    }
+     
+    /**
+     * The default behavior of this method is to return isRequestedSessionIdFromCookie()
+     * on the wrapped request object.
+     */
+    @Override
+    public boolean isRequestedSessionIdFromCookie() {
+        return this._getHttpServletRequest().isRequestedSessionIdFromCookie();
+    }
+    
+    /**
+     * The default behavior of this method is to return isRequestedSessionIdFromURL()
+     * on the wrapped request object.
+     */ 
+    @Override
+    public boolean isRequestedSessionIdFromURL() {
+        return this._getHttpServletRequest().isRequestedSessionIdFromURL();
+    }
+
+    /**
+     * The default behavior of this method is to return isRequestedSessionIdFromUrl()
+     * on the wrapped request object.
+     *
+     * @deprecated  As of Version 4.0 of the Java Servlet API,
+     *              use {@link #isRequestedSessionIdFromURL} instead.
+     */
+    @Deprecated
+    @Override
+    public boolean isRequestedSessionIdFromUrl() {
+        return this._getHttpServletRequest().isRequestedSessionIdFromUrl();
+    }
+
+    /**
+     * The default behavior of this method is to call authenticate on the
+     * wrapped request object.
+     *
+     * @since Servlet 3.0
+     */
+    @Override
+    public boolean authenticate(HttpServletResponse response)
+            throws IOException, ServletException {
+        return this._getHttpServletRequest().authenticate(response);
+    }
+
+    /**
+     * The default behavior of this method is to call login on the wrapped
+     * request object.
+     *
+     * @since Servlet 3.0
+     */
+    @Override
+    public void login(String username, String password)
+            throws ServletException {
+        this._getHttpServletRequest().login(username,password);
+    }
+
+    /**
+     * The default behavior of this method is to call login on the wrapped
+     * request object.
+     *
+     * @since Servlet 3.0
+     */
+    @Override
+    public void logout() throws ServletException {
+        this._getHttpServletRequest().logout();
+    }
+
+    /**
+     * The default behavior of this method is to call getParts on the wrapped
+     * request object.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>HttpServletRequestWrapper</code>.
+     *
+     * @since Servlet 3.0
+     */
+    @Override
+    public Collection<Part> getParts() throws IOException, ServletException {
+        return this._getHttpServletRequest().getParts(); 
+    }
+
+    /**
+     * The default behavior of this method is to call getPart on the wrapped
+     * request object.
+     *
+     * @since Servlet 3.0
+     */
+    @Override
+    public Part getPart(String name) throws IOException, ServletException {
+        return this._getHttpServletRequest().getPart(name); 
+    
+    }
+
+    /**
+     * Create an instance of <code>HttpUpgradeHandler</code> for a given
+     * class and uses it for the http protocol upgrade processing.
+     *
+     * @since Servlet 3.1
+     */
+    @Override
+    public <T extends HttpUpgradeHandler> T upgrade(Class<T> handlerClass)
+            throws IOException, ServletException {
+        return this._getHttpServletRequest().upgrade(handlerClass);
+    }
+
+    /**
+     * The default behavior of this method is to call newPushBuilder on the
+     * wrapped request object.
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public PushBuilder newPushBuilder() {
+        return this._getHttpServletRequest().newPushBuilder();
+    }
+
+    /**
+     * The default behavior of this method is to call getTrailerFields on the
+     * wrapped request object.
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public Map<String, String> getTrailerFields() {
+        return this._getHttpServletRequest().getTrailerFields();
+    }
+
+    /**
+     * The default behavior of this method is to call isTrailerFieldsReady on the
+     * wrapped request object.
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public boolean isTrailerFieldsReady() {
+        return this._getHttpServletRequest().isTrailerFieldsReady();
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletResponse.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletResponse.java
new file mode 100644
index 0000000..08888ac
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletResponse.java
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.function.Supplier;
+import javax.servlet.ServletResponse;
+
+/**
+ *
+ * Extends the {@link ServletResponse} interface to provide HTTP-specific
+ * functionality in sending a response.  For example, it has methods
+ * to access HTTP headers and cookies.
+ *
+ * <p>The servlet container creates an <code>HttpServletResponse</code> object
+ * and passes it as an argument to the servlet's service methods
+ * (<code>doGet</code>, <code>doPost</code>, etc).
+ *
+ * 
+ * @author	Various
+ *
+ * @see		javax.servlet.ServletResponse
+ *
+ */
+public interface HttpServletResponse extends ServletResponse {
+
+    /**
+     * Adds the specified cookie to the response.  This method can be called
+     * multiple times to set more than one cookie.
+     *
+     * @param cookie the Cookie to return to the client
+     *
+     */
+    public void addCookie(Cookie cookie);
+
+    /**
+     * Returns a boolean indicating whether the named response header 
+     * has already been set.
+     * 
+     * @param	name	the header name
+     * @return		<code>true</code> if the named response header 
+     *			has already been set; 
+     * 			<code>false</code> otherwise
+     */
+    public boolean containsHeader(String name);
+
+    /**
+     * Encodes the specified URL by including the session ID,
+     * or, if encoding is not needed, returns the URL unchanged.
+     * The implementation of this method includes the logic to
+     * determine whether the session ID needs to be encoded in the URL.
+     * For example, if the browser supports cookies, or session
+     * tracking is turned off, URL encoding is unnecessary.
+     * 
+     * <p>For robust session tracking, all URLs emitted by a servlet 
+     * should be run through this
+     * method.  Otherwise, URL rewriting cannot be used with browsers
+     * which do not support cookies.
+     *
+     * <p>If the URL is relative, it is always relative to the current
+     * HttpServletRequest.
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed;
+     * 			the unchanged URL otherwise.
+     * @exception IllegalArgumentException if the url is not valid
+     */
+    public String encodeURL(String url);
+
+    /**
+     * Encodes the specified URL for use in the
+     * <code>sendRedirect</code> method or, if encoding is not needed,
+     * returns the URL unchanged.  The implementation of this method
+     * includes the logic to determine whether the session ID
+     * needs to be encoded in the URL.  For example, if the browser supports
+     * cookies, or session tracking is turned off, URL encoding is
+     * unnecessary.  Because the rules for making this determination can
+     * differ from those used to decide whether to
+     * encode a normal link, this method is separated from the
+     * <code>encodeURL</code> method.
+     * 
+     * <p>All URLs sent to the <code>HttpServletResponse.sendRedirect</code>
+     * method should be run through this method.  Otherwise, URL
+     * rewriting cannot be used with browsers which do not support
+     * cookies.
+     *
+     * <p>If the URL is relative, it is always relative to the current
+     * HttpServletRequest.
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed;
+     * 			the unchanged URL otherwise.
+     * @exception IllegalArgumentException if the url is not valid
+     *
+     * @see #sendRedirect
+     * @see #encodeUrl
+     */
+    public String encodeRedirectURL(String url);
+
+    /**
+     * @deprecated	As of version 2.1, use encodeURL(String url) instead
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed; 
+     * 			the unchanged URL otherwise.
+     * @exception IllegalArgumentException if the url is not valid
+     */
+    @Deprecated
+    public String encodeUrl(String url);
+    
+    /**
+     * @deprecated	As of version 2.1, use 
+     *			encodeRedirectURL(String url) instead
+     *
+     * @param	url	the url to be encoded.
+     * @return		the encoded URL if encoding is needed; 
+     * 			the unchanged URL otherwise.
+     * @exception IllegalArgumentException if the url is not valid
+     */
+    @Deprecated
+    public String encodeRedirectUrl(String url);
+
+    /**
+     * <p>Sends an error response to the client using the specified
+     * status and clears the buffer.  The server defaults to creating
+     * the response to look like an HTML-formatted server error page
+     * containing the specified message, setting the content type to
+     * "text/html".  The caller is <strong>not</strong> responsible for
+     * escaping or re-encoding the message to ensure it is safe with
+     * respect to the current response encoding and content type.  This
+     * aspect of safety is the responsibility of the container, as it is
+     * generating the error page containing the message.  The server
+     * will preserve cookies and may clear or update any headers needed
+     * to serve the error page as a valid response.</p>
+     *
+     * <p>If an error-page declaration has been made for the web
+     * application corresponding to the status code passed in, it will
+     * be served back in preference to the suggested msg parameter and
+     * the msg parameter will be ignored.</p>
+     *
+     * <p>If the response has already been committed, this method throws 
+     * an IllegalStateException.
+     * After using this method, the response should be considered
+     * to be committed and should not be written to.
+     *
+     * @param	sc	the error status code
+     * @param	msg	the descriptive message
+     * @exception	IOException	If an input or output exception occurs
+     * @exception	IllegalStateException	If the response was committed
+     */
+    public void sendError(int sc, String msg) throws IOException;
+
+    /**
+     * Sends an error response to the client using the specified status
+     * code and clears the buffer.
+     * 
+     * The server will preserve cookies and may clear or
+     * update any headers needed to serve the error page as a valid response.
+     *
+     * If an error-page declaration has been made for the web application
+     * corresponding to the status code passed in, it will be served back
+     * the error page
+     * 
+     * <p>If the response has already been committed, this method throws 
+     * an IllegalStateException.
+     * After using this method, the response should be considered
+     * to be committed and should not be written to.
+     *
+     * @param	sc	the error status code
+     * @exception	IOException	If an input or output exception occurs
+     * @exception	IllegalStateException	If the response was committed
+     *						before this method call
+     */
+    public void sendError(int sc) throws IOException;
+
+    /**
+     * Sends a temporary redirect response to the client using the
+     * specified redirect location URL and clears the buffer. The buffer will
+     * be replaced with the data set by this method. Calling this method sets the
+     * status code to {@link #SC_FOUND} 302 (Found).
+     * This method can accept relative URLs;the servlet container must convert
+     * the relative URL to an absolute URL
+     * before sending the response to the client. If the location is relative 
+     * without a leading '/' the container interprets it as relative to
+     * the current request URI. If the location is relative with a leading
+     * '/' the container interprets it as relative to the servlet container root.
+     * If the location is relative with two leading '/' the container interprets
+     * it as a network-path reference (see
+     * <a href="http://www.ietf.org/rfc/rfc3986.txt">
+     * RFC 3986: Uniform Resource Identifier (URI): Generic Syntax</a>, section 4.2
+     * &quot;Relative Reference&quot;).
+     *
+     * <p>If the response has already been committed, this method throws 
+     * an IllegalStateException.
+     * After using this method, the response should be considered
+     * to be committed and should not be written to.
+     *
+     * @param		location	the redirect location URL
+     * @exception	IOException	If an input or output exception occurs
+     * @exception	IllegalStateException	If the response was committed or
+     *              if a partial URL is given and cannot be converted into a valid URL
+     */
+    public void sendRedirect(String location) throws IOException;
+    
+    /**
+     * 
+     * Sets a response header with the given name and
+     * date-value.  The date is specified in terms of
+     * milliseconds since the epoch.  If the header had already
+     * been set, the new value overwrites the previous one.  The
+     * <code>containsHeader</code> method can be used to test for the
+     * presence of a header before setting its value.
+     * 
+     * @param	name	the name of the header to set
+     * @param	date	the assigned date value
+     * 
+     * @see #containsHeader
+     * @see #addDateHeader
+     */
+    public void setDateHeader(String name, long date);
+    
+    /**
+     * 
+     * Adds a response header with the given name and
+     * date-value.  The date is specified in terms of
+     * milliseconds since the epoch.  This method allows response headers 
+     * to have multiple values.
+     * 
+     * @param	name	the name of the header to set
+     * @param	date	the additional date value
+     * 
+     * @see #setDateHeader
+     */
+    public void addDateHeader(String name, long date);
+    
+    /**
+     *
+     * Sets a response header with the given name and value.
+     * If the header had already been set, the new value overwrites the
+     * previous one.  The <code>containsHeader</code> method can be
+     * used to test for the presence of a header before setting its
+     * value.
+     * 
+     * @param	name	the name of the header
+     * @param	value	the header value  If it contains octet string,
+     *		it should be encoded according to RFC 2047
+     *		(http://www.ietf.org/rfc/rfc2047.txt)
+     *
+     * @see #containsHeader
+     * @see #addHeader
+     */
+    public void setHeader(String name, String value);
+    
+    /**
+     * Adds a response header with the given name and value.
+     * This method allows response headers to have multiple values.
+     * 
+     * @param	name	the name of the header
+     * @param	value	the additional header value   If it contains
+     *		octet string, it should be encoded
+     *		according to RFC 2047
+     *		(http://www.ietf.org/rfc/rfc2047.txt)
+     *
+     * @see #setHeader
+     */
+    public void addHeader(String name, String value);
+
+    /**
+     * Sets a response header with the given name and
+     * integer value.  If the header had already been set, the new value
+     * overwrites the previous one.  The <code>containsHeader</code>
+     * method can be used to test for the presence of a header before
+     * setting its value.
+     *
+     * @param	name	the name of the header
+     * @param	value	the assigned integer value
+     *
+     * @see #containsHeader
+     * @see #addIntHeader
+     */
+    public void setIntHeader(String name, int value);
+
+    /**
+     * Adds a response header with the given name and
+     * integer value.  This method allows response headers to have multiple
+     * values.
+     *
+     * @param	name	the name of the header
+     * @param	value	the assigned integer value
+     *
+     * @see #setIntHeader
+     */
+    public void addIntHeader(String name, int value);
+
+    /**
+     * Sets the status code for this response. 
+     *
+     * <p>This method is used to set the return status code when there is
+     * no error (for example, for the SC_OK or SC_MOVED_TEMPORARILY status
+     * codes).
+     *
+     * <p>If this method is used to set an error code, then the container's
+     * error page mechanism will not be triggered. If there is an error and
+     * the caller wishes to invoke an error page defined in the web
+     * application, then {@link #sendError} must be used instead.
+     *
+     * <p>This method preserves any cookies and other response headers. 
+     *
+     * <p>Valid status codes are those in the 2XX, 3XX, 4XX, and 5XX ranges.
+     * Other status codes are treated as container specific.
+     *
+     * @param	sc	the status code
+     *
+     * @see #sendError
+     */
+    public void setStatus(int sc);
+  
+
+    /**
+     * @deprecated As of version 2.1, due to ambiguous meaning of the 
+     * message parameter. To set a status code 
+     * use <code>setStatus(int)</code>, to send an error with a description
+     * use <code>sendError(int, String)</code>.
+     *
+     * Sets the status code and message for this response.
+     * 
+     * @param	sc	the status code
+     * @param	sm	the status message
+     */
+    @Deprecated
+    public void setStatus(int sc, String sm);
+
+    /**
+     * Gets the current status code of this response.
+     *
+     * @return the current status code of this response
+     *
+     * @since Servlet 3.0
+     */
+    public int getStatus();
+
+    /**
+     * Gets the value of the response header with the given name.
+     * 
+     * <p>If a response header with the given name exists and contains
+     * multiple values, the value that was added first will be returned.
+     *
+     * <p>This method considers only response headers set or added via
+     * {@link #setHeader}, {@link #addHeader}, {@link #setDateHeader},
+     * {@link #addDateHeader}, {@link #setIntHeader}, or
+     * {@link #addIntHeader}, respectively.
+     *
+     * @param name the name of the response header whose value to return
+     *
+     * @return the value of the response header with the given name,
+     * or <tt>null</tt> if no header with the given name has been set
+     * on this response
+     *
+     * @since Servlet 3.0
+     */
+    public String getHeader(String name); 
+
+    /**
+     * Gets the values of the response header with the given name.
+     *
+     * <p>This method considers only response headers set or added via
+     * {@link #setHeader}, {@link #addHeader}, {@link #setDateHeader},
+     * {@link #addDateHeader}, {@link #setIntHeader}, or
+     * {@link #addIntHeader}, respectively.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>HttpServletResponse</code>.
+     *
+     * @param name the name of the response header whose values to return
+     *
+     * @return a (possibly empty) <code>Collection</code> of the values
+     * of the response header with the given name
+     *
+     * @since Servlet 3.0
+     */			
+    public Collection<String> getHeaders(String name); 
+    
+    /**
+     * Gets the names of the headers of this response.
+     *
+     * <p>This method considers only response headers set or added via
+     * {@link #setHeader}, {@link #addHeader}, {@link #setDateHeader},
+     * {@link #addDateHeader}, {@link #setIntHeader}, or
+     * {@link #addIntHeader}, respectively.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>HttpServletResponse</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the names
+     * of the headers of this response
+     *
+     * @since Servlet 3.0
+     */
+    public Collection<String> getHeaderNames();
+
+    /**
+     * Sets the supplier of trailer headers.
+     *
+     * <p>The trailer header field value is defined as a comma-separated list
+     * (see Section 3.2.2 and Section 4.1.2 of RFC 7230).</p>
+     *
+     * <p>The supplier will be called within the scope of whatever thread/call
+     * causes the response content to be completed. Typically this will
+     * be any thread calling close() on the output stream or writer.</p>
+     *
+     * <p>The trailers that run afoul of the provisions of section 4.1.2 of
+     * RFC 7230 are ignored.</p>
+     *
+     * <p>The RFC requires the name of every key that is to be in the
+     * supplied Map is included in the comma separated list that is the value
+     * of the "Trailer" response header.  The application is responsible for
+     * ensuring this requirement is met.  Failure to do so may lead to
+     * interoperability failures.</p>
+     *
+     * @implSpec
+     * The default implementation is a no-op.
+     *
+     * @param supplier the supplier of trailer headers
+     *
+     * @exception IllegalStateException if it is invoked after the response has
+     *         has been committed,
+     *         or the trailer is not supported in the request, for instance,
+     *         the underlying protocol is HTTP 1.0, or the response is not
+     *         in chunked encoding in HTTP 1.1.
+     *
+     * @since Servlet 4.0
+     */
+    default public void setTrailerFields(Supplier<Map<String, String>> supplier) {
+    }
+
+    /**
+     * Gets the supplier of trailer headers.
+     *
+     * @implSpec
+     * The default implememtation return null.
+     *
+     * @return <code>Supplier</code> of trailer headers
+     * 
+     * @since Servlet 4.0
+     */
+    default public Supplier<Map<String, String>> getTrailerFields() {
+        return null;
+    }
+
+
+    /*
+     * Server status codes; see RFC 2068.
+     */
+
+    /**
+     * Status code (100) indicating the client can continue.
+     */
+    public static final int SC_CONTINUE = 100;
+
+    /**
+     * Status code (101) indicating the server is switching protocols
+     * according to Upgrade header.
+     */
+    public static final int SC_SWITCHING_PROTOCOLS = 101;
+
+    /**
+     * Status code (200) indicating the request succeeded normally.
+     */
+    public static final int SC_OK = 200;
+
+    /**
+     * Status code (201) indicating the request succeeded and created
+     * a new resource on the server.
+     */
+    public static final int SC_CREATED = 201;
+
+    /**
+     * Status code (202) indicating that a request was accepted for
+     * processing, but was not completed.
+     */
+    public static final int SC_ACCEPTED = 202;
+
+    /**
+     * Status code (203) indicating that the meta information presented
+     * by the client did not originate from the server.
+     */
+    public static final int SC_NON_AUTHORITATIVE_INFORMATION = 203;
+
+    /**
+     * Status code (204) indicating that the request succeeded but that
+     * there was no new information to return.
+     */
+    public static final int SC_NO_CONTENT = 204;
+
+    /**
+     * Status code (205) indicating that the agent <em>SHOULD</em> reset
+     * the document view which caused the request to be sent.
+     */
+    public static final int SC_RESET_CONTENT = 205;
+
+    /**
+     * Status code (206) indicating that the server has fulfilled
+     * the partial GET request for the resource.
+     */
+    public static final int SC_PARTIAL_CONTENT = 206;
+
+    /**
+     * Status code (300) indicating that the requested resource
+     * corresponds to any one of a set of representations, each with
+     * its own specific location.
+     */
+    public static final int SC_MULTIPLE_CHOICES = 300;
+
+    /**
+     * Status code (301) indicating that the resource has permanently
+     * moved to a new location, and that future references should use a
+     * new URI with their requests.
+     */
+    public static final int SC_MOVED_PERMANENTLY = 301;
+
+    /**
+     * Status code (302) indicating that the resource has temporarily
+     * moved to another location, but that future references should
+     * still use the original URI to access the resource.
+     *
+     * This definition is being retained for backwards compatibility.
+     * SC_FOUND is now the preferred definition.
+     */
+    public static final int SC_MOVED_TEMPORARILY = 302;
+
+    /**
+    * Status code (302) indicating that the resource reside
+    * temporarily under a different URI. Since the redirection might
+    * be altered on occasion, the client should continue to use the
+    * Request-URI for future requests.(HTTP/1.1) To represent the
+    * status code (302), it is recommended to use this variable.
+    */
+    public static final int SC_FOUND = 302;
+
+    /**
+     * Status code (303) indicating that the response to the request
+     * can be found under a different URI.
+     */
+    public static final int SC_SEE_OTHER = 303;
+
+    /**
+     * Status code (304) indicating that a conditional GET operation
+     * found that the resource was available and not modified.
+     */
+    public static final int SC_NOT_MODIFIED = 304;
+
+    /**
+     * Status code (305) indicating that the requested resource
+     * <em>MUST</em> be accessed through the proxy given by the
+     * <code><em>Location</em></code> field.
+     */
+    public static final int SC_USE_PROXY = 305;
+
+     /**
+     * Status code (307) indicating that the requested resource 
+     * resides temporarily under a different URI. The temporary URI
+     * <em>SHOULD</em> be given by the <code><em>Location</em></code> 
+     * field in the response.
+     */
+    public static final int SC_TEMPORARY_REDIRECT = 307;
+
+    /**
+     * Status code (400) indicating the request sent by the client was
+     * syntactically incorrect.
+     */
+    public static final int SC_BAD_REQUEST = 400;
+
+    /**
+     * Status code (401) indicating that the request requires HTTP
+     * authentication.
+     */
+    public static final int SC_UNAUTHORIZED = 401;
+
+    /**
+     * Status code (402) reserved for future use.
+     */
+    public static final int SC_PAYMENT_REQUIRED = 402;
+
+    /**
+     * Status code (403) indicating the server understood the request
+     * but refused to fulfill it.
+     */
+    public static final int SC_FORBIDDEN = 403;
+
+    /**
+     * Status code (404) indicating that the requested resource is not
+     * available.
+     */
+    public static final int SC_NOT_FOUND = 404;
+
+    /**
+     * Status code (405) indicating that the method specified in the
+     * <code><em>Request-Line</em></code> is not allowed for the resource
+     * identified by the <code><em>Request-URI</em></code>.
+     */
+    public static final int SC_METHOD_NOT_ALLOWED = 405;
+
+    /**
+     * Status code (406) indicating that the resource identified by the
+     * request is only capable of generating response entities which have
+     * content characteristics not acceptable according to the accept
+     * headers sent in the request.
+     */
+    public static final int SC_NOT_ACCEPTABLE = 406;
+
+    /**
+     * Status code (407) indicating that the client <em>MUST</em> first
+     * authenticate itself with the proxy.
+     */
+    public static final int SC_PROXY_AUTHENTICATION_REQUIRED = 407;
+
+    /**
+     * Status code (408) indicating that the client did not produce a
+     * request within the time that the server was prepared to wait.
+     */
+    public static final int SC_REQUEST_TIMEOUT = 408;
+
+    /**
+     * Status code (409) indicating that the request could not be
+     * completed due to a conflict with the current state of the
+     * resource.
+     */
+    public static final int SC_CONFLICT = 409;
+
+    /**
+     * Status code (410) indicating that the resource is no longer
+     * available at the server and no forwarding address is known.
+     * This condition <em>SHOULD</em> be considered permanent.
+     */
+    public static final int SC_GONE = 410;
+
+    /**
+     * Status code (411) indicating that the request cannot be handled
+     * without a defined <code><em>Content-Length</em></code>.
+     */
+    public static final int SC_LENGTH_REQUIRED = 411;
+
+    /**
+     * Status code (412) indicating that the precondition given in one
+     * or more of the request-header fields evaluated to false when it
+     * was tested on the server.
+     */
+    public static final int SC_PRECONDITION_FAILED = 412;
+
+    /**
+     * Status code (413) indicating that the server is refusing to process
+     * the request because the request entity is larger than the server is
+     * willing or able to process.
+     */
+    public static final int SC_REQUEST_ENTITY_TOO_LARGE = 413;
+
+    /**
+     * Status code (414) indicating that the server is refusing to service
+     * the request because the <code><em>Request-URI</em></code> is longer
+     * than the server is willing to interpret.
+     */
+    public static final int SC_REQUEST_URI_TOO_LONG = 414;
+
+    /**
+     * Status code (415) indicating that the server is refusing to service
+     * the request because the entity of the request is in a format not
+     * supported by the requested resource for the requested method.
+     */
+    public static final int SC_UNSUPPORTED_MEDIA_TYPE = 415;
+
+    /**
+     * Status code (416) indicating that the server cannot serve the
+     * requested byte range.
+     */
+    public static final int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;
+
+    /**
+     * Status code (417) indicating that the server could not meet the
+     * expectation given in the Expect request header.
+     */
+    public static final int SC_EXPECTATION_FAILED = 417;
+
+    /**
+     * Status code (500) indicating an error inside the HTTP server
+     * which prevented it from fulfilling the request.
+     */
+    public static final int SC_INTERNAL_SERVER_ERROR = 500;
+
+    /**
+     * Status code (501) indicating the HTTP server does not support
+     * the functionality needed to fulfill the request.
+     */
+    public static final int SC_NOT_IMPLEMENTED = 501;
+
+    /**
+     * Status code (502) indicating that the HTTP server received an
+     * invalid response from a server it consulted when acting as a
+     * proxy or gateway.
+     */
+    public static final int SC_BAD_GATEWAY = 502;
+
+    /**
+     * Status code (503) indicating that the HTTP server is
+     * temporarily overloaded, and unable to handle the request.
+     */
+    public static final int SC_SERVICE_UNAVAILABLE = 503;
+
+    /**
+     * Status code (504) indicating that the server did not receive
+     * a timely response from the upstream server while acting as
+     * a gateway or proxy.
+     */
+    public static final int SC_GATEWAY_TIMEOUT = 504;
+
+    /**
+     * Status code (505) indicating that the server does not support
+     * or refuses to support the HTTP protocol version that was used
+     * in the request message.
+     */
+    public static final int SC_HTTP_VERSION_NOT_SUPPORTED = 505;
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletResponseWrapper.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletResponseWrapper.java
new file mode 100644
index 0000000..ee92253
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpServletResponseWrapper.java
@@ -0,0 +1,317 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.Map;
+import java.util.function.Supplier;
+import javax.servlet.ServletResponseWrapper;
+
+/**
+ * 
+ * Provides a convenient implementation of the HttpServletResponse interface that
+ * can be subclassed by developers wishing to adapt the response from a Servlet.
+ * This class implements the Wrapper or Decorator pattern. Methods default to
+ * calling through to the wrapped response object.
+ * 
+ * @author Various
+ * @since Servlet 2.3
+ *
+ * @see javax.servlet.http.HttpServletResponse
+ */
+
+public class HttpServletResponseWrapper extends ServletResponseWrapper implements HttpServletResponse {
+
+    /** 
+     * Constructs a response adaptor wrapping the given response.
+     * @throws java.lang.IllegalArgumentException if the response is null
+     *
+     * @param response the {@link HttpServletResponse} to be wrapped.
+     */
+    public HttpServletResponseWrapper(HttpServletResponse response) {
+        super(response);
+    }
+    
+    private HttpServletResponse _getHttpServletResponse() {
+        return (HttpServletResponse) super.getResponse();
+    }
+    
+    /**
+     * The default behavior of this method is to call addCookie(Cookie cookie)
+     * on the wrapped response object.
+     */
+    @Override
+    public void addCookie(Cookie cookie) {
+        this._getHttpServletResponse().addCookie(cookie);
+    }
+
+    /**
+     * The default behavior of this method is to call containsHeader(String name)
+     * on the wrapped response object.
+     */
+    @Override
+    public boolean containsHeader(String name) {
+        return this._getHttpServletResponse().containsHeader(name);
+    }
+    
+    /**
+     * The default behavior of this method is to call encodeURL(String url)
+     * on the wrapped response object.
+     */
+    @Override
+    public String encodeURL(String url) {
+        return this._getHttpServletResponse().encodeURL(url);
+    }
+
+    /**
+     * The default behavior of this method is to return encodeRedirectURL(String url)
+     * on the wrapped response object.
+     */
+    @Override
+    public String encodeRedirectURL(String url) {
+        return this._getHttpServletResponse().encodeRedirectURL(url);
+    }
+
+    /**
+     * The default behavior of this method is to call encodeUrl(String url)
+     * on the wrapped response object.
+     *
+     * @deprecated As of version 2.1, use {@link #encodeURL(String url)}
+     * instead
+     */
+    @Deprecated
+    @Override
+    public String encodeUrl(String url) {
+        return this._getHttpServletResponse().encodeUrl(url);
+    }
+    
+    /**
+     * The default behavior of this method is to return
+     * encodeRedirectUrl(String url) on the wrapped response object.
+     *
+     * @deprecated As of version 2.1, use 
+     * {@link #encodeRedirectURL(String url)} instead
+     */
+    @Deprecated
+    @Override
+    public String encodeRedirectUrl(String url) {
+        return this._getHttpServletResponse().encodeRedirectUrl(url);
+    }
+    
+    /**
+     * The default behavior of this method is to call sendError(int sc, String msg)
+     * on the wrapped response object.
+     */
+    @Override
+    public void sendError(int sc, String msg) throws IOException {
+        this._getHttpServletResponse().sendError(sc, msg);
+    }
+
+    /**
+     * The default behavior of this method is to call sendError(int sc)
+     * on the wrapped response object.
+     */
+    @Override
+    public void sendError(int sc) throws IOException {
+        this._getHttpServletResponse().sendError(sc);
+    }
+
+    /**
+     * The default behavior of this method is to return sendRedirect(String location)
+     * on the wrapped response object.
+     */
+    @Override
+    public void sendRedirect(String location) throws IOException {
+        this._getHttpServletResponse().sendRedirect(location);
+    }
+    
+    /**
+     * The default behavior of this method is to call setDateHeader(String name, long date)
+     * on the wrapped response object.
+     */
+    @Override
+    public void setDateHeader(String name, long date) {
+        this._getHttpServletResponse().setDateHeader(name, date);
+    }
+    
+    /**
+     * The default behavior of this method is to call addDateHeader(String name, long date)
+     * on the wrapped response object.
+     */
+    @Override
+    public void addDateHeader(String name, long date) {
+        this._getHttpServletResponse().addDateHeader(name, date);
+    }
+    
+    /**
+     * The default behavior of this method is to return setHeader(String name, String value)
+     * on the wrapped response object.
+     */
+    @Override
+    public void setHeader(String name, String value) {
+        this._getHttpServletResponse().setHeader(name, value);
+    }
+    
+    /**
+     * The default behavior of this method is to return addHeader(String name, String value)
+     * on the wrapped response object.
+     */
+    @Override
+    public void addHeader(String name, String value) {
+        this._getHttpServletResponse().addHeader(name, value);
+    }
+    
+    /**
+     * The default behavior of this method is to call setIntHeader(String name, int value)
+     * on the wrapped response object.
+     */
+    @Override
+    public void setIntHeader(String name, int value) {
+        this._getHttpServletResponse().setIntHeader(name, value);
+    }
+    
+    /**
+     * The default behavior of this method is to call addIntHeader(String name, int value)
+     * on the wrapped response object.
+     */
+    @Override
+    public void addIntHeader(String name, int value) {
+        this._getHttpServletResponse().addIntHeader(name, value);
+    }
+
+    /**
+     * The default behavior of this method is to call setStatus(int sc)
+     * on the wrapped response object.
+     */
+    @Override
+    public void setStatus(int sc) {
+        this._getHttpServletResponse().setStatus(sc);
+    }
+    
+    /**
+     * The default behavior of this method is to call
+     * setStatus(int sc, String sm) on the wrapped response object.
+     *
+     * @deprecated As of version 2.1, due to ambiguous meaning of the 
+     * message parameter. To set a status code 
+     * use {@link #setStatus(int)}, to send an error with a description
+     * use {@link #sendError(int, String)}
+     */
+    @Deprecated
+    @Override
+    public void setStatus(int sc, String sm) {
+        this._getHttpServletResponse().setStatus(sc, sm);
+    }
+
+    /**
+     * The default behaviour of this method is to call
+     * {@link HttpServletResponse#getStatus} on the wrapped response
+     * object.
+     *
+     * @return the current status code of the wrapped response
+     */
+    @Override
+    public int getStatus() {
+        return _getHttpServletResponse().getStatus();
+    }
+
+    /**
+     * The default behaviour of this method is to call
+     * {@link HttpServletResponse#getHeader} on the wrapped response
+     * object.
+     *
+     * @param name the name of the response header whose value to return
+     *
+     * @return the value of the response header with the given name,
+     * or <tt>null</tt> if no header with the given name has been set
+     * on the wrapped response
+     *
+     * @since Servlet 3.0
+     */
+    @Override
+    public String getHeader(String name) {
+        return _getHttpServletResponse().getHeader(name);
+    }
+
+    /**
+     * The default behaviour of this method is to call
+     * {@link HttpServletResponse#getHeaders} on the wrapped response
+     * object.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>HttpServletResponseWrapper</code>.
+     *
+     * @param name the name of the response header whose values to return
+     *
+     * @return a (possibly empty) <code>Collection</code> of the values
+     * of the response header with the given name
+     *
+     * @since Servlet 3.0
+     */                        
+    @Override
+    public Collection<String> getHeaders(String name) {
+        return _getHttpServletResponse().getHeaders(name);
+    }
+
+    /**
+     * The default behaviour of this method is to call
+     * {@link HttpServletResponse#getHeaderNames} on the wrapped response
+     * object.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>HttpServletResponseWrapper</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the names
+     * of the response headers
+     *
+     * @since Servlet 3.0
+     */
+    @Override
+    public Collection<String> getHeaderNames() {
+        return _getHttpServletResponse().getHeaderNames();
+    }
+
+    /**
+     * The default behaviour of this method is to call
+     * {@link HttpServletResponse#setTrailerFields} on the wrapped response
+     * object.
+     *
+     * @param supplier of trailer headers
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public void setTrailerFields(Supplier<Map<String, String>> supplier) {
+        _getHttpServletResponse().setTrailerFields(supplier);
+    }
+
+    /**
+     * The default behaviour of this method is to call
+     * {@link HttpServletResponse#getTrailerFields} on the wrapped response
+     * object.
+     *
+     * @return supplier of trailer headers
+     *
+     * @since Servlet 4.0
+     */
+    @Override
+    public Supplier<Map<String, String>> getTrailerFields() {
+        return _getHttpServletResponse().getTrailerFields();
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSession.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSession.java
new file mode 100644
index 0000000..158d0bc
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSession.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.util.Enumeration;
+import javax.servlet.ServletContext;
+
+/**
+ *
+ * Provides a way to identify a user across more than one page
+ * request or visit to a Web site and to store information about that user.
+ *
+ * <p>The servlet container uses this interface to create a session
+ * between an HTTP client and an HTTP server. The session persists
+ * for a specified time period, across more than one connection or
+ * page request from the user. A session usually corresponds to one 
+ * user, who may visit a site many times. The server can maintain a 
+ * session in many ways such as using cookies or rewriting URLs.
+ *
+ * <p>This interface allows servlets to 
+ * <ul>
+ * <li>View and manipulate information about a session, such as
+ *     the session identifier, creation time, and last accessed time
+ * <li>Bind objects to sessions, allowing user information to persist 
+ *     across multiple user connections
+ * </ul>
+ *
+ * <p>When an application stores an object in or removes an object from a
+ * session, the session checks whether the object implements
+ * {@link HttpSessionBindingListener}. If it does, 
+ * the servlet notifies the object that it has been bound to or unbound 
+ * from the session. Notifications are sent after the binding methods complete. 
+ * For session that are invalidated or expire, notifications are sent after
+ * the session has been invalidated or expired.
+ *
+ * <p> When container migrates a session between VMs in a distributed container
+ * setting, all session attributes implementing the {@link HttpSessionActivationListener}
+ * interface are notified.
+ * 
+ * <p>A servlet should be able to handle cases in which
+ * the client does not choose to join a session, such as when cookies are
+ * intentionally turned off. Until the client joins the session,
+ * <code>isNew</code> returns <code>true</code>.  If the client chooses 
+ * not to join
+ * the session, <code>getSession</code> will return a different session
+ * on each request, and <code>isNew</code> will always return
+ * <code>true</code>.
+ *
+ * <p>Session information is scoped only to the current web application
+ * (<code>ServletContext</code>), so information stored in one context
+ * will not be directly visible in another.
+ *
+ * @author	Various
+ *
+ * @see 	HttpSessionBindingListener
+ * @see 	HttpSessionContext
+ */
+
+public interface HttpSession {
+
+    /**
+     *
+     * Returns the time when this session was created, measured
+     * in milliseconds since midnight January 1, 1970 GMT.
+     *
+     * @return				a <code>long</code> specifying
+     * 					when this session was created,
+     *					expressed in 
+     *					milliseconds since 1/1/1970 GMT
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    public long getCreationTime();
+    
+        
+    /**
+     * Returns a string containing the unique identifier assigned 
+     * to this session. The identifier is assigned 
+     * by the servlet container and is implementation dependent.
+     * 
+     * @return				a string specifying the identifier
+     *					assigned to this session
+     */
+    public String getId();
+    
+
+    /**
+     *
+     * Returns the last time the client sent a request associated with
+     * this session, as the number of milliseconds since midnight
+     * January 1, 1970 GMT, and marked by the time the container received the
+     * request. 
+     *
+     * <p>Actions that your application takes, such as getting or setting
+     * a value associated with the session, do not affect the access
+     * time.
+     *
+     * @return				a <code>long</code>
+     *					representing the last time 
+     *					the client sent a request associated
+     *					with this session, expressed in 
+     *					milliseconds since 1/1/1970 GMT
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    public long getLastAccessedTime();
+    
+    
+    /**
+     * Returns the ServletContext to which this session belongs.
+     *    
+     * @return The ServletContext object for the web application
+     * @since Servlet 2.3
+     */
+    public ServletContext getServletContext();
+
+
+    /**
+     * Specifies the time, in seconds, between client requests before the 
+     * servlet container will invalidate this session. 
+     *
+     * <p>An <tt>interval</tt> value of zero or less indicates that the
+     * session should never timeout.
+     *
+     * @param interval		An integer specifying the number
+     * 				of seconds 
+     */    
+    public void setMaxInactiveInterval(int interval);
+
+
+    /**
+     * Returns the maximum time interval, in seconds, that 
+     * the servlet container will keep this session open between 
+     * client accesses. After this interval, the servlet container
+     * will invalidate the session.  The maximum time interval can be set
+     * with the <code>setMaxInactiveInterval</code> method.
+     *
+     * <p>A return value of zero or less indicates that the
+     * session will never timeout.
+     *
+     * @return		an integer specifying the number of
+     *			seconds this session remains open
+     *			between client requests
+     *
+     * @see		#setMaxInactiveInterval
+     */
+    public int getMaxInactiveInterval();
+    
+
+    /**
+     *
+     * @deprecated 	As of Version 2.1, this method is
+     *			deprecated and has no replacement.
+     *			It will be removed in a future
+     *			version of the Java Servlet API.
+     *
+     * @return the {@link HttpSessionContext} for this session.
+     */
+    @Deprecated
+    public HttpSessionContext getSessionContext();
+    
+
+    /**
+     * Returns the object bound with the specified name in this session, or
+     * <code>null</code> if no object is bound under the name.
+     *
+     * @param name		a string specifying the name of the object
+     *
+     * @return			the object with the specified name
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    public Object getAttribute(String name);
+    
+    
+    /**
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #getAttribute}.
+     *
+     * @param name		a string specifying the name of the object
+     *
+     * @return			the object with the specified name
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    @Deprecated
+    public Object getValue(String name);
+        
+
+    /**
+     * Returns an <code>Enumeration</code> of <code>String</code> objects
+     * containing the names of all the objects bound to this session. 
+     *
+     * @return			an <code>Enumeration</code> of 
+     *				<code>String</code> objects specifying the
+     *				names of all the objects bound to
+     *				this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */    
+    public Enumeration<String> getAttributeNames();
+    
+
+    /**
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #getAttributeNames}
+     *
+     * @return				an array of <code>String</code>
+     *					objects specifying the
+     *					names of all the objects bound to
+     *					this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    @Deprecated
+    public String[] getValueNames();
+    
+
+    /**
+     * Binds an object to this session, using the name specified.
+     * If an object of the same name is already bound to the session,
+     * the object is replaced.
+     *
+     * <p>After this method executes, and if the new object
+     * implements <code>HttpSessionBindingListener</code>,
+     * the container calls 
+     * <code>HttpSessionBindingListener.valueBound</code>. The container then   
+     * notifies any <code>HttpSessionAttributeListener</code>s in the web 
+     * application.
+     
+     * <p>If an object was already bound to this session of this name
+     * that implements <code>HttpSessionBindingListener</code>, its 
+     * <code>HttpSessionBindingListener.valueUnbound</code> method is called.
+     *
+     * <p>If the value passed in is null, this has the same effect as calling 
+     * <code>removeAttribute()</code>.
+     *
+     *
+     * @param name			the name to which the object is bound;
+     *					cannot be null
+     *
+     * @param value			the object to be bound
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    public void setAttribute(String name, Object value);
+    
+
+    /**
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #setAttribute}
+     *
+     * @param name			the name to which the object is bound;
+     *					cannot be null
+     *
+     * @param value			the object to be bound; cannot be null
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    @Deprecated
+    public void putValue(String name, Object value);
+
+
+    /**
+     * Removes the object bound with the specified name from
+     * this session. If the session does not have an object
+     * bound with the specified name, this method does nothing.
+     *
+     * <p>After this method executes, and if the object
+     * implements <code>HttpSessionBindingListener</code>,
+     * the container calls 
+     * <code>HttpSessionBindingListener.valueUnbound</code>. The container
+     * then notifies any <code>HttpSessionAttributeListener</code>s in the web 
+     * application.
+     *
+     * @param name				the name of the object to
+     *						remove from this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    public void removeAttribute(String name);
+
+
+    /**
+     * @deprecated 	As of Version 2.2, this method is
+     * 			replaced by {@link #removeAttribute}
+     *
+     * @param name				the name of the object to
+     *						remove from this session
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					invalidated session
+     */
+    @Deprecated
+    public void removeValue(String name);
+
+
+    /**
+     * Invalidates this session then unbinds any objects bound
+     * to it. 
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					already invalidated session
+     */
+    public void invalidate();
+    
+    
+    /**
+     * Returns <code>true</code> if the client does not yet know about the
+     * session or if the client chooses not to join the session.  For 
+     * example, if the server used only cookie-based sessions, and
+     * the client had disabled the use of cookies, then a session would
+     * be new on each request.
+     *
+     * @return 				<code>true</code> if the 
+     *					server has created a session, 
+     *					but the client has not yet joined
+     *
+     * @exception IllegalStateException	if this method is called on an
+     *					already invalidated session
+     */
+    public boolean isNew();
+
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionActivationListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionActivationListener.java
new file mode 100644
index 0000000..3206927
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionActivationListener.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.util.EventListener;
+
+/** Objects that are bound to a session may listen to container
+ * events notifying them that sessions will be passivated and that
+ * session will be activated. A container that migrates session
+ * between VMs or persists sessions is required to notify all
+ * attributes bound to sessions implementing
+ * HttpSessionActivationListener.
+ *
+ * @since Servlet 2.3
+ */
+
+public interface HttpSessionActivationListener extends EventListener { 
+
+    /**
+     * Notification that the session is about to be passivated.
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     * 
+     * @param se the {@link HttpSessionEvent} indicating the passivation
+     * of the session
+     */
+    default public void sessionWillPassivate(HttpSessionEvent se) {}
+
+    /**
+     * Notification that the session has just been activated.
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     * 
+     * @param se the {@link HttpSessionEvent} indicating the activation
+     * of the session
+     */
+    default public void sessionDidActivate(HttpSessionEvent se) {}
+} 
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionAttributeListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionAttributeListener.java
new file mode 100644
index 0000000..2a1eceb
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionAttributeListener.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.util.EventListener;
+
+/**
+ * Interface for receiving notification events about HttpSession
+ * attribute changes.
+ *
+ * <p>In order to receive these notification events, the implementation
+ * class must be either declared in the deployment descriptor of the web
+ * application, annotated with {@link javax.servlet.annotation.WebListener},
+ * or registered via one of the addListener methods defined on
+ * {@link javax.servlet.ServletContext}.
+ *
+ * <p>The order in which implementations of this interface are invoked is
+ * unspecified.
+ *
+ * @since Servlet 2.3
+ */
+
+public interface HttpSessionAttributeListener extends EventListener {
+
+    /**
+     * Receives notification that an attribute has been added to a
+     * session.
+     *
+     * @param event the HttpSessionBindingEvent containing the session
+     * and the name and value of the attribute that was added
+     */
+    default public void attributeAdded(HttpSessionBindingEvent event) {}
+
+    /**
+     * Receives notification that an attribute has been removed from a
+     * session.
+     *
+     * @param event the HttpSessionBindingEvent containing the session
+     * and the name and value of the attribute that was removed
+     */
+    default public void attributeRemoved(HttpSessionBindingEvent event) {}
+
+    /**
+     * Receives notification that an attribute has been replaced in a
+     * session.
+     *
+     * @param event the HttpSessionBindingEvent containing the session
+     * and the name and (old) value of the attribute that was replaced
+     */
+    default public void attributeReplaced(HttpSessionBindingEvent event) {}
+
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionBindingEvent.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionBindingEvent.java
new file mode 100644
index 0000000..2538817
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionBindingEvent.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+/**
+ *
+ * Events of this type are either sent to an object that implements
+ * {@link HttpSessionBindingListener} when it is bound or unbound from a
+ * session, or to a {@link HttpSessionAttributeListener} that has been
+ * configured in the deployment descriptor when any attribute is bound, unbound
+ * or replaced in a session.
+ *
+ * <p>The session binds the object by a call to
+ * <code>HttpSession.setAttribute</code> and unbinds the object
+ * by a call to <code>HttpSession.removeAttribute</code>.
+ *
+ * @author Various
+ * 
+ * @see HttpSession
+ * @see HttpSessionBindingListener
+ * @see HttpSessionAttributeListener
+ */
+
+public class HttpSessionBindingEvent extends HttpSessionEvent {
+
+    private static final long serialVersionUID = 7308000419984825907L;
+
+    /* The name to which the object is being bound or unbound */
+    private String name;
+    
+    /* The object is being bound or unbound */
+    private Object value;
+    
+    /**
+     *
+     * Constructs an event that notifies an object that it
+     * has been bound to or unbound from a session. 
+     * To receive the event, the object must implement
+     * {@link HttpSessionBindingListener}.
+     *
+     * @param session the session to which the object is bound or unbound
+     * @param name the name with which the object is bound or unbound
+     *
+     * @see #getName
+     * @see #getSession
+     */
+    public HttpSessionBindingEvent(HttpSession session, String name) {
+        super(session);
+        this.name = name;
+    }
+    
+    /**
+     *
+     * Constructs an event that notifies an object that it
+     * has been bound to or unbound from a session. 
+     * To receive the event, the object must implement
+     * {@link HttpSessionBindingListener}.
+     *
+     * @param session the session to which the object is bound or unbound
+     * @param name the name with which the object is bound or unbound
+     * @param value the object that is bound or unbound
+     *
+     * @see #getName
+     * @see #getSession
+     */
+    public HttpSessionBindingEvent(HttpSession session, String name, Object value) {
+        super(session);
+        this.name = name;
+        this.value = value;
+    }
+    
+    /** Return the session that changed. */
+    @Override
+    public HttpSession getSession () { 
+        return super.getSession();
+    }
+ 
+    /**
+     * Returns the name with which the attribute is bound to or
+     * unbound from the session.
+     *
+     * @return a string specifying the name with which
+     *         the object is bound to or unbound from the session
+     */
+    public String getName() {
+        return name;
+    }
+    
+    /**
+     * Returns the value of the attribute that has been added, removed or
+     * replaced. If the attribute was added (or bound), this is the value of the
+     * attribute. If the attribute was removed (or unbound), this is the value
+     * of the removed attribute. If the attribute was replaced, this is the old
+     * value of the attribute.
+     *
+     * @return the value of the attribute that has been added, removed
+     * or replaced
+     *
+     * @since Servlet 2.3
+     */
+    public Object getValue() {
+        return this.value;   
+    }
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionBindingListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionBindingListener.java
new file mode 100644
index 0000000..9dd95db
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionBindingListener.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.util.EventListener;
+
+
+ 
+ 
+
+/**
+ * Causes an object to be notified when it is bound to
+ * or unbound from a session. The object is notified
+ * by an {@link HttpSessionBindingEvent} object. This may be as a result
+ * of a servlet programmer explicitly unbinding an attribute from a session,
+ * due to a session being invalidated, or due to a session timing out.
+ *
+ *
+ * @author		Various
+ *
+ * @see HttpSession
+ * @see HttpSessionBindingEvent
+ *
+ */
+
+public interface HttpSessionBindingListener extends EventListener {
+
+    /**
+     *
+     * Notifies the object that it is being bound to
+     * a session and identifies the session.
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     * 
+     * @param event		the event that identifies the
+     *				session 
+     *
+     * @see #valueUnbound
+     *
+     */ 
+    default public void valueBound(HttpSessionBindingEvent event) {}
+
+    /**
+     *
+     * Notifies the object that it is being unbound
+     * from a session and identifies the session.
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     *
+     * @param event		the event that identifies
+     *				the session 
+     *	
+     * @see #valueBound
+     *
+     */
+    default public void valueUnbound(HttpSessionBindingEvent event) {}
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionContext.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionContext.java
new file mode 100644
index 0000000..e9ef098
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionContext.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.util.Enumeration;
+
+/**
+ *
+ * @author		Various
+ *
+ * @deprecated		As of Java(tm) Servlet API 2.1
+ *			for security reasons, with no replacement.
+ *			This interface will be removed in a future
+ *			version of this API.
+ *
+ * @see			HttpSession
+ * @see			HttpSessionBindingEvent
+ * @see			HttpSessionBindingListener
+ *
+ */
+
+@Deprecated
+public interface HttpSessionContext {
+
+    /**
+     *
+     * @deprecated 	As of Java Servlet API 2.1 with
+     *			no replacement. This method must 
+     *			return null and will be removed in
+     *			a future version of this API.
+     * @param sessionId the id of the session to be returned
+     *
+     * @return null in all cases
+     */
+    @Deprecated
+    public HttpSession getSession(String sessionId);
+    
+    
+    
+  
+    /**
+     *
+     * @deprecated	As of Java Servlet API 2.1 with
+     *			no replacement. This method must return 
+     *			an empty <code>Enumeration</code> and will be removed
+     *			in a future version of this API.
+     *
+     * @return null 
+     *
+     */
+    @Deprecated
+    public Enumeration<String> getIds();
+}
+
+
+
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionEvent.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionEvent.java
new file mode 100644
index 0000000..7a348b8
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionEvent.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+/**
+ * This is the class representing event notifications for changes to
+ * sessions within a web application.
+ *
+ * @since Servlet 2.3
+ */
+public class HttpSessionEvent extends java.util.EventObject {
+
+    private static final long serialVersionUID = -7622791603672342895L;
+
+    /**
+     * Construct a session event from the given source.
+     *
+     * @param source the {@link HttpSession} corresponding to this event
+     */
+    public HttpSessionEvent(HttpSession source) {
+        super(source);
+    }
+
+    /**
+     * Return the session that changed.
+     * @return the {@link HttpSession} for this event.
+     */
+    public HttpSession getSession () { 
+        return (HttpSession) super.getSource();
+    }
+}
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionIdListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionIdListener.java
new file mode 100644
index 0000000..412ea46
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionIdListener.java
@@ -0,0 +1,74 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+import java.util.EventListener;
+
+/**
+ * Interface for receiving notification events about HttpSession
+ * id changes.
+ *
+ * <p>In order to receive these notification events, the implementation
+ * class must be either declared in the deployment descriptor of the web
+ * application, annotated with {@link javax.servlet.annotation.WebListener},
+ * or registered via one of the addListener methods defined on
+ * {@link javax.servlet.ServletContext}.
+ *
+ * <p>The order in which implementations of this interface are invoked is
+ * unspecified.
+ *
+ * @since Servlet 3.1
+ */
+
+public interface HttpSessionIdListener extends EventListener {
+
+    /**
+     * Receives notification that session id has been changed in a
+     * session.
+     *
+     * @param event the HttpSessionBindingEvent containing the session
+     * and the name and (old) value of the attribute that was replaced
+     *
+     * @param oldSessionId the old session id
+     */
+    public void sessionIdChanged(HttpSessionEvent event, String oldSessionId);
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionListener.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionListener.java
new file mode 100644
index 0000000..9b4dc8c
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpSessionListener.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import java.util.EventListener;
+
+/** 
+ * Interface for receiving notification events about HttpSession
+ * lifecycle changes.
+ *
+ * <p>In order to receive these notification events, the implementation
+ * class must be either declared in the deployment descriptor of the web
+ * application, annotated with {@link javax.servlet.annotation.WebListener},
+ * or registered via one of the addListener methods defined on
+ * {@link javax.servlet.ServletContext}.
+ *
+ * <p>Implementations of this interface are invoked at their
+ * {@link #sessionCreated} method in the order in which they have been
+ * declared, and at their {@link #sessionDestroyed} method in reverse
+ * order.
+ *
+ * @see HttpSessionEvent
+ *
+ * @since Servlet 2.3
+ */
+public interface HttpSessionListener extends EventListener {
+    
+    /** 
+     * Receives notification that a session has been created.
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     *
+     * @param se the HttpSessionEvent containing the session
+     */
+    default public void sessionCreated(HttpSessionEvent se) {}
+    
+    /** 
+     * Receives notification that a session is about to be invalidated.
+     *
+     * @implSpec
+     * The default implementation takes no action.
+     *
+     * @param se the HttpSessionEvent containing the session
+     */
+    default public void sessionDestroyed(HttpSessionEvent se) {}
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpUpgradeHandler.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpUpgradeHandler.java
new file mode 100644
index 0000000..23e9689
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpUpgradeHandler.java
@@ -0,0 +1,64 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+/**
+ * This interface encapsulates the upgrade protocol processing.
+ * A HttpUpgradeHandler implementation would allow the servlet container
+ * to communicate with it.
+ *
+ * @since Servlet 3.1
+ */
+
+public interface HttpUpgradeHandler {
+    /**
+     * It is called once the HTTP Upgrade process has been completed and
+     * the upgraded connection is ready to start using the new protocol.
+     *
+     * @param wc the WebConnection object associated to this upgrade request
+     */
+    public void init(WebConnection wc);
+
+    /**
+     * It is called when the client is disconnected.
+     */
+    public void destroy();
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpUtils.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpUtils.java
new file mode 100644
index 0000000..372f056
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/HttpUtils.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * 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 javax.servlet.http;
+
+import javax.servlet.ServletInputStream;
+import java.util.Hashtable;
+import java.util.ResourceBundle;
+import java.util.StringTokenizer;
+import java.io.IOException;
+
+/**
+ * @deprecated		As of Java(tm) Servlet API 2.3. 
+ *			These methods were only useful
+ *			with the default encoding and have been moved
+ *			to the request interfaces.
+ *
+ */
+@Deprecated
+public class HttpUtils {
+
+    private static final String LSTRING_FILE =
+	"javax.servlet.http.LocalStrings";
+    private static ResourceBundle lStrings =
+	ResourceBundle.getBundle(LSTRING_FILE);
+        
+    
+    /**
+     * Constructs an empty <code>HttpUtils</code> object.
+     */
+    public HttpUtils() {}
+    
+
+    /**
+     * Parses a query string passed from the client to the
+     * server and builds a <code>HashTable</code> object
+     * with key-value pairs. 
+     * The query string should be in the form of a string
+     * packaged by the GET or POST method, that is, it
+     * should have key-value pairs in the form <i>key=value</i>,
+     * with each pair separated from the next by a &amp; character.
+     *
+     * <p>A key can appear more than once in the query string
+     * with different values. However, the key appears only once in 
+     * the hashtable, with its value being
+     * an array of strings containing the multiple values sent
+     * by the query string.
+     * 
+     * <p>The keys and values in the hashtable are stored in their
+     * decoded form, so
+     * any + characters are converted to spaces, and characters
+     * sent in hexadecimal notation (like <i>%xx</i>) are
+     * converted to ASCII characters.
+     *
+     * @param s		a string containing the query to be parsed
+     *
+     * @return		a <code>HashTable</code> object built
+     * 			from the parsed key-value pairs
+     *
+     * @exception IllegalArgumentException if the query string is invalid
+     */
+    public static Hashtable<String, String[]> parseQueryString(String s) {
+
+        String valArray[] = null;
+	
+        if (s == null) {
+            throw new IllegalArgumentException();
+        }
+
+        Hashtable<String, String[]> ht = new Hashtable<String, String[]>();
+        StringBuilder sb = new StringBuilder();
+        StringTokenizer st = new StringTokenizer(s, "&");
+        while (st.hasMoreTokens()) {
+        String pair = st.nextToken();
+        int pos = pair.indexOf('=');
+        if (pos == -1) {
+            // XXX
+            // should give more detail about the illegal argument
+            throw new IllegalArgumentException();
+        }
+        String key = parseName(pair.substring(0, pos), sb);
+        String val = parseName(pair.substring(pos+1, pair.length()), sb);
+        if (ht.containsKey(key)) {
+            String oldVals[] = ht.get(key);
+            valArray = new String[oldVals.length + 1];
+            for (int i = 0; i < oldVals.length; i++) {
+                valArray[i] = oldVals[i];
+            }
+            valArray[oldVals.length] = val;
+        } else {
+            valArray = new String[1];
+            valArray[0] = val;
+        }
+        ht.put(key, valArray);
+    }
+
+	return ht;
+    }
+
+
+    /**
+     *
+     * Parses data from an HTML form that the client sends to 
+     * the server using the HTTP POST method and the 
+     * <i>application/x-www-form-urlencoded</i> MIME type.
+     *
+     * <p>The data sent by the POST method contains key-value
+     * pairs. A key can appear more than once in the POST data
+     * with different values. However, the key appears only once in 
+     * the hashtable, with its value being
+     * an array of strings containing the multiple values sent
+     * by the POST method.
+     *
+     * <p>The keys and values in the hashtable are stored in their
+     * decoded form, so
+     * any + characters are converted to spaces, and characters
+     * sent in hexadecimal notation (like <i>%xx</i>) are
+     * converted to ASCII characters.
+     *
+     * @param len	an integer specifying the length,
+     *			in characters, of the 
+     *			<code>ServletInputStream</code>
+     *			object that is also passed to this
+     *			method
+     *
+     * @param in	the <code>ServletInputStream</code>
+     *			object that contains the data sent
+     *			from the client
+     * 
+     * @return		a <code>HashTable</code> object built
+     *			from the parsed key-value pairs
+     *
+     * @exception IllegalArgumentException if the data
+     * sent by the POST method is invalid
+     */
+    public static Hashtable<String, String[]> parsePostData(int len, 
+                ServletInputStream in) {
+	// XXX
+	// should a length of 0 be an IllegalArgumentException
+	
+	if (len <=0) {
+            // cheap hack to return an empty hash
+	    return new Hashtable<String, String[]>(); 
+        }
+
+	if (in == null) {
+	    throw new IllegalArgumentException();
+	}
+	
+	//
+	// Make sure we read the entire POSTed body.
+	//
+        byte[] postedBytes = new byte [len];
+        try {
+            int offset = 0;
+       
+	    do {
+		int inputLen = in.read (postedBytes, offset, len - offset);
+		if (inputLen <= 0) {
+		    String msg = lStrings.getString("err.io.short_read");
+		    throw new IllegalArgumentException (msg);
+		}
+		offset += inputLen;
+	    } while ((len - offset) > 0);
+
+	} catch (IOException e) {
+	    throw new IllegalArgumentException(e.getMessage());
+	}
+
+        // XXX we shouldn't assume that the only kind of POST body
+        // is FORM data encoded using ASCII or ISO Latin/1 ... or
+        // that the body should always be treated as FORM data.
+        //
+
+        try {
+            String postedBody = new String(postedBytes, 0, len, "8859_1");
+            return parseQueryString(postedBody);
+        } catch (java.io.UnsupportedEncodingException e) {
+            // XXX function should accept an encoding parameter & throw this
+            // exception.  Otherwise throw something expected.
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+
+
+    /*
+     * Parse a name in the query string.
+     */
+    private static String parseName(String s, StringBuilder sb) {
+        sb.setLength(0);
+        for (int i = 0; i < s.length(); i++) {
+            char c = s.charAt(i); 
+            switch (c) {
+                case '+':
+                    sb.append(' ');
+                    break;
+                case '%':
+                    try {
+                        sb.append((char) Integer.parseInt(s.substring(i+1, i+3), 
+                                16));
+                        i += 2;
+                    } catch (NumberFormatException e) {
+                        // XXX
+                        // need to be more specific about illegal arg
+                        throw new IllegalArgumentException();
+                    } catch (StringIndexOutOfBoundsException e) {
+                        String rest  = s.substring(i);
+                        sb.append(rest);
+                        if (rest.length()==2)
+                            i++;
+                        }
+
+                        break;
+                default:
+                    sb.append(c);
+                    break;
+            }
+        }
+
+        return sb.toString();
+    }
+
+
+    /**
+     *
+     * Reconstructs the URL the client used to make the request,
+     * using information in the <code>HttpServletRequest</code> object.
+     * The returned URL contains a protocol, server name, port
+     * number, and server path, but it does not include query
+     * string parameters.
+     * 
+     * <p>Because this method returns a <code>StringBuffer</code>,
+     * not a string, you can modify the URL easily, for example,
+     * to append query parameters.
+     *
+     * <p>This method is useful for creating redirect messages
+     * and for reporting errors.
+     *
+     * @param req	a <code>HttpServletRequest</code> object
+     *			containing the client's request
+     * 
+     * @return		a <code>StringBuffer</code> object containing
+     *			the reconstructed URL
+     */
+    public static StringBuffer getRequestURL (HttpServletRequest req) {
+        StringBuffer url = new StringBuffer();
+        String scheme = req.getScheme ();
+        int port = req.getServerPort ();
+        String urlPath = req.getRequestURI();
+
+        //String		servletPath = req.getServletPath ();
+        //String		pathInfo = req.getPathInfo ();
+
+        url.append (scheme);		// http, https
+        url.append ("://");
+        url.append (req.getServerName ());
+        if ((scheme.equals ("http") && port != 80)
+        || (scheme.equals ("https") && port != 443)) {
+            url.append (':');
+            url.append (req.getServerPort ());
+        }
+        //if (servletPath != null)
+        //    url.append (servletPath);
+        //if (pathInfo != null)
+        //    url.append (pathInfo);
+        url.append(urlPath);
+
+        return url;
+    }
+}
+
+
+
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings.properties b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings.properties
new file mode 100644
index 0000000..e52aa45
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings.properties
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright 2004 The Apache Software Foundation
+#
+# 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.
+#
+
+# Default localized string information
+# Localized for Locale en_US
+
+err.cookie_name_is_token=Cookie name \"{0}\" is a reserved token
+err.cookie_name_blank=Cookie name must not be null or empty
+err.io.nullArray=Null passed for byte array in write method
+err.io.indexOutOfBounds=Invalid offset [{0}] and / or length [{1}] specified for array of size [{2}]
+err.io.short_read=Short Read
+err.ise.getWriter=Illegal to call getWriter() after getOutputStream() has been called
+err.ise.getOutputStream=Illegal to call getOutputStream() after getWriter() has been called
+
+http.method_not_implemented=Method {0} is not defined in RFC 2068 and is not supported by the Servlet API 
+
+http.method_get_not_supported=HTTP method GET is not supported by this URL
+http.method_post_not_supported=HTTP method POST is not supported by this URL
+http.method_put_not_supported=HTTP method PUT is not supported by this URL
+http.method_delete_not_supported=Http method DELETE is not supported by this URL
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_es.properties b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_es.properties
new file mode 100644
index 0000000..65367d9
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_es.properties
@@ -0,0 +1,32 @@
+#
+# Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright 2004 The Apache Software Foundation
+#
+# 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.
+#
+
+# $Id: LocalStrings_es.properties,v 1.1.1.1 2003/01/27 16:07:47 ja120174 Exp $
+#
+# Default localized string information
+# Localized para Locale es_ES
+
+err.cookie_name_is_token=El Nombre de Cookie {0} es una palabra reservada
+err.io.negativelength=Longitud Negativa en el metodo write
+err.io.short_read=Lectura Corta
+
+http.method_not_implemented=El Metodo {0} no esta definido en la especificacion RFC 2068 y no es soportado por la API Servlet 
+
+http.method_get_not_supported=El Metodo HTTP GET no es soportado por esta URL
+http.method_post_not_supported=El Metodo HTTP POST no es soportado por esta URL
+http.method_put_not_supported=El Metodo HTTP PUT no es soportado por esta URL
+http.method_delete_not_supported=El Metodo HTTP DELETE no es soportado por esta URL
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_fr.properties b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_fr.properties
new file mode 100644
index 0000000..0c3f5d6
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_fr.properties
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright 2004 The Apache Software Foundation
+#
+# 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.
+#
+
+# Default localized string information
+# Localized for Locale fr_FR
+
+err.cookie_name_is_token=Le nom de cookie \"{0}\" est un \"token\" réservé
+err.io.negativelength=Taille négative donnée dans la méthode \"write\"
+err.io.short_read=Lecture partielle
+
+http.method_not_implemented=Le méthode {0} n''est pas définie dans la RFC 2068 et n''est pas supportée par l''API Servlet
+
+http.method_get_not_supported=La méthode HTTP GET n''est pas supportée par cette URL
+http.method_post_not_supported=La méthode HTTP POST n''est pas supportée par cette URL
+http.method_put_not_supported=La méthode HTTP PUT n''est pas supportée par cette URL
+http.method_delete_not_supported=La méthode HTTP DELETE n''est pas supportée par cette URL 
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_ja.properties b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_ja.properties
new file mode 100644
index 0000000..eec2148
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/LocalStrings_ja.properties
@@ -0,0 +1,30 @@
+#
+# Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+# Copyright 2004 The Apache Software Foundation
+#
+# 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.
+#
+
+# Default localized string information
+# Localized for Locale ja_JP
+
+err.cookie_name_is_token=\u30af\u30c3\u30ad\u30fc\u540d \"{0}\" \u306f\u4e88\u7d04\u6e08\u306e\u30c8\u30fc\u30af\u30f3\u3067\u3059\u3002
+err.io.negativelength=write\u30e1\u30bd\u30c3\u30c9\u306b\u8ca0\u306e\u9577\u3055\u304c\u6307\u5b9a\u3055\u308c\u307e\u3057\u305f\u3002
+err.io.short_read=\u8aad\u307f\u8fbc\u307f\u304c\u3059\u3050\u306b\u7d42\u308f\u308a\u307e\u3057\u305f\u3002
+
+http.method_not_implemented=\u30e1\u30bd\u30c3\u30c9 {0} \u306fRFC 2068\u306b\u306f\u5b9a\u7fa9\u3055\u308c\u3066\u304a\u3089\u305a\u3001\u30b5\u30fc\u30d6\u30ec\u30c3\u30c8API\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u307e\u305b\u3093\u3002
+
+http.method_get_not_supported=HTTP\u306eGET\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+http.method_post_not_supported=HTTP\u306ePOST\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+http.method_put_not_supported=HTTP\u306ePUT\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
+http.method_delete_not_supported=HTTP\u306eDELETE\u30e1\u30bd\u30c3\u30c9\u306f\u3001\u3053\u306eURL\u3067\u306f\u30b5\u30dd\u30fc\u30c8\u3055\u308c\u3066\u3044\u307e\u305b\u3093\u3002
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/MappingMatch.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/MappingMatch.java
new file mode 100644
index 0000000..4077cc5
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/MappingMatch.java
@@ -0,0 +1,75 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+/**
+ * <p>Enumeration of Servlet mapping types.</p>
+ *
+ * @since 4.0
+ */
+public enum MappingMatch {
+    /**
+     * <p>This is used when the mapping was achieved
+     * with an exact match to the application's context root.</p>
+     */
+    CONTEXT_ROOT,
+    /**
+     * <p>This is used when the mapping was achieved
+     * with an exact match to the default servlet of the application, the '{@code /}'
+     * character.</p>
+     */
+    DEFAULT,
+    /**
+     * <p>This is used when the mapping was achieved
+     * with an exact match to the incoming request.</p>
+     */
+    EXACT,
+    /**
+     * <p>This is used when the mapping was achieved
+     * using an extension, such as "{@code *.xhtml}".</p>
+     */
+    EXTENSION,
+    /**
+     * <p>This is used when the mapping was achieved
+     * using a path, such as "{@code /faces/*}".</p>
+     */
+    PATH
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/Part.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/Part.java
new file mode 100644
index 0000000..6df5083
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/Part.java
@@ -0,0 +1,174 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+import java.io.*;
+import java.util.*;
+
+/**
+ * <p> This class represents a part or form item that was received within a
+ * <code>multipart/form-data</code> POST request.
+ * 
+ * @since Servlet 3.0
+ */
+public interface Part {
+
+    /**
+     * Gets the content of this part as an <tt>InputStream</tt>
+     * 
+     * @return The content of this part as an <tt>InputStream</tt>
+     * @throws IOException If an error occurs in retrieving the content
+     * as an <tt>InputStream</tt>
+     */
+    public InputStream getInputStream() throws IOException;
+
+    /**
+     * Gets the content type of this part.
+     *
+     * @return The content type of this part.
+     */
+    public String getContentType();
+
+    /**
+     * Gets the name of this part
+     *
+     * @return The name of this part as a <tt>String</tt>
+     */
+    public String getName();
+
+    /**
+     * Gets the file name specified by the client
+     *
+     * @return the submitted file name
+     *
+     * @since Servlet 3.1
+     */
+    public String getSubmittedFileName();
+
+    /**
+     * Returns the size of this fille.
+     *
+     * @return a <code>long</code> specifying the size of this part, in bytes.
+     */
+    public long getSize();
+
+    /**
+     * A convenience method to write this uploaded item to disk.
+     * 
+     * <p>This method is not guaranteed to succeed if called more than once for
+     * the same part. This allows a particular implementation to use, for
+     * example, file renaming, where possible, rather than copying all of the
+     * underlying data, thus gaining a significant performance benefit.
+     *
+     * @param fileName The location into which the uploaded part should
+       be stored. The value may be a file name or a path.  The actual
+       location of the file in the filesystem is relative to {@link
+       javax.servlet.MultipartConfigElement#getLocation()}.  Absolute
+       paths are used as provided and are relative to
+       <code>getLocation()</code>.  Note: that this is a system
+       dependent string and URI notation may not be acceptable on all
+       systems. For portability, this string should be generated with
+       the File or Path APIs.
+     *
+     * @throws IOException if an error occurs.
+     */
+    public void write(String fileName) throws IOException;
+
+    /**
+     * Deletes the underlying storage for a file item, including deleting any
+     * associated temporary disk file.
+     *
+     * @throws IOException if an error occurs.
+     */
+    public void delete() throws IOException;
+
+    /**
+     *
+     * Returns the value of the specified mime header
+     * as a <code>String</code>. If the Part did not include a header
+     * of the specified name, this method returns <code>null</code>.
+     * If there are multiple headers with the same name, this method
+     * returns the first header in the part.
+     * The header name is case insensitive. You can use
+     * this method with any request header.
+     *
+     * @param name		a <code>String</code> specifying the
+     *				header name
+     *
+     * @return			a <code>String</code> containing the
+     *				value of the requested
+     *				header, or <code>null</code>
+     *				if the part does not
+     *				have a header of that name
+     */
+    public String getHeader(String name);
+
+    /**
+     * Gets the values of the Part header with the given name.
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>Part</code>.
+     *
+     * <p>Part header names are case insensitive.
+     *
+     * @param name the header name whose values to return
+     *
+     * @return a (possibly empty) <code>Collection</code> of the values of
+     * the header with the given name
+     */
+    public Collection<String> getHeaders(String name);
+
+    /**
+     * Gets the header names of this Part.
+     *
+     * <p>Some servlet containers do not allow
+     * servlets to access headers using this method, in
+     * which case this method returns <code>null</code>
+     *
+     * <p>Any changes to the returned <code>Collection</code> must not 
+     * affect this <code>Part</code>.
+     *
+     * @return a (possibly empty) <code>Collection</code> of the header
+     * names of this Part
+     */
+    public Collection<String> getHeaderNames();
+
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/PushBuilder.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/PushBuilder.java
new file mode 100644
index 0000000..08c68cd
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/PushBuilder.java
@@ -0,0 +1,279 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+import java.util.Set;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+/** 
+ * Build a request to be pushed.
+ * 
+ * According section 8.2 of RFC 7540, a promised request must be cacheable and
+ * safe without a request body.
+ *
+ * <p>A PushBuilder is obtained by calling {@link
+ * HttpServletRequest#newPushBuilder()}.  Each call to this method will
+ * a new instance of a PushBuilder based off the current {@code
+ * HttpServletRequest}, or null.  Any mutations to the returned PushBuilder are
+ * not reflected on future returns.</p>
+ *
+ * <p>The instance is initialized as follows:</p>
+ *
+ * <ul>
+ *
+ * <li>The method is initialized to "GET"</li>
+ *
+ * <li>The existing request headers of the current {@link HttpServletRequest}
+ * are added to the builder, except for:
+ *
+ * <ul>
+ *   <li>Conditional headers (defined in RFC 7232)
+ *   <li>Range headers
+ *   <li>Expect headers
+ *   <li>Authorization headers
+ *   <li>Referrer headers
+ * </ul>
+ *
+ * </li>
+ *
+ * <li>If the request was authenticated, an Authorization header will 
+ * be set with a container generated token that will result in equivalent
+ * Authorization for the pushed request.</li>
+ *
+ * <li>The session ID will be the value returned from {@link
+ * HttpServletRequest#getRequestedSessionId()}, unless {@link
+ * HttpServletRequest#getSession(boolean)} has previously been called to
+ * create a new {@link HttpSession} prior to the call to create the
+ * {@code PushBuilder}, in which case the new session ID will be used as
+ * the PushBuilder's requested session ID.  Note that the session ID
+ * returned from the request can effectively come from one of two
+ * "sources": a cookie or the URL (as specified in {@link
+ * HttpServletRequest#isRequestedSessionIdFromCookie} and {@link
+ * HttpServletRequest#isRequestedSessionIdFromURL}, respectively).  The
+ * session ID for the {@code PushBuilder} will also come from the same
+ * source as the request.</li>
+ *
+ * <li>The Referer(sic) header will be set to {@link
+ * HttpServletRequest#getRequestURL()} plus any {@link
+ * HttpServletRequest#getQueryString()} </li>
+ *
+ * <li>If {@link HttpServletResponse#addCookie(Cookie)} has been called
+ * on the associated response, then a corresponding Cookie header will be added
+ * to the PushBuilder, unless the {@link Cookie#getMaxAge()} is &lt;=0, in which
+ * case the Cookie will be removed from the builder.</li>
+ *
+ * </ul> 
+ *
+ * <p>The {@link #path} method must be called on the {@code PushBuilder}
+ * instance before the call to {@link #push}.  Failure to do so must
+ * cause an exception to be thrown from {@link
+ * #push}, as specified in that method.</p>
+ * 
+ * <p>A PushBuilder can be customized by chained calls to mutator
+ * methods before the {@link #push()} method is called to initiate an
+ * asynchronous push request with the current state of the builder.
+ * After the call to {@link #push()}, the builder may be reused for
+ * another push, however the implementation must make it so the {@link
+ * #path(String)} and conditional headers (defined in RFC 7232) 
+ * values are cleared before returning from {@link #push}.
+ * All other values are retained over calls to {@link #push()}.
+ *
+ * @since Servlet 4.0
+ */
+public interface PushBuilder {
+    /** 
+     * <p>Set the method to be used for the push.</p>
+     * 
+     * @throws NullPointerException if the argument is {@code null}
+     *
+     * @throws IllegalArgumentException if the argument is the empty String,
+     *         or any non-cacheable or unsafe methods defined in RFC 7231,
+     *         which are POST, PUT, DELETE, CONNECT, OPTIONS and TRACE.
+     *
+     * @param method the method to be used for the push.  
+     * @return this builder.
+     */
+    public PushBuilder method(String method);
+    
+    /**
+     * Set the query string to be used for the push.  
+     *
+     * The query string will be appended to any query String included in a call
+     * to {@link #path(String)}.  Any duplicate parameters must be preserved.
+     * This method should be used instead of a query in {@link #path(String)}
+     * when multiple {@link #push()} calls are to be made with the same
+     * query string.
+     * @param  queryString the query string to be used for the push. 
+     * @return this builder.
+     */
+    public PushBuilder queryString(String queryString);
+    
+    /**
+     * Set the SessionID to be used for the push.
+     * The session ID will be set in the same way it was on the associated request (ie
+     * as a cookie if the associated request used a cookie, or as a url parameter if
+     * the associated request used a url parameter).
+     * Defaults to the requested session ID or any newly assigned session id from
+     * a newly created session.
+     * @param sessionId the SessionID to be used for the push.
+     * @return this builder.
+     */
+    public PushBuilder sessionId(String sessionId);
+    
+    /** 
+     * <p>Set a request header to be used for the push.  If the builder has an
+     * existing header with the same name, its value is overwritten.</p>
+     *
+     * @param name The header name to set
+     * @param value The header value to set
+     * @return this builder.
+     */
+    public PushBuilder setHeader(String name, String value);
+    
+    /** 
+     * <p>Add a request header to be used for the push.</p>
+     * @param name The header name to add
+     * @param value The header value to add
+     * @return this builder.
+     */
+    public PushBuilder addHeader(String name, String value);
+
+    /** 
+     * <p>Remove the named request header.  If the header does not exist, take
+     * no action.</p>
+     *
+     * @param name The name of the header to remove
+     * @return this builder.
+     */
+    public PushBuilder removeHeader(String name);
+
+    /** 
+     * Set the URI path to be used for the push.  The path may start
+     * with "/" in which case it is treated as an absolute path,
+     * otherwise it is relative to the context path of the associated
+     * request.  There is no path default and {@link #path(String)} must
+     * be called before every call to {@link #push()}.  If a query
+     * string is present in the argument {@code path}, its contents must
+     * be merged with the contents previously passed to {@link
+     * #queryString}, preserving duplicates.
+     *
+     * @param path the URI path to be used for the push, which may include a
+     * query string.
+     * @return this builder.
+     */
+    public PushBuilder path(String path);
+    
+    /**
+     * Push a resource given the current state of the builder,
+     * the method must be non-blocking.
+     *
+     * <p>Push a resource based on the current state of the PushBuilder.
+     * Calling this method does not guarantee the resource will actually
+     * be pushed, since it is possible the client can decline acceptance
+     * of the pushed resource using the underlying HTTP/2 protocol.</p>
+     *
+     * <p>If the builder has a session ID, then the pushed request will
+     * include the session ID either as a Cookie or as a URI parameter
+     * as appropriate. The builders query string is merged with any
+     * passed query string.</p>
+     *
+     * <p>Before returning from this method, the builder has its path,
+     * conditional headers (defined in RFC 7232) nulled. All other fields
+     * are left as is for possible reuse in another push.</p>
+     *
+     * @throws IllegalStateException if there was no call to {@link
+     * #path} on this instance either between its instantiation or the
+     * last call to {@code push()} that did not throw an
+     * IllegalStateException.
+     */
+    public void push();
+    
+    /**
+     * Return the method to be used for the push.
+     *
+     * @return the method to be used for the push.
+     */
+    public String getMethod();
+
+    /**
+     * Return the query string to be used for the push.
+     *
+     * @return the query string to be used for the push.
+     */
+    public String getQueryString();
+
+    /**
+     * Return the SessionID to be used for the push.
+     * 
+     * @return the SessionID to be used for the push.
+     */
+    public String getSessionId();
+
+    /**
+     * Return the set of header to be used for the push.
+     *
+     * <p>The returned set is not backed by the {@code PushBuilder} object,
+     * so changes in the returned set are not reflected in the
+     * {@code PushBuilder} object, and vice-versa.</p>
+     *
+     * @return the set of header to be used for the push.
+     */
+    public Set<String> getHeaderNames();
+
+    /**
+     * Return the header of the given name to be used for the push.
+     * @param name the name of the header
+     *
+     * @return the header of the given name to be used for the push.
+     */
+    public String getHeader(String name);
+
+    /**
+     * Return the URI path to be used for the push.
+     *
+     * @return the URI path to be used for the push.
+     */
+    public String getPath();
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/WebConnection.java b/third_party/servlet-spec/src/main/java/javax/servlet/http/WebConnection.java
new file mode 100644
index 0000000..cf208d5
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/WebConnection.java
@@ -0,0 +1,73 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2017-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package javax.servlet.http;
+
+import java.io.IOException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletOutputStream;
+
+/**
+ * This interface encapsulates the connection for an upgrade request.
+ * It allows the protocol handler to send service requests and status
+ * queries to the container.
+ *
+ * @since Servlet 3.1
+ */
+
+public interface WebConnection extends AutoCloseable {
+    /**
+     * Returns an input stream for this web connection.
+     *
+     * @return a ServletInputStream for reading binary data
+     *
+     * @exception IOException if an I/O error occurs
+     */
+    public ServletInputStream getInputStream() throws IOException;
+
+    /**
+     * Returns an output stream for this web connection.
+     *
+     * @return a ServletOutputStream for writing binary data
+     *
+     * @exception IOException if an I/O error occurs
+     */
+    public ServletOutputStream getOutputStream() throws IOException;
+}
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/http/package.html b/third_party/servlet-spec/src/main/java/javax/servlet/http/package.html
new file mode 100644
index 0000000..831ffad
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/http/package.html
@@ -0,0 +1,35 @@
+<!--
+
+    Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright 2004 The Apache Software Foundation
+
+    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.
+
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+
+
+</HEAD>
+<BODY BGCOLOR="white">
+
+The javax.servlet.http package contains a number of classes and interfaces
+that describe and define the contracts between a servlet class
+running under the HTTP protocol and the runtime environment provided
+for an instance of such a class by a conforming servlet container.
+
+
+</BODY>
+</HTML>
diff --git a/third_party/servlet-spec/src/main/java/javax/servlet/package.html b/third_party/servlet-spec/src/main/java/javax/servlet/package.html
new file mode 100644
index 0000000..04d1e5a
--- /dev/null
+++ b/third_party/servlet-spec/src/main/java/javax/servlet/package.html
@@ -0,0 +1,35 @@
+<!--
+
+    Copyright (c) 1997-2018 Oracle and/or its affiliates. All rights reserved.
+    Copyright 2004 The Apache Software Foundation
+
+    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.
+
+-->
+
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<HTML>
+<HEAD>
+
+
+</HEAD>
+<BODY BGCOLOR="white">
+
+The javax.servlet package contains a number of classes and interfaces that
+describe and define the contracts between a servlet class and the
+runtime environment provided for an instance of such a class by a
+conforming servlet container.
+
+
+</BODY>
+</HTML>
diff --git a/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-blank.graffle b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-blank.graffle
new file mode 100644
index 0000000..9818b37
--- /dev/null
+++ b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-blank.graffle
@@ -0,0 +1,298 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+<plist version="1.0">
+<dict>
+	<key>ActiveLayerIndex</key>
+	<integer>0</integer>
+	<key>ApplicationVersion</key>
+	<array>
+		<string>com.omnigroup.OmniGrafflePro</string>
+		<string>139.16.0.171715</string>
+	</array>
+	<key>AutoAdjust</key>
+	<false/>
+	<key>BackgroundGraphic</key>
+	<dict>
+		<key>Bounds</key>
+		<string>{{0, 0}, {576, 753.9000244140625}}</string>
+		<key>Class</key>
+		<string>SolidGraphic</string>
+		<key>ID</key>
+		<integer>2</integer>
+		<key>Style</key>
+		<dict>
+			<key>shadow</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+			<key>stroke</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+		</dict>
+	</dict>
+	<key>BaseZoom</key>
+	<integer>0</integer>
+	<key>CanvasOrigin</key>
+	<string>{0, 0}</string>
+	<key>ColumnAlign</key>
+	<integer>1</integer>
+	<key>ColumnSpacing</key>
+	<real>36</real>
+	<key>CreationDate</key>
+	<string>2006-07-19 19:53:09 +0000</string>
+	<key>Creator</key>
+	<string>Edward Burns</string>
+	<key>DisplayScale</key>
+	<string>1 0/72 in = 1.0000 in</string>
+	<key>GraphDocumentVersion</key>
+	<integer>8</integer>
+	<key>GraphicsList</key>
+	<array>
+		<dict>
+			<key>Bounds</key>
+			<string>{{31, 54.125}, {13, 14}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>3</integer>
+			<key>Rotation</key>
+			<real>66</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf510
+{\fonttbl\f0\fnil\fcharset0 AmericanTypewriter;}
+{\colortbl;\red255\green255\blue255;\red255\green242\blue230;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2  }</string>
+				<key>VerticalPad</key>
+				<integer>0</integer>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+	</array>
+	<key>GridInfo</key>
+	<dict/>
+	<key>GuidesLocked</key>
+	<string>NO</string>
+	<key>GuidesVisible</key>
+	<string>YES</string>
+	<key>HPages</key>
+	<integer>1</integer>
+	<key>ImageCounter</key>
+	<integer>1</integer>
+	<key>KeepToScale</key>
+	<false/>
+	<key>Layers</key>
+	<array>
+		<dict>
+			<key>Lock</key>
+			<string>NO</string>
+			<key>Name</key>
+			<string>Layer 1</string>
+			<key>Print</key>
+			<string>YES</string>
+			<key>View</key>
+			<string>YES</string>
+		</dict>
+	</array>
+	<key>LayoutInfo</key>
+	<dict>
+		<key>Animate</key>
+		<string>NO</string>
+		<key>circoMinDist</key>
+		<real>18</real>
+		<key>circoSeparation</key>
+		<real>0.0</real>
+		<key>layoutEngine</key>
+		<string>dot</string>
+		<key>neatoSeparation</key>
+		<real>0.0</real>
+		<key>twopiSeparation</key>
+		<real>0.0</real>
+	</dict>
+	<key>LinksVisible</key>
+	<string>NO</string>
+	<key>MagnetsVisible</key>
+	<string>NO</string>
+	<key>MasterSheets</key>
+	<array/>
+	<key>ModificationDate</key>
+	<string>2012-12-05 21:20:18 +0000</string>
+	<key>Modifier</key>
+	<string>Edward Burns</string>
+	<key>NotesVisible</key>
+	<string>NO</string>
+	<key>Orientation</key>
+	<integer>2</integer>
+	<key>OriginVisible</key>
+	<string>NO</string>
+	<key>PageBreaks</key>
+	<string>YES</string>
+	<key>PrintInfo</key>
+	<dict>
+		<key>NSBottomMargin</key>
+		<array>
+			<string>float</string>
+			<string>4.97998</string>
+		</array>
+		<key>NSHorizonalPagination</key>
+		<array>
+			<string>coded</string>
+			<string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
+		</array>
+		<key>NSLeftMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSPaperSize</key>
+		<array>
+			<string>size</string>
+			<string>{612, 792}</string>
+		</array>
+		<key>NSPrintAllPages</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSPrintReverseOrientation</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSRightMargin</key>
+		<array>
+			<string>float</string>
+			<string>18</string>
+		</array>
+		<key>NSTopMargin</key>
+		<array>
+			<string>float</string>
+			<string>33.12</string>
+		</array>
+	</dict>
+	<key>PrintOnePage</key>
+	<false/>
+	<key>ReadOnly</key>
+	<string>NO</string>
+	<key>RowAlign</key>
+	<integer>1</integer>
+	<key>RowSpacing</key>
+	<real>36</real>
+	<key>SheetTitle</key>
+	<string>Canvas 1</string>
+	<key>SmartAlignmentGuidesActive</key>
+	<string>YES</string>
+	<key>SmartDistanceGuidesActive</key>
+	<string>YES</string>
+	<key>UniqueID</key>
+	<integer>1</integer>
+	<key>UseEntirePage</key>
+	<true/>
+	<key>VPages</key>
+	<integer>1</integer>
+	<key>WindowInfo</key>
+	<dict>
+		<key>CurrentSheet</key>
+		<integer>0</integer>
+		<key>ExpandedCanvases</key>
+		<array/>
+		<key>Frame</key>
+		<string>{{78, 0}, {591, 828}}</string>
+		<key>ListView</key>
+		<false/>
+		<key>OutlineWidth</key>
+		<integer>142</integer>
+		<key>RightSidebar</key>
+		<false/>
+		<key>Sidebar</key>
+		<true/>
+		<key>SidebarWidth</key>
+		<integer>138</integer>
+		<key>VisibleRegion</key>
+		<string>{{0.5, 1}, {219.5, 359.5}}</string>
+		<key>Zoom</key>
+		<real>2</real>
+		<key>ZoomValues</key>
+		<array>
+			<array>
+				<string>Canvas 1</string>
+				<real>2</real>
+				<real>1.5</real>
+			</array>
+		</array>
+	</dict>
+</dict>
+</plist>
diff --git a/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-blank.png b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-blank.png
new file mode 100644
index 0000000..346a7d8
--- /dev/null
+++ b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-blank.png
Binary files differ
diff --git a/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-non-blank.graffle b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-non-blank.graffle
new file mode 100644
index 0000000..63b54c2
--- /dev/null
+++ b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-non-blank.graffle
@@ -0,0 +1,298 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<!--
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 2018 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://oss.oracle.com/licenses/CDDL+GPL-1.1
+    or LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+-->
+
+<plist version="1.0">
+<dict>
+	<key>ActiveLayerIndex</key>
+	<integer>0</integer>
+	<key>ApplicationVersion</key>
+	<array>
+		<string>com.omnigroup.OmniGrafflePro</string>
+		<string>139.18.0.187838</string>
+	</array>
+	<key>AutoAdjust</key>
+	<false/>
+	<key>BackgroundGraphic</key>
+	<dict>
+		<key>Bounds</key>
+		<string>{{0, 0}, {578.800048828125, 754.800048828125}}</string>
+		<key>Class</key>
+		<string>SolidGraphic</string>
+		<key>ID</key>
+		<integer>2</integer>
+		<key>Style</key>
+		<dict>
+			<key>shadow</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+			<key>stroke</key>
+			<dict>
+				<key>Draws</key>
+				<string>NO</string>
+			</dict>
+		</dict>
+	</dict>
+	<key>BaseZoom</key>
+	<integer>0</integer>
+	<key>CanvasOrigin</key>
+	<string>{0, 0}</string>
+	<key>ColumnAlign</key>
+	<integer>1</integer>
+	<key>ColumnSpacing</key>
+	<real>36</real>
+	<key>CreationDate</key>
+	<string>2006-07-19 19:53:09 +0000</string>
+	<key>Creator</key>
+	<string>Edward Burns</string>
+	<key>DisplayScale</key>
+	<string>1 0/72 in = 1.0000 in</string>
+	<key>GraphDocumentVersion</key>
+	<integer>8</integer>
+	<key>GraphicsList</key>
+	<array>
+		<dict>
+			<key>Bounds</key>
+			<string>{{-28, 54.125}, {131, 14}}</string>
+			<key>Class</key>
+			<string>ShapedGraphic</string>
+			<key>FitText</key>
+			<string>YES</string>
+			<key>Flow</key>
+			<string>Resize</string>
+			<key>ID</key>
+			<integer>1</integer>
+			<key>Rotation</key>
+			<real>66</real>
+			<key>Shape</key>
+			<string>Rectangle</string>
+			<key>Style</key>
+			<dict>
+				<key>fill</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>shadow</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+				<key>stroke</key>
+				<dict>
+					<key>Draws</key>
+					<string>NO</string>
+				</dict>
+			</dict>
+			<key>Text</key>
+			<dict>
+				<key>Text</key>
+				<string>{\rtf1\ansi\ansicpg1252\cocoartf1265\cocoasubrtf210
+\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 AmericanTypewriter;}
+{\colortbl;\red255\green255\blue255;\red170\green162\blue153;}
+\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc
+
+\f0\fs24 \cf2 Expert Draft Version}</string>
+				<key>VerticalPad</key>
+				<integer>0</integer>
+			</dict>
+			<key>Wrap</key>
+			<string>NO</string>
+		</dict>
+	</array>
+	<key>GridInfo</key>
+	<dict/>
+	<key>GuidesLocked</key>
+	<string>NO</string>
+	<key>GuidesVisible</key>
+	<string>YES</string>
+	<key>HPages</key>
+	<integer>1</integer>
+	<key>ImageCounter</key>
+	<integer>1</integer>
+	<key>KeepToScale</key>
+	<false/>
+	<key>Layers</key>
+	<array>
+		<dict>
+			<key>Lock</key>
+			<string>NO</string>
+			<key>Name</key>
+			<string>Layer 1</string>
+			<key>Print</key>
+			<string>YES</string>
+			<key>View</key>
+			<string>YES</string>
+		</dict>
+	</array>
+	<key>LayoutInfo</key>
+	<dict>
+		<key>Animate</key>
+		<string>NO</string>
+		<key>circoMinDist</key>
+		<real>18</real>
+		<key>circoSeparation</key>
+		<real>0.0</real>
+		<key>layoutEngine</key>
+		<string>dot</string>
+		<key>neatoSeparation</key>
+		<real>0.0</real>
+		<key>twopiSeparation</key>
+		<real>0.0</real>
+	</dict>
+	<key>LinksVisible</key>
+	<string>NO</string>
+	<key>MagnetsVisible</key>
+	<string>NO</string>
+	<key>MasterSheets</key>
+	<array/>
+	<key>ModificationDate</key>
+	<string>2011-06-16 16:56:40 +0000</string>
+	<key>Modifier</key>
+	<string>Edward Burns</string>
+	<key>NotesVisible</key>
+	<string>NO</string>
+	<key>Orientation</key>
+	<integer>2</integer>
+	<key>OriginVisible</key>
+	<string>NO</string>
+	<key>PageBreaks</key>
+	<string>YES</string>
+	<key>PrintInfo</key>
+	<dict>
+		<key>NSBottomMargin</key>
+		<array>
+			<string>float</string>
+			<string>18.6</string>
+		</array>
+		<key>NSHorizonalPagination</key>
+		<array>
+			<string>coded</string>
+			<string>BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG</string>
+		</array>
+		<key>NSLeftMargin</key>
+		<array>
+			<string>float</string>
+			<string>16.6</string>
+		</array>
+		<key>NSPaperSize</key>
+		<array>
+			<string>size</string>
+			<string>{612.00002479553223, 792}</string>
+		</array>
+		<key>NSPrintAllPages</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSPrintReverseOrientation</key>
+		<array>
+			<string>int</string>
+			<string>0</string>
+		</array>
+		<key>NSRightMargin</key>
+		<array>
+			<string>float</string>
+			<string>16.6</string>
+		</array>
+		<key>NSTopMargin</key>
+		<array>
+			<string>float</string>
+			<string>18.6</string>
+		</array>
+	</dict>
+	<key>PrintOnePage</key>
+	<false/>
+	<key>ReadOnly</key>
+	<string>NO</string>
+	<key>RowAlign</key>
+	<integer>1</integer>
+	<key>RowSpacing</key>
+	<real>36</real>
+	<key>SheetTitle</key>
+	<string>Canvas 1</string>
+	<key>SmartAlignmentGuidesActive</key>
+	<string>YES</string>
+	<key>SmartDistanceGuidesActive</key>
+	<string>YES</string>
+	<key>UniqueID</key>
+	<integer>1</integer>
+	<key>UseEntirePage</key>
+	<true/>
+	<key>VPages</key>
+	<integer>1</integer>
+	<key>WindowInfo</key>
+	<dict>
+		<key>CurrentSheet</key>
+		<integer>0</integer>
+		<key>ExpandedCanvases</key>
+		<array/>
+		<key>Frame</key>
+		<string>{{244, 0}, {591, 828}}</string>
+		<key>ListView</key>
+		<false/>
+		<key>OutlineWidth</key>
+		<integer>142</integer>
+		<key>RightSidebar</key>
+		<false/>
+		<key>Sidebar</key>
+		<true/>
+		<key>SidebarWidth</key>
+		<integer>138</integer>
+		<key>VisibleRegion</key>
+		<string>{{0.5, 2}, {219.5, 351.5}}</string>
+		<key>Zoom</key>
+		<real>2</real>
+		<key>ZoomValues</key>
+		<array>
+			<array>
+				<string>Canvas 1</string>
+				<real>2</real>
+				<real>1.5</real>
+			</array>
+		</array>
+	</dict>
+</dict>
+</plist>
diff --git a/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-non-blank.png b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-non-blank.png
new file mode 100644
index 0000000..714e00c
--- /dev/null
+++ b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg-non-blank.png
Binary files differ
diff --git a/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg.png b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg.png
new file mode 100644
index 0000000..497f46c
--- /dev/null
+++ b/third_party/servlet-spec/src/main/javadoc/doc-files/expert-draft-bg.png
Binary files differ
diff --git a/third_party/servlet-spec/src/main/javadoc/doc-files/speclicense.html b/third_party/servlet-spec/src/main/javadoc/doc-files/speclicense.html
new file mode 100644
index 0000000..ceee9d7
--- /dev/null
+++ b/third_party/servlet-spec/src/main/javadoc/doc-files/speclicense.html
@@ -0,0 +1,215 @@
+<html>
+<head>
+<title>Specification License</title>
+</head>
+<body>
+Specification: JSR-340 Java Servlet 3.1 Specification ("Specification")
+<br/>
+Version: 3.1
+<br/>
+Status: Final Release
+<br/>
+Specification Lead: Oracle America, Inc. ("Specification Lead")
+<br/>
+Release: April 2017
+<br/>
+
+<br/>
+Copyright &#169; 2017 Oracle America, Inc.
+<br/>
+All rights reserved.
+<br/>
+<p>
+LIMITED LICENSE GRANTS
+<br/>
+1. License for Evaluation Purposes. Specification Lead hereby grants
+you a fully-paid, non-exclusive, non-transferable, worldwide, limited
+license (without the right to sublicense), under Specification Lead's
+applicable intellectual property rights to view, download, use and
+reproduce the Specification only for the purpose of internal
+evaluation.  This includes (i) developing applications intended to run
+on an implementation of the Specification, provided that such
+applications do not themselves implement any portion(s) of the
+Specification, and (ii) discussing the Specification with any third
+party; and (iii) excerpting brief portions of the Specification in oral
+or written communications which discuss the Specification provided that
+such excerpts do not in the aggregate constitute a significant portion
+of the Specification.
+</p>
+<p>
+2. License for the Distribution of Compliant Implementations.
+Specification Lead  also grants you a perpetual, non-exclusive,
+non-transferable, worldwide, fully paid-up, royalty free, limited
+license (without the right to sublicense) under any applicable
+copyrights or, subject to the provisions of subsection 4 below, patent
+rights it may have covering the Specification to create and/or
+distribute an Independent Implementation of the Specification that: (a)
+fully implements the Specification including all its required
+interfaces and functionality; (b) does not modify, subset, superset or
+otherwise extend the Licensor Name Space, or include any public or
+protected packages, classes, Java interfaces, fields or methods within
+the Licensor Name Space other than those required/authorized by the
+Specification or Specifications being implemented; and (c) passes the
+Technology Compatibility Kit (including satisfying the requirements of
+the applicable TCK Users Guide) for such Specification ("Compliant
+Implementation").  In addition, the foregoing license is expressly
+conditioned on your not acting outside its scope.  No license is
+granted hereunder for any other purpose (including, for example,
+modifying the Specification, other than to the extent of your fair use
+rights, or distributing the Specification to third parties).  Also, no
+right, title, or interest in or to any trademarks, service marks, or
+trade names of Specification Lead or Specification Lead's licensors is
+granted hereunder.  Java, and Java-related logos, marks and names are
+trademarks or registered trademarks of Oracle America, Inc. in the U.S.
+and other countries.
+</p>
+<p>
+3. Pass-through Conditions. You need not include limitations (a)-(c)
+from the previous paragraph or any other particular "pass through"
+requirements in any license You grant concerning the use of your
+Independent Implementation or products derived from it.  However,
+except with respect to Independent Implementations (and products
+derived from them) that satisfy limitations (a)-(c) from the previous
+paragraph, You may neither:  (a) grant or otherwise pass through to
+your licensees any licenses under Specification Lead's  applicable
+intellectual property rights; nor (b) authorize your licensees to make
+any claims concerning their implementation's compliance with the
+Specification in question.
+</p>
+<p>
+4. Reciprocity Concerning Patent Licenses.  
+<br/>
+a.  With respect to any patent claims covered by the license granted
+under subparagraph 2 above that would be infringed by all technically
+feasible implementations of the Specification, such license is
+conditioned upon your offering on fair, reasonable and
+non-discriminatory terms, to any party seeking it from You, a
+perpetual, non-exclusive, non-transferable, worldwide license under
+Your patent rights which are or would be infringed by all technically
+feasible implementations of the Specification to develop, distribute
+and use a Compliant Implementation.
+<br/>
+b.  With respect to any patent claims owned by Specification Lead and
+covered by the license granted under subparagraph 2, whether or not
+their infringement can be avoided in a technically feasible manner when
+implementing the Specification, such license shall terminate with
+respect to such claims if You initiate a claim against Specification
+Lead that it has, in the course of performing its responsibilities as
+the Specification Lead, induced any other entity to infringe Your
+patent rights.
+<br/>
+c.  Also with respect to any patent claims owned by Specification Lead
+and covered by the license granted under subparagraph 2 above, where
+the infringement of such claims can be avoided in a technically
+feasible manner when implementing the Specification such license, with
+respect to such claims, shall terminate if You initiate a claim against
+Specification Lead  that its making, having made, using, offering to
+sell, selling or importing a Compliant Implementation infringes Your
+patent rights.
+</p>
+<p>
+5. Definitions. For the purposes of this Agreement:  "Independent
+Implementation" shall mean an implementation of the Specification that
+neither derives from any of Specification Lead's  source code or binary
+code materials nor, except with an appropriate and separate license
+from Specification Lead, includes any of Specification Lead's  source
+code or binary code materials; "Licensor Name Space" shall mean the
+public class or interface declarations whose names begin with "java",
+"javax", "com.sun" and "com.oracle" or their equivalents in any
+subsequent naming convention adopted by Oracle America, Inc. through
+the Java Community Process, or any recognized successors or
+replacements thereof; and "Technology Compatibility Kit" or "TCK" shall
+mean the test suite and accompanying TCK User's Guide provided by
+Specification Lead  which corresponds to the Specification and that was
+available either (i) from Specification Lead's 120 days before the
+first release of Your Independent Implementation that allows its use
+for commercial purposes, or (ii) more recently than 120 days from such
+release but against which You elect to test Your implementation of the
+Specification.
+</p>
+<p>
+This Agreement will terminate immediately without notice from
+Specification Lead if you breach the Agreement or act outside the scope
+of the licenses granted above.
+</p>
+<p>
+DISCLAIMER OF WARRANTIES 
+<br/>
+THE SPECIFICATION IS PROVIDED "AS IS". SPECIFICATION LEAD MAKES NO
+REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING BUT
+NOT LIMITED TO, WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+PURPOSE, NON-INFRINGEMENT (INCLUDING AS A CONSEQUENCE OF ANY PRACTICE
+OR IMPLEMENTATION OF THE SPECIFICATION), OR THAT THE CONTENTS OF THE
+SPECIFICATION ARE SUITABLE FOR ANY PURPOSE.  This document does not
+represent any commitment to release or implement any portion of the
+Specification in any product. In addition, the Specification could
+include technical inaccuracies or typographical errors.
+</p>
+<p>
+LIMITATION OF LIABILITY
+<br/>
+TO THE EXTENT NOT PROHIBITED BY LAW, IN NO EVENT WILL SPECIFICATION
+LEAD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES, INCLUDING WITHOUT
+LIMITATION, LOST REVENUE, PROFITS OR DATA, OR FOR SPECIAL, INDIRECT,
+CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
+REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF OR RELATED IN ANY
+WAY TO YOUR HAVING, IMPELEMENTING OR OTHERWISE USING USING  THE
+SPECIFICATION, EVEN IF SPECIFICATION LEAD AND/OR ITS LICENSORS HAVE
+BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.  You will indemnify,
+hold harmless, and defend Specification Lead and its licensors from any
+claims arising or resulting from: (i) your use of the Specification;
+(ii) the use or distribution of your Java application, applet and/or
+implementation; and/or (iii) any claims that later versions or releases
+of any Specification furnished to you are incompatible with the
+Specification provided to you under this license.
+</p>
+<p>
+RESTRICTED RIGHTS LEGEND 
+<br/>
+U.S. Government: If this Specification is being acquired by or on
+behalf of the U.S. Government or by a U.S. Government prime contractor
+or subcontractor (at any tier), then the Government's rights in the
+Software and accompanying documentation shall be only as set forth in
+this license; this is in accordance with 48 C.F.R. 227.7201 through
+227.7202-4 (for Department of Defense (DoD) acquisitions) and with 48
+C.F.R. 2.101 and 12.212 (for non-DoD acquisitions).
+</p>
+<p>
+REPORT
+<br/>
+If you provide Specification Lead with any comments or suggestions
+concerning the Specification ("Feedback"), you hereby: (i) agree that
+such Feedback is provided on a non-proprietary and non-confidential
+basis, and (ii) grant Specification Lead a perpetual, non-exclusive,
+worldwide, fully paid-up, irrevocable license, with the right to
+sublicense through multiple levels of sublicensees, to incorporate,
+disclose, and use without limitation the Feedback for any purpose.
+</p>
+<p>
+GENERAL TERMS
+<br/>
+Any action related to this Agreement will be governed by California law
+and controlling U.S. federal law. The U.N. Convention for the
+International Sale of Goods and the choice of law rules of any
+jurisdiction will not apply.
+</p>
+<p>
+The Specification is subject to U.S. export control laws and may be
+subject to export or import regulations in other countries. Licensee
+agrees to comply strictly with all such laws and regulations and
+acknowledges that it has the responsibility to obtain such licenses to
+export, re-export or import as may be required after delivery to
+Licensee.
+</p>
+<p>
+This Agreement is the parties' entire agreement relating to its subject
+matter. It supersedes all prior or contemporaneous oral or written
+communications, proposals, conditions, representations and warranties
+and prevails over any conflicting or additional terms of any quote,
+order,  acknowledgment, or other communication between the parties
+relating to its subject matter during the term of this Agreement. No
+modification to this Agreement will be binding, unless in writing and
+signed by an authorized representative of each party.
+</p>
+</body>
+</html>
diff --git a/third_party/servlet-spec/src/main/javadoc/javax.servlet-api.css b/third_party/servlet-spec/src/main/javadoc/javax.servlet-api.css
new file mode 100644
index 0000000..4062a9f
--- /dev/null
+++ b/third_party/servlet-spec/src/main/javadoc/javax.servlet-api.css
@@ -0,0 +1,641 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 2011-2017 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License").  You
+ * may not use this file except in compliance with the License.  You can
+ * obtain a copy of the License at
+ * https://oss.oracle.com/licenses/CDDL+GPL-1.1
+ * or LICENSE.txt.  See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license."  If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above.  However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+/* Javadoc style sheet */
+/*
+Overall document style
+*/
+
+@import url('resources/fonts/dejavu.css');
+
+/*    background: url(doc-files/expert-draft-bg.png); */
+
+body {
+    background-color:#ffffff;
+    color:#353833;
+    font-family:'DejaVu Sans', Arial, Helvetica, sans-serif;
+    font-size:14px;
+    margin:0;
+}
+a:link, a:visited {
+    text-decoration:none;
+    color:#4A6782;
+}
+a:hover, a:focus {
+    text-decoration:none;
+    color:#bb7a2a;
+}
+a:active {
+    text-decoration:none;
+    color:#4A6782;
+}
+a[name] {
+    color:#353833;
+}
+a[name]:hover {
+    text-decoration:none;
+    color:#353833;
+}
+pre {
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
+}
+h1 {
+    font-size:20px;
+}
+h2 {
+    font-size:18px;
+}
+h3 {
+    font-size:16px;
+    font-style:italic;
+}
+h4 {
+    font-size:13px;
+}
+h5 {
+    font-size:12px;
+}
+h6 {
+    font-size:11px;
+}
+ul {
+    list-style-type:disc;
+}
+code, tt {
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
+    padding-top:4px;
+    margin-top:8px;
+    line-height:1.4em;
+}
+dt code {
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
+    padding-top:4px;
+}
+table tr td dt code {
+    font-family:'DejaVu Sans Mono', monospace;
+    font-size:14px;
+    vertical-align:top;
+    padding-top:4px;
+}
+sup {
+    font-size:8px;
+}
+/*
+Document title and Copyright styles
+*/
+.clear {
+    clear:both;
+    height:0px;
+    overflow:hidden;
+}
+.aboutLanguage {
+    float:right;
+    padding:0px 21px;
+    font-size:11px;
+    z-index:200;
+    margin-top:-9px;
+}
+.legalCopy {
+    margin-left:.5em;
+}
+.bar a, .bar a:link, .bar a:visited, .bar a:active {
+    color:#FFFFFF;
+    text-decoration:none;
+}
+.bar a:hover, .bar a:focus {
+    color:#bb7a2a;
+}
+.tab {
+    background-color:#0066FF;
+    color:#ffffff;
+    padding:8px;
+    width:5em;
+    font-weight:bold;
+}
+/*
+Navigation bar styles
+*/
+.bar {
+    background-color:#4D7A97;
+    color:#FFFFFF;
+    padding:.8em .5em .4em .8em;
+    height:auto;/*height:1.8em;*/
+    font-size:11px;
+    margin:0;
+}
+.topNav {
+    background-color:#4D7A97;
+    color:#FFFFFF;
+    float:left;
+    padding:0;
+    width:100%;
+    clear:right;
+    height:2.8em;
+    padding-top:10px;
+    overflow:hidden;
+    font-size:12px; 
+}
+.bottomNav {
+    margin-top:10px;
+    background-color:#4D7A97;
+    color:#FFFFFF;
+    float:left;
+    padding:0;
+    width:100%;
+    clear:right;
+    height:2.8em;
+    padding-top:10px;
+    overflow:hidden;
+    font-size:12px;
+}
+.subNav {
+    background-color:#dee3e9;
+    float:left;
+    width:100%;
+    overflow:hidden;
+    font-size:12px;
+}
+.subNav div {
+    clear:left;
+    float:left;
+    padding:0 0 5px 6px;
+    text-transform:uppercase;
+}
+ul.navList, ul.subNavList {
+    float:left;
+    margin:0 25px 0 0;
+    padding:0;
+}
+ul.navList li{
+    list-style:none;
+    float:left;
+    padding: 5px 6px;
+    text-transform:uppercase;
+}
+ul.subNavList li{
+    list-style:none;
+    float:left;
+}
+.topNav a:link, .topNav a:active, .topNav a:visited, .bottomNav a:link, .bottomNav a:active, .bottomNav a:visited {
+    color:#FFFFFF;
+    text-decoration:none;
+    text-transform:uppercase;
+}
+.topNav a:hover, .bottomNav a:hover {
+    text-decoration:none;
+    color:#bb7a2a;
+    text-transform:uppercase;
+}
+.navBarCell1Rev {
+    background-color:#F8981D;
+    color:#253441;
+    margin: auto 5px;
+}
+.skipNav {
+    position:absolute;
+    top:auto;
+    left:-9999px;
+    overflow:hidden;
+}
+/*
+Page header and footer styles
+*/
+.header, .footer {
+    clear:both;
+    margin:0 20px;
+    padding:5px 0 0 0;
+}
+.indexHeader {
+    margin:10px;
+    position:relative;
+}
+.indexHeader span{
+    margin-right:15px;
+}
+.indexHeader h1 {
+    font-size:13px;
+}
+.title {
+    color:#2c4557;
+    margin:10px 0;
+}
+.subTitle {
+    margin:5px 0 0 0;
+}
+.header ul {
+    margin:0 0 15px 0;
+    padding:0;
+}
+.footer ul {
+    margin:20px 0 5px 0;
+}
+.header ul li, .footer ul li {
+    list-style:none;
+    font-size:13px;
+}
+/*
+Heading styles
+*/
+div.details ul.blockList ul.blockList ul.blockList li.blockList h4, div.details ul.blockList ul.blockList ul.blockListLast li.blockList h4 {
+    background-color:#dee3e9;
+    border:1px solid #d0d9e0;
+    margin:0 0 6px -8px;
+    padding:7px 5px;
+}
+ul.blockList ul.blockList ul.blockList li.blockList h3 {
+    background-color:#dee3e9;
+    border:1px solid #d0d9e0;
+    margin:0 0 6px -8px;
+    padding:7px 5px;
+}
+ul.blockList ul.blockList li.blockList h3 {
+    padding:0;
+    margin:15px 0;
+}
+ul.blockList li.blockList h2 {
+    padding:0px 0 20px 0;
+}
+/*
+Page layout container styles
+*/
+.contentContainer, .sourceContainer, .classUseContainer, .serializedFormContainer, .constantValuesContainer {
+    clear:both;
+    padding:10px 20px;
+    position:relative;
+}
+.indexContainer {
+    margin:10px;
+    position:relative;
+    font-size:12px;
+}
+.indexContainer h2 {
+    font-size:13px;
+    padding:0 0 3px 0;
+}
+.indexContainer ul {
+    margin:0;
+    padding:0;
+}
+.indexContainer ul li {
+    list-style:none;
+    padding-top:2px;
+}
+.contentContainer .description dl dt, .contentContainer .details dl dt, .serializedFormContainer dl dt {
+    font-size:12px;
+    font-weight:bold;
+    margin:10px 0 0 0;
+    color:#4E4E4E;
+}
+.contentContainer .description dl dd, .contentContainer .details dl dd, .serializedFormContainer dl dd {
+    margin:5px 0 10px 0px;
+    font-size:14px;
+    font-family:'DejaVu Sans Mono',monospace;
+}
+.serializedFormContainer dl.nameValue dt {
+    margin-left:1px;
+    font-size:1.1em;
+    display:inline;
+    font-weight:bold;
+}
+.serializedFormContainer dl.nameValue dd {
+    margin:0 0 0 1px;
+    font-size:1.1em;
+    display:inline;
+}
+/*
+List styles
+*/
+ul.horizontal li {
+    display:inline;
+    font-size:0.9em;
+}
+ul.inheritance {
+    margin:0;
+    padding:0;
+}
+ul.inheritance li {
+    display:inline;
+    list-style:none;
+}
+ul.inheritance li ul.inheritance {
+    margin-left:15px;
+    padding-left:15px;
+    padding-top:1px;
+}
+ul.blockList, ul.blockListLast {
+    margin:10px 0 10px 0;
+    padding:0;
+}
+ul.blockList li.blockList, ul.blockListLast li.blockList {
+    list-style:none;
+    margin-bottom:15px;
+    line-height:1.4;
+}
+ul.blockList ul.blockList li.blockList, ul.blockList ul.blockListLast li.blockList {
+    padding:0px 20px 5px 10px;
+    border:1px solid #ededed; 
+    background-color:#f8f8f8;
+}
+ul.blockList ul.blockList ul.blockList li.blockList, ul.blockList ul.blockList ul.blockListLast li.blockList {
+    padding:0 0 5px 8px;
+    background-color:#ffffff;
+    border:none;
+}
+ul.blockList ul.blockList ul.blockList ul.blockList li.blockList {
+    margin-left:0;
+    padding-left:0;
+    padding-bottom:15px;
+    border:none;
+}
+ul.blockList ul.blockList ul.blockList ul.blockList li.blockListLast {
+    list-style:none;
+    border-bottom:none;
+    padding-bottom:0;
+}
+table tr td dl, table tr td dl dt, table tr td dl dd {
+    margin-top:0;
+    margin-bottom:1px;
+}
+/*
+Table styles
+*/
+.overviewSummary, .memberSummary, .typeSummary, .useSummary, .constantsSummary, .deprecatedSummary {
+    width:100%;
+    border-left:1px solid #EEE; 
+    border-right:1px solid #EEE; 
+    border-bottom:1px solid #EEE; 
+}
+.overviewSummary, .memberSummary  {
+    padding:0px;
+}
+.overviewSummary caption, .memberSummary caption, .typeSummary caption,
+.useSummary caption, .constantsSummary caption, .deprecatedSummary caption {
+    position:relative;
+    text-align:left;
+    background-repeat:no-repeat;
+    color:#253441;
+    font-weight:bold;
+    clear:none;
+    overflow:hidden;
+    padding:0px;
+    padding-top:10px;
+    padding-left:1px;
+    margin:0px;
+    white-space:pre;
+}
+.overviewSummary caption a:link, .memberSummary caption a:link, .typeSummary caption a:link,
+.useSummary caption a:link, .constantsSummary caption a:link, .deprecatedSummary caption a:link,
+.overviewSummary caption a:hover, .memberSummary caption a:hover, .typeSummary caption a:hover,
+.useSummary caption a:hover, .constantsSummary caption a:hover, .deprecatedSummary caption a:hover,
+.overviewSummary caption a:active, .memberSummary caption a:active, .typeSummary caption a:active,
+.useSummary caption a:active, .constantsSummary caption a:active, .deprecatedSummary caption a:active,
+.overviewSummary caption a:visited, .memberSummary caption a:visited, .typeSummary caption a:visited,
+.useSummary caption a:visited, .constantsSummary caption a:visited, .deprecatedSummary caption a:visited {
+    color:#FFFFFF;
+}
+.overviewSummary caption span, .memberSummary caption span, .typeSummary caption span,
+.useSummary caption span, .constantsSummary caption span, .deprecatedSummary caption span {
+    white-space:nowrap;
+    padding-top:5px;
+    padding-left:12px;
+    padding-right:12px;
+    padding-bottom:7px;
+    display:inline-block;
+    float:left;
+    background-color:#F8981D;
+    border: none;
+    height:16px;
+}
+.memberSummary caption span.activeTableTab span {
+    white-space:nowrap;
+    padding-top:5px;
+    padding-left:12px;
+    padding-right:12px;
+    margin-right:3px;
+    display:inline-block;
+    float:left;
+    background-color:#F8981D;
+    height:16px;
+}
+.memberSummary caption span.tableTab span {
+    white-space:nowrap;
+    padding-top:5px;
+    padding-left:12px;
+    padding-right:12px;
+    margin-right:3px;
+    display:inline-block;
+    float:left;
+    background-color:#4D7A97;
+    height:16px;
+}
+.memberSummary caption span.tableTab, .memberSummary caption span.activeTableTab {
+    padding-top:0px;
+    padding-left:0px;
+    padding-right:0px;
+    background-image:none;
+    float:none;
+    display:inline;
+}
+.overviewSummary .tabEnd, .memberSummary .tabEnd, .typeSummary .tabEnd,
+.useSummary .tabEnd, .constantsSummary .tabEnd, .deprecatedSummary .tabEnd {
+    display:none;
+    width:5px;
+    position:relative;
+    float:left;
+    background-color:#F8981D;
+}
+.memberSummary .activeTableTab .tabEnd {
+    display:none;
+    width:5px;
+    margin-right:3px;
+    position:relative; 
+    float:left;
+    background-color:#F8981D;
+}
+.memberSummary .tableTab .tabEnd {
+    display:none;
+    width:5px;
+    margin-right:3px;
+    position:relative;
+    background-color:#4D7A97;
+    float:left;
+
+}
+.overviewSummary td, .memberSummary td, .typeSummary td,
+.useSummary td, .constantsSummary td, .deprecatedSummary td {
+    text-align:left;
+    padding:0px 0px 12px 10px;
+    width:100%;
+}
+th.colOne, th.colFirst, th.colLast, .useSummary th, .constantsSummary th,
+td.colOne, td.colFirst, td.colLast, .useSummary td, .constantsSummary td{
+    vertical-align:top;
+    padding-right:0px;
+    padding-top:8px;
+    padding-bottom:3px;
+}
+th.colFirst, th.colLast, th.colOne, .constantsSummary th {
+    background:#dee3e9;
+    text-align:left;
+    padding:8px 3px 3px 7px;
+}
+td.colFirst, th.colFirst {
+    white-space:nowrap;
+    font-size:13px;
+}
+td.colLast, th.colLast {
+    font-size:13px;
+}
+td.colOne, th.colOne {
+    font-size:13px;
+}
+.overviewSummary td.colFirst, .overviewSummary th.colFirst,
+.overviewSummary td.colOne, .overviewSummary th.colOne,
+.memberSummary td.colFirst, .memberSummary th.colFirst,
+.memberSummary td.colOne, .memberSummary th.colOne,
+.typeSummary td.colFirst{
+    width:25%;
+    vertical-align:top;
+}
+td.colOne a:link, td.colOne a:active, td.colOne a:visited, td.colOne a:hover, td.colFirst a:link, td.colFirst a:active, td.colFirst a:visited, td.colFirst a:hover, td.colLast a:link, td.colLast a:active, td.colLast a:visited, td.colLast a:hover, .constantValuesContainer td a:link, .constantValuesContainer td a:active, .constantValuesContainer td a:visited, .constantValuesContainer td a:hover {
+    font-weight:bold;
+}
+.tableSubHeadingColor {
+    background-color:#EEEEFF;
+}
+.altColor {
+    background-color:#FFFFFF;
+}
+.rowColor {
+    background-color:#EEEEEF;
+}
+/*
+Content styles
+*/
+.description pre {
+    margin-top:0;
+}
+.deprecatedContent {
+    margin:0;
+    padding:10px 0;
+}
+.docSummary {
+    padding:0;
+}
+
+ul.blockList ul.blockList ul.blockList li.blockList h3 {
+    font-style:normal;
+}
+
+div.block {
+    font-size:14px;
+    font-family:'DejaVu Serif', Georgia, "Times New Roman", Times, serif;
+}
+
+td.colLast div {
+    padding-top:0px;
+}
+
+
+td.colLast a {
+    padding-bottom:3px;
+}
+/*
+Formatting effect styles
+*/
+.sourceLineNo {
+    color:green;
+    padding:0 30px 0 0;
+}
+h1.hidden {
+    visibility:hidden;
+    overflow:hidden;
+    font-size:10px;
+}
+.block {
+    display:block;
+    margin:3px 10px 2px 0px;
+    color:#474747;
+}
+.deprecatedLabel, .descfrmTypeLabel, .memberNameLabel, .memberNameLink,
+.overrideSpecifyLabel, .packageHierarchyLabel, .paramLabel, .returnLabel,
+.seeLabel, .simpleTagLabel, .throwsLabel, .typeNameLabel, .typeNameLink {
+    font-weight:bold;
+}
+.deprecationComment, .emphasizedPhrase, .interfaceName {
+    font-style:italic;
+}
+
+div.block div.block span.deprecationComment, div.block div.block span.emphasizedPhrase,
+div.block div.block span.interfaceName {
+    font-style:normal;
+}
+
+div.contentContainer ul.blockList li.blockList h2{
+    padding-bottom:0px;
+}
+
+
+/* Change bars from http://www.geocities.com/hentaihelper/2atimlin.htm */
+
+/*
+   .changed_added_4_0 { cursor: url(doc-files/changed_added_4_0_cursor.cur), auto;
+                 background: url(doc-files/changed_added_4_0.png); 
+                 padding-left:0.2em; border-left:solid;
+                 border-left-width:thin; border-right:none;
+                 border-top:none; border-bottom:none; border-color:green }
+
+   .changed_modified_4_0 { cursor: url(doc-files/changed_modified_4_0_cursor.cur), auto;
+                 background: url(doc-files/changed_modified_4_0.png); 
+                 padding-left:0.2em; border-left:solid;
+                 border-left-width:thin; border-right:none;
+                 border-top:none; border-bottom:none; border-color:orange }
+
+   .changed_deleted_4_0 { cursor: url(doc-files/changed_deleted_4_0_cursor.cur), auto;
+                 background: url(doc-files/changed_deleted_4_0.png); 
+                 padding-left:0.2em; border-left:solid;
+                 border-left-width:thin; border-right:none;
+                 border-top:none; border-bottom:none; border-color:red;
+                 text-decoration: line-through; }
+
+*/
diff --git a/third_party/servlet-spec/src/main/resources/META-INF/MANIFEST.MF b/third_party/servlet-spec/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/third_party/servlet-spec/src/main/resources/META-INF/MANIFEST.MF
diff --git a/third_party/servlet-spec/src/main/resources/META-INF/README b/third_party/servlet-spec/src/main/resources/META-INF/README
new file mode 100644
index 0000000..56bb2b5
--- /dev/null
+++ b/third_party/servlet-spec/src/main/resources/META-INF/README
@@ -0,0 +1,49 @@
+
+    DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+    Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
+
+    The contents of this file are subject to the terms of either the GNU
+    General Public License Version 2 only ("GPL") or the Common Development
+    and Distribution License("CDDL") (collectively, the "License").  You
+    may not use this file except in compliance with the License.  You can
+    obtain a copy of the License at
+    https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+    or packager/legal/LICENSE.txt.  See the License for the specific
+    language governing permissions and limitations under the License.
+
+    When distributing the software, include this License Header Notice in each
+    file and include the License file at packager/legal/LICENSE.txt.
+
+    GPL Classpath Exception:
+    Oracle designates this particular file as subject to the "Classpath"
+    exception as provided by Oracle in the GPL Version 2 section of the License
+    file that accompanied this code.
+
+    Modifications:
+    If applicable, add the following below the License Header, with the fields
+    enclosed by brackets [] replaced by your own identifying information:
+    "Portions Copyright [year] [name of copyright owner]"
+
+    Contributor(s):
+    If you wish your version of this file to be governed by only the CDDL or
+    only the GPL Version 2, indicate your decision by adding "[Contributor]
+    elects to include this software in this distribution under the [CDDL or GPL
+    Version 2] license."  If you don't indicate a single choice of license, a
+    recipient has the option to distribute your version of this file under
+    either the CDDL, the GPL Version 2 or to extend the choice of license to
+    its licensees as provided above.  However, if you add GPL Version 2 code
+    and therefore, elected the GPL Version 2 license, then the option applies
+    only if the new code is made subject to such option by the copyright
+    holder.
+
+
+The empty MANIFEST.MF is needed because of the way we have configured maven-jar-plugin 
+and maven-bundle-plugin to interact with each other. We may be able to avoid it now, 
+but that will require some effort. I have filed [1] and hopefully I will have some time 
+to fix it in future. 
+
+Thanks,
+Sahoo
+
+[1] https://glassfish.dev.java.net/issues/show_bug.cgi?id=11422