diff -Nru libmojolicious-perl-4.58+dfsg/Changes libmojolicious-perl-4.63+dfsg/Changes --- libmojolicious-perl-4.58+dfsg/Changes 2013-11-19 16:59:12.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/Changes 2013-12-19 18:47:49.000000000 +0000 @@ -1,4 +1,33 @@ +4.63 2013-12-19 + - Deprecated Mojolicious::secret in favor of Mojolicious::secrets. + - Added support for rotating secrets. + - Added secrets method to Mojolicious. + +4.62 2013-12-17 + - Deprecated Mojo::URL::to_rel. + +4.61 2013-12-16 + - Added select_one method to Mojo::DOM::CSS. + - Improved performance of Mojo::DOM::at significantly. + +4.60 2013-12-11 + - Improved Mojolicious::Validator::Validation to allow custom validation + errors. + +4.59 2013-12-04 + - Added CSRF protection support. + - Added support for permessage-deflate WebSocket compression. + - Added csrf_protect method to Mojolicious::Validator::Validation. + - Added build_message method to Mojo::Transaction::WebSocket. + - Added csrf_token attribute to Mojolicious::Validator::Validation. + - Added compressed and context_takeover attributes to + Mojo::Transaction::WebSocket. + - Added csrf_token helper to Mojolicious::Plugin::DefaultHelpers. + - Added csrf_field helper to Mojolicious::Plugin::TagHelpers. + - Removed deprecated mode specific methods in application class. + - Relicensed all artwork to CC-SA version 4.0. + 4.58 2013-11-19 - Improved IIS and WebSphere compatibility of Mojo::Message::Request. - Improved Mojo::Collection to allow join without arguments. diff -Nru libmojolicious-perl-4.58+dfsg/META.json libmojolicious-perl-4.63+dfsg/META.json --- libmojolicious-perl-4.58+dfsg/META.json 2013-11-19 20:45:38.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/META.json 2013-12-19 22:58:18.000000000 +0000 @@ -4,7 +4,7 @@ "Sebastian Riedel " ], "dynamic_config" : 1, - "generated_by" : "ExtUtils::MakeMaker version 6.82, CPAN::Meta::Converter version 2.132830", + "generated_by" : "ExtUtils::MakeMaker version 6.84, CPAN::Meta::Converter version 2.133380", "license" : [ "artistic_2" ], @@ -51,5 +51,5 @@ }, "x_MailingList" : "http://groups.google.com/group/mojolicious" }, - "version" : "4.58" + "version" : "4.63" } diff -Nru libmojolicious-perl-4.58+dfsg/META.yml libmojolicious-perl-4.63+dfsg/META.yml --- libmojolicious-perl-4.58+dfsg/META.yml 2013-11-19 20:45:38.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/META.yml 2013-12-19 22:58:18.000000000 +0000 @@ -7,7 +7,7 @@ configure_requires: ExtUtils::MakeMaker: 0 dynamic_config: 1 -generated_by: 'ExtUtils::MakeMaker version 6.82, CPAN::Meta::Converter version 2.132830' +generated_by: 'ExtUtils::MakeMaker version 6.84, CPAN::Meta::Converter version 2.133380' license: artistic_2 meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html @@ -26,4 +26,4 @@ homepage: http://mojolicio.us license: http://www.opensource.org/licenses/artistic-license-2.0 repository: http://github.com/kraih/mojo -version: 4.58 +version: 4.63 diff -Nru libmojolicious-perl-4.58+dfsg/debian/changelog libmojolicious-perl-4.63+dfsg/debian/changelog --- libmojolicious-perl-4.58+dfsg/debian/changelog 2013-11-24 21:49:48.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/debian/changelog 2013-12-26 19:53:36.000000000 +0000 @@ -1,6 +1,15 @@ +libmojolicious-perl (4.63+dfsg-1) unstable; urgency=low + + * New upstream release + * upstream relicensed artwork with CC4-BY-SA + * upgraded/replaced legal text for above + + -- CSILLAG Tamas Mon, 23 Dec 2013 23:56:19 +0100 + libmojolicious-perl (4.58+dfsg-1) unstable; urgency=low * New upstream release + * declare as conforming to standards-version 3.9.5 -- CSILLAG Tamas Sun, 24 Nov 2013 20:25:08 +0100 diff -Nru libmojolicious-perl-4.58+dfsg/debian/copyright libmojolicious-perl-4.63+dfsg/debian/copyright --- libmojolicious-perl-4.58+dfsg/debian/copyright 2013-11-24 21:49:48.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/debian/copyright 2013-12-26 19:53:36.000000000 +0000 @@ -11,7 +11,7 @@ Files: lib/Mojolicious/public/mojo/* Copyright: 2010-2013, Sebastian Riedel -License: CC-By-SA-3.0 +License: CC-By-SA-4.0 Files: lib/Mojolicious/public/mojo/prettify/prettify.js lib/Mojolicious/public/mojo/prettify/run_prettify.js @@ -245,348 +245,306 @@ DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -License: CC-By-SA-3.0 - THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE - COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY - COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS - AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. - . - BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE - TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY - BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS - CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND - CONDITIONS. - . - 1. Definitions - . - 1. "Adaptation" means a work based upon the Work, or upon the Work - and other pre-existing works, such as a translation, adaptation, - derivative work, arrangement of music or other alterations of a - literary or artistic work, or phonogram or performance and - includes cinematographic adaptations or any other form in which - the Work may be recast, transformed, or adapted including in any - form recognizably derived from the original, except that a work - that constitutes a Collection will not be considered an Adaptation - for the purpose of this License. For the avoidance of doubt, where - the Work is a musical work, performance or phonogram, the - synchronization of the Work in timed-relation with a moving image - ("synching") will be considered an Adaptation for the purpose of - this License. - 2. "Collection" means a collection of literary or artistic works, - such as encyclopedias and anthologies, or performances, phonograms - or broadcasts, or other works or subject matter other than works - listed in Section 1(f) below, which, by reason of the selection - and arrangement of their contents, constitute intellectual - creations, in which the Work is included in its entirety in - unmodified form along with one or more other contributions, each - constituting separate and independent works in themselves, which - together are assembled into a collective whole. A work that - constitutes a Collection will not be considered an Adaptation (as - defined below) for the purposes of this License. - 3. "Creative Commons Compatible License" means a license that is - listed at http://creativecommons.org/compatiblelicenses that has - been approved by Creative Commons as being essentially equivalent - to this License, including, at a minimum, because that license: - (i) contains terms that have the same purpose, meaning and effect - as the License Elements of this License; and, (ii) explicitly - permits the relicensing of adaptations of works made available - under that license under this License or a Creative Commons - jurisdiction license with the same License Elements as this License. - 4. "Distribute" means to make available to the public the original - and copies of the Work or Adaptation, as appropriate, through sale - or other transfer of ownership. - 5. "License Elements" means the following high-level license - attributes as selected by Licensor and indicated in the title of - this License: Attribution, ShareAlike. - 6. "Licensor" means the individual, individuals, entity or entities - that offer(s) the Work under the terms of this License. - 7. "Original Author" means, in the case of a literary or artistic - work, the individual, individuals, entity or entities who created - the Work or if no individual or entity can be identified, the - publisher; and in addition (i) in the case of a performance the - actors, singers, musicians, dancers, and other persons who act, - sing, deliver, declaim, play in, interpret or otherwise perform - literary or artistic works or expressions of folklore; (ii) in the - case of a phonogram the producer being the person or legal entity - who first fixes the sounds of a performance or other sounds; and, - (iii) in the case of broadcasts, the organization that transmits - the broadcast. - 8. "Work" means the literary and/or artistic work offered under the - terms of this License including without limitation any production - in the literary, scientific and artistic domain, whatever may be - the mode or form of its expression including digital form, such as - a book, pamphlet and other writing; a lecture, address, sermon or - other work of the same nature; a dramatic or dramatico-musical - work; a choreographic work or entertainment in dumb show; a - musical composition with or without words; a cinematographic work - to which are assimilated works expressed by a process analogous to - cinematography; a work of drawing, painting, architecture, - sculpture, engraving or lithography; a photographic work to which - are assimilated works expressed by a process analogous to - photography; a work of applied art; an illustration, map, plan, - sketch or three-dimensional work relative to geography, - topography, architecture or science; a performance; a broadcast; a - phonogram; a compilation of data to the extent it is protected as - a copyrightable work; or a work performed by a variety or circus - performer to the extent it is not otherwise considered a literary - or artistic work. - 9. "You" means an individual or entity exercising rights under this - License who has not previously violated the terms of this License - with respect to the Work, or who has received express permission - from the Licensor to exercise rights under this License despite a - previous violation. - 10. "Publicly Perform" means to perform public recitations of the - Work and to communicate to the public those public recitations, by - any means or process, including by wire or wireless means or - public digital performances; to make available to the public Works - in such a way that members of the public may access these Works - from a place and at a place individually chosen by them; to - perform the Work to the public by any means or process and the - communication to the public of the performances of the Work, - including by public digital performance; to broadcast and - rebroadcast the Work by any means including signs, sounds or images. - 11. "Reproduce" means to make copies of the Work by any means - including without limitation by sound or visual recordings and the - right of fixation and reproducing fixations of the Work, including - storage of a protected performance or phonogram in digital form or - other electronic medium. - . - 2. Fair Dealing Rights. Nothing in this License is intended to reduce, - limit, or restrict any uses free from copyright or rights arising from - limitations or exceptions that are provided for in connection with the - copyright protection under copyright law or other applicable laws. - . - 3. License Grant. Subject to the terms and conditions of this License, - Licensor hereby grants You a worldwide, royalty-free, non-exclusive, - perpetual (for the duration of the applicable copyright) license to - exercise the rights in the Work as stated below: - . - 1. to Reproduce the Work, to incorporate the Work into one or more - Collections, and to Reproduce the Work as incorporated in the - Collections; - 2. to create and Reproduce Adaptations provided that any such - Adaptation, including any translation in any medium, takes - reasonable steps to clearly label, demarcate or otherwise identify - that changes were made to the original Work. For example, a - translation could be marked "The original work was translated from - English to Spanish," or a modification could indicate "The - original work has been modified."; - 3. to Distribute and Publicly Perform the Work including as - incorporated in Collections; and, - 4. to Distribute and Publicly Perform Adaptations. - 5. - . - For the avoidance of doubt: - . - 1. Non-waivable Compulsory License Schemes. In those - jurisdictions in which the right to collect royalties - through any statutory or compulsory licensing scheme cannot - be waived, the Licensor reserves the exclusive right to - collect such royalties for any exercise by You of the rights - granted under this License; - 2. Waivable Compulsory License Schemes. In those - jurisdictions in which the right to collect royalties - through any statutory or compulsory licensing scheme can be - waived, the Licensor waives the exclusive right to collect - such royalties for any exercise by You of the rights granted - under this License; and, - 3. Voluntary License Schemes. The Licensor waives the right - to collect royalties, whether individually or, in the event - that the Licensor is a member of a collecting society that - administers voluntary licensing schemes, via that society, - from any exercise by You of the rights granted under this - License. - . - The above rights may be exercised in all media and formats whether now - known or hereafter devised. The above rights include the right to make - such modifications as are technically necessary to exercise the rights - in other media and formats. Subject to Section 8(f), all rights not - expressly granted by Licensor are hereby reserved. - . - 4. Restrictions. The license granted in Section 3 above is expressly - made subject to and limited by the following restrictions: - . - 1. You may Distribute or Publicly Perform the Work only under the - terms of this License. You must include a copy of, or the Uniform - Resource Identifier (URI) for, this License with every copy of the - Work You Distribute or Publicly Perform. You may not offer or - impose any terms on the Work that restrict the terms of this - License or the ability of the recipient of the Work to exercise - the rights granted to that recipient under the terms of the - License. You may not sublicense the Work. You must keep intact all - notices that refer to this License and to the disclaimer of - warranties with every copy of the Work You Distribute or Publicly - Perform. When You Distribute or Publicly Perform the Work, You may - not impose any effective technological measures on the Work that - restrict the ability of a recipient of the Work from You to - exercise the rights granted to that recipient under the terms of - the License. This Section 4(a) applies to the Work as incorporated - in a Collection, but this does not require the Collection apart - from the Work itself to be made subject to the terms of this - License. If You create a Collection, upon notice from any Licensor - You must, to the extent practicable, remove from the Collection - any credit as required by Section 4(c), as requested. If You - create an Adaptation, upon notice from any Licensor You must, to - the extent practicable, remove from the Adaptation any credit as - required by Section 4(c), as requested. - 2. You may Distribute or Publicly Perform an Adaptation only under - the terms of: (i) this License; (ii) a later version of this - License with the same License Elements as this License; (iii) a - Creative Commons jurisdiction license (either this or a later - license version) that contains the same License Elements as this - License (e.g., Attribution-ShareAlike 3.0 US)); (iv) a Creative - Commons Compatible License. If you license the Adaptation under - one of the licenses mentioned in (iv), you must comply with the - terms of that license. If you license the Adaptation under the - terms of any of the licenses mentioned in (i), (ii) or (iii) (the - "Applicable License"), you must comply with the terms of the - Applicable License generally and the following provisions: (I) You - must include a copy of, or the URI for, the Applicable License - with every copy of each Adaptation You Distribute or Publicly - Perform; (II) You may not offer or impose any terms on the - Adaptation that restrict the terms of the Applicable License or - the ability of the recipient of the Adaptation to exercise the - rights granted to that recipient under the terms of the Applicable - License; (III) You must keep intact all notices that refer to the - Applicable License and to the disclaimer of warranties with every - copy of the Work as included in the Adaptation You Distribute or - Publicly Perform; (IV) when You Distribute or Publicly Perform the - Adaptation, You may not impose any effective technological - measures on the Adaptation that restrict the ability of a - recipient of the Adaptation from You to exercise the rights - granted to that recipient under the terms of the Applicable - License. This Section 4(b) applies to the Adaptation as - incorporated in a Collection, but this does not require the - Collection apart from the Adaptation itself to be made subject to - the terms of the Applicable License. - 3. If You Distribute, or Publicly Perform the Work or any Adaptations - or Collections, You must, unless a request has been made pursuant - to Section 4(a), keep intact all copyright notices for the Work - and provide, reasonable to the medium or means You are utilizing: - (i) the name of the Original Author (or pseudonym, if applicable) - if supplied, and/or if the Original Author and/or Licensor - designate another party or parties (e.g., a sponsor institute, - publishing entity, journal) for attribution ("Attribution - Parties") in Licensor's copyright notice, terms of service or by - other reasonable means, the name of such party or parties; (ii) - the title of the Work if supplied; (iii) to the extent reasonably - practicable, the URI, if any, that Licensor specifies to be - associated with the Work, unless such URI does not refer to the - copyright notice or licensing information for the Work; and (iv) , - consistent with Ssection 3(b), in the case of an Adaptation, a - credit identifying the use of the Work in the Adaptation (e.g., - "French translation of the Work by Original Author," or - "Screenplay based on original Work by Original Author"). The - credit required by this Section 4(c) may be implemented in any - reasonable manner; provided, however, that in the case of a - Adaptation or Collection, at a minimum such credit will appear, if - a credit for all contributing authors of the Adaptation or - Collection appears, then as part of these credits and in a manner - at least as prominent as the credits for the other contributing - authors. For the avoidance of doubt, You may only use the credit - required by this Section for the purpose of attribution in the - manner set out above and, by exercising Your rights under this - License, You may not implicitly or explicitly assert or imply any - connection with, sponsorship or endorsement by the Original - Author, Licensor and/or Attribution Parties, as appropriate, of - You or Your use of the Work, without the separate, express prior - written permission of the Original Author, Licensor and/or - Attribution Parties. - 4. Except as otherwise agreed in writing by the Licensor or as may be - otherwise permitted by applicable law, if You Reproduce, - Distribute or Publicly Perform the Work either by itself or as - part of any Adaptations or Collections, You must not distort, - mutilate, modify or take other derogatory action in relation to - the Work which would be prejudicial to the Original Author's honor - or reputation. Licensor agrees that in those jurisdictions (e.g. - Japan), in which any exercise of the right granted in Section 3(b) - of this License (the right to make Adaptations) would be deemed to - be a distortion, mutilation, modification or other derogatory - action prejudicial to the Original Author's honor and reputation, - the Licensor will waive or not assert, as appropriate, this - Section, to the fullest extent permitted by the applicable - national law, to enable You to reasonably exercise Your right - under Section 3(b) of this License (right to make Adaptations) but - not otherwise. - . - 5. Representations, Warranties and Disclaimer - . - UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR - OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY - KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, - INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, - FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF - LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, - WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE - EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. - . - 6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY - APPLICABLE LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL - THEORY FOR ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY - DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF - LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. - . - 7. Termination - . - 1. This License and the rights granted hereunder will terminate - automatically upon any breach by You of the terms of this License. - Individuals or entities who have received Adaptations or - Collections from You under this License, however, will not have - their licenses terminated provided such individuals or entities - remain in full compliance with those licenses. Sections 1, 2, 5, - 6, 7, and 8 will survive any termination of this License. - 2. Subject to the above terms and conditions, the license granted - here is perpetual (for the duration of the applicable copyright in - the Work). Notwithstanding the above, Licensor reserves the right - to release the Work under different license terms or to stop - distributing the Work at any time; provided, however that any such - election will not serve to withdraw this License (or any other - license that has been, or is required to be, granted under the - terms of this License), and this License will continue in full - force and effect unless terminated as stated above. - . - 8. Miscellaneous - . - 1. Each time You Distribute or Publicly Perform the Work or a - Collection, the Licensor offers to the recipient a license to the - Work on the same terms and conditions as the license granted to - You under this License. - 2. Each time You Distribute or Publicly Perform an Adaptation, - Licensor offers to the recipient a license to the original Work on - the same terms and conditions as the license granted to You under - this License. - 3. If any provision of this License is invalid or unenforceable under - applicable law, it shall not affect the validity or enforceability - of the remainder of the terms of this License, and without further - action by the parties to this agreement, such provision shall be - reformed to the minimum extent necessary to make such provision - valid and enforceable. - 4. No term or provision of this License shall be deemed waived and no - breach consented to unless such waiver or consent shall be in - writing and signed by the party to be charged with such waiver or - consent. - 5. This License constitutes the entire agreement between the parties - with respect to the Work licensed here. There are no - understandings, agreements or representations with respect to the - Work not specified here. Licensor shall not be bound by any - additional provisions that may appear in any communication from - You. This License may not be modified without the mutual written - agreement of the Licensor and You. - 6. The rights granted under, and the subject matter referenced, in - this License were drafted utilizing the terminology of the Berne - Convention for the Protection of Literary and Artistic Works (as - amended on September 28, 1979), the Rome Convention of 1961, the - WIPO Copyright Treaty of 1996, the WIPO Performances and - Phonograms Treaty of 1996 and the Universal Copyright Convention - (as revised on July 24, 1971). These rights and subject matter - take effect in the relevant jurisdiction in which the License - terms are sought to be enforced according to the corresponding - provisions of the implementation of those treaty provisions in the - applicable national law. If the standard suite of rights granted - under applicable copyright law includes additional rights not - granted under this License, such additional rights are deemed to - be included in the License; this License is not intended to - restrict the license of any rights under applicable law. +License: CC-By-SA-4.0 + Creative Commons Attribution-ShareAlike 4.0 International Public License + . + By exercising the Licensed Rights (defined below), You accept and + agree to be bound by the terms and conditions of this Creative Commons + Attribution-ShareAlike 4.0 International Public License ("Public + License"). To the extent this Public License may be interpreted as a + contract, You are granted the Licensed Rights in consideration of Your + acceptance of these terms and conditions, and the Licensor grants You + such rights in consideration of benefits the Licensor receives from + making the Licensed Material available under these terms and + conditions. + . + Section 1 – Definitions. + . +  a. Adapted Material means material subject to Copyright and Similar + Rights that is derived from or based upon the Licensed Material + and in which the Licensed Material is translated, altered, + arranged, transformed, or otherwise modified in a manner requiring + permission under the Copyright and Similar Rights held by the + Licensor. For purposes of this Public License, where the Licensed + Material is a musical work, performance, or sound recording, + Adapted Material is always produced where the Licensed Material is + synched in timed relation with a moving image. +  b. Adapter's License means the license You apply to Your Copyright + and Similar Rights in Your contributions to Adapted Material in + accordance with the terms and conditions of this Public License. +  c. BY-SA Compatible License means a license listed at + creativecommons.org/compatiblelicenses, approved by Creative + Commons as essentially the equivalent of this Public License. +  d. Copyright and Similar Rights means copyright and/or similar rights + closely related to copyright including, without limitation, + performance, broadcast, sound recording, and Sui Generis Database + Rights, without regard to how the rights are labeled or + categorized. For purposes of this Public License, the rights + specified in Section 2(b)(1)-(2) are not Copyright and Similar + Rights. +  e. Effective Technological Measures means those measures that, in the + absence of proper authority, may not be circumvented under laws + fulfilling obligations under Article 11 of the WIPO Copyright + Treaty adopted on December 20, 1996, and/or similar international + agreements. +  f. Exceptions and Limitations means fair use, fair dealing, and/or + any other exception or limitation to Copyright and Similar Rights + that applies to Your use of the Licensed Material. +  g. License Elements means the license attributes listed in the name + of a Creative Commons Public License. The License Elements of this + Public License are Attribution and ShareAlike. +  h. Licensed Material means the artistic or literary work, database, + or other material to which the Licensor applied this Public + License. +  i. Licensed Rights means the rights granted to You subject to the + terms and conditions of this Public License, which are limited to + all Copyright and Similar Rights that apply to Your use of the + Licensed Material and that the Licensor has authority to license. +  j. Licensor means the individual(s) or entity(ies) granting rights + under this Public License. +  k. Share means to provide material to the public by any means or + process that requires permission under the Licensed Rights, such + as reproduction, public display, public performance, distribution, + dissemination, communication, or importation, and to make material + available to the public including in ways that members of the + public may access the material from a place and at a time + individually chosen by them. +  l. Sui Generis Database Rights means rights other than copyright + resulting from Directive 96/9/EC of the European Parliament and of + the Council of 11 March 1996 on the legal protection of databases, + as amended and/or succeeded, as well as other essentially + equivalent rights anywhere in the world. +  m. You means the individual or entity exercising the Licensed Rights + under this Public License. Your has a corresponding meaning. + . + Section 2 – Scope. + . +  a. License grant. + . +  1. Subject to the terms and conditions of this Public License, + the Licensor hereby grants You a worldwide, royalty-free, + non-sublicensable, non-exclusive, irrevocable license to + exercise the Licensed Rights in the Licensed Material to: + . +  A. reproduce and Share the Licensed Material, in whole or + in part; and +  B. produce, reproduce, and Share Adapted Material. + . +  2. Exceptions and Limitations. For the avoidance of doubt, where + Exceptions and Limitations apply to Your use, this Public + License does not apply, and You do not need to comply with + its terms and conditions. +  3. Term. The term of this Public License is specified in Section + 6(a). +  4. Media and formats; technical modifications allowed. The + Licensor authorizes You to exercise the Licensed Rights in + all media and formats whether now known or hereafter created, + and to make technical modifications necessary to do so. The + Licensor waives and/or agrees not to assert any right or + authority to forbid You from making technical modifications + necessary to exercise the Licensed Rights, including + technical modifications necessary to circumvent Effective + Technological Measures. For purposes of this Public License, + simply making modifications authorized by this Section + 2(a)(4) never produces Adapted Material. +  5. Downstream recipients. + . +  A. Offer from the Licensor – Licensed Material. Every + recipient of the Licensed Material automatically + receives an offer from the Licensor to exercise the + Licensed Rights under the terms and conditions of this + Public License. +  B. Additional offer from the Licensor – Adapted Material. + Every recipient of Adapted Material from You + automatically receives an offer from the Licensor to + exercise the Licensed Rights in the Adapted Material + under the conditions of the Adapter’s License You apply. +  C. No downstream restrictions. You may not offer or impose + any additional or different terms or conditions on, or + apply any Effective Technological Measures to, the + Licensed Material if doing so restricts exercise of the + Licensed Rights by any recipient of the Licensed + Material. + . +  6. No endorsement. Nothing in this Public License constitutes or + may be construed as permission to assert or imply that You + are, or that Your use of the Licensed Material is, connected + with, or sponsored, endorsed, or granted official status by, + the Licensor or others designated to receive attribution as + provided in Section 3(a)(1)(A)(i). + . +  b. Other rights. + . +  1. Moral rights, such as the right of integrity, are not + licensed under this Public License, nor are publicity, + privacy, and/or other similar personality rights; however, to + the extent possible, the Licensor waives and/or agrees not to + assert any such rights held by the Licensor to the limited + extent necessary to allow You to exercise the Licensed + Rights, but not otherwise. +  2. Patent and trademark rights are not licensed under this + Public License. +  3. To the extent possible, the Licensor waives any right to + collect royalties from You for the exercise of the Licensed + Rights, whether directly or through a collecting society + under any voluntary or waivable statutory or compulsory + licensing scheme. In all other cases the Licensor expressly + reserves any right to collect such royalties. + . + Section 3 – License Conditions. + . + Your exercise of the Licensed Rights is expressly made subject to the + following conditions. + . +  a. Attribution. + . +  1. If You Share the Licensed Material (including in modified + form), You must: + . +  A. retain the following if it is supplied by the Licensor + with the Licensed Material: + . + i. identification of the creator(s) of the Licensed + Material and any others designated to receive + attribution, in any reasonable manner requested by + the Licensor (including by pseudonym if designated); + ii. a copyright notice; + iii. a notice that refers to this Public License; + iv. a notice that refers to the disclaimer of + warranties; + v. a URI or hyperlink to the Licensed Material to the + extent reasonably practicable; + . +  B. indicate if You modified the Licensed Material and + retain an indication of any previous modifications; and +  C. indicate the Licensed Material is licensed under this + Public License, and include the text of, or the URI or + hyperlink to, this Public License. + . +  2. You may satisfy the conditions in Section 3(a)(1) in any + reasonable manner based on the medium, means, and context in + which You Share the Licensed Material. For example, it may be + reasonable to satisfy the conditions by providing a URI or + hyperlink to a resource that includes the required + information. +  3. If requested by the Licensor, You must remove any of the + information required by Section 3(a)(1)(A) to the extent + reasonably practicable. + . +  b. ShareAlike. + . + In addition to the conditions in Section 3(a), if You Share + Adapted Material You produce, the following conditions also apply. + . +  1. The Adapter’s License You apply must be a Creative Commons + license with the same License Elements, this version or + later, or a BY-SA Compatible License. +  2. You must include the text of, or the URI or hyperlink to, the + Adapter's License You apply. You may satisfy this condition + in any reasonable manner based on the medium, means, and + context in which You Share Adapted Material. +  3. You may not offer or impose any additional or different terms + or conditions on, or apply any Effective Technological + Measures to, Adapted Material that restrict exercise of the + rights granted under the Adapter's License You apply. + . + Section 4 – Sui Generis Database Rights. + . + Where the Licensed Rights include Sui Generis Database Rights that + apply to Your use of the Licensed Material: + . +  a. for the avoidance of doubt, Section 2(a)(1) grants You the right + to extract, reuse, reproduce, and Share all or a substantial + portion of the contents of the database; +  b. if You include all or a substantial portion of the database + contents in a database in which You have Sui Generis Database + Rights, then the database in which You have Sui Generis Database + Rights (but not its individual contents) is Adapted Material, + including for purposes of Section 3(b); and +  c. You must comply with the conditions in Section 3(a) if You Share + all or a substantial portion of the contents of the database. + . + For the avoidance of doubt, this Section 4 supplements and does not + replace Your obligations under this Public License where the Licensed + Rights include other Copyright and Similar Rights. + . + Section 5 – Disclaimer of Warranties and Limitation of Liability. + . +  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE + EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS + AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF + ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS, + IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION, + WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR + PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS, + ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT + KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT + ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU. +  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE TO + YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION, + NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT, + INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES, + COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR + USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN + ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR + DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR + IN PART, THIS LIMITATION MAY NOT APPLY TO YOU. +  c. the disclaimer of warranties and limitation of liability provided + above shall be interpreted in a manner that, to the extent + possible, most closely approximates an absolute disclaimer and + waiver of all liability. + . + Section 6 – Term and Termination. + . +  a. This Public License applies for the term of the Copyright and + Similar Rights licensed here. However, if You fail to comply with + this Public License, then Your rights under this Public License + terminate automatically. +  b. Where Your right to use the Licensed Material has terminated under + Section 6(a), it reinstates: + . +  1. automatically as of the date the violation is cured, provided + it is cured within 30 days of Your discovery of the + violation; or +  2. upon express reinstatement by the Licensor. + . + For the avoidance of doubt, this Section 6(b) does not affect any + right the Licensor may have to seek remedies for Your violations + of this Public License. +  c. For the avoidance of doubt, the Licensor may also offer the + Licensed Material under separate terms or conditions or stop + distributing the Licensed Material at any time; however, doing so + will not terminate this Public License. +  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public + License. + . + Section 7 – Other Terms and Conditions. + . +  a. The Licensor shall not be bound by any additional or different + terms or conditions communicated by You unless expressly agreed. +  b. Any arrangements, understandings, or agreements regarding the + Licensed Material not stated herein are separate from and + independent of the terms and conditions of this Public License. + . + Section 8 – Interpretation. + . +  a. For the avoidance of doubt, this Public License does not, and + shall not be interpreted to, reduce, limit, restrict, or impose + conditions on any use of the Licensed Material that could lawfully + be made without permission under this Public License. +  b. To the extent possible, if any provision of this Public License is + deemed unenforceable, it shall be automatically reformed to the + minimum extent necessary to make it enforceable. If the provision + cannot be reformed, it shall be severed from this Public License + without affecting the enforceability of the remaining terms and + conditions. +  c. No term or condition of this Public License will be waived and no + failure to comply consented to unless expressly agreed to by the + Licensor. +  d. Nothing in this Public License constitutes or may be interpreted + as a limitation upon, or waiver of, any privileges and immunities + that apply to the Licensor or You, including from the legal + processes of any jurisdiction or authority. License: GPL-1+ This program is free software; you can redistribute it and/or modify diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/Asset/File.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/Asset/File.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/Asset/File.pm 2013-11-01 14:30:51.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/Asset/File.pm 2013-12-18 00:10:06.000000000 +0000 @@ -26,7 +26,7 @@ my $name = $path // $base; until ($handle->open($name, O_CREAT | O_EXCL | O_RDWR)) { croak qq{Can't open file "$name": $!} if defined $path || $! != $!{EEXIST}; - $name = "$base." . md5_sum(time . $$ . rand 9 x 7); + $name = "$base." . md5_sum(time . $$ . rand 999); } $self->path($name); diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/Base.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/Base.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/Base.pm 2013-11-13 19:48:58.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/Base.pm 2013-11-30 00:42:15.000000000 +0000 @@ -36,9 +36,7 @@ } # Mojo modules are strict! - strict->import; - warnings->import; - utf8->import; + $_->import for qw(strict warnings utf8); feature->import(':5.10'); } diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/ByteStream.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/ByteStream.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/ByteStream.pm 2013-11-01 14:19:20.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/ByteStream.pm 2013-11-19 23:24:35.000000000 +0000 @@ -74,8 +74,9 @@ =head1 SYNOPSIS - # Manipulate bytestreams use Mojo::ByteStream; + + # Manipulate bytestream my $stream = Mojo::ByteStream->new('foo_bar_baz'); say $stream->camelize; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/Collection.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/Collection.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/Collection.pm 2013-11-17 02:30:53.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/Collection.pm 2013-12-15 04:08:49.000000000 +0000 @@ -110,15 +110,22 @@ =head1 SYNOPSIS - # Manipulate collections use Mojo::Collection; + + # Manipulate collection my $collection = Mojo::Collection->new(qw(just works)); unshift @$collection, 'it'; - $collection->map(sub { ucfirst })->each(sub { + + # Chain methods + $collection->map(sub { ucfirst })->shuffle->each(sub { my ($word, $count) = @_; say "$count: $word"; }); + # Stringify collection + say $collection->join("\n"); + say "$collection"; + # Use the alternative constructor use Mojo::Collection 'c'; c(qw(a b c))->join('/')->url_escape->say; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/DOM/CSS.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/DOM/CSS.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/DOM/CSS.pm 2013-11-01 14:30:41.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/DOM/CSS.pm 2013-12-19 20:52:06.000000000 +0000 @@ -40,28 +40,8 @@ return $self->_match($self->_compile(shift), $tree, $tree); } -sub select { - my $self = shift; - - my @results; - my $pattern = $self->_compile(shift); - my $tree = $self->tree; - my @queue = ($tree); - while (my $current = shift @queue) { - my $type = $current->[0]; - - # Tag - if ($type eq 'tag') { - unshift @queue, @$current[4 .. $#$current]; - push @results, $current if $self->_match($pattern, $current, $tree); - } - - # Root - elsif ($type eq 'root') { unshift @queue, @$current[1 .. $#$current] } - } - - return \@results; -} +sub select { shift->_select(0, @_) } +sub select_one { shift->_select(1, @_) } sub _ancestor { my ($self, $selectors, $current, $tree) = @_; @@ -314,6 +294,30 @@ return qr/^$value$/; } +sub _select { + my ($self, $one, $selector) = @_; + + my @results; + my $pattern = $self->_compile($selector); + my $tree = $self->tree; + my @queue = ($tree); + while (my $current = shift @queue) { + my $type = $current->[0]; + + # Tag + if ($type eq 'tag') { + unshift @queue, @$current[4 .. $#$current]; + next unless $self->_match($pattern, $current, $tree); + $one ? return $current : push @results, $current; + } + + # Root + elsif ($type eq 'root') { unshift @queue, @$current[1 .. $#$current] } + } + + return $one ? undef : \@results; +} + sub _selector { my ($self, $selector, $current) = @_; @@ -623,6 +627,13 @@ Run CSS selector against L. +=head2 select_one + + my $result = $css->select_one('head > title'); + +Run CSS selector against L and stop as soon as the first node +matched. + =head1 SEE ALSO L, L, L. diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/DOM.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/DOM.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/DOM.pm 2013-11-07 00:41:34.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/DOM.pm 2013-12-16 02:35:02.000000000 +0000 @@ -49,7 +49,11 @@ return $self; } -sub at { shift->find(@_)->[0] } +sub at { + my $self = shift; + return undef unless my $result = $self->_css->select_one(@_); + return $self->new->tree($result)->xml($self->xml); +} sub attr { my $self = shift; @@ -80,17 +84,9 @@ return join '', map { _render($_, $xml) } _nodes($self->tree); } -sub find { - my $self = shift; - my $results = Mojo::DOM::CSS->new(tree => $self->tree)->select(@_); - return $self->_collect(@$results); -} +sub find { $_[0]->_collect(@{$_[0]->_css->select($_[1])}) } -sub match { - my $self = shift; - return undef unless Mojo::DOM::CSS->new(tree => $self->tree)->match(@_); - return $self; -} +sub match { $_[0]->_css->match($_[1]) ? $_[0] : undef } sub namespace { my $self = shift; @@ -246,6 +242,8 @@ return _text([_nodes($tree)], shift, _trim($tree, @_)); } +sub _css { Mojo::DOM::CSS->new(tree => shift->tree) } + sub _delegate { my ($self, $method) = (shift, shift); return $self->[0]->$method unless @_; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/JSON.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/JSON.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/JSON.pm 2013-11-19 16:59:06.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/JSON.pm 2013-11-19 23:25:44.000000000 +0000 @@ -329,8 +329,9 @@ =head1 SYNOPSIS - # Encode and decode JSON use Mojo::JSON; + + # Encode and decode JSON my $json = Mojo::JSON->new; my $bytes = $json->encode({foo => [1, 2], bar => 'hello!', baz => \1}); my $hash = $json->decode($bytes); diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/Template.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/Template.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/Template.pm 2013-11-13 16:25:45.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/Template.pm 2013-12-17 20:21:11.000000000 +0000 @@ -326,9 +326,9 @@ =head1 SYNOPSIS use Mojo::Template; - my $mt = Mojo::Template->new; # Simple + my $mt = Mojo::Template->new; my $output = $mt->render(<<'EOF'); % use Time::Piece; @@ -642,20 +642,20 @@ $mt = $mt->build; -Build Perl code from tree. +Build Perl L from L. =head2 compile my $exception = $mt->compile; -Compile Perl code for template. +Compile Perl L for template. =head2 interpret my $output = $mt->interpret; my $output = $mt->interpret(@args); -Interpret compiled template code. +Interpret L template code. # Reuse template say $mt->render('Hello <%= $_[0] %>!', 'Bender'); @@ -666,7 +666,7 @@ $mt = $mt->parse($template); -Parse template into tree. +Parse template into L. =head2 render diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/Transaction/HTTP.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/Transaction/HTTP.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/Transaction/HTTP.pm 2013-11-01 14:35:06.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/Transaction/HTTP.pm 2013-12-18 00:13:01.000000000 +0000 @@ -262,9 +262,10 @@ =head2 previous my $previous = $tx->previous; - $tx = $tx->previous(Mojo::Transaction->new); + $tx = $tx->previous(Mojo::Transaction::HTTP->new); -Previous transaction that triggered this followup transaction. +Previous transaction that triggered this followup transaction, usually a +L object. # Paths of previous requests say $tx->previous->previous->req->url->path; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/Transaction/WebSocket.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/Transaction/WebSocket.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/Transaction/WebSocket.pm 2013-11-01 14:35:04.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/Transaction/WebSocket.pm 2013-12-18 00:10:58.000000000 +0000 @@ -1,6 +1,7 @@ package Mojo::Transaction::WebSocket; use Mojo::Base 'Mojo::Transaction'; +use Compress::Raw::Zlib 'Z_SYNC_FLUSH'; use Config; use Mojo::JSON; use Mojo::Transaction::HTTP; @@ -25,8 +26,9 @@ PONG => 10 }; -has handshake => sub { Mojo::Transaction::HTTP->new }; -has 'masked'; +has [qw(compressed masked)]; +has context_takeover => 1; +has handshake => sub { Mojo::Transaction::HTTP->new }; has max_websocket_size => sub { $ENV{MOJO_MAX_WEBSOCKET_SIZE} || 262144 }; sub new { @@ -81,10 +83,42 @@ return $frame . $payload; } +sub build_message { + my ($self, $frame) = @_; + + # Text + $frame = {text => encode('UTF-8', $frame)} if ref $frame ne 'HASH'; + + # JSON + $frame->{text} = Mojo::JSON->new->encode($frame->{json}) if $frame->{json}; + + # Raw text or binary + if (exists $frame->{text}) { $frame = [1, 0, 0, 0, TEXT, $frame->{text}] } + else { $frame = [1, 0, 0, 0, BINARY, $frame->{binary}] } + + # "permessage-deflate" extension + return $self->build_frame(@$frame) unless $self->compressed; + my $deflate = $self->{deflate} + || Compress::Raw::Zlib::Deflate->new(WindowBits => -15, MemLevel => 8); + $self->{deflate} = $deflate if $self->context_takeover; + $deflate->deflate(\$frame->[5], my $out); + $deflate->flush($out, Z_SYNC_FLUSH); + @$frame[1, 5] = (1, substr($out, 0, length($out) - 4)); + return $self->build_frame(@$frame); +} + sub client_challenge { my $self = shift; + + # "permessage-deflate" extension + my $headers = $self->res->headers; + my $extensions = $headers->sec_websocket_extensions // ''; + $self->context_takeover(0) + if $self->_deflate($extensions) + && $extensions =~ /client_no_context_takeover/i; + return _challenge($self->req->headers->sec_websocket_key) eq - $self->res->headers->sec_websocket_accept; + $headers->sec_websocket_accept; } sub client_handshake { @@ -94,6 +128,8 @@ $headers->upgrade('websocket') unless $headers->upgrade; $headers->connection('Upgrade') unless $headers->connection; $headers->sec_websocket_version(13) unless $headers->sec_websocket_version; + $headers->sec_websocket_extensions('permessage-deflate') + unless $headers->sec_websocket_extensions; # Generate 16 byte WebSocket challenge my $challenge = b64_encode sprintf('%16u', int(rand 9 x 16)), ''; @@ -197,26 +233,11 @@ } sub send { - my ($self, $frame, $cb) = @_; - - if (ref $frame eq 'HASH') { - - # JSON - $frame->{text} = Mojo::JSON->new->encode($frame->{json}) if $frame->{json}; - - # Binary or raw text - $frame - = exists $frame->{text} - ? [1, 0, 0, 0, TEXT, $frame->{text}] - : [1, 0, 0, 0, BINARY, $frame->{binary}]; - } - - # Text - $frame = [1, 0, 0, 0, TEXT, encode('UTF-8', $frame)] - if ref $frame ne 'ARRAY'; + my ($self, $msg, $cb) = @_; $self->once(drain => $cb) if $cb; - $self->{write} .= $self->build_frame(@$frame); + if (ref $msg eq 'ARRAY') { $self->{write} .= $self->build_frame(@$msg) } + else { $self->{write} .= $self->build_message($msg) } $self->{state} = 'write'; return $self->emit('resume'); @@ -238,6 +259,10 @@ and $res_headers->sec_websocket_protocol($1); $res_headers->sec_websocket_accept( _challenge($req_headers->sec_websocket_key)); + + # "permessage-deflate" extension + $res_headers->sec_websocket_extensions('permessage-deflate') + if $self->_deflate($req_headers->sec_websocket_extensions // ''); } sub server_read { @@ -264,6 +289,8 @@ sub _challenge { b64_encode(sha1_bytes(($_[0] || '') . GUID), '') } +sub _deflate { $_[1] =~ /permessage-deflate/i && $_[0]->compressed(1) } + sub _message { my ($self, $frame) = @_; @@ -290,8 +317,16 @@ # No FIN bit (Continuation) return unless $frame->[0]; - # Whole message + # "permessage-deflate" extension (handshake and RSV1) my $msg = delete $self->{message}; + if ($self->compressed && $frame->[1]) { + my $inflate = $self->{inflate} + || Compress::Raw::Zlib::Inflate->new(WindowBits => -15); + $self->{inflate} = $inflate if $self->context_takeover; + $inflate->inflate(\($msg .= "\x00\x00\xff\xff"), my $out); + $msg = $out; + } + $self->emit(json => Mojo::JSON->new->decode($msg)) if $self->has_subscribers('json'); $op = delete $self->{op}; @@ -443,6 +478,21 @@ L inherits all attributes from L and implements the following new ones. +=head2 compressed + + my $bool = $ws->compressed; + $ws = $ws->compressed($bool); + +Compress messages with C extension. + +=head2 context_takeover + + my $bool = $ws->context_takeover; + $ws = $ws->context_takeover($bool); + +Reuse LZ77 sliding window for C extension, defaults to +true. + =head2 handshake my $handshake = $ws->handshake; @@ -503,6 +553,15 @@ # Pong frame with FIN bit and payload say $ws->build_frame(1, 0, 0, 0, 10, 'Test 123'); +=head2 build_message + + my $bytes = $ws->build_message({binary => $bytes}); + my $bytes = $ws->build_message({text => $bytes}); + my $bytes = $ws->build_message({json => {test => [1, 2, 3]}}); + my $bytes = $ws->build_message($chars); + +Build WebSocket message. + =head2 client_challenge my $bool = $ws->client_challenge; @@ -616,7 +675,7 @@ $ws = $ws->send({binary => $bytes}); $ws = $ws->send({text => $bytes}); $ws = $ws->send({json => {test => [1, 2, 3]}}); - $ws = $ws->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]); + $ws = $ws->send([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]); $ws = $ws->send($chars); $ws = $ws->send($chars => sub {...}); diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/URL.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/URL.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/URL.pm 2013-11-01 14:28:33.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/URL.pm 2013-12-18 00:09:31.000000000 +0000 @@ -4,7 +4,8 @@ use Mojo::Parameters; use Mojo::Path; -use Mojo::Util qw(punycode_decode punycode_encode url_escape url_unescape); +use Mojo::Util + qw(deprecated punycode_decode punycode_encode url_escape url_unescape); has base => sub { Mojo::URL->new }; has [qw(fragment host port scheme userinfo)]; @@ -159,7 +160,9 @@ return $abs; } +# DEPRECATED in Top Hat! sub to_rel { + deprecated 'Mojo::URL::to_rel is DEPRECATED'; my $self = shift; my $rel = $self->clone; @@ -257,7 +260,7 @@ my $base = $url->base; $url = $url->base(Mojo::URL->new); -Base of this URL. +Base of this URL, defaults to a L object. =head2 fragment @@ -427,26 +430,6 @@ Mojo::URL->new('//example.com/foo/baz.xml?test=123') ->to_abs(Mojo::URL->new('http://example.com/foo/bar.html')); -=head2 to_rel - - my $rel = $url->to_rel; - my $rel = $url->to_rel(Mojo::URL->new('http://example.com/foo')); - -Clone absolute URL and turn it into a relative one using L or -provided base URL. - - # "foo/bar.html?test=123" - Mojo::URL->new('http://example.com/foo/bar.html?test=123') - ->to_rel(Mojo::URL->new('http://example.com')); - - # "bar.html?test=123" - Mojo::URL->new('http://example.com/foo/bar.html?test=123') - ->to_rel(Mojo::URL->new('http://example.com/foo/')); - - # "//example.com/foo/bar.html?test=123" - Mojo::URL->new('http://example.com/foo/bar.html?test=123') - ->to_rel(Mojo::URL->new('http://')); - =head2 to_string my $str = $url->to_string; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojo/UserAgent.pm libmojolicious-perl-4.63+dfsg/lib/Mojo/UserAgent.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojo/UserAgent.pm 2013-11-14 14:56:27.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojo/UserAgent.pm 2013-12-19 21:08:23.000000000 +0000 @@ -50,15 +50,15 @@ # DEPRECATED in Top Hat! sub app { - deprecated "Mojo::UserAgent::app is DEPRECATED in favor of" - . " Mojo::UserAgent::Server::app"; + deprecated 'Mojo::UserAgent::app is DEPRECATED in favor of' + . ' Mojo::UserAgent::Server::app'; shift->_delegate('server', 'app', @_); } # DEPRECATED in Top Hat! sub app_url { - deprecated "Mojo::UserAgent::app_url is DEPRECATED in favor of" - . " Mojo::UserAgent::Server::url"; + deprecated 'Mojo::UserAgent::app_url is DEPRECATED in favor of' + . ' Mojo::UserAgent::Server::url'; shift->_delegate('server', 'url', @_); } @@ -67,43 +67,43 @@ # DEPRECATED in Top Hat! sub detect_proxy { - deprecated "Mojo::UserAgent::detect_proxy is DEPRECATED in favor of" - . " Mojo::UserAgent::Proxy::detect"; + deprecated 'Mojo::UserAgent::detect_proxy is DEPRECATED in favor of' + . ' Mojo::UserAgent::Proxy::detect'; shift->tap(sub { $_->proxy->detect }); } # DEPRECATED in Top Hat! sub http_proxy { - deprecated "Mojo::UserAgent::http_proxy is DEPRECATED in favor of" - . " Mojo::UserAgent::Proxy::http"; + deprecated 'Mojo::UserAgent::http_proxy is DEPRECATED in favor of' + . ' Mojo::UserAgent::Proxy::http'; shift->_delegate('proxy', 'http', @_); } # DEPRECATED in Top Hat! sub https_proxy { - deprecated "Mojo::UserAgent::https_proxy is DEPRECATED in favor of" - . " Mojo::UserAgent::Proxy::https"; + deprecated 'Mojo::UserAgent::https_proxy is DEPRECATED in favor of' + . ' Mojo::UserAgent::Proxy::https'; shift->_delegate('proxy', 'https', @_); } # DEPRECATED in Top Hat! sub name { - deprecated "Mojo::UserAgent::name is DEPRECATED in favor of" - . " Mojo::UserAgent::Transactor::name"; + deprecated 'Mojo::UserAgent::name is DEPRECATED in favor of' + . ' Mojo::UserAgent::Transactor::name'; shift->_delegate('transactor', 'name', @_); } # DEPRECATED in Top Hat! sub no_proxy { - deprecated "Mojo::UserAgent::no_proxy is DEPRECATED in favor of" - . " Mojo::UserAgent::Proxy::not"; + deprecated 'Mojo::UserAgent::no_proxy is DEPRECATED in favor of' + . ' Mojo::UserAgent::Proxy::not'; shift->_delegate('proxy', 'not', @_); } # DEPRECATED in Top Hat! sub need_proxy { - deprecated "Mojo::UserAgent::need_proxy is DEPRECATED in favor of" - . " Mojo::UserAgent::Proxy::is_needed"; + deprecated 'Mojo::UserAgent::need_proxy is DEPRECATED in favor of' + . ' Mojo::UserAgent::Proxy::is_needed'; shift->proxy->is_needed(@_); } @@ -458,9 +458,9 @@ =head1 SYNOPSIS use Mojo::UserAgent; - my $ua = Mojo::UserAgent->new; # Say hello to the Unicode snowman with "Do Not Track" header + my $ua = Mojo::UserAgent->new; say $ua->get('www.☃.net?hello=there' => {DNT => 1})->res->body; # Form POST with exception handling @@ -711,7 +711,7 @@ L object. # Introspect - say $ua->server->app->secret; + say for @{$ua->server->app->secrets}; # Change log level $ua->server->app->log->level('fatal'); @@ -754,8 +754,8 @@ =head2 build_websocket_tx my $tx = $ua->build_websocket_tx('ws://example.com'); - my $tx = - $ua->build_websocket_tx('ws://example.com' => {DNT => 1} => ['v1.proto']); + my $tx = $ua->build_websocket_tx( + 'ws://example.com' => {DNT => 1} => ['v1.proto']); Generate L object with L. diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Command/get.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Command/get.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Command/get.pm 2013-10-22 19:46:07.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Command/get.pm 2013-12-16 15:55:43.000000000 +0000 @@ -109,7 +109,7 @@ say $json->encode($data); } -sub _say { say encode('UTF-8', $_[0]) if length $_[0] } +sub _say { length && say encode('UTF-8', $_) for @_ } sub _select { my ($buffer, $selector, $charset, @args) = @_; @@ -117,33 +117,29 @@ $buffer = decode($charset, $buffer) // $buffer if $charset; my $results = Mojo::DOM->new($buffer)->find($selector); - my $finished; while (defined(my $command = shift @args)) { # Number - if ($command =~ /^\d+$/) { - return unless ($results = [$results->[$command]])->[0]; - next; - } + ($results = [$results->[$command]])->[0] ? next : return + if $command =~ /^\d+$/; # Text - elsif ($command eq 'text') { _say($_->text) for @$results } + return _say(map { $_->text } @$results) if $command eq 'text'; # All text - elsif ($command eq 'all') { _say($_->all_text) for @$results } + return _say(map { $_->all_text } @$results) if $command eq 'all'; # Attribute - elsif ($command eq 'attr') { - next unless my $name = shift @args; - _say($_->attr->{$name}) for @$results; + if ($command eq 'attr') { + return unless my $name = shift @args; + return _say(map { $_->attr->{$name} } @$results); } # Unknown - else { die qq{Unknown command "$command".\n} } - $finished++; + die qq{Unknown command "$command".\n}; } - unless ($finished) { _say($_) for @$results } + _say(@$results); } 1; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Controller.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Controller.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Controller.pm 2013-11-17 17:26:15.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Controller.pm 2013-12-19 20:53:26.000000000 +0000 @@ -324,31 +324,32 @@ my ($self, $name, $value, $options) = @_; # Response cookie - my $secret = $self->stash->{'mojo.secret'}; + my $secrets = $self->stash->{'mojo.secrets'}; return $self->cookie($name, - "$value--" . Mojo::Util::hmac_sha1_sum($value, $secret), $options) + "$value--" . Mojo::Util::hmac_sha1_sum($value, $secrets->[0]), $options) if defined $value; # Request cookies my @results; for my $value ($self->cookie($name)) { - # Check signature + # Check signature with rotating secrets if ($value =~ s/--([^\-]+)$//) { - my $sig = $1; + my $signature = $1; - # Verified - my $check = Mojo::Util::hmac_sha1_sum $value, $secret; - if (Mojo::Util::secure_compare $sig, $check) { push @results, $value } + my $valid; + for my $secret (@$secrets) { + my $check = Mojo::Util::hmac_sha1_sum($value, $secret); + ++$valid and last if Mojo::Util::secure_compare($signature, $check); + } + if ($valid) { push @results, $value } - # Bad cookie else { $self->app->log->debug( qq{Bad signed cookie "$name", possible hacking attempt.}); } } - # Not signed else { $self->app->log->debug(qq{Cookie "$name" not signed.}) } } @@ -417,8 +418,17 @@ sub validation { my $self = shift; - return $self->stash->{'mojo.validation'} - ||= $self->app->validator->validation->input($self->req->params->to_hash); + + my $stash = $self->stash; + return $stash->{'mojo.validation'} if $stash->{'mojo.validation'}; + + my $req = $self->req; + my $token = $self->session->{csrf_token}; + my $header = $req->headers->header('X-CSRF-Token'); + my $hash = $req->params->to_hash; + $hash->{csrf_token} //= $header if $token && $header; + my $validation = $self->app->validator->validation->input($hash); + return $stash->{'mojo.validation'} = $validation->csrf_token($token); } sub write { @@ -800,7 +810,7 @@ $c = $c->send({binary => $bytes}); $c = $c->send({text => $bytes}); $c = $c->send({json => {test => [1, 2, 3]}}); - $c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $bytes]); + $c = $c->send([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]); $c = $c->send($chars); $c = $c->send($chars => sub {...}); diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Contributing.pod libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Contributing.pod --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Contributing.pod 2013-11-13 18:54:33.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Contributing.pod 2013-12-12 20:51:17.000000000 +0000 @@ -35,7 +35,7 @@ =head2 Reporting security issues Please report security issues directly to the CPAN email address of the -pumpking, which is currently C, and give us a few days to +pumpkin-holder, which is currently C, and give us a few days to develop and release a proper fix. =head2 Feature requests @@ -68,7 +68,9 @@ documentation improvements. While the L are carefully curated by the core team, everybody with a (free) GitHub account can make changes and add new information to the -L. +L. Pull requests with +additions or changes to the documentation included in the L +distribution follow the same rules as code contributions. =head1 CONTRIBUTING CODE @@ -123,12 +125,12 @@ than a minute on most common hardware is a good rule of thumb) The addition and modification of features is decided by majority vote or the -pumpking. +pumpkin-holder. Any core developer may nominate a new one, who must then be accepted by a 2/3 majority vote. -The pumpking has veto rights and may select his successor. +The pumpkin-holder has veto rights and may select their successor. It's not a feature without a test and documentation. diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Cookbook.pod libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Cookbook.pod --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Cookbook.pod 2013-11-01 17:57:53.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Cookbook.pod 2013-12-19 21:08:39.000000000 +0000 @@ -1105,11 +1105,8 @@ sub run { my ($self, $target) = @_; - # Leak secret passphrase - if ($target eq 'secret') { - my $secret = $self->app->secret; - say qq{The secret of this application is "$secret".}; - } + # Leak secret passphrases + say for @{$self->app->secrets} if $target eq 'secrets'; } 1; @@ -1117,11 +1114,11 @@ There are many more useful attributes and methods in L that you can use or overload. - $ mojo spy secret - The secret of this application is "HelloWorld". + $ mojo spy secrets + HelloWorld - $ ./myapp.pl spy secret - The secret of this application is "secr3t". + $ ./myapp.pl spy secrets + secr3t And to make your commands application specific, just put them in a different namespace. diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/FAQ.pod libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/FAQ.pod --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/FAQ.pod 2013-11-14 04:06:32.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/FAQ.pod 2013-12-19 19:55:09.000000000 +0000 @@ -105,12 +105,12 @@ =head2 What does "Your secret passphrase needs to be changed" mean? -L uses a secret passphrase for security features such as signed +L uses secret passphrases for security features such as signed cookies. It defaults to the moniker of your application, which is not very secure, so we added this log message as a reminder. You can change the -passphrase with the attribute L. +passphrase with the attribute L. - app->secret('My very secret passphrase.'); + app->secrets(['My very secret passphrase.']); =head2 What does "Nothing has been rendered, expecting delayed response" mean? @@ -133,7 +133,8 @@ This error message is often related to the one above, and means that the web server closed the connection before the user agent could receive the whole -response. +response or that the user agent got destroyed, which forces all connections to +be closed immediately. =head2 What does "Worker 31842 has no heartbeat, restarting" mean? diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Growing.pod libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Growing.pod --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Growing.pod 2013-10-08 05:40:58.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Growing.pod 2013-12-19 20:00:47.000000000 +0000 @@ -349,9 +349,9 @@ Sessions in L pretty much just work out of the box once you start using the method L, there is no setup required, but we suggest setting a more secure passphrase with -L. +L. - app->secret('Mojolicious rocks'); + app->secrets(['Mojolicious rocks']); This passphrase is used by the C algorithm to make signed cookies secure and can be changed at any time to invalidate all existing sessions. @@ -392,7 +392,7 @@ use MyUsers; # Make signed cookies secure - app->secret('Mojolicious rocks'); + app->secrets(['Mojolicious rocks']); helper users => sub { state $users = MyUsers->new }; @@ -513,7 +513,7 @@ sub startup { my $self = shift; - $self->secret('Mojolicious rocks'); + $self->secrets(['Mojolicious rocks']); $self->helper(users => sub { state $users = MyUsers->new }); my $r = $self->routes; @@ -620,7 +620,7 @@ sub startup { my $self = shift; - $self->secret('Mojolicious rocks'); + $self->secrets(['Mojolicious rocks']); $self->helper(users => sub { state $users = MyUsers->new }); my $r = $self->routes; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Rendering.pod libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Rendering.pod --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Guides/Rendering.pod 2013-10-28 14:49:52.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Guides/Rendering.pod 2013-12-07 14:39:53.000000000 +0000 @@ -740,9 +740,52 @@ %= text_field 'number' %= submit_button % end - + +=head2 Cross-site request forgery + +CSRF is a very common attack on web applications that trick your logged in +users to submit forms they did not intend to send. All you have to do to +protect your users from this, is to add an additional hidden field to your +forms with L and validate it +with L. + + use Mojolicious::Lite; + + get '/' => {template => 'target'}; + + post '/' => sub { + my $self = shift; + + # Check CSRF token + my $validation = $self->validation; + return $self->render(text => 'Bad CSRF token!', status => 403) + if $validation->csrf_protect->has_error('csrf_token'); + + my $city = $validation->required('city')->param('city'); + $self->render(text => "Low orbit ion cannon pointed at $city!") + unless $validation->has_error; + } => 'target'; + + app->start; + __DATA__ + + @@ target.html.ep + + + + %= form_for target => begin + %= csrf_field + %= label_for city => 'Which city to point low orbit ion cannon at?' + %= text_field 'city' + %= submit_button + %= end + + + +The token can also be submitted with the C request header. + =head2 Adding helpers Adding and redefining helpers is very easy, you can use them to do pretty much @@ -1141,7 +1184,7 @@ =head2 Adding a handler to generate binary data By default the renderer assumes that every C generates characters -that need to be automatically encoded, but this can be be easily disabled if +that need to be automatically encoded, but this can be easily disabled if you're generating bytes instead. use Mojolicious::Lite; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Lite.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Lite.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Lite.pm 2013-11-01 17:53:25.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Lite.pm 2013-12-19 19:50:51.000000000 +0000 @@ -792,10 +792,10 @@ @@ counter.html.ep Counter: <%= session 'counter' %> -Note that you should use a custom L to make signed +Note that you should use custom L to make signed cookies really secure. - app->secret('My secret passphrase here'); + app->secrets(['My secret passphrase here']); =head2 File uploads diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Plugin/DefaultHelpers.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Plugin/DefaultHelpers.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Plugin/DefaultHelpers.pm 2013-11-01 14:47:32.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Plugin/DefaultHelpers.pm 2013-12-19 19:56:48.000000000 +0000 @@ -2,7 +2,7 @@ use Mojo::Base 'Mojolicious::Plugin'; use Mojo::ByteStream; -use Mojo::Util 'dumper'; +use Mojo::Util qw(dumper sha1_sum steady_time); sub register { my ($self, $app) = @_; @@ -28,6 +28,7 @@ $app->helper(config => sub { shift->app->config(@_) }); $app->helper(content => \&_content); $app->helper(content_for => \&_content_for); + $app->helper(csrf_token => \&_csrf_token); $app->helper(current_route => \&_current_route); $app->helper(dumper => sub { shift; dumper(@_) }); $app->helper(include => \&_include); @@ -55,6 +56,12 @@ return $c->{$name} .= ref $content eq 'CODE' ? $content->() : $content; } +sub _csrf_token { + my $self = shift; + $self->session->{csrf_token} + ||= sha1_sum($self->app->secrets->[0] . steady_time . rand 999); +} + sub _current_route { return '' unless my $endpoint = shift->match->endpoint; return $endpoint->name unless @_; @@ -112,7 +119,7 @@ =head2 app - %= app->secret + %= app->secrets->[0] Alias for L. @@ -155,6 +162,12 @@ % end %= content_for 'message' +=head2 csrf_token + + %= csrf_token + +Get CSRF token from L, and generate one if none exists. + =head2 current_route % if (current_route 'login') { diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Plugin/TagHelpers.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Plugin/TagHelpers.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Plugin/TagHelpers.pm 2013-11-13 15:53:35.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Plugin/TagHelpers.pm 2013-12-18 00:16:34.000000000 +0000 @@ -15,6 +15,7 @@ $app->helper(check_box => sub { _input(shift, shift, value => shift, @_, type => 'checkbox') }); + $app->helper(csrf_field => \&_csrf_field); $app->helper(file_field => sub { shift; _tag('input', name => shift, @_, type => 'file') }); @@ -41,6 +42,11 @@ $app->helper(text_area => \&_text_area); } +sub _csrf_field { + my $self = shift; + return $self->hidden_field(csrf_token => $self->csrf_token, @_); +} + sub _form_for { my ($self, @url) = (shift, shift); push @url, shift if ref $_[0] eq 'HASH'; @@ -304,6 +310,15 @@ +=head2 csrf_field + + %= csrf_field + +Generate hidden input element with +L. + + + =head2 date_field %= date_field 'end' @@ -639,7 +654,7 @@ % end <%= tag div => (id => 'foo') => begin %>some & content<% end %> -HTML tag generator. +HTML/XML tag generator.
diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Routes/Route.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Routes/Route.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Routes/Route.pm 2013-11-01 14:51:58.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Routes/Route.pm 2013-12-18 00:18:45.000000000 +0000 @@ -289,7 +289,7 @@ my $parent = $r->parent; $r = $r->parent(Mojolicious::Routes::Route->new); -The parent of this route, used for nesting routes. +The parent of this route, usually a L object. =head2 partial diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Validator/Validation.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Validator/Validation.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Validator/Validation.pm 2013-11-01 14:51:56.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Validator/Validation.pm 2013-12-18 00:19:02.000000000 +0000 @@ -4,8 +4,8 @@ use Carp 'croak'; use Scalar::Util 'blessed'; +has [qw(csrf_token topic validator)]; has [qw(input output)] => sub { {} }; -has [qw(topic validator)]; sub AUTOLOAD { my $self = shift; @@ -31,15 +31,27 @@ my $input = $self->input->{$name}; for my $value (ref $input eq 'ARRAY' ? @$input : $input) { next unless my $result = $self->$cb($name, $value, @_); - delete $self->output->{$name}; - $self->{error}{$name} = [$check, $result, @_]; - last; + return $self->error($name => [$check, $result, @_]); } return $self; } -sub error { shift->{error}{shift()} } +sub csrf_protect { + my $self = shift; + my $token = $self->input->{csrf_token}; + $self->error(csrf_token => ['csrf_protect']) + unless $token && $token eq ($self->csrf_token // ''); + return $self; +} + +sub error { + my ($self, $name) = (shift, shift); + return $self->{error}{$name} unless @_; + $self->{error}{$name} = shift; + delete $self->output->{$name}; + return $self; +} sub has_data { !!keys %{shift->input} } @@ -74,8 +86,8 @@ sub required { my ($self, $name) = @_; - $self->{error}{$name} = ['required'] unless $self->optional($name)->is_valid; - return $self; + return $self if $self->optional($name)->is_valid; + return $self->error($name => ['required']); } 1; @@ -107,6 +119,13 @@ L implements the following attributes. +=head2 csrf_token + + my $token = $validation->token; + $validation = $validation->token('fa6a08...'); + +CSRF token. + =head2 input my $input = $validation->input; @@ -145,14 +164,21 @@ $validation = $validation->check('size', 2, 7); Perform validation check on all values of the current L, no more -checks will be performend on them after the first one failed. +checks will be performed on them after the first one failed. + +=head2 csrf_protect + + $validation = $validation->csrf_protect; + +Validate C and protect from cross-site request forgery. =head2 error - my $err = $validation->error('foo'); + my $err = $validation->error('foo'); + $validation = $validation->error(foo => ['custom_check']); -Return details about failed validation check, at any given time there can only -be one per field. +Get or set details for failed validation check, at any given time there can +only be one per field. my ($check, $result, @args) = @{$validation->error('foo')}; diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Validator.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Validator.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious/Validator.pm 2013-11-01 14:43:49.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious/Validator.pm 2013-12-03 22:00:16.000000000 +0000 @@ -43,7 +43,7 @@ =head1 NAME -Mojolicious::Validator - Validate form data +Mojolicious::Validator - Validate parameter =head1 SYNOPSIS @@ -57,7 +57,7 @@ =head1 DESCRIPTION -L validates form data for L. +L validates parameters for L. =head1 CHECKS diff -Nru libmojolicious-perl-4.58+dfsg/lib/Mojolicious.pm libmojolicious-perl-4.63+dfsg/lib/Mojolicious.pm --- libmojolicious-perl-4.58+dfsg/lib/Mojolicious.pm 2013-11-13 19:48:58.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/lib/Mojolicious.pm 2013-12-19 22:32:48.000000000 +0000 @@ -28,14 +28,14 @@ has plugins => sub { Mojolicious::Plugins->new }; has renderer => sub { Mojolicious::Renderer->new }; has routes => sub { Mojolicious::Routes->new }; -has secret => sub { +has secrets => sub { my $self = shift; # Warn developers about insecure default $self->log->debug('Your secret passphrase needs to be changed!!!'); # Default to moniker - return $self->moniker; + return [$self->moniker]; }; has sessions => sub { Mojolicious::Sessions->new }; has static => sub { Mojolicious::Static->new }; @@ -43,7 +43,7 @@ has validator => sub { Mojolicious::Validator->new }; our $CODENAME = 'Top Hat'; -our $VERSION = '4.58'; +our $VERSION = '4.63'; sub AUTOLOAD { my $self = shift; @@ -91,12 +91,6 @@ # Reduced log output outside of development mode $self->log->level('info') unless $mode eq 'development'; - # DEPRECATED in Top Hat! - if (my $sub = $self->can("${mode}_mode")) { - deprecated qq{"sub ${mode}_mode {...}" in application class is DEPRECATED}; - $self->$sub; - } - $self->startup; return $self; @@ -149,7 +143,7 @@ # Embedded application my $stash = {}; if (my $sub = $tx->can('stash')) { ($stash, $tx) = ($tx->$sub, $tx->tx) } - $stash->{'mojo.secret'} //= $self->secret; + $stash->{'mojo.secrets'} //= $self->secrets; # Build default controller my $defaults = $self->defaults; @@ -187,6 +181,16 @@ $self->plugins->register_plugin(shift, $self, @_); } +# DEPRECATED in Top Hat! +sub secret { + deprecated + 'Mojolicious::secret is DEPRECATED in favor of Mojolicious::secrets'; + my $self = shift; + return $self->secrets->[0] unless @_; + $self->secrets->[0] = shift; + return $self; +} + sub start { shift->commands->run(@_ ? @_ : @ARGV) } sub startup { } @@ -444,15 +448,22 @@ # Add another namespace to load controllers from push @{$app->routes->namespaces}, 'MyApp::Controller'; -=head2 secret +=head2 secrets - my $secret = $app->secret; - $app = $app->secret('passw0rd'); + my $secrets = $app->secrets; + $app = $app->secrets(['passw0rd']); -A secret passphrase used for signed cookies and the like, defaults to the +Secret passphrases used for signed cookies and the like, defaults to the L of this application, which is not very secure, so you should change it!!! As long as you are using the insecure default there will be debug -messages in the log file reminding you to change your passphrase. +messages in the log file reminding you to change your passphrase. Only the +first passphrase is used to create new signatures, but all of them for +verification. So you can increase security without invalidating all your +signed cookies by rotating passphrases, just add new ones to the front and +remove old ones from the back. + + # Rotate passphrases + $app->secrets(['new_passw0rd', 'old_passw0rd', 'very_old_passw0rd']); =head2 sessions @@ -497,7 +508,7 @@ my $validator = $app->validator; $app = $app->validator(Mojolicious::Validator->new); -Validate form data, defaults to a L object. +Validate parameters, defaults to a L object. =head1 METHODS @@ -547,7 +558,8 @@ $app->handler(Mojo::Transaction::HTTP->new); $app->handler(Mojolicious::Controller->new); -Sets up the default controller and calls process for every request. +Sets up the default controller and emits the L hook for +every request. =head2 helper @@ -639,8 +651,8 @@ Copyright (C) 2010-2013, Sebastian Riedel. -Licensed under the CC-SA License, Version 3.0 -L. +Licensed under the CC-SA License, Version 4.0 +L. =head2 jQuery diff -Nru libmojolicious-perl-4.58+dfsg/t/mojo/asset.t libmojolicious-perl-4.63+dfsg/t/mojo/asset.t --- libmojolicious-perl-4.58+dfsg/t/mojo/asset.t 2013-07-17 09:35:25.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojo/asset.t 2013-12-17 19:17:56.000000000 +0000 @@ -36,20 +36,22 @@ ok !$mem->is_range, 'no range'; is $mem->contains('a'), -1, 'does not contain "a"'; -# File asset range support (a[bcdef]) +# File asset range support (a[bcdefabc]) $file = Mojo::Asset::File->new(start_range => 1); ok $file->is_range, 'has range'; -$file->add_chunk('abcdef'); +$file->add_chunk('abcdefabc'); is $file->contains('bcdef'), 0, '"bcdef" at position 0'; is $file->contains('cdef'), 1, '"cdef" at position 1'; +is $file->contains('abc'), 5, '"abc" at position 5'; is $file->contains('db'), -1, 'does not contain "db"'; -# Memory asset range support (a[bcdef]) +# Memory asset range support (a[bcdefabc]) $mem = Mojo::Asset::Memory->new(start_range => 1); ok $mem->is_range, 'has range'; -$mem->add_chunk('abcdef'); +$mem->add_chunk('abcdefabc'); is $mem->contains('bcdef'), 0, '"bcdef" at position 0'; is $mem->contains('cdef'), 1, '"cdef" at position 1'; +is $mem->contains('abc'), 5, '"abc" at position 5'; is $mem->contains('db'), -1, 'does not contain "db"'; # File asset range support (ab[cdefghi]jk) diff -Nru libmojolicious-perl-4.58+dfsg/t/mojo/daemon.t libmojolicious-perl-4.63+dfsg/t/mojo/daemon.t --- libmojolicious-perl-4.58+dfsg/t/mojo/daemon.t 2013-11-07 02:35:01.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojo/daemon.t 2013-12-04 21:22:55.000000000 +0000 @@ -7,14 +7,12 @@ use Test::More; use File::Spec::Functions 'catdir'; -use IO::Socket::INET; use Mojo; use Mojo::IOLoop; use Mojo::Log; use Mojo::Server::Daemon; use Mojo::UserAgent; use Mojolicious; -use Socket qw(SO_REUSEPORT SOL_SOCKET); # Timeout { @@ -243,34 +241,4 @@ is $tx->res->code, 200, 'right status'; is $tx->res->body, 'Whatever!', 'right content'; -# SO_REUSEPORT -SKIP: { - skip 'SO_REUSEPORT support required!', 2 unless eval { _probe() }; - - $port = Mojo::IOLoop->generate_port; - $daemon = Mojo::Server::Daemon->new( - listen => ["http://127.0.0.1:$port"], - silent => 1 - )->start; - ok !$daemon->ioloop->acceptor($daemon->acceptors->[0]) - ->handle->getsockopt(SOL_SOCKET, SO_REUSEPORT), - 'no SO_REUSEPORT socket option'; - $daemon = Mojo::Server::Daemon->new( - listen => ["http://127.0.0.1:$port?reuse=1"], - silent => 1 - ); - $daemon->start; - ok $daemon->ioloop->acceptor($daemon->acceptors->[0]) - ->handle->getsockopt(SOL_SOCKET, SO_REUSEPORT), - 'SO_REUSEPORT socket option'; -} - -sub _probe { - IO::Socket::INET->new( - Listen => 1, - LocalPort => Mojo::IOLoop->generate_port, - ReusePort => 1 - ); -} - done_testing(); diff -Nru libmojolicious-perl-4.58+dfsg/t/mojo/dom.t libmojolicious-perl-4.63+dfsg/t/mojo/dom.t --- libmojolicious-perl-4.58+dfsg/t/mojo/dom.t 2013-11-17 00:58:07.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojo/dom.t 2013-12-16 15:54:19.000000000 +0000 @@ -2127,26 +2127,27 @@ is $dom->find('a[accesskey]')->[0]->text, 'Zero', 'right text'; is $dom->find('a[accesskey]')->[1]->text, 'O&gTn>e', 'right text'; is $dom->find('a[accesskey]')->[2], undef, 'no result'; -is $dom->find('a[accesskey="0"]')->[0]->text, 'Zero', 'right text'; -is $dom->find('a[accesskey="0"]')->[1], undef, 'no result'; -is $dom->find('a[accesskey^="0"]')->[0]->text, 'Zero', 'right text'; -is $dom->find('a[accesskey^="0"]')->[1], undef, 'no result'; -is $dom->find('a[accesskey$="0"]')->[0]->text, 'Zero', 'right text'; -is $dom->find('a[accesskey$="0]')->[1], undef, 'no result'; -is $dom->find('a[accesskey~="0"]')->[0]->text, 'Zero', 'right text'; -is $dom->find('a[accesskey~="0]')->[1], undef, 'no result'; -is $dom->find('a[accesskey*="0"]')->[0]->text, 'Zero', 'right text'; -is $dom->find('a[accesskey*="0]')->[1], undef, 'no result'; -is $dom->find('a[accesskey="1"]')->[0]->text, 'O&gTn>e', 'right text'; -is $dom->find('a[accesskey="1"]')->[1], undef, 'no result'; -is $dom->find('a[accesskey^="1"]')->[0]->text, 'O&gTn>e', 'right text'; -is $dom->find('a[accesskey^="1"]')->[1], undef, 'no result'; -is $dom->find('a[accesskey$="1"]')->[0]->text, 'O&gTn>e', 'right text'; -is $dom->find('a[accesskey$="1]')->[1], undef, 'no result'; -is $dom->find('a[accesskey~="1"]')->[0]->text, 'O&gTn>e', 'right text'; -is $dom->find('a[accesskey~="1]')->[1], undef, 'no result'; -is $dom->find('a[accesskey*="1"]')->[0]->text, 'O&gTn>e', 'right text'; -is $dom->find('a[accesskey*="1]')->[1], undef, 'no result'; +is $dom->find('a[accesskey=0]')->[0]->text, 'Zero', 'right text'; +is $dom->find('a[accesskey=0]')->[1], undef, 'no result'; +is $dom->find('a[accesskey^=0]')->[0]->text, 'Zero', 'right text'; +is $dom->find('a[accesskey^=0]')->[1], undef, 'no result'; +is $dom->find('a[accesskey$=0]')->[0]->text, 'Zero', 'right text'; +is $dom->find('a[accesskey$=0]')->[1], undef, 'no result'; +is $dom->find('a[accesskey~=0]')->[0]->text, 'Zero', 'right text'; +is $dom->find('a[accesskey~=0]')->[1], undef, 'no result'; +is $dom->find('a[accesskey*=0]')->[0]->text, 'Zero', 'right text'; +is $dom->find('a[accesskey*=0]')->[1], undef, 'no result'; +is $dom->find('a[accesskey=1]')->[0]->text, 'O&gTn>e', 'right text'; +is $dom->find('a[accesskey=1]')->[1], undef, 'no result'; +is $dom->find('a[accesskey^=1]')->[0]->text, 'O&gTn>e', 'right text'; +is $dom->find('a[accesskey^=1]')->[1], undef, 'no result'; +is $dom->find('a[accesskey$=1]')->[0]->text, 'O&gTn>e', 'right text'; +is $dom->find('a[accesskey$=1]')->[1], undef, 'no result'; +is $dom->find('a[accesskey~=1]')->[0]->text, 'O&gTn>e', 'right text'; +is $dom->find('a[accesskey~=1]')->[1], undef, 'no result'; +is $dom->find('a[accesskey*=1]')->[0]->text, 'O&gTn>e', 'right text'; +is $dom->find('a[accesskey*=1]')->[1], undef, 'no result'; +is $dom->at('a[accesskey*="."]'), undef, 'no result'; # Empty attribute value $dom = Mojo::DOM->new->parse(< 1; @@ -117,6 +119,36 @@ kill 'INT', $pid; sleep 1 while _port($port); +# SO_REUSEPORT +SKIP: { + skip 'SO_REUSEPORT support required!', 2 unless eval { _reuse_port() }; + + my $port = Mojo::IOLoop->generate_port; + my $daemon = Mojo::Server::Daemon->new( + listen => ["http://127.0.0.1:$port"], + silent => 1 + )->start; + ok !$daemon->ioloop->acceptor($daemon->acceptors->[0]) + ->handle->getsockopt(SOL_SOCKET, SO_REUSEPORT), + 'no SO_REUSEPORT socket option'; + $daemon = Mojo::Server::Daemon->new( + listen => ["http://127.0.0.1:$port?reuse=1"], + silent => 1 + ); + $daemon->start; + ok $daemon->ioloop->acceptor($daemon->acceptors->[0]) + ->handle->getsockopt(SOL_SOCKET, SO_REUSEPORT), + 'SO_REUSEPORT socket option'; +} + sub _port { IO::Socket::INET->new(PeerAddr => '127.0.0.1', PeerPort => shift) } +sub _reuse_port { + IO::Socket::INET->new( + Listen => 1, + LocalPort => Mojo::IOLoop->generate_port, + ReusePort => 1 + ); +} + done_testing(); diff -Nru libmojolicious-perl-4.58+dfsg/t/mojo/url.t libmojolicious-perl-4.63+dfsg/t/mojo/url.t --- libmojolicious-perl-4.58+dfsg/t/mojo/url.t 2013-09-22 21:09:36.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojo/url.t 2013-12-18 14:40:13.000000000 +0000 @@ -175,10 +175,6 @@ $url = Mojo::URL->new('/foo?foo=bar#23'); ok !$url->is_abs, 'is not absolute'; is "$url", '/foo?foo=bar#23', 'right relative version'; -$url = Mojo::URL->new('http://sri:foobar@example.com:8080/foo?foo=bar#23'); -$url->base->parse('http://sri:foobar@example.com:8080/'); -ok $url->is_abs, 'is absolute'; -is $url->to_rel, 'foo?foo=bar#23', 'right relative version'; # Relative without scheme $url = Mojo::URL->new('//localhost/23/'); @@ -207,88 +203,6 @@ is $url->path, '//bar//23/', 'right path'; is "$url", '////bar//23/', 'right relative version'; -# Relative (base without trailing slash) -$url = Mojo::URL->new('http://sri:foobar@example.com:8080/baz/foo?foo=bar#23'); -$url->base->parse('http://sri:foobar@example.com:8080'); -is $url->to_rel, 'baz/foo?foo=bar#23', 'right relative version'; -is $url->to_rel->to_abs, - 'http://sri:foobar@example.com:8080/baz/foo?foo=bar#23', - 'right absolute version'; -$url = Mojo::URL->new('http://sri:foobar@example.com:8080/baz/foo?foo=bar#23'); -$url->base->parse('http://sri:foobar@example.com:8080/baz'); -is $url->to_rel, 'baz/foo?foo=bar#23', 'right relative version'; -is $url->to_rel->to_abs, - 'http://sri:foobar@example.com:8080/baz/foo?foo=bar#23', - 'right absolute version'; - -# Relative (base without authority) -$url = Mojo::URL->new('http://sri:foobar@example.com:8080/baz/foo?foo=bar#23'); -$url->base->parse('http://'); -is $url->to_rel, '//sri:foobar@example.com:8080/baz/foo?foo=bar#23', - 'right relative version'; -is $url->to_rel->to_abs, - 'http://sri:foobar@example.com:8080/baz/foo?foo=bar#23', - 'right absolute version'; - -# Relative with path -$url = Mojo::URL->new('http://example.com/foo/index.html?foo=bar#23'); -$url->base->parse('http://example.com/foo/'); -my $rel = $url->to_rel; -is $rel, 'index.html?foo=bar#23', 'right format'; -ok !$rel->is_abs, 'not absolute'; -is $rel->to_abs, 'http://example.com/foo/index.html?foo=bar#23', - 'right absolute version'; - -# Relative (base argument) -$url = Mojo::URL->new('http://example.com/'); -$rel = $url->to_rel($url->clone); -is $rel, '', 'right relative version'; -is $rel->to_abs, 'http://example.com/', 'right absolute version'; -is $rel->to_abs->to_rel, '', 'right relative version'; -$rel = $url->to_rel(Mojo::URL->new('http://example.com/a/')); -is $rel, '..', 'right relative version'; -is $rel->to_abs, 'http://example.com/', 'right absolute version'; -is $rel->to_abs->to_rel, '..', 'right relative version'; -$rel = $url->to_rel(Mojo::URL->new('http://example.com/a/b/')); -is $rel, '../..', 'right relative version'; -is $rel->to_abs, 'http://example.com/', 'right absolute version'; -is $rel->to_abs->to_rel, '../..', 'right relative version'; -$url = Mojo::URL->new('http://example.com/index.html'); -$rel = $url->to_rel(Mojo::URL->new('http://example.com/')); -is $rel, 'index.html', 'right relative version'; -is $rel->to_abs, 'http://example.com/index.html', 'right absolute version'; -is $rel->to_abs->to_rel, 'index.html', 'right relative version'; -$url = Mojo::URL->new('http://example.com/index.html'); -$rel = $url->to_rel(Mojo::URL->new('http://example.com/a/')); -is $rel, '../index.html', 'right relative version'; -is $rel->to_abs, 'http://example.com/index.html', 'right absolute version'; -is $rel->to_abs->to_rel, '../index.html', 'right relative version'; -$url = Mojo::URL->new('http://example.com/index.html'); -$rel = $url->to_rel(Mojo::URL->new('http://example.com/a/b/')); -is $rel, '../../index.html', 'right relative version'; -is $rel->to_abs, 'http://example.com/index.html', 'right absolute version'; -is $rel->to_abs->to_rel, '../../index.html', 'right relative version'; -$url = Mojo::URL->new('http://example.com/a/b/c/index.html'); -$rel = $url->to_rel(Mojo::URL->new('http://example.com/a/b/')); -is $rel, 'c/index.html', 'right relative version'; -is $rel->to_abs, 'http://example.com/a/b/c/index.html', - 'right absolute version'; -is $rel->to_abs->to_rel, 'c/index.html', 'right relative version'; -$url = Mojo::URL->new('http://example.com/a/b/c/d/index.html'); -$rel = $url->to_rel(Mojo::URL->new('http://example.com/a/b/')); -is $rel, 'c/d/index.html', 'right relative version'; -is $rel->to_abs, 'http://example.com/a/b/c/d/index.html', - 'right absolute version'; -is $rel->to_abs->to_rel, 'c/d/index.html', 'right relative version'; -$url = Mojo::URL->new('/foo'); -is $url->base, '', 'no base'; -is $url->to_abs(Mojo::URL->new('http://example.com'))->base, - 'http://example.com', 'right base'; -$url = Mojo::URL->new('http://example.com/foo'); -is $url->base, '', 'no base'; -is $url->to_rel(Mojo::URL->new('http://example.com'))->base, - 'http://example.com', 'right base'; - # Relative path $url = Mojo::URL->new('http://example.com/foo/?foo=bar#23'); $url->path('bar'); @@ -330,11 +244,6 @@ ok !$url->is_abs, 'not absolute'; is $url->to_abs, 'http://example.com/bar/foo?foo=bar#23', 'right absolute version'; -is $url->to_abs->to_rel, '../foo?foo=bar#23', 'right relative version'; -is $url->to_abs->to_rel->to_abs, 'http://example.com/bar/foo?foo=bar#23', - 'right absolute version'; -is $url->to_abs, 'http://example.com/bar/foo?foo=bar#23', - 'right absolute version'; is $url->to_abs->base, 'http://example.com/bar/baz/', 'right base'; # Clone (advanced) @@ -472,28 +381,19 @@ $url = Mojo::URL->new('http://foo.com/'); is $url->to_abs, 'http://foo.com/', 'right absolute version'; -# Already relative -$url = Mojo::URL->new('http://sri:foobar@example.com:8080/foo?foo=bar#23'); -$url->base->parse('http://sri:foobar@example.com:8080/'); -my $url2 = $url->to_rel; -is $url->to_rel, 'foo?foo=bar#23', 'right relative version'; - # Empty path elements $url = Mojo::URL->new('http://example.com/foo//bar/23/'); -$url->base->parse('http://example.com/'); ok $url->is_abs, 'is absolute'; -is $url->to_rel, 'foo//bar/23/', 'right relative version'; +is $url->path, '/foo//bar/23/', 'right path'; +is "$url", 'http://example.com/foo//bar/23/', 'right format'; $url = Mojo::URL->new('http://example.com//foo//bar/23/'); -$url->base->parse('http://example.com/'); ok $url->is_abs, 'is absolute'; -is $url->to_rel, '/foo//bar/23/', 'right relative version'; +is $url->path, '//foo//bar/23/', 'right path'; +is "$url", 'http://example.com//foo//bar/23/', 'right format'; $url = Mojo::URL->new('http://example.com/foo///bar/23/'); -$url->base->parse('http://example.com/'); -ok $url->is_abs, 'is absolute'; -is $url->to_rel, 'foo///bar/23/', 'right relative version'; -is $url->to_abs, 'http://example.com/foo///bar/23/', 'right absolute version'; ok $url->is_abs, 'is absolute'; -is $url->to_rel, 'foo///bar/23/', 'right relative version'; +is $url->path, '/foo///bar/23/', 'right path'; +is "$url", 'http://example.com/foo///bar/23/', 'right format'; # Merge relative path $url = Mojo::URL->new('http://foo.bar/baz?yada'); diff -Nru libmojolicious-perl-4.58+dfsg/t/mojo/websocket.t libmojolicious-perl-4.63+dfsg/t/mojo/websocket.t --- libmojolicious-perl-4.58+dfsg/t/mojo/websocket.t 2013-10-22 19:43:28.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojo/websocket.t 2013-11-28 16:36:53.000000000 +0000 @@ -455,15 +455,17 @@ like $log, qr/Inactivity timeout\./, 'right log message'; app->log->unsubscribe(message => $msg); -# Ping/pong -my $pong; +# Ping/pong (with negotiated compression) +my ($pong, $compressed, $extensions); $ua->websocket( '/echo' => sub { my ($ua, $tx) = @_; $tx->on( frame => sub { my ($tx, $frame) = @_; - $pong = $frame->[5] if $frame->[4] == 10; + $pong = $frame->[5] if $frame->[4] == 10; + $compressed = $tx->compressed; + $extensions = $tx->res->headers->sec_websocket_extensions; Mojo::IOLoop->stop; } ); @@ -472,5 +474,7 @@ ); Mojo::IOLoop->start; is $pong, 'test', 'received pong with payload'; +ok $compressed, 'WebSocket has compression'; +is $extensions, 'permessage-deflate', 'right "Sec-WebSocket-Extensions" value'; done_testing(); diff -Nru libmojolicious-perl-4.58+dfsg/t/mojo/websocket_frames.t libmojolicious-perl-4.63+dfsg/t/mojo/websocket_frames.t --- libmojolicious-perl-4.58+dfsg/t/mojo/websocket_frames.t 2013-05-14 08:08:38.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojo/websocket_frames.t 2013-11-28 22:39:44.000000000 +0000 @@ -206,4 +206,31 @@ isnt(Mojo::Transaction::WebSocket->new->build_frame(1, 0, 0, 0, 2, ''), $bytes, 'frames are not equal'); +# Compressed binary message roundtrip +$ws = Mojo::Transaction::WebSocket->new(compressed => 1); +$bytes = $ws->build_message({binary => 'just works'}); +$frame = $ws->parse_frame(\($dummy = $bytes)); +is $frame->[0], 1, 'fin flag is set'; +is $frame->[1], 1, 'rsv1 flag is not set'; +is $frame->[2], 0, 'rsv2 flag is not set'; +is $frame->[3], 0, 'rsv3 flag is not set'; +is $frame->[4], 2, 'binary frame'; +ok $frame->[5], 'has payload'; +isnt( + Mojo::Transaction::WebSocket->new->build_message({binary => 'just works'}), + $bytes, 'messages are not equal'); + +# Compressed binary message roundtrip with context takeover +$ws = Mojo::Transaction::WebSocket->new(compressed => 1); +my $first = $ws->build_message({binary => 'just works'}); +my $second = $ws->build_message({binary => 'just works'}); +isnt $first, $second, 'messages are not equal'; + +# Compressed binary message roundtrip without context takeover +$ws + = Mojo::Transaction::WebSocket->new(compressed => 1, context_takeover => 0); +$first = $ws->build_message({binary => 'just works'}); +$second = $ws->build_message({binary => 'just works'}); +is $first, $second, 'messages are equal'; + done_testing(); diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/app.t libmojolicious-perl-4.63+dfsg/t/mojolicious/app.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/app.t 2013-10-28 16:34:34.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/app.t 2013-12-19 19:57:33.000000000 +0000 @@ -59,7 +59,7 @@ is $t->app->static->file('hello.txt')->slurp, "Hello Mojo from a development static file!\n", 'right content'; is $t->app->moniker, 'mojolicious_test', 'right moniker'; -is $t->app->secret, $t->app->moniker, 'secret defaults to moniker'; +is $t->app->secrets->[0], $t->app->moniker, 'secret defaults to moniker'; # Missing methods and functions (AUTOLOAD) eval { $t->app->missing }; diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/embedded_app.t libmojolicious-perl-4.63+dfsg/t/mojolicious/embedded_app.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/embedded_app.t 2013-11-17 21:53:22.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/embedded_app.t 2013-12-19 19:57:29.000000000 +0000 @@ -11,7 +11,7 @@ use Test::Mojo; # Custom secret -app->secret('very secr3t!'); +app->secrets(['very secr3t!']); # Mount full external application a few times use FindBin; diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/group_lite_app.t libmojolicious-perl-4.63+dfsg/t/mojolicious/group_lite_app.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/group_lite_app.t 2013-09-21 14:04:01.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/group_lite_app.t 2013-12-19 19:59:46.000000000 +0000 @@ -11,6 +11,8 @@ use Mojolicious::Lite; use Test::Mojo; +app->secrets(['test1']); + get '/expiration' => sub { my $self = shift; if ($self->param('redirect')) { @@ -262,7 +264,7 @@ # Broken session cookie $t->reset_session; my $session = b("☃☃☃☃☃")->encode->b64_encode(''); -my $hmac = $session->clone->hmac_sha1_sum($t->app->secret); +my $hmac = $session->clone->hmac_sha1_sum($t->app->secrets->[0]); $t->get_ok('/bridge2stash' => {Cookie => "mojolicious=$session--$hmac"}) ->status_is(200)->content_is("stash too!!!!!!!!\n"); @@ -291,14 +293,16 @@ ->content_is( "stash too!cookie!!signed_cookie!!bad_cookie--12345678!session!flash!\n"); -# With cookies and session but no flash +# With cookies and session but no flash (rotating secrets) +$t->app->secrets(['test2', 'test1']); $t->get_ok('/bridge2stash' => {'X-Flash2' => 1})->status_is(200) ->content_is( "stash too!cookie!!signed_cookie!!bad_cookie--12345678!session!!\n"); ok $t->tx->res->cookie('mojolicious')->expires->epoch < time, 'session cookie expires'; -# With cookies and session cleared +# With cookies and session cleared (rotating secrets) +$t->app->secrets(['test3', 'test2']); $t->get_ok('/bridge2stash')->status_is(200) ->content_is("stash too!cookie!!signed_cookie!!bad_cookie--12345678!!!\n"); diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/lite_app.t libmojolicious-perl-4.63+dfsg/t/mojolicious/lite_app.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/lite_app.t 2013-10-23 17:58:16.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/lite_app.t 2013-12-19 19:57:52.000000000 +0000 @@ -445,7 +445,7 @@ is $t->app->moniker, 'lite_app', 'right moniker'; my $log = ''; my $cb = $t->app->log->on(message => sub { $log .= pop }); -is $t->app->secret, $t->app->moniker, 'secret defaults to moniker'; +is $t->app->secrets->[0], $t->app->moniker, 'secret defaults to moniker'; like $log, qr/Your secret passphrase needs to be changed!!!/, 'right message'; $t->app->log->unsubscribe(message => $cb); diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/ojo.t libmojolicious-perl-4.63+dfsg/t/mojolicious/ojo.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/ojo.t 2013-10-13 09:11:54.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/ojo.t 2013-12-19 19:58:12.000000000 +0000 @@ -12,8 +12,8 @@ # Application a('/' => sub { $_->render(data => $_->req->method . $_->req->body) }) - ->secret('foobarbaz'); -is a->secret, 'foobarbaz', 'right secret'; + ->secrets(['foobarbaz']); +is a->secrets->[0], 'foobarbaz', 'right secret'; # Requests is g('/')->body, 'GET', 'right content'; diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/tag_helper_lite_app.t libmojolicious-perl-4.63+dfsg/t/mojolicious/tag_helper_lite_app.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/tag_helper_lite_app.t 2013-10-28 00:49:44.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/tag_helper_lite_app.t 2013-12-03 02:10:44.000000000 +0000 @@ -15,6 +15,8 @@ get 'small_tags'; +get 'circle'; + get 'tags_with_error'; any [qw(GET POST)] => 'links'; @@ -62,6 +64,13 @@
works
EOF +# XML +$t->get_ok('/circle.svg')->status_is(200)->content_is(< + + +EOF + # Tags with error $t->get_ok('/tags_with_error')->status_is(200)->content_is(<0 @@ -460,6 +469,14 @@ 0 %= end +@@ circle.svg.ep +%= tag svg => begin +<%= + tag 'circle', cx => 75, cy => 55, r => 35, stroke => 'black', + 'stroke-width' => 2, fill => 'red' +%> +%= end + @@ links.html.ep <%= link_to 'Pa '/path' %> <%= link_to 'http://example.com/', title => 'Foo', sub { 'Foo' } %> diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/validation_lite_app.t libmojolicious-perl-4.63+dfsg/t/mojolicious/validation_lite_app.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/validation_lite_app.t 2013-10-28 01:23:21.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/validation_lite_app.t 2013-12-11 17:15:54.000000000 +0000 @@ -24,6 +24,13 @@ $validation->optional('yada')->two; } => 'index'; +any '/forgery' => sub { + my $self = shift; + my $validation = $self->validation; + return $self->render unless $validation->has_data; + $validation->csrf_protect->required('foo'); +}; + my $t = Test::Mojo->new; # Required and optional values @@ -120,6 +127,35 @@ is_deeply $validation->output, {0 => 0}, 'right result'; is $validation->param('0'), 0, 'right value'; +# Custom error +$validation = $t->app->validation->input({foo => 'bar'}); +ok !$validation->required('foo')->has_error, 'no error'; +is_deeply $validation->output, {foo => 'bar'}, 'right result'; +ok $validation->error(foo => ['custom_check'])->has_error, 'has error'; +is_deeply $validation->output, {}, 'right result'; +is_deeply $validation->size(1, 2)->error('foo'), ['custom_check'], + 'right error'; + +# CSRF protection +$validation = $t->app->validation->input({foo => 'bar'})->csrf_protect; +ok $validation->has_data, 'has data'; +ok $validation->has_error, 'has error'; +is_deeply $validation->error('csrf_token'), ['csrf_protect'], 'right error'; +$validation = $t->app->validation->input({csrf_token => 'abc'}); +ok $validation->has_data, 'has data'; +ok $validation->csrf_protect->has_error, 'has error'; +ok $validation->has_data, 'has data'; +is_deeply $validation->error('csrf_token'), ['csrf_protect'], 'right error'; +$validation = $t->app->validation->input({csrf_token => 'abc', foo => 'bar'}) + ->csrf_token('cba')->csrf_protect; +ok $validation->has_error, 'has error'; +is_deeply $validation->error('csrf_token'), ['csrf_protect'], 'right error'; +$validation = $t->app->validation->input({csrf_token => 'abc', foo => 'bar'}) + ->csrf_token('abc')->csrf_protect; +ok !$validation->has_error, 'no error'; +ok $validation->required('foo')->is_valid, 'valid'; +is_deeply $validation->output, {foo => 'bar'}, 'right result'; + # Missing method and function (AUTOLOAD) eval { $t->app->validation->missing }; my $package = 'Mojolicious::Validator::Validation'; @@ -152,6 +188,38 @@ ->element_exists_not('select.field-with-error') ->element_exists_not('input.field-with-error[type="password"]'); +# Missing CSRF token +$t->get_ok('/forgery' => form => {foo => 'bar'})->status_is(200) + ->content_like(qr/Wrong or missing CSRF token!/) + ->element_exists('[value=bar]')->element_exists_not('.field-with-error'); + +# Correct CSRF token +my $token + = $t->ua->get('/forgery')->res->dom->at('[name=csrf_token]')->{value}; +$t->post_ok('/forgery' => form => {csrf_token => $token, foo => 'bar'}) + ->status_is(200)->content_unlike(qr/Wrong or missing CSRF token!/) + ->element_exists('[value=bar]')->element_exists_not('.field-with-error'); + +# Correct CSRF token (header) +$t->post_ok('/forgery' => {'X-CSRF-Token' => $token} => form => {foo => 'bar'}) + ->status_is(200)->content_unlike(qr/Wrong or missing CSRF token!/) + ->element_exists('[value=bar]')->element_exists_not('.field-with-error'); + +# Wrong CSRF token (header) +$t->post_ok('/forgery' => {'X-CSRF-Token' => 'abc'} => form => {foo => 'bar'}) + ->status_is(200)->content_like(qr/Wrong or missing CSRF token!/) + ->element_exists('[value=bar]')->element_exists_not('.field-with-error'); + +# Missing CSRF token and form +$t->get_ok('/forgery')->status_is(200) + ->content_unlike(qr/Wrong or missing CSRF token!/) + ->element_exists_not('.field-with-error'); + +# Correct CSRF token and missing form +$t->post_ok('/forgery' => {'X-CSRF-Token' => $token})->status_is(200) + ->content_unlike(qr/Wrong or missing CSRF token!/) + ->element_exists('.field-with-error'); + # Failed validation for all fields (with custom helper) $t->app->helper( tag_with_error => sub { @@ -192,3 +260,10 @@ %= select_field baz => [qw(yada yada)] %= password_field 'yada' % end + +@@ forgery.html.ep +%= form_for forgery => begin + %= 'Wrong or missing CSRF token!' if validation->has_error('csrf_token') + %= csrf_field + %= text_field 'foo' +%= end diff -Nru libmojolicious-perl-4.58+dfsg/t/mojolicious/websocket_lite_app.t libmojolicious-perl-4.63+dfsg/t/mojolicious/websocket_lite_app.t --- libmojolicious-perl-4.58+dfsg/t/mojolicious/websocket_lite_app.t 2013-09-01 17:27:43.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/mojolicious/websocket_lite_app.t 2013-11-29 03:29:15.000000000 +0000 @@ -55,6 +55,21 @@ ); }; +websocket '/no_context_takeover' => sub { + my $self = shift; + $self->tx->context_takeover(0); + $self->res->headers->sec_websocket_extensions( + 'permessage-deflate;client_no_context_takeover'); + $self->on(binary => sub { shift->send({binary => shift}) }); +}; + +websocket '/no_compression' => sub { + my $self = shift; + $self->tx->compressed(0); + $self->res->headers->remove('Sec-WebSocket-Extensions'); + $self->on(binary => sub { shift->send({binary => shift}) }); +}; + websocket '/bytes' => sub { my $self = shift; $self->on( @@ -120,8 +135,12 @@ is $t->tx->req->headers->sec_websocket_protocol, 'foo, bar, baz', 'right "Sec-WebSocket-Protocol" value'; -# Bytes -$t->websocket_ok('/echo')->send_ok({binary => 'bytes!'}) +# Bytes with compression (offer "client_no_context_takeover") +my $extensions = 'permessage-deflate;client_no_context_takeover'; +$t->websocket_ok('/echo' => {'Sec-WebSocket-Extensions' => $extensions}); +ok $t->tx->compressed, 'WebSocket has compression'; +ok $t->tx->context_takeover, 'with context takeover'; +$t->send_ok({binary => 'bytes!'}) ->message_ok->message_is({binary => 'bytes!'}) ->send_ok({binary => 'bytes!'}) ->message_ok->message_isnt({text => 'bytes!'})->finish_ok; @@ -131,17 +150,34 @@ ->send_ok(0)->message_ok->message_like({text => qr/0/})->finish_ok(1000) ->finished_ok(1000); -# 64bit binary message (extended limit) -$t->websocket_ok('/echo'); +# 64bit binary message (extended limit and no compression) +$t->websocket_ok('/echo' => {'Sec-WebSocket-Extensions' => 'nothing'}); is $t->tx->max_websocket_size, 262144, 'right size'; $t->tx->max_websocket_size(262145); $t->send_ok({binary => 'a' x 262145}) ->message_ok->message_is({binary => 'a' x 262145}) ->finish_ok->finished_ok(1005); -# 64bit binary message (too large) -$t->websocket_ok('/echo')->send_ok({binary => 'b' x 262145}) - ->finished_ok(1009); +# 64bit binary message (too large and no compression) +$t->websocket_ok('/echo' => {'Sec-WebSocket-Extensions' => 'nothing'}) + ->send_ok({binary => 'b' x 262145})->finished_ok(1009); + +# Compressed message ("permessage-deflate") +$t->websocket_ok('/echo'); +$t->send_ok({binary => 'a' x 50000}) + ->header_is('Sec-WebSocket-Extensions' => 'permessage-deflate'); +is $t->tx->req->headers->sec_websocket_extensions, 'permessage-deflate', + 'right "Sec-WebSocket-Extensions" value'; +my $payload; +$t->tx->once( + frame => sub { + my ($tx, $frame) = @_; + $payload = $frame->[5]; + } +); +$t->message_ok->message_is({binary => 'a' x 50000}); +ok length $payload < 262145, 'message has been compressed'; +$t->finish_ok->finished_ok(1005); # Binary message in two 64bit frames without FIN bit (too large) $t->websocket_ok('/echo')->send_ok([0, 0, 0, 0, 2, 'c' x 100000]) @@ -194,9 +230,28 @@ ->send_ok('and one ☃ more time') ->message_ok->message_is('♥: and one ☃ more time')->finish_ok; -# Binary frame and events +# Compression with forced "client_no_context_takeover" +$t->websocket_ok('/no_context_takeover'); +ok $t->tx->compressed, 'WebSocket has compression'; +ok !$t->tx->context_takeover, 'no context takeover'; +$t->send_ok({binary => 'a' x 500}) + ->message_ok->message_is({binary => 'a' x 500}) + ->send_ok({binary => 'a' x 500}) + ->message_ok->message_is({binary => 'a' x 500})->finish_ok; + +# Compression denied by the server +$t->websocket_ok('/no_compression'); +is $t->tx->req->headers->sec_websocket_extensions, 'permessage-deflate', + 'right "Sec-WebSocket-Extensions" value'; +ok !$t->tx->compressed, 'WebSocket has no compression'; +$t->send_ok({binary => 'a' x 500}) + ->message_ok->message_is({binary => 'a' x 500})->finish_ok; + +# Binary frame and events (no compression) my $bytes = b("I ♥ Mojolicious")->encode('UTF-16LE')->to_string; -$t->websocket_ok('/bytes'); +$t->websocket_ok('/bytes' => {'Sec-WebSocket-Extensions' => 'nothing'}) + ->header_isnt('Sec-WebSocket-Extensions' => 'permessage-deflate'); +ok !$t->tx->compressed, 'WebSocket has no compression'; my $binary; $t->tx->on( frame => sub { @@ -214,10 +269,10 @@ $t->finish_ok(1000 => 'Have a nice day!'); is_deeply $close, [1000, 'Have a nice day!'], 'right status and message'; -# Binary roundtrips -$t->websocket_ok('/bytes')->send_ok({binary => $bytes}) - ->message_ok->message_is($bytes)->send_ok({binary => $bytes}) - ->message_ok->message_is($bytes)->finish_ok; +# Binary roundtrips (no compression) +$t->websocket_ok('/bytes' => {'Sec-WebSocket-Extensions' => 'nothing'}) + ->send_ok({binary => $bytes})->message_ok->message_is($bytes) + ->send_ok({binary => $bytes})->message_ok->message_is($bytes)->finish_ok; # Two responses $t->websocket_ok('/once')->send_ok('hello') diff -Nru libmojolicious-perl-4.58+dfsg/t/pod_coverage.t libmojolicious-perl-4.63+dfsg/t/pod_coverage.t --- libmojolicious-perl-4.58+dfsg/t/pod_coverage.t 2013-10-22 19:32:53.000000000 +0000 +++ libmojolicious-perl-4.63+dfsg/t/pod_coverage.t 2013-12-19 18:29:02.000000000 +0000 @@ -10,7 +10,7 @@ # DEPRECATED in Top Hat! my @tophat = ( qw(app app_url detect_proxy http_proxy https_proxy name need_proxy new), - qw(no_proxy) + qw(no_proxy secret to_rel) ); # False positive constants