libmojolicious-perl-4.63+dfsg.orig/0000755000175000017500000000000012256126533017164 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/.perltidyrc0000644000175000017500000000071712200150752021340 0ustar cstamascstamas-pbp # Start with Perl Best Practices -w # Show all warnings -iob # Ignore old breakpoints -l=79 # 79 characters per line -mbl=2 # No more than 2 blank lines -i=2 # Indentation is 2 columns -ci=2 # Continuation indentation is 2 columns -vt=0 # Less vertical tightness -pt=2 # High parenthesis tightness -bt=2 # High brace tightness -sbt=2 # High square bracket tightness -isbc # Don't indent comments without leading space libmojolicious-perl-4.63+dfsg.orig/Changes0000644000175000017500000043420512254637525020475 0ustar cstamascstamas 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. - Improved Mojo::DOM::HTML performance. - Fixed recursion bug in Mojo::Reactor::EV where timers could run more than once. - Fixed a few "0" value bugs in Mojo::DOM::HTML. 4.57 2013-11-11 - Improved compatibility with IO::Socket::SSL 1.957. - Fixed error event bug in Mojo::IOLoop::Delay. 4.56 2013-11-09 - Fixed backspace escaping bug in Mojo::JSON. (ig3) 4.55 2013-11-07 - Fixed Windows bug in "daemon.t". 4.54 2013-11-07 - Added parts attribute to Mojo::Home. - Fixed keep alive connection timeout bug in Mojo::UserAgent. - Fixed support for links within a page in Mojolicious::Plugin::PODRenderer. - Fixed home detection bug in Mojo. 4.53 2013-10-30 - Fixed a few unsubscribe and error event bugs in Mojo::EventEmitter. 4.52 2013-10-29 - Improved Mojo::EventEmitter to allow unhandled error events to be fatal. (powerman, sri) 4.51 2013-10-28 - Added tag_with_error helper to Mojolicious::Plugin::TagHelpers. - Improved .ep template performance significantly, the number of helpers no longer has any effect. (jberger, sri) - Improved form_for performance. - Improved built-in templates with documentation search. - Fixed template inheritance bug in include helper. - Fixed a few multipart form handling bugs. 4.50 2013-10-22 - Deprecated Mojo::UserAgent::app in favor of Mojo::UserAgent::Server::app. - Deprecated Mojo::UserAgent::app_url in favor of Mojo::UserAgent::Server::url. - Deprecated Mojo::UserAgent::detect_proxy in favor of Mojo::UserAgent::Proxy::detect. - Deprecated Mojo::UserAgent::http_proxy in favor of Mojo::UserAgent::Proxy::http. - Deprecated Mojo::UserAgent::https_proxy in favor of Mojo::UserAgent::Proxy::https. - Deprecated Mojo::UserAgent::no_proxy in favor of Mojo::UserAgent::Proxy::not. - Deprecated Mojo::UserAgent::need_proxy in favor of Mojo::UserAgent::Proxy::is_needed. - Deprecated Mojo::UserAgent::name in favor of Mojo::UserAgent::Transactor::name. - Added modules Mojo::UserAgent::Proxy and Mojo::UserAgent::Server. - Added proxy and server attributes to Mojo::UserAgent. - Removed deprecated attrs method from Mojo::DOM. - Improved Mojo::Message to allow max_message_size check to be disabled. - Fixed small assignment bug in content helper. 4.49 2013-10-17 - Added tls_ciphers option to Mojo::IOLoop::Server::listen. - Added ciphers parameter to Mojo::Server::Daemon::listen. - Removed experimental status from Mojolicioua::Validator. - Removed experimental status from Mojolicioua::Validator::Validation. - Removed experimental status from validation method in Mojolicious::Controller. - Removed experimental status from validator attribute in Mojolicious. - Removed experimental status from validation helper in Mojolicious::Plugin::DefaultHelpers. - Fixed parameter bug in Mojolicious::Validator::Validation. 4.48 2013-10-16 - Fixed support for Net::SSLeay 1.55. 4.47 2013-10-15 - Added dumper function to Mojo::Util. - Improved compatibility with IO::Socket::SSL 1.955. - Improved IIS compatibility of Mojo::Server::CGI. 4.46 2013-10-11 - Changed default name for generated applications from MyMojoliciousApp to MyApp. - Improved performance of route matching in Mojolicious::Routes::Pattern. - Improved HTML Living Standard compliance of Mojo::DOM::HTML. 4.45 2013-10-06 - Changed return values of validation checks in Mojolicious::Validator. - Fixed unquoted attribute selector bug in Mojo::DOM::CSS. 4.44 2013-10-04 - Removed experimental status from label_for helper. - Renamed regex check in Mojolicious::Validator to like. 4.43 2013-10-02 - Removed generators for dynamic error messages from Mojolicious::Validator. 4.42 2013-09-30 - Added EXPERIMENTAL form validation support. - Added EXPERIMENTAL modules Mojolicious::Validator and Mojolicious::Validator::Validation. - Added EXPERIMENTAL validation method to Mojolicious::Controller. - Added EXPERIMENTAL validator attribute to Mojolicious. - Added EXPERIMENTAL label_for and validation helpers to Mojolicious::Plugin::DefaultHelpers. 4.41 2013-09-22 - Improved documentation browser to be a little more RESTful. - Fixed flatten to work with older versions of Perl. (jamadam) 4.40 2013-09-21 - Added text method to Mojo::Message. - Added siblings method to Mojo::DOM. - Added flatten method to Mojo::Collection. - Improved documentation browser with source links. - Fixed smart whitespace trimming bug in Mojo::DOM. - Fixed table parsing bug in Mojo::DOM::HTML. - Fixed bug in Mojolicious::Types where the txt MIME type did not specify a charset. 4.39 2013-09-17 - Improved HTML5.1 compliance of Mojo::DOM::HTML. 4.38 2013-09-16 - Added is_binary method to Mojo::Loader. - Fixed support for binary files in inflate command. - Fixed stylesheet helper not to enforce a media attribute. 4.37 2013-09-13 - Improved design of built-in templates. 4.36 2013-09-12 - Added match method to Mojo::DOM. - Added match method to Mojo::DOM::CSS. - Improved ancestors and children methods in Mojo::DOM to support all CSS selectors. - Improved syntax highlighting in documentation browser. - Improved compatibility with different object systems. 4.35 2013-09-10 - Added origin attribute to Mojo::Cookie::Response. - Fixed RFC 6265 compliance bugs in Mojo::Cookie::Request, Mojo::Cookie::Response and Mojo::UserAgent::CookieJar. 4.34 2013-09-08 - Fixed portability bug in SO_REUSEPORT tests. 4.33 2013-09-07 - Fixed portability bug in Mojo::IOLoop::Delay. 4.32 2013-09-06 - Added error event to Mojo::IOLoop::Delay. 4.31 2013-09-04 - Deprecated mode specific methods in application class. sub production_mode {...} becomes (in the startup method) if ($app->mode eq 'production') {...} 4.30 2013-09-01 - Fixed memory leak in Mojolicious::Routes. 4.29 2013-08-31 - Fixed automatic rendering to work after non-blocking operations have been performed in bridges. 4.28 2013-08-29 - Added support for non-blocking operations in bridges to Mojolicious::Routes. - Added continue method to Mojolicious::Controller. - Added continue method to Mojolicious::Routes. - Added current attribute to Mojolicious::Routes::Match. - Fixed automatic rendering bug in Mojolicious::Routes. 4.27 2013-08-26 - Added acceptors attribute to Mojo::Server::Daemon. - Added handle method to Mojo::IOLoop::Server. - Added -V option to eval command. - Added reuse option to Mojo::IOLoop::Server::listen. - Added reuse parameter to Mojo::Server::Daemon::listen. - Fixed console message bug in Mojo::Server::Daemon. - Fixed SNI bug in online tests. 4.26 2013-08-18 - Fixed support for Netscape cookies in Mojo::Cookie::Response. - Fixed element method bug in Mojo::Collection. 4.25 2013-08-17 - Added support for calling element methods to Mojo::Collection. - Added compact method to Mojo::Collection. 4.24 2013-08-08 - Added ancestors method to Mojo::DOM. - Fixed bug where Mojo::IOLoop::Stream timeout was not always available. 4.23 2013-08-01 - Added redirects method to Mojo::Transaction::HTTP. 4.22 2013-07-30 - Improved Mojo::Server to use FindBin more defensively. - Fixed empty attribute bug in Mojo::DOM::CSS. - Fixed partial route handling in routes command. 4.21 2013-07-29 - Added strip method to Mojo::DOM. - Fixed return values of remove and replace methods in Mojo::DOM. 4.20 2013-07-28 - Deprecated Mojo::DOM::attrs in favor of Mojo::DOM::attr. - Improved Mojo::UserAgent connection management to be fork-safe. 4.19 2013-07-21 - Improved invalid tag handling in Mojo::DOM::HTML. 4.18 2013-07-08 - Added --mode option to Morbo. - Fixed bug in Mojo::UserAgent where not all 2xx responses would be accepted for CONNECT requests. 4.17 2013-07-04 - Updated jQuery to version 2.0.3. - Improved Mojo::IOLoop::Server to use Perfect Forward Secrecy for TLS. - Fixed Mojo::Transaction::WebSocket to generate RFC 6455 compliant Sec-WebSocket-Key headers. (josh) - Fixed bug where not all uppercase methods were hidden from the router. 4.16 2013-06-19 - Improved Perl 5.10.x and 5.12.x compatibility. (trinitum) 4.15 2013-06-18 - Added around_action hook. - Improved ojo to make the current controller object available to actions as $_. (jberger, sri) - Fixed a few error reporting bugs in Mojo::IOLoop::Client and Mojo::IOLoop::Server. - Fixed small emit_chain bug in Mojolicious::Plugins. 4.14 2013-06-10 - Improved url_for performance slightly. - Fixed bug where match attribute and render_later method were not hidden from the router. 4.13 2013-06-09 - Replaced ua method in Mojolicious::Controller with a helper. - Fixed url_for support for absolute URLs without scheme or authority. (bduggan, sri) 4.12 2013-06-07 - Improved Mojo::Message::Request to allow a few more ASCII characters in URLs. 4.11 2013-06-03 - Added allow and append methods to Mojo::Headers. - Added split_header function to Mojo::Util. - Fixed cookie quoting bugs. - Fixed a few small boundary and charset detection bugs in Mojo::Content. - Fixed a few small filename detection bugs in Mojo::Message. - Fixed small quality detection bug in Mojolicious::Types. 4.10 2013-06-01 - Added link and vary methods to Mojo::Headers. 4.09 2013-05-31 - Updated jQuery to version 2.0.2. - Increased default max_message_size from 5MB to 10MB in Mojo::Message. 4.08 2013-05-30 - Improved Mojo::Message::Request to allow curly brackets in URLs. - Improved HMAC-SHA1 performance in Mojo::Util. 4.07 2013-05-26 - Updated jQuery to version 2.0.1. - Fixed format handling in routes command. 4.06 2013-05-25 - Fixed Windows bug in "log.t". 4.05 2013-05-24 - Fixed encoding bug in Mojo::Log. 4.04 2013-05-23 - Added WebSocket subprotocol support to Mojo::UserAgent::Transactor. 4.03 2013-05-21 - Fixed redirect support in get command. 4.02 2013-05-20 - Fixed extends, layout and title helpers not to generate unnecessary log messages. 4.01 2013-05-19 - Fixed small drain event bug in Mojo::IOLoop::Stream. (ChinaXing) 4.0 2013-05-15 - Code name "Top Hat", this is a major release. - Added simple JSON serialization and deserialization support to Mojo::Transaction::WebSocket. - Added json event to Mojo::Transaction::WebSocket. - Added render_maybe method to Mojolicious::Controller. - Added again method to Mojo::Reactor, Mojo::Reactor::Poll and Mojo::Reactor::EV. - Added is_empty method to Mojo::Transaction::HTTP. - Added close_gracefully method to Mojo::IOLoop::Stream. - Changed Mojolicious default secret to the application moniker to make it slightly more secure. - Changed types in Mojolicious::Types to consistently use arrays. - Changed heuristics for number detection in Mojo::JSON to better line up with user expectations. - Changed render and render_static methods in Mojolicious::Controller to call render_not_found if no response could be generated. - Removed callback support from body method in Mojo::Message. - Removed Mojolicious::Plugin::PoweredBy and Mojolicious::Plugin::RequestTimer. - Removed pair_separator attribute from Mojolicious::Parameters. - Removed data attribute from Mojo::URL. - Removed captures attribute from Mojolicious::Routes::Match. - Removed charset attribute from Mojo::DOM::HTML. - Removed charset method from Mojo::DOM. - Removed render_data, render_json, render_partial and render_text methods from Mojolicious::Controller. - Removed json_content_is method from Test::Mojo. - Removed has_leftovers method from Mojo::Content. - Removed is_chunked, is_dynamic, is_multipart, has_leftovers, leftovers, write and write_chunk methods from Mojo::Message. - Removed hmac_md5_sum method from Mojo::ByteStream. - Removed hmac_md5_sum function from Mojo::Util. - Removed memorize helper. - Removed deprecated end method from Mojo::IOLoop::Delay. - Removed deprecated build_form_tx, build_json_tx, post_form and post_json methods from Mojo::UserAgent. - Removed deprecated form and json methods from Mojo::UserAgent::Transactor. - Removed deprecated post_form_ok and post_json_ok methods from Test::Mojo. - Removed deprecated f and n functions from ojo. - Removed deprecated after_static_dispatch hook. - Renamed shape_match method in Mojolicious::Routes::Pattern to match_partial. - Reduced idle CPU usage of Mojo::IOLoop. - Increased default lock_timeout from 0.5 to 1 second in Mojo::Server::Prefork and Mojo::Server::Hypnotoad. - Improved Mojo::IOLoop performance significantly and reduced CPU usage when managing more than 10k concurrent connections. - Improved Mojolicious to be able to detect the current operating mode from the PLACK_ENV environment variable. - Improved Mojolicious to not trap exceptions if the default exception handling has been deactivated. - Improved json_is and json_message_is methods in Test::Mojo by making the JSON Pointer optional. (jberger) - Improved renderer performance. - Improved Mojo::DOM::HTML performance. - Improved Mojo::Reactor::Poll performance. - Improved html_unescape performance in Mojo::Util. - Improved Mojolicious::Plugin::EPLRenderer to cache templates more efficiently. - Fixed Perl 5.17.11+ compatibility. - Fixed Mojo::JSON to encode "inf" and "nan" values as strings. (chansen) - Fixed a few authority and rendering bugs in Mojo::URL. - Fixed layout bugs in Mojolicious::Renderer. - Fixed support for HEAD request method in Mojo::Server::CGI and Mojo::Server::PSGI. - Fixed small line directive bug in Mojo::Template. - Fixed small limit bug in Mojo::Message. 3.97 2013-04-25 - Added data attribute to Mojo::URL. - Improved compatibility with IO::Socket::SSL 1.87. - Improved Test::Mojo diagnostics messages. - Fixed a few small timing bugs in WebSocket tests. 3.96 2013-04-22 - Updated jQuery to version 2.0. - Updated prettify.js to version 4-Mar-2013. - Improved Mojo::URL to be able to contain scheme data for unknown schemes. - Improved form content generator for GET and HEAD requests. (jberger) - Improved default descriptions in Test::Mojo. - Fixed host normalization bug in Mojo::URL. - Fixed small html_unescape bug in Mojo::Util. - Fixed small encoding bug in routes command. - Fixed a few small clone bugs. - Fixed a few small redirect and proxy connect bugs in Mojo::UserAgent::Transactor. - Fixed a few small method handling bugs in Mojo::Transaction::HTTP. 3.95 2013-04-12 - Added finished_ok method to Test::Mojo. - Removed deprecated slurp_rel_file method from Mojo::Home. - Removed deprecated html_escape function from Mojo::Util. - Improved Mojo::Transaction::WebSocket with support for status codes and reasons. - Fixed message size limit bug in Mojo::Transaction::WebSocket. - Fixed a few small timing bugs in Mojo::Server::Daemon. - Fixed small description bug in Test::Mojo. 3.94 2013-04-08 - Added is_hidden method to Mojolicious::Routes. - Removed deprecated start method from Mojolicious::Commands. - Fixed small selector bug in get command. - Fixed small anchor bug in Mojolicious::Plugin::PODRenderer. 3.93 2013-04-05 - Deprecated Mojo::IOLoop::Delay::end in favor of generated callbacks. - Improved Mojo::IOLoop::Delay to be able to generate callbacks that can capture all arguments. - Improved prefork command to allow -a and -L values below 1 second. - Fixed multiple timing bugs in Mojo::IOLoop::Delay. 3.92 2013-04-03 - Added monotonic clock support to make Mojolicious more resilient to time jumps. - Added steady_time function to Mojo::Util. - Removed deprecated namespace method from Mojolicious::Routes. - Removed deprecated base_tag helper. - Improved WebSocket send method to stringify objects. (jberger) - Improved version command to show required versions of optional dependencies. - Fixed RFC 6901 compliance of Mojo::JSON::Pointer. (jberger, sri) - Fixed a few small Unicode bugs in get command. 3.91 2013-03-17 - Improved bad charset handling in Mojo::DOM::HTML. - Fixed HTTPS proxy support for blocking requests in Mojo::UserAgent. - Fixed support for RFC 2817 in Mojo::Message::Request. - Fixed whitespace bug in Mojo::DOM::HTML. - Fixed proxy detection bug in get command. 3.90 2013-03-14 - Added direct array access for parsed parameters to Mojo::Parameters. - Added direct array access for path parts to Mojo::Path. - Improved dumper helper to sort hash keys. - Fixed bug in Mojo::Headers that prevented multiline headers from being parsed correctly. - Fixed multiline header support in hash representation of Mojo::Headers. - Fixed cloning bug in Mojo::Headers. 3.89 2013-03-04 - Fixed installable scripts to not "use lib", which sadly breaks updated dual-life modules. (jberger, sri) - Fixed bug preventing delayed normalization for reused Mojo::Path objects. - Fixed path matching bug in Mojo::Path. 3.88 2013-03-03 - Improved Mojo::Path to delay normalization as long as possible. - Improved Mojo::Path performance. - Fixed small domain detection bug in Mojo::UserAgent::CookieJar. 3.87 2013-02-23 - Added deprecated function to Mojo::Util. (marcus) - Removed deprecated render_content helper. 3.86 2013-02-22 - Welcome to the Mojolicious core team Joel Berger. - Improved portability of Mojo::Asset::File tests. - Fixed path generation bug in Mojolicious::Routes::Pattern. (jberger) - Fixed small domain detection bug in Mojo::UserAgent::CookieJar. (dione, sri) - Fixed comment lines in Mojo::Template to cover the whole line. 3.85 2013-02-13 - Deprecated Mojo::UserAgent::build_form_tx in favor of Mojo::UserAgent::build_tx. - Deprecated Mojo::UserAgent::build_json_tx in favor of Mojo::UserAgent::build_tx. - Deprecated Mojo::UserAgent::post_form in favor of Mojo::UserAgent::post. - Deprecated Mojo::UserAgent::post_json in favor of Mojo::UserAgent::post. - Deprecated Mojo::UserAgent::Transactor::form in favor of Mojo::UserAgent::Transactor::tx. - Deprecated Mojo::UserAgent::Transactor::json in favor of Mojo::UserAgent::Transactor::tx. - Deprecated Test::Mojo::post_form_ok in favor of Test::Mojo::post_ok. - Deprecated Test::Mojo::post_json_ok in favor of Test::Mojo::post_ok. - Deprecated ojo::f in favor of ojo::p. - Deprecated ojo::n in favor of ojo::p. - Added support for pluggable content generators to Mojo::UserAgent::Transactor. (judofyr, sri) - Added generators attribute to Mojo::UserAgent::Transactor. - Added add_generator method to Mojo::UserAgent::Transactor. - Updated jQuery to version 1.9.1. - Fixed memory leak in development not found page. - Fixed custom temporary directory bug in Mojo::Asset::File. 3.84 2013-01-30 - Deprecated after_static_dispatch hook in favor of before_routes. - Added after_static hook. - Fixed small file descriptor leak in Mojo::UserAgent. 3.83 2013-01-27 - Moved bundled static files to mojo directory. - Fixed small Getopt::Long configuration bug in Mojolicious::Commands. 3.82 2013-01-18 - Fixed Windows bugs in tests. (kmx, sri) 3.81 2013-01-17 - Added modules Mojo::Server::Prefork and Mojolicious::Command::prefork. - Added lookup method to Mojolicious::Routes. - Updated jQuery to version 1.9. - Improved url_for performance significantly. - Improved Mojo::Server::Hypnotoad to be a small wrapper around Mojo::Server::Prefork. - Fixed small memory leak in Hypnotoad that only shows when Perl is compiled with -DPERL_USE_SAFE_PUTENV. (lewoberst) 3.80 2013-01-15 - Deprecated testing WebSocket messages without calling Test::Mojo::message_ok. - Deprecated Mojo::Util::html_escape in favor of Mojo::Util::xml_escape. - Deprecated Mojo::ByteStream::html_escape in favor of Mojo::ByteStream::xml_escape. - Deprecated Mojo::Home::slurp_rel_file in favor of Mojo::Util::slurp. - Added message attribute to Test::Mojo. - Added json_message_has, json_message_hasnt and message_ok methods to Test::Mojo. - Fixed support for multi-character entities in Mojo::Util. 3.79 2013-01-13 - Fixed small domain detection bug in Mojo::UserAgent::CookieJar. 3.78 2013-01-13 - Added to_dir method to Mojo::Path. - Fixed domain and path detection bugs in Mojo::UserAgent::CookieJar. - Fixed IDNA support in Mojo::UserAgent::CookieJar. 3.77 2013-01-12 - Added support for advanced binary WebSocket message tests to Test::Mojo. - Added binary and text events to Mojo::Transaction::WebSocket. - Added json_message_is method to Test::Mojo. - Added j function to Mojo::JSON. - Updated a few example scripts. - Fixed aliasing bug in Mojo::EventEmitter. - Fixed WebSocket cookie bug in Mojo::UserAgent. - Fixed small upgrade bugs in Mojo::UserAgent::Transactor. 3.76 2013-01-10 - Added support for multiple uploads sharing the same name to Mojo::UserAgent::Transactor. - Improved performance and memory usage of Mojo::EventEmitter. - Fixed support for multiple uploads in Mojolicious::Controller. 3.75 2013-01-08 - Added to_route method to Mojo::Path. - Improved router performance slightly. 3.74 2013-01-07 - Fixed bug where Mojolicious::Lite applications in modules would generate the wrong moniker. 3.73 2013-01-06 - Deprecated Mojolicious::Commands::start in favor of Mojolicious::Commands::start_app. - Added moniker attribute to Mojolicious. - Added after_render hook. - Improved name detection in Mojolicious::Plugin::Config. 3.72 2013-01-05 - Deprecated base_tag helper. 3.71 2013-01-02 - Modernized ".travis.yml". - Improved Mojo::EventEmitter to warn about unhandled error events. - Improved Mojo::UserAgent to warn more often about failed events. - Improved monkey_patch to patch multiple functions at once. (jberger) - Fixed small memory leak in Mojo::DOM. 3.70 2012-12-23 - Added accept_interval setting to Hypnotoad. - Reduced idle CPU usage of Mojo::Reactor::Poll. - Improved Mojo::Server to die more gracefully if an application class could not be found. 3.69 2012-12-20 - Deprecated Mojolicious::Routes::namespace in favor of Mojolicious::Routes::namespaces. - Added color_field helper to Mojolicious::Plugin::TagHelpers. - Added date_field helper to Mojolicious::Plugin::TagHelpers. - Added datetime_field helper to Mojolicious::Plugin::TagHelpers. - Added email_field helper to Mojolicious::Plugin::TagHelpers. - Added month_field helper to Mojolicious::Plugin::TagHelpers. - Added number_field helper to Mojolicious::Plugin::TagHelpers. - Added range_field helper to Mojolicious::Plugin::TagHelpers. - Added search_field helper to Mojolicious::Plugin::TagHelpers. - Added tel_field helper to Mojolicious::Plugin::TagHelpers. - Added time_field helper to Mojolicious::Plugin::TagHelpers. - Added url_field helper to Mojolicious::Plugin::TagHelpers. - Added week_field helper to Mojolicious::Plugin::TagHelpers. - Improved Mojo::Base to use utf8. 3.68 2012-12-16 - Added monkey_patch function to Mojo::Util. - Added ".travis.yml". - Modernized ".gitignore". - Updated jQuery to version 1.8.3. - Converted README to markdown. - Fixed small export bug in Mojolicious::Lite. (jberger) 3.67 2012-12-15 - Added support for MIME type prioritization to Mojolicious::Types. - Improved respond_to to prioritize multiple MIME types if the X-Requested-With header is set to the value "XMLHttpRequest". 3.66 2012-12-14 - Added request_ok method to Test::Mojo. - Fixed multipart boundary detection bug in Mojo::Content. - Fixed format regex generation bug in Mojolicious::Routes::Pattern. 3.65 2012-12-09 - Added upgrade method to Mojo::UserAgent::Transactor. - Added is_range method to Mojo::Asset. - Fixed parameter replacement bug in Mojo::Parameters. (alexbyk, sri) - Fixed small paragraph bug in Mojo::DOM::HTML. 3.64 2012-12-01 - Fixed bug where Mojo::UserAgent::Transactor would escape Content-Disposition values. 3.63 2012-11-28 - Added support for smooth restarting to Morbo. - Added acceptor method to Mojo::IOLoop. - Added stop method to Mojo::Server::Daemon. - Improved memory usage of chunked transfer encoding parser in Mojo::Content. 3.62 2012-11-26 - Improved compatibility with IO::Socket::SSL 1.79. - Improved encode/decode performance in Mojo::Util by using a cache. - Fixed clone bugs in Mojo::URL. 3.61 2012-11-25 - Added protocol method to Mojo::URL. - Added charset attribute to Mojo::Path. - Improved support for relative redirects in Mojo::UserAgent::Transactor. - Fixed clone bugs in Mojo::Parameters and Mojo::URL. - Fixed case sensitivity bugs in Mojo::UserAgent::Transactor. 3.60 2012-11-22 - Added unexpected event to Mojo::Transaction::HTTP. - Fixed Mojo::UserAgent to ignore unexpected 1xx responses. 3.59 2012-11-20 - Fixed memory leak in Mojo::Message::Request. - Fixed keep-alive bug in Mojo::Server::Daemon. 3.58 2012-11-19 - Fixed state bugs in Mojo::Content::MultiPart. - Fixed Mojo::UserAgent to remove codes from parser errors. 3.57 2012-11-12 - Deprecated Mojo::Exception::raw_message. - Improved error message accuracy in Mojo::Template by using line directives. - Improved performance of contains method in Mojo::Asset::File by 100%. - Fixed range bug in Mojo::Asset::Memory. 3.56 2012-11-09 - Improved performance of contains method in Mojo::Asset::File significantly. - Fixed offset bug in Mojo::Asset::File. 3.55 2012-11-08 - Added gzip compression support to Mojo::UserAgent. - Added is_compressed method to Mojo::Content. - Fixed bug that prevented around_dispatch hooks from working correctly in embedded applications. - Fixed small bug where "chunked" would not always be the default transfer encoding. 3.54 2012-11-01 - Added next and previous methods to Mojo::DOM. 3.53 2012-10-31 - Replaced Mojolicious::Guides::CodingGuidelines with Mojolicious::Guides::Contributing. 3.52 2012-10-26 - Added boolean shortcut support to Mojo::JSON. - Added escape attribute to Mojo::Template. (jberger) - Added max_buffer_size attribute to Mojo::Content. - Added is_limit_exceeded method to Mojo::Content. 3.51 2012-10-23 - Fixed multiple small context bugs. 3.50 2012-10-20 - Improved option handling of all commands. 3.49 2012-10-19 - Fixed % escaping bug in Mojo::Parameters. (dmw397) 3.48 2012-10-16 - Improved Mojo::Content performance slightly. - Fixed memory leak in Mojo::Headers. 3.47 2012-10-13 - Added all method to Mojo::UserAgent::CookieJar. - Fixed WebSocket bug in Mojo::Content. 3.46 2012-10-11 - Improved router and renderer to allow CamelCase controllers. 3.45 2012-10-10 - Added multi_accept attribute to Mojo::IOLoop. - Added multi_accept attribute to Mojo::IOLoop::Server. - Added multi_accept setting to Hypnotoad. - Relaxed comment handling in Mojo::DOM::HTML a little. (jberger) - Improved accept performance of all built-in web servers significantly. - Improved responsiveness of documentation browser. - Improved documentation browser CSS. (tempire) 3.44 2012-09-29 - Improved html_escape to favor lowercase entities. (judofyr) - Improved javascript and stylesheet helpers to not generate type attributes. 3.43 2012-09-22 - Updated jQuery to version 1.8.2. - Improved Hypnotoad to clean up old PID files containing a 0. (coffeemonster) 3.42 2012-09-16 - Improved Hypnotoad to clean up old PID files. 3.41 2012-09-13 - Improved Mojo::EventEmitter to warn about failed error events. - Improved resilience of Mojo::IOLoop exception handling. - Fixed small CGI bug. 3.40 2012-09-11 - Fixed Perl 5.10.1 compatibility. - Fixed FindBin support in Mojolicious applications. - Fixed a few multipart bugs. 3.39 2012-09-10 - Improved Mojo::URL and Mojo::Parameters performance. - Fixed support for query parameters in Mojolicious::Plugin::Charset. 3.38 2012-09-07 - Added xor_encode method to Mojo::ByteStream. - Added xor_encode function to Mojo::Util. - Fixed small xor_encode bug. (dod, crab) 3.37 2012-09-04 - Added finish method to Mojo::Message. - Updated jQuery to version 1.8.1. - Fixed Mojo::Transaction to propagate connection close to Mojo::Message. - Fixed small state bug in Mojo::Transaction. 3.36 2012-08-30 - Fixed small multipart bug. 3.35 2012-08-28 - Deprecated Mojolicious::Controller::render_content in favor of content helper. - Improved Mojolicious::Plugin::Config to accept mode specific config files without a normal config file. (alexbyk, sri) 3.34 2012-08-24 - Improved documentation. 3.33 2012-08-23 - Improved Mojo::DOM::HTML to handle bad charsets more gracefully. 3.32 2012-08-20 - Added event sequentialization support to delay method in Mojo::IOLoop. (judofyr, marcus, sri) - Added support for expiration session value to Mojolicious::Sessions. - Added steps method to Mojo::IOLoop::Delay. (judofyr, marcus, sri) - Added tap method to Mojo::Base. - Added squish method to Mojo::ByteStream. - Added squish function to Mojo::Util. - Fixed json_has method in Test::Mojo. - Fixed bug in Mojo::Log that prevented some message events from being emitted. - Fixed get command to allow ":" character in header values. - Fixed small class_to_file bug. - Fixed a few small namespace handling bugs. 3.31 2012-08-15 - Added accept_charset, accept_encoding, content_encoding, origin and sec_websocket_extensions methods to Mojo::Headers. 3.30 2012-08-14 - Added te method to Mojo::Headers. - Fixed small content encoding bug in Mojo::Message. 3.29 2012-08-13 - Fixed small timing bugs in WebSocket and TLS tests. 3.28 2012-08-10 - Added skip_body attribute to Mojo::Content. - Added is_empty method to Mojo::Message::Response. - Updated jQuery to version 1.8. - Improved Mojo::Base to assign names to generated subroutines. - Improved message parser performance slightly. - Fixed 1xx, 204 and 304 response support. 3.27 2012-08-09 - Improved tests. 3.26 2012-08-09 - Improved tests. 3.25 2012-08-08 - Fixed cleanup bugs in Mojo::Server::Daemon and Mojo::UserAgent. 3.24 2012-08-08 - Improved tests. 3.23 2012-08-07 - Added appcache MIME type. 3.22 2012-08-06 - Added mp4, ogg, ogv and webm MIME types. - Removed x- prefix from js and woff MIME types. - Fixed gz and xml MIME types. 3.21 2012-08-05 - Fixed Perl 5.17.3+ compatibility. - Fixed small AUTOLOAD bug in Mojolicious::Lite. 3.20 2012-08-04 - Added extract_start_line method to Mojo::Message, Mojo::Message::Request and Mojo::Message::Response. - Added get_start_line_chunk method to Mojo::Message::Request and Mojo::Message::Request. - Improved end method in Mojo::IOLoop::Delay to return the number of remaining events. 3.19 2012-08-03 - Fixed dynamic content generation bug in Mojo::Message. - Fixed bug that prevented multiple anchors with the same name in Mojolicious::Plugin::PODRenderer. 3.18 2012-08-02 - Fixed chunked transfer encoding bug in Mojo::Content. 3.17 2012-08-01 - Fixed bug in after_static_dispatch hook that prevented custom responses. - Fixed bug that prevented conditions from generating responses. 3.16 2012-07-31 - Fixed small memory leak in Mojolicious::Plugin::TagHelpers. 3.15 2012-07-28 - Improved Mojo::Base to load IO::Handle. 3.14 2012-07-27 - Improved documentation. 3.13 2012-07-24 - Added multi name support to param method in Mojolicious::Controller. - Added remove method to Mojo::DOM. - Improved RFC 3986 compliance of Mojo::Parameters. - Improved Mojolicious::Plugin::Config log messages. (jberger) - Fixed selector bug in dom method of Mojo::Message. - Fixed small charset bug in get command. 3.12 2012-07-20 - Deprecated Mojo::Home::app_class. - Deprecated Mojo::IOLoop::client_class. - Deprecated Mojo::IOLoop::server_class. - Deprecated Mojo::IOLoop::stream_class. - Deprecated Mojo::Message::dom_class. - Deprecated Mojo::Message::json_class. - Added json method to Mojo::UserAgent::Transactor. - Added build_json_tx and post_json methods to Mojo::UserAgent. - Added post_json_ok method to Test::Mojo. - Added n function to ojo. - Improved text_field helper to always set the type attribute. (marty, sri) - Fixed file and content type detection bugs in Mojolicious::Static. (marty, sri) 3.11 2012-07-19 - Added or method to Test::Mojo. (moritz, sri) - Added file and serve_asset methods to Mojolicious::Static. - Improved default descriptions for many methods in Test::Mojo. - Improved Mojo::Cache performance. (nic) - Fixed a few small encoding bugs in Test::Mojo. 3.10 2012-07-17 - Fixed small bug in Mojo::Asset::File. 3.09 2012-07-16 - Added spurt function to Mojo::Util. - Added spurt method to Mojo::ByteStream. 3.08 2012-07-14 - Fixed small Mojo::Template bug. 3.07 2012-07-13 - Improved template error messages for generator commands and config files. - Fixed small bug in Mojolicious::Plugin::EPRenderer that prevented code to be added to templates. - Fixed small bug in Mojolicious::Plugin::JSONConfig that prevented code to be added to config files. 3.06 2012-07-11 - Added tls_verify option to Mojo::IOLoop::Server::listen. (scottw) - Added verify parameter to Mojo::Server::Daemon::listen. (scottw) - Fixed small bug in Mojo::UserAgent that prevented port reuse. 3.05 2012-07-08 - Reduced default graceful_timeout from 30 to 20 seconds in Mojo::Server::Hypnotoad. - Fixed small initialization bug in Mojo::IOLoop::Stream. 3.04 2012-07-07 - Improved Mojo::IOLoop performance by reducing stream timeout precision from 0.025 to 0.5 seconds. 3.03 2012-07-06 - Improved load balancing between Hypnotoad worker processes. - Improved Hypnotoad log messages. - Fixed default format handling bug in render_exception and render_not_found. - Fixed small namespace detection bug in Mojo::DOM. - Fixed small session reset bug in Test::Mojo. 3.02 2012-07-03 - Added pluck and uniq methods to Mojo::Collection. - Added regular expression support to first and grep methods in Mojo::Collection. - Fixed JSON Pointer escaping. - Fixed small text and attribute extraction bugs in Mojo::DOM. - Fixed small inconsistency between routes and static dispatchers. 3.01 2012-07-01 - Improved CSS of built-in templates. 3.0 2012-06-25 - Code name "Rainbow", this is a major release. - Removed Mojolicious::Plugin::I18N so it can be maintained as a separate distribution. - Removed app_class attribute from Mojo::Server. - Removed qp_decode and qp_encode methods from Mojo::ByteStream. - Removed qp_decode and qp_encode functions from Mojo::Util. - Removed render_to_file and render_file_to_file methods from Mojo::Template. - Renamed Mojo::CookieJar to Mojo::UserAgent::CookieJar. - Renamed Mojo::Command to Mojolicious::Command. - Renamed format, reqs, symbol_start and symbols attributes in Mojolicious::Routes::Pattern to format_regex, constraints, placeholder_start and placeholders. - Merged get_all_data and get_data methods from Mojo::Command into data method in Mojo::Loader. - Moved class_to_file and class_to_path methods from Mojo::Command to Mojo::Util. - Updated IO::Socket::SSL requirement to 1.75 for IO::Socket::IP support. - Switched back from IO::Socket::INET6 to IO::Socket::IP for IPv6 support. - Switched from HMAC-MD5 to HMAC-SHA1 for signed cookies. - Added slurp function to Mojo::Util. - Added slurp method to Mojo::ByteStream. - Added j and r functions to ojo. (sharifulin, sri) - Added accept_interval attribute to Mojo::IOLoop. - Added support for new HTTP status code. - Modernized ".perltidyrc". - Improved Mojo::IOLoop::Server to prioritize RC4 cipher, which mitigates the BEAST attack. (Danny Thomas) - Improved not found page to highlight custom route names. - Improved to method in Mojolicious::Routes::Route to give easier access to default parameters. - Improved message parser performance slightly. - Fixed bug that prevented sessions from working in embedded applications. - Fixed JSON Pointer escaping. - Fixed small JSON Pointer bug in get command. (avkhozov) - Fixed small application initialization bug in Mojo::Server. 2.98 2012-05-30 - Switched from IO::Socket::IP to IO::Socket::INET6 for IPv6 support. - Improved IPv6 exception handling in Mojo::IOLoop::Client. - Fixed array appending bug in Mojo::Parameters. 2.97 2012-05-28 - Added workaround to make IO::Socket::SSL work with IO::Socket::IP. - Removed Bonjour support. - Fixed bug that prevented Test::Mojo from working with normal Mojolicious applications that use Mojolicious::Plugin::Config. - Fixed a few small Unicode bugs in documentation. 2.96 2012-05-21 - Added merge method to Mojo::Path. - Fixed small memory leak in Mojolicious. - Fixed small bug that prevented already prepared IO::Socket::SSL handles to be used by Mojo::UserAgent. - Fixed small Mojo::URL and Mojo::Path stringification bugs. 2.95 2012-05-10 - Fixed bug that caused inactivity timeouts to be logged too often. 2.94 2012-05-09 - Added support for 308 redirects to Mojo::UserAgent. - Added support for new HTTP status codes. - Improved exception handling of all scripts. - Improved built-in web servers to log inactivity timeouts as debug messages instead of errors. - Fixed html_escape to always use entities with semicolon. (OlegG, crab) - Fixed typo in 414 status message. - Fixed small cookie formatting bug. - Fixed small bug in cookie parser. - Fixed small backlog bug in Mojo::Server::Daemon. 2.93 2012-05-05 - Added remove method to Mojolicious::Routes::Route. - Improved 32bit Perl support of Mojo::Transaction::WebSocket. (mikemagowan, sri) - Improved exception handling of application and config file loaders. - Improved exception handling of Mojolicious::Plugin::I18N. - Improved renderer log messages. - Fixed bug that prevented helper names from starting with "end". (Akron) - Fixed bug that prevented helper names from ending with "begin". - Fixed empty frame handling in Mojo::Transaction::WebSocket. - Fixed small rendering bug in Mojolicious::Plugin::PODRenderer. - Fixed small code generation bug in Mojolicious::Plugin::I18N. - Fixed small escaping bug in Mojo::URL. 2.92 2012-04-30 - Added commands attribute to Mojolicious. - Fixed attribute namespace selector bugs in Mojo::DOM::CSS. 2.91 2012-04-26 - Added cookies method to Mojo::Message. - Updated HTML5 entities in Mojo::Util. 2.90 2012-04-25 - Fixed small JavaScript bug in Mojolicious::Plugin::PODRenderer. 2.89 2012-04-24 - Made logo on built-in templates smaller. - Improved CSS of built-in templates. 2.88 2012-04-24 - Improved documentation. 2.87 2012-04-23 - Improved html_escape performance and added pattern support. - Fixed small escaping bug. 2.86 2012-04-23 - Added support for TO_JSON method to Mojo::JSON. - Updated HTML5 entities in Mojo::Util. - Increased default heartbeat_timeout from 10 to 20 seconds in Mojo::Server::Hypnotoad. - Improved Mojo::Template exception handling. - Improved ojo exception handling. - Fixed a few HTML5 unescaping bugs. 2.85 2012-04-19 - Modernized ".perltidyrc". - Fixed bug in "user_agent.t". 2.84 2012-04-19 - Fixed flash. 2.83 2012-04-18 - Added hostname verification support to Mojo::IOLoop::Client and Mojo::UserAgent. - Added SNI support to Mojo::IOLoop::Client and Mojo::UserAgent. - Fixed bug that prevented conditions to work in embedded applications. - Fixed bug that changed default values in embedded applications. - Fixed small bug in cpanify command. 2.82 2012-04-16 - Deprecated relaxed placeholders "/(.foo)" in favor of "/#foo". - Deprecated Mojolicious::Routes::Route::waypoint. - Deprecated Mojolicious::Routes::Route::block. - Improved Mojolicious::Routes::Pattern to render formats. - Improved regex formatting in routes command. 2.81 2012-04-15 - Improved router to allow disabled format detection to be inheritable by nested routes. - Improved error handling in Mojolicious::Plugin::JSONConfig. - Improved match method in Mojolicious::Routes::Pattern to support format detection. - Improved router log messages. - Improved all debug messages. - Fixed format detection bugs in Mojolicious::Routes::Pattern. - Fixed format handling in routes command. 2.80 2012-04-10 - Added support for alternative MIME types to Mojolicious::Types. - Added endpoint method to Mojo::UserAgent::Transactor. - Fixed HTTPS proxy keep-alive bug in Mojo::UserAgent. 2.79 2012-04-10 - Improved makefile and plugin generators to always use the latest Mojolicious version. - Fixed HTTPS proxy support in Mojo::UserAgent. - Fixed multiple Mojo::UserAgent::Transactor bugs. 2.78 2012-04-09 - Improved Mojolicious::Routes to allow redispatching controllers. - Improved Mojolicious::Routes logging. 2.77 2012-04-09 - Improved Mojo::Transaction::WebSocket to allow custom message parsers. - Improved help command to be less strict. - Fixed bug that prevented --help and -h flags from working for generator commands. - Fixed small bug that prevented non-string secrets in Mojolicious. 2.76 2012-04-05 - Improved documentation. 2.75 2012-04-05 - Fixed small bug in params method of Mojo::Parameters. 2.74 2012-04-04 - Fixed multiple small bugs in form method of Mojo::UserAgent::Transactor. 2.73 2012-04-03 - Fixed multiple progress event bugs in Mojo::Message. 2.72 2012-04-03 - Added kept_alive method to Mojo::Transaction::WebSocket. 2.71 2012-04-03 - Improved Hypnotoad error handling. - Improved version command to detect proxy servers automatically. - Fixed small argument bug in to_hash method of Mojo::Headers. 2.70 2012-03-30 - Improved speed of version command by switching to the MetaCPAN API. - Improved all bundled TLS test certificates to expire at the same time. - Fixed handler detection precedence bug in Mojolicious::Renderer. - Fixed ability to disable inactivity timeout in Hypnotoad. - Fixed ability to disable accepts limit in Hypnotoad. - Fixed small bug in get_all_data method of Mojo::Command. - Fixed small bug in inflate command. (memowe) 2.69 2012-03-26 - Removed X-Forwarded-Host support since it is redundant for well configured reverse proxies. - Changed number of redirects ojo and the get command will follow to 10. - Improved ojo to detect proxy servers automatically. - Improved Mojo::DOM::CSS performance. - Improved Mojo::Reactor tests to be less strict. - Fixed a bug where paths and classes in Mojolicious::Static and Mojolicious::Renderer would have the wrong precedence. - Fixed small bug where Hypnotoad would ignore the MOJO_REVERSE_PROXY environment variable. 2.68 2012-03-24 - Fixed generate command. 2.67 2012-03-24 - Added start_app method to Mojo::Command. - Fixed small bugs in Mojo::Command and Mojolicious::Commands. 2.66 2012-03-23 - Reformatted "Changes". - Improved Mojo::Reactor::Poll performance. - Fixed one_tick semantics to be equal in Mojo::Reactor::Poll and Mojo::Reactor::EV. 2.65 2012-03-22 - Deprecated Mojo::IOLoop::drop in favor of Mojo::IOLoop::remove. - Renamed Mojo::Reactor::drop to Mojo::Reactor::remove. - Added Mojo::Reactor::Poll. - Added one_tick method to Mojo::Reactor and Mojo::Reactor::EV. - Removed experimental status from Mojo::IOLoop::Client. - Removed experimental status from Mojo::IOLoop::Server. - Removed experimental status from Mojo::IOLoop::Stream. - Removed experimental status from Mojo::Reactor. - Removed experimental status from Mojo::Reactor::EV. - Removed experimental status from client_class, max_accepts, reactor, server_class and stream_class attributes in Mojo::IOLoop. - Removed experimental status from client server and stream methods in Mojo::IOLoop. - Updated jQuery to version 1.7.2. 2.64 2012-03-21 - Deprecated Mojolicious::Routes::controller_base_class in favor of Mojolicious::Routes::base_classes. - Removed handle argument from io watchers in Mojo::Reactor. 2.63 2012-03-20 - Renamed Mojo::IOWatcher to Mojo::Reactor. - Added Mojolicious::Routes::Route. - Added find and root methods to Mojolicious::Routes::Route. - Improved form_for helper to automatically add method="POST" attributes when necessary. - Improved memory usage of Mojolicious::Routes. - Improved Mojolicious::Renderer performance. - Fixed bug that slowed down Mojolicious::Renderer. - Fixed small newline capture bug in Mojolicious::Routes::Match. 2.62 2012-03-17 - Deprecated Mojolicious::Renderer::default_template_class in favor of Mojolicious::Renderer::classes. - Deprecated Mojolicious::Static::default_static_class in favor of Mojolicious::Static::classes. - Added options function to Mojolicious::Lite. - Added options method to Mojolicious::Routes. - Added options method to Mojo::UserAgent. - Added options_ok method to Test::Mojo. - Added o function to ojo. - Removed experimental status from Mojo::Cache. - Removed experimental status from Mojo::DOM::CSS. - Removed experimental status from Mojo::DOM::HTML. - Removed experimental status from Mojo::Server::Morbo. - Removed experimental status from Mojo::Transaction::WebSocket. - Removed experimental status from Mojo::UserAgent::Transactor. - Removed experimental status from Mojolicious::Command::cpanify. - Removed experimental status from upgrade event in Mojo::Transaction::HTTP. - Removed experimental status from t helper in Mojolicious::Plugin::TagHelpers. - Removed experimental status from current_route and url_with helpers in Mojolicious::Plugin::DefaultHelpers. - Removed experimental status from websocket function in Mojolicious::Lite. - Removed experimental status from cache attribute in Mojolicious::Renderer. - Removed experimental status from format attribute in Mojolicious::Routes::Pattern. - Removed experimental status from ca and local_address, request_timeout and transactor attributes in Mojo::UserAgent. - Removed experimental status from cache attribute in Mojolicious::Routes. - Removed experimental status from send method in Mojolicious::Controller. - Removed experimental status from finish_ok, message_is, message_isnt, message_like, message_unlike, send_ok and websocket_ok methods in Test::Mojo. - Removed experimental status from detect method in Mojolicious::Types. - Removed experimental status from app_url, build_websocket_tx and websocket methods in Mojo::UserAgent. - Removed experimental status from emit_safe method in Mojo::EventEmitter. - Removed experimental status from to_psgi_app method in Mojo::Server::PSGI. - Removed experimental status from clone method in Mojo::Message::Request. - Removed experimental status from has_conditions, has_custom_name, has_websocket, is_websocket and websocket methods in Mojolicious::Routes. - Removed experimental status from clone, is_limit_exceeded and max_line_size methods in Mojo::Headers. - Removed experimental status from text_after, text_before and xml methods, as well as trim arguments in Mojo::DOM. - Removed experimental status from boundary, charset, clone, is_dynamic, progress and max_leftover_size methods in Mojo::Content. - Removed experimental status from clone method in Mojo::Content::MultiPart. - Removed experimental status from clone method in Mojo::Content::Single. - Removed experimental status from is_dynamic, is_limit_exceeded and max_line_size methods in Mojo::Message. - Improved Mojo::IOWatcher exception handling a little. - Improved Mojolicious::Routes logging. - Fixed port generation bug. (xaka) - Fixed IPv6 listen value bug in Mojo::Server::Daemon. 2.61 2012-03-14 - Merged Mojolicious exception handling into the around_dispatch hook, this will allow a whole new category of exception handling plugins. 2.60 2012-03-13 - Added EXPERIMENTAL current_route helper to Mojolicious::Plugin::DefaultHelpers. - Made text_area helper a little smarter. (sshaw, sri) - Improved inactivity timeout logging for WebSockets. - Fixed escaping bug in select_field and text_area helpers. - Fixed Windows bug in "asset.t". 2.59 2012-03-09 - Removed duplicate 2.58 directory. 2.58 2012-03-09 - Added support for MOJO_LISTEN environment variable. - Removed listen attribute from Mojo::Server::Morbo. - Improved event loop compatibility of Mojo::Server::PSGI. - Fixed Mojo::URL object handling bug in url_for. - Fixed bug in Hypnotoad that prevented disabling of reverse proxy support between zero downtime software upgrades. - Fixed small caching bug in Morbo file watcher. - Fixed Windows bug in "asset.t". 2.57 2012-03-03 - Replaced protection from excessively large form values in Mojo::Message with documentation. 2.56 2012-03-01 - Deprecated custom HTTPS listen values in favor of URLs for all built-in web servers. https://*:3000:/x/server.crt:/y/server.key:/z/ca.crt becomes https://*:3000?cert=/x/server.crt&key=/y/server.key&ca=/z/ca.crt - Removed experimental status from patch function in Mojolicious::Lite. - Removed experimental status from patch method in Mojolicious::Routes. - Removed experimental status from patch method in Mojo::UserAgent. - Removed experimental status from patch_ok method in Test::Mojo. - Removed experimental status from t function in ojo. - Fixed small inconsistency between Mojo::IOWatcher and Mojo::IOWatcher::EV where Mojo::IOWatcher wouldn't stop automatically when not watching for events anymore. - Fixed Mojo::IOLoop to clean up after itself. 2.55 2012-02-28 - Combined WebSocket timeout with normal inactivity timeout. 2.54 2012-02-27 - Deprecated class and method stash values in favor of controller and action. - Added EXPERIMENTAL patch function to Mojolicious::Lite. - Added EXPERIMENTAL patch method to Mojolicious::Routes. - Added EXPERIMENTAL patch method to Mojo::UserAgent. - Added EXPERIMENTAL patch_ok method to Test::Mojo. - Added EXPERIMENTAL t function to ojo. - Added support for MOJO_CONNECT_TIMEOUT, MOJO_INACTIVITY_TIMEOUT, MOJO_REQUEST_TIMEOUT and MOJO_WEBSOCKET_TIMEOUT environment variables. - Split up Mojolicious::Guides::Cheatsheet into more reference documentation. - Increased default connect timeout from 3 to 10 seconds in Mojo::UserAgent and Mojo::IOLoop::Client. - Improved resilience of Mojo::IOLoop::Stream. - Improved test command to colorize by default. - Fixed small rendering bug in Mojolicious::Plugin::PODRenderer. 2.53 2012-02-25 - Improved Hypnotoad with many info level log messages. - Improved resilience of Mojo::IOLoop::Stream. - Fixed Hypnotoad upgrade timeout bug. 2.52 2012-02-24 - Removed experimental status from config method in Mojo. - Renamed send_message method in Mojolicious::Controller to send. - Renamed send_message_ok method in Test::mojo to send_ok. - Renamed to_psgi method in Mojo::Server::PSGI to to_psgi_app. - Combined send_message and send_frame methods in Mojo::Transaction::WebSocket to send. - Improved emit_chain method in Mojolicious::Plugins to allow reforwarding. (jamadam) - Fixed bug that prevented Mojo::IOLoop from dying when started twice. - Fixed a cookie jar path parsing bug. (marcus) - Fixed multiple value bug in param method of Mojolicious::Controller. 2.51 2012-02-19 - Added EXPERIMENTAL to_psgi method to Mojo::Server::PSGI. - Removed experimental status from around_dispatch hook. - Removed experimental status from emit_chain method in Mojolicious::Plugins. - Removed experimental status from drain event in Mojo::Content. - Improved portability of scripts. - Fixed bug that can prevent foreign event loops from being able to control Mojo::IOLoop. 2.50 2012-02-18 - Added EXPERIMENTAL is_running method to Mojo::IOWatcher and Mojo::IOWatcher::EV. - Added file upload support to param method in Mojolicious::Controller. - Removed gitignore command. - Improved Mojo::IOLoop to be controllable from foreign event loops. - Improved protection from excessively large form values in Mojo::Message. - Improved resilience of Mojo::IOLoop::Client. - Fixed Mojo::Template expressions and escaped expressions to consistently enforce scalar context. - Fixed small bugs in makefile command. (tempire, marcus, sri) 2.49 2012-02-13 - Deprecated Mojolicious::Renderer::root in favor of Mojolicious::Renderer::paths. (memowe, sri) - Deprecated Mojolicious::Static::root in favor of Mojolicious::Static::paths. (memowe, sri) - Added support for multiple "templates" and "public" directories to Mojolicious. (memowe, sri) - Improved version command to be more responsive. (crab) - Improved resilience of Mojo::IOLoop::Client. - Fixed parent combinator bug in Mojo::DOM::CSS. (sharifulin, sri) 2.48 2012-02-09 - Fixed Hypnotoad HTTPS bug. - Fixed small URL escaping bug in Mojo::UserAgent::Transactor. - Fixed small MIME::Base64 and MIME::QuotedPrint related bugs in Mojo::Util. (sestegra, sri) 2.47 2012-02-06 - Deprecated Hypnotoad configuration files in favor of more powerful application configuration files. - Deprecated Mojo::Server::Daemon::prepare_ioloop in favor of Mojo::Server::Daemon::start. - Deprecated Mojo::Headers::x_forwarded_for. - Added EXPERIMENTAL config method to Mojo. - Added EXPERIMENTAL ca attribute to Mojo::UserAgent. - Added EXPERIMENTAL drain event to Mojo::Content. - Added EXPERIMENTAL drain event to Mojo::Transaction::WebSocket. - Added EXPERIMENTAL support for RSV1-3 flags to Mojo::Transaction::WebSocket. - Added EXPERIMENTAL tls_ca option to Mojo::IOLoop::Client::connect. - Added lock_timeout parameter to Hypnotoad. - Removed experimental status from JSON Pointer support. - Removed Cygwin exception from Hypnotoad. - Replaced drop_handle and drop_timer methods in Mojo::IOWatcher with drop method. - Renamed change and watch methods in Mojo::IOWatcher to watch and io. - Renamed resume and pause methods in Mojo::IOLoop::Server to start and stop. - Renamed resume and pause methods in Mojo::IOLoop::Stream to start and stop. - Added pdf MIME type. (bfaist) - Improved CSS of some built-in templates. - Fixed bug that prevented newer dual-life modules to be loaded. - Fixed small bug in Mojo::IOLoop::Stream that caused close events to fail sometimes. - Fixed small relative URL detection bug in get command. 2.46 2012-01-25 - Added EXPERIMENTAL request_timeout attribute to Mojo::UserAgent. - Added EXPERIMENTAL text_after and text_before methods to Mojo::DOM. - Improved all uses of syswrite to be more defensive. (bduggan, sri) - Fixed small parser bug in Mojo::Message::Response. - Fixed small partial rendering bug. - Fixed small HTML5 parser bug in Mojo::DOM::HTML. (dougwilson) 2.45 2012-01-18 - Removed T-Shirt link. - Fixed small caching bug in Mojolicious::Plugin::EPRenderer. - Fixed typo in exception template. 2.44 2012-01-18 - Added new not_found page for development mode. - Added EXPERIMENTAL url_with helper to Mojolicious::Plugin::DefaultHelpers. (diegok, marcus, judofyr, sri) - Added EXPERIMENTAL support for removing query parameters while merging to query method of Mojo::URL. (marcus, judofyr, sri) - Removed experimental status from Mojo::IOLoop::Delay. - Removed defer method from Mojo::IOLoop. - Improved exception page for development mode. - Improved syntax highlighting in documentation browser slightly. - Fixed Mojo::Command::app to be an attribute and not a method. - Fixed Mojo::ByteStream, Mojo::Collection and Mojo::DOM to not be subclasses of Mojo::Base. 2.43 2012-01-08 - Improved most commands with shortcut options. - Improved get command to automatically enable verbose mode for HEAD requests. (simotrone) 2.42 2012-01-02 - Deprecated Test::Mojo::max_redirects. - Removed exprimental status from respond_to method in Mojolicious::Controller. - Removed experimental status from error event in Mojo::UserAgent. - Removed experimental status from connect_timeout attribute in Mojo::UserAgent. - Removed experimental status from connection event in Mojo::Transaction. - Removed experimental status from upgrade event in Mojo::Asset::Memory. - Removed experimental status from auto_upgrade and max_memory_size attributes in Mojo::Asset::Memory. - Removed experimental status from part event in Mojo::Content::MultiPart. - Removed experimental status from upgrade event in Mojo::Content::Single. - Removed experimental status from auto_upgrade attribute in Mojo::Content::Single. - Removed experimental status from body event in Mojo::Content. - Removed experimental status from mojo_lib_dir and slurp_rel_file methods in Mojo::Home. - Removed experimental status from message event in Mojo::Log. - Removed experimental status from contains method in Mojo::Path. - Removed test_server method from Test::Mojo. - Renamed test_server method in Mojo::UserAgent to app_url. - Improved RFC 6265 compliance of generated request headers. - Fixed bug that prevented sessions without expiration. 2.41 2011-12-28 - Deprecated Mojo::Cookie::version. - Deprecated Mojo::Cookie::Response::comment and Mojo::Cookie::Response::port. - Removed experimental status from group feature of Mojolicious::Lite. - Removed experimental status from Mojo::Collection. - Removed experimental status from Mojolicious::Plugin::Mount. - Removed experimental status from dnt and etag methods in Mojo::Headers. - Improved session expiration by allowing it to be disabled. (nwatkiss, sri) - Improved session cookies to always enable the HttpOnly flag. (nwatkiss, sri) - Improved RFC 6265 compliance of cookie implementation. 2.40 2011-12-24 - Added EXPERIMENTAL JSON Pointer support. (crab) - Improved inactivity timeouts by allowing them to be disabled. - Improved class detection of inflate command. - Fixed small bug in Mojo::IOLoop::Server that prevented TLS tests from running parallel. (nwatkiss) - Fixed repository to not favor specific editors. 2.39 2011-12-22 - Deprecated all keep_alive_timeout attributes and parameters in favor of inactivity_timeout. - Added EXPERIMENTAL error event to Mojo::UserAgent. - Added EXPERIMENTAL local_address attribute to Mojo::UserAgent. - Added EXPERIMENTAL local_address option to Mojo::IOLoop::Client::connect. - Added EXPERIMENTAL close method to Mojo::IOLoop::Stream. - Added "hello.pl" and "fast.pl" to example scripts. - Removed log attribute from Mojo::UserAgent. - Removed MOJO_STATIC_CLASS and MOJO_TEMPLATE_CLASS environment variables. - Improved tests for many environment variables. - Fixed Morbo to ignore hidden directories. - Fixed small argument bug in client method of Mojo::IOLoop. - Fixed small memory leak in Mojo::IOLoop::Stream. - Fixed multiple small error reporting bugs in Mojo::UserAgent. - Fixed online tests to not be affected by geographical location. (marcus) 2.38 2011-12-17 - Changed Mojo::IOLoop::client arguments from ($loop, $stream, $err) to ($loop, $err, $stream). - Improved resilience of Mojo::IOLoop::Stream. - Fixed memory leaks caused by named capture groups bug in Perl. (plu, sri) - Fixed small cleanup bug in Mojo::Asset::File. - Fixed small multipart bug in Mojo::Message. (augensalat) - Fixed missing status method in Mojo::Headers. (crab) - Fixed small Mojo::IOLoop::Stream timeout bug. 2.37 2011-12-10 - Welcome to the Mojolicious core team Marcus Ramberg, Glen Hinkle and Abhijit Menon-Sen. - Removed cleanup_interval attribute from Mojo::IOLoop. - Deprecated Mojo::IOLoop::timeout in favor of Mojo::IOLoop::Stream::timeout. - Added EXPERIMENTAL timeout event to Mojo::IOLoop::Stream. - Added EXPERIMENTAL timeout attribute to Mojo::IOLoop::Stream. - Changed default keep-alive timeout of Mojo::UserAgent from 15 to 20 seconds. - Fixed inline template double encoding bug. 2.36 2011-12-05 - Changed default heartbeat timeout of Hypnotoad from 5 to 10 seconds. - Fixed default keep-alive timeout of Hypnotoad. 2.35 2011-12-01 - Added EXPERIMENTAL etag method to Mojo::Headers. - Fixed one-byte payload bug in Mojo::Transaction::WebSocket. (tinx) - Fixed body event in Mojo::Content to work more reliably in CGI environments. - Fixed small portability issue in loader test. 2.34 2011-11-28 - Added "websocket.pl" to example scripts. - Fixed small bugs in example scripts. 2.33 2011-11-28 - Improved Mojo::EventEmitter performance slightly. - Fixed a few small inline template issues. - Fixed small WebSocket handshake bug. 2.32 2011-11-24 - Added EXPERIMENTAL error event to Mojo::IOWatcher. - Updated jQuery to version 1.7.1. - Improved Mojo::IOLoop performance by changing the default cleanup interval from 0 to 0.025 seconds. 2.31 2011-11-21 - Improved stacktraces by making them a lot simpler. 2.30 2011-11-20 - Deprecated Mojo::IOLoop::on_lock in favor of Mojo::IOLoop::lock. - Deprecated Mojo::IOLoop::on_unlock in favor of Mojo::IOLoop::unlock. 2.29 2011-11-19 - Deprecated Mojolicious::on_process in favor of around_dispatch hook. - Added EXPERIMENTAL emit_chain method to Mojolicious::Plugins. (Akron, sri) - Added EXPERIMENTAL around_dispatch hook. - Fixed small bug in boundary and charset methods of Mojo::Content. 2.28 2011-11-18 - Fixed small IPv6 portabilty issue in Mojo::IOLoop::Client. 2.27 2011-11-16 - Deprecated Mojo::IOLoop::connect in favor of Mojo::IOLoop::client. - Deprecated Mojo::IOLoop::listen in favor of Mojo::IOLoop::server. - Deprecated Mojo::IOLoop::connection_timeout in favor of Mojo::IOLoop::timeout. - Deprecated Mojo::IOLoop::write in favor of Mojo::IOLoop::Stream::write. - Deprecated Mojo::IOLoop::connect_timeout in favor of timeout argument. - Deprecated on_* methods in Mojo::IOLoop. - Removed Mojo::IOLoop::Resolver. - Added EXPERIMENTAL connect_timeout attribute to Mojo::UserAgent. - Added EXPERIMENTAL is_readable method to Mojo::IOLoop::Stream. - Added EXPERIMENTAL charset method to Mojo::Content. - Added EXPERIMENTAL write event to Mojo::IOLoop::Stream. - Added EXPERIMENTAL connection event to Mojo::Transaction. - Improved CSS of some built-in templates. - Fixed many small memory leaks. - Fixed multiple drain callback bugs. - Fixed small attribute selector bug in Mojo::DOM::CSS. (tladesignz) 2.26 2011-11-10 - Added EXPERIMENTAL upgrade event to Mojo::Asset::Memory. - Added EXPERIMENTAL upgrade event to Mojo::Transaction::HTTP. - Added EXPERIMENTAL auto_upgrade attribute to Mojo::Asset::Memory. - Improved Mojo::Content::Single and Mojo::Content::MultiPart parsers to reuse events. - Fixed small route caching bug. 2.25 2011-11-08 - Removed canonicalize method from Mojo::URL. - Fixed URL without scheme handling in Mojo::URL. - Fixed a few small bugs in Mojo::URL. 2.24 2011-11-05 - Added EXPERIMENTAL canonicalize method to Mojo::URL. - Fixed small path canonicalization bug in Mojo::URL. - Fixed small trailing slash bug in Mojo::Path. 2.23 2011-11-04 - Changed semantics of get_line function in Mojo::Util. - Removed experimental status from Mojo::Util. - Updated jQuery to version 1.7. - Improved empty path element handling in Mojo::URL. - Fixed empty path element bug in Mojo::Path. 2.22 2011-11-03 - Added EXPERIMENTAL --verbose flag to routes command. - Fixed a few attribute without value selector bugs in Mojo::DOM::CSS. - Fixed template inheritance bug in Mojolicious::Renderer. 2.21 2011-11-02 - Removed profile helper. - Removed CSS4 selector subject support from Mojo::DOM::CSS until we actually know the exact semantics. - Improved Mojo::ByteStream to generate most Mojo::Util based methods automatically. - Fixed route pattern bug. - Fixed bug in "user_agent.t". 2.20 2011-11-01 - Changed semantics of almost all functions in Mojo::Util. 2.19 2011-10-31 - Deprecated Mojolicious::Plugins::add_hook in favor of Mojolicious::Plugins::on. - Deprecated Mojolicious::Plugins::run_hook in favor of Mojolicious::Plugins::emit_hook. - Deprecated Mojolicious::Plugins::run_hook_reverse in favor of Mojolicious::Plugins::emit_hook_reverse. 2.18 2011-10-30 - Fixed small rendering bug. 2.17 2011-10-30 - Fixed bug in "user_agent.t". 2.16 2011-10-30 - Removed experimental status from Mojo::EventEmitter. - Merged unsubscribe and unsubscribe_all methods in Mojo::EventEmitter. 2.15 2011-10-29 - Deprecated Mojolicious::Controller::on_finish in favor of Mojolicious::Controller::on. - Removed Mojolicious::Controller::on_message, you can now use Mojolicious::Controller::on instead. $c->on(message => sub {...}) - Added EXPERIMENTAL message event to Mojo::Log. 2.14 2011-10-29 - Deprecated Mojo::DOM::new with arguments. - Renamed Mojo::IOLoop::Trigger to Mojo::IOLoop::Delay. - Renamed watch method in Mojo::IOWatcher to change. - Renamed io method in Mojo::IOWatcher to watch. - Renamed cancel method in Mojo::IOWatcher to drop_timer. - Renamed remove method in Mojo::IOWatcher to drop_handle. - Added EXPERIMENTAL --verbose flag to test command. 2.13 2011-10-28 - Removed experimental status from many classes, methods, attributes and functions. - Removed before_render hook. - Removed Mojolicious::Plugin::CallbackCondition. 2.12 2011-10-27 - Added EXPERIMENTAL cleanup_interval attribute to Mojo::IOLoop. - Added EXPERIMENTAL max_leftover_size attribute to Mojo::Content. - Replaced handle method in Mojo::IOLoop with stream method. - Replaced writing and not_writing methods in Mojo::IOWatcher with watch method. - Replaced is_finished method in Mojo::IOLoop::Stream with is_writing method. - Replaced add method in Mojo::IOWatcher with io method. - Reduced memory usage of Mojo::Headers significantly. - Fixed finish event timing in Mojo::Server::Daemon. 2.11 2011-10-26 - Improved Mojo::IOLoop::Stream to only emit close events once. 2.10 2011-10-25 - Added EXPERIMENTAL send_frame method to Mojo::Transaction::WebSocket. - Added EXPERIMENTAL frame event to Mojo::Transaction::WebSocket. - Changed syntax for binary messages in Mojo::Transaction::WebSocket. [$bytes] becomes [binary => $bytes] 2.09 2011-10-23 - Fixed small environment cleanup bug in Mojo::IOLoop::Server. 2.08 2011-10-23 - Fixed a few more small test bugs. 2.07 2011-10-23 - Fixed a few small test bugs. 2.06 2011-10-23 - Improved documentation. 2.05 2011-10-22 - Added EXPERIMENTAL max_memory_size attribute to Mojo::Asset::Memory. - Added EXPERIMENTAL is_file method to Mojo::Asset and Mojo::Asset::File. - Improved start_tls method in Mojo::IOLoop by allowing it to accept more options. - Improved MOJO_MAX_MEMORY_SIZE handling by moving it from Mojo::Content::Single to Mojo::Asset::Memory. - Fixed HTTPS proxy bug in Mojo::UserAgent. 2.04 2011-10-21 - Fixed small HTTP response parser bug. - Fixed Windows portability issue in "upload_lite_app.t". 2.03 2011-10-20 - Deprecated all is_done methods in favor of is_finished. - Renamed done event in Mojo::IOLoop::Trigger to finish. - Added EXPERIMENTAL support for new HTTP status codes from draft-nottingham-http-new-status. - Fixed small bug in "upload_lite_app.t". 2.02 2011-10-20 - Merged request and upgrade events in Mojo::Transaction::HTTP. - Improved Mojolicious::Controller attribute default values. 2.01 2011-10-19 - Added EXPERIMENTAL upgrade event to Mojo::Content::Single. - Added EXPERIMENTAL part event to Mojo::Content::MultiPart. - Fixed arguments of upgrade event in Mojo::Transaction::HTTP. - Fixed small WebSocket upgrade bug in Mojo::Server::Daemon. 2.0 2011-10-17 - Code name "Leaf Fluttering In Wind", this is a major release. - Increased Perl version requirement to 5.10.1. - Renamed Mojo::IOLoop::EventEmitter to Mojo::EventEmitter. - Replaced one_tick method in Mojo::IOWatcher with start and stop methods. - Added EXPERIMENTAL contains method to Mojo::Path. - Added EXPERIMENTAL auto_upgrade attribute to Mojo::Content::Single. - Added EXPERIMENTAL boundary method to Mojo::Content. - Added EXPERIMENTAL slice method to Mojo::Collection. - Added EXPERIMENTAL build and parse methods to Mojo::IOLoop::Resolver. - Updated WebSocket implementation to ietf-17. - Improved many modules to use events instead of callbacks. - Improved message parser performance slightly. - Improved Mojo::IOLoop to die if started twice. - Improved setuidgid in Mojo::Server::Daemon. - Improved Mojo::IOWatcher backend detection. - Improved Mojo::IOLoop::Stream to handle unexpected connection close more gracefully. - Fixed many portability issues. - Fixed on_finish callback to work consistently with all servers. - Fixed on_finish callback to work consistently with the user agent. - Fixed big memory and file descriptor leak in the TLS code of Mojo::IOLoop::Server. - Fixed small memory leak in Mojolicious. - Fixed small memory leak in Mojo::DOM. - Fixed small memory leak in Mojo::Message. - Fixed small boundary bug in Mojo::Content::MultiPart. - Fixed small formatting bug in Mojo::Headers. - Fixed small proxy message generation bug. - Fixed small detection bug in Mojolicious::Types. 1.99 2011-09-29 - Deprecated direct hash access to the flash in Mojolicious::Controller. - Added EXPERIMENTAL group function to Mojolicious::Lite. - Added EXPERIMENTAL build_frame and parse_frame methods to Mojo::Transaction::WebSocket. - Added EXPERIMENTAL accepts attribute to Mojo::IOLoop::Server. - Added EXPERIMENTAL profile helper. - Added EXPERIMENTAL binary support to Mojo::Transaction::WebSocket. - Updated WebSocket implementation to ietf-16. - Changed default upgrade timeout of Hypnotoad from 30 to 60 seconds. - Improved accept performance of all built-in web servers by up to 1000% with the EV backend. - Improved connection_timeout method in Mojo::IOLoop by allowing it to be called as a class method. - Improved CSS of some built-in templates. - Improved resilience of HTTP parser. - Fixed CSS of built-in exception template. - Fixed close event bug in Mojo::IOLoop. - Fixed small redirect_to bug. (judofyr, sri) - Fixed small attribute selector bug in Mojo::DOM::CSS. - Fixed small Unicode bug in Mojolicious::Plugin::EPRenderer. - Fixed a few small route bugs. - Fixed Perl 5.8.7 compatibility. 1.98 2011-09-14 - Removed Mojo::Server::FastCGI so it can be maintained as a separate distribution. - Added EXPERIMENTAL mojo_lib_dir and slurp_rel_file methods to Mojo::Home. - Improved host condition to work in more environments. - Improved CSS of all built-in templates. - Improved test command to run tests in alphabetical order. (viliampucik) - Improved non-blocking resolver by allowing it to be disabled. - Improved DATA templates by removing a whitespace requirement. - Fixed small name generation bug in Mojolicious::Plugin::Config. - Fixed small bug in cookie jar. - Fixed small plugin loader bug. - Fixed Hypnotoad to clean up lock files. - Fixed small bug that caused exceptions to be logged twice. 1.97 2011-09-03 - Improved Unicode handling to be more correct and less forgiving. 1.96 2011-09-02 - Updated jQuery to version 1.6.3. - Fixed Mojo::IOLoop to ignore SIGPIPE. 1.95 2011-09-01 - Improved cookie generation slightly. (cosimo, sri) - Fixed Mojo::IOLoop to not ignore SIGPIPE. 1.94 2011-08-27 - Fixed lite_app and plugin generators. 1.93 2011-08-27 - Added EXPERIMENTAL support for escaped tags to Mojo::Template. - Improved Morbo to ignore dotfiles. - Fixed trimming bug in Mojo::Template. - Fixed a few small bugs in Mojo::Template. - Fixed small version detection bug in Mojo::Cookie. 1.92 2011-08-26 - Fixed quoting bug in Mojo::Cookie. 1.91 2011-08-25 - Added EXPERIMENTAL support for cloning Mojo::Message::Request objects. - Improved redirect support in Mojo::UserAgent to be closer to commonly used browsers. 1.90 2011-08-24 - Improved respond_to to automatically render an empty 204 response for unknown formats. - Improved render_exception and render_not_found to use the current format if available. (alnewkirk) 1.89 2011-08-23 - Improved Mojo::Home portability. (omega) 1.88 2011-08-23 - Added EXPERIMENTAL split method to Mojo::ByteStream. - Fixed small bug in Mojo::JSON. 1.87 2011-08-23 - Added EXPERIMENTAL app method to Mojo::Command. - Added EXPERIMENTAL t helper to Mojolicious::Plugin::TagHelpers. - Made tag helper a little smarter. - Made camelize a little smarter. - Fixed small route rendering bug. 1.86 2011-08-21 - Deprecated CamelCase command modules and lowercased all the built-in ones. - Added EXPERIMENTAL support for testing WebSockets with Test::Mojo. - Added GET/POST parameter support to respond_to. - Made class_to_file slightly smarter. 1.85 2011-08-20 - Fixed a url_for bug where captures would be ignored. 1.84 2011-08-19 - Added EXPERIMENTAL first, reverse, shuffle and sort methods to Mojo::Collection. - Fixed small test portablity bug. 1.83 2011-08-19 - Renamed filter method in Mojo::Collection to grep. 1.82 2011-08-19 - Added EXPERIMENTAL filter method to Mojo::Collection. - Removed while and until methods from Mojo::Collection. 1.81 2011-08-19 - Renamed Mojo::DOM::Collection to Mojo::Collection and added a few new methods. - Made Mojolicious::Plugins loader quite a bit smarter. - Improved Test::Mojo diagnostics. 1.80 2011-08-17 - Deprecated Mojolicious::Plugin::EpRenderer in favor of Mojolicious::Plugin::EPRenderer. - Deprecated Mojolicious::Plugin::EplRenderer in favor of Mojolicious::Plugin::EPLRenderer. - Deprecated Mojolicious::Plugin::I18n in favor of Mojolicious::Plugin::I18N. - Deprecated Mojolicious::Plugin::JsonConfig in favor of Mojolicious::Plugin::JSONConfig. - Deprecated Mojolicious::Plugin::PodRenderer in favor of Mojolicious::Plugin::PODRenderer. 1.79 2011-08-17 - Added support for uppercase relative plugin names. (lammel) 1.78 2011-08-16 - Added EXPERIMENTAL modules Mojolicious::Command::Cpanify and Mojolicious::Command::Generate::Plugin. (sri, yko, tempire) - Fixed "websocket_lite_app.t" to require Perl 5.10+. - Fixed small empty cookie bug. - Fixed small command bug. 1.77 2011-08-14 - Deprecated Mojo::Path::append in favor of using Mojo::Path::parts directly. - Improved handling of preformatted text in Mojo::DOM. - Improved Mojo::DOM to allow smart whitespace trimming to be disabled. (Akron) - Fixed small Unicode bug in get command. 1.76 2011-08-12 - Fixed small Mojo::URL escaping bug. 1.75 2011-08-12 - Added secure_compare function to Mojo::Util as a precaution against timing attacks in the future. (judofyr) - Added EXPERIMENTAL CSS4 selector subject support to Mojo::DOM::CSS. 1.74 2011-08-09 - Added EXPERIMENTAL --verbose flag to Morbo. 1.73 2011-08-09 - Added EXPERIMENTAL -strict flag to Mojo::Base. - Added EXPERIMENTAL respond_to method to Mojolicious::Controller. - Added EXPERIMENTAL detect method to Mojolicious::Types. - Added accept method to Mojo::Headers. - Made Mojo::UserAgent slightly more efficient. - Improved get command to autoflush STDOUT. 1.72 2011-08-05 - Changed default keep-alive timeout in Mojo::Server::Daemon from 5 to 15 seconds. - Fixed small alternative placeholder value bug in routes. - Fixed small bug in Mojo::IOWatcher. - Fixed small bug in Mojo::IOLoop::Client. 1.71 2011-08-05 - Improved Mojo::IOWatcher to use higher resolution timers. 1.70 2011-08-04 - Added EXPERIMENTAL defer method to Mojo::IOLoop. - Added extended callback support to Mojo::IOLoop::Trigger. - Fixed a few small bugs in Mojo::URL. (sshaw) 1.69 2011-08-03 - Added EXPERIMENTAL module Mojo::IOLoop::Trigger. - Modernized Mojo::HelloWorld. - Improved HTML healing capabilities of Mojo::DOM::HTML. - Improved HTML rendering in Mojo::DOM::HTML. - Improved 64bit support in Mojo::Transaction::WebSocket. - Fixed memory leak in Mojo::IOLoop::Client. - Fixed memory leak in Mojolicious. - Fixed small bug in Mojo::IOLoop::Server. 1.68 2011-07-29 - Moved is_ipv4 and is_ipv6 methods from Mojo::URL to Mojo::IOLoop::Resolver. 1.67 2011-07-27 - Fixed version command. - Fixed small Mojo::DOM bug. (Akron) 1.66 2011-07-27 - Added EXPERIMENTAL detect method to Mojo::IOWatcher. - Improved Mojo::IOLoop::Resolver efficiency. 1.65 2011-07-25 - Added EXPERIMENTAL modules Mojo::IOLoop::Client, Mojo::IOLoop::EventEmitter, Mojo::IOLoop::Server and Mojo::IOLoop::Stream, which contain extracted functionality from Mojo::IOLoop. - Added EXPERIMENTAL module Mojo::IOWatcher::EV. (xantus) - Removed modules Mojo::IOWatcher::Epoll and Mojo::IOWatcher::KQueue, since Mojo::IOWatcher::EV is a much better alternative. - Renamed Mojo::Resolver to Mojo::IOLoop::Resolver. - Improved Mojolicious::Routes to automatically disable the routing cache if conditions are used. - Improved route constraint alternatives. - Improved documentation browser CSS. (judofyr) - Fixed small bug in get command. 1.64 2011-07-10 - Added EXPERIMENTAL module Mojo::DOM::HTML. 1.63 2011-07-10 - Added EXPERIMENTAL modules Mojo::DOM::CSS and Mojo::DOM::Collection. - Renamed Mojo::Transactor to Mojo::UserAgent::Transactor. 1.62 2011-07-10 - Merged Mojo::HTML into Mojo::DOM again. 1.61 2011-07-09 - Added module Mojo::HTML, which contains extracted functionality from Mojo::DOM. 1.60 2011-07-08 - Added xsl MIME type. (shiftycow) - Fixed Windows portability issue. 1.59 2011-07-08 - Added peer method to Mojo::Transactor. - Deprecated Test::Mojo->new(app => 'MyApp') in favor of Test::Mojo->new('MyApp'). - Made $t->app always return the application instance in tests. 1.58 2011-07-07 - Fixed fork bug in Mojo::IOLoop. - Fixed small Hypnotoad issues. 1.57 2011-07-07 - Added --stop option to Hypnotoad. - Made hot deployment with Hypnotoad even easier. 1.56 2011-07-04 - Fixed small memory leaks in Hypnotoad and Mojo::IOLoop. 1.55 2011-07-04 - Fixed some portability issues in tests. 1.54 2011-07-03 - Fixed small Windows issue. 1.53 2011-07-02 - Added EXPERIMENTAL format method to Mojo::Log and simplified the default log file format. - Improved include helper argument localization. (miyagawa) 1.52 2011-07-01 - Fixed small static file in DATA section bug. 1.51 2011-07-01 - Renamed build_url method in Test::Mojo to test_server. - Improved test_server method in Mojo::UserAgent. - Fixed small timing issue in "morbo.t". 1.50 2011-07-01 - Removed idle event from Mojo::IOLoop. - Updated jQuery to version 1.6.2. - Fixed small routes bug that prevented some false values from disabling format detection. 1.49 2011-06-30 - Added EXPERIMENTAL modules Mojo::IOWatcher and Mojo::Resolver, which contain extracted functionality from Mojo::IOLoop. - Added EXPERIMENTAL module Mojo::Transactor, which contains extracted functionality from Mojo::UserAgent. - Added EXPERIMENTAL support for simple alternative placeholder values to routes. - Improved Morbo restarter to also check for changed file size in addition to mtime. - Fixed many small routes bugs. - Fixed small reparse bug in Mojo::Parameters. (dmw397) - Fixed url_for to incorporate trailing slash for current route. - Fixed a few small error reporting bugs around Mojo::UserAgent. - Fixed portability issue in "command.t". 1.48 2011-06-24 - Added debug log message for missing action to router. - Improved Mojo::Command tests. - Fixed support for multiple checkboxes with same name in Mojolicious::Plugin::TagHelper. (sri, kimoto) - Fixed portability issue in "lite_app.t". (marcus) 1.47 2011-06-22 - Added EXPERIMENTAL callback condition plugin. - Added EXPERIMENTAL host condition to Mojolicious::Plugin::HeaderCondition. - Added host support to Mojolicious::Plugin::Mount. (sri, alnewkirk) - Removed Mojolicious::Plugin::AgentCondition and added its functionality to Mojolicious::Plugin::HeaderCondition. - Improved overall performance slightly. - Fixed render_static return value. - Fixed dispatcher return values. 1.46 2011-06-21 - Improved Morbo to only attempt restarting applications after a file change has been detected. - Improved overall performance by about 3% with many small optimizations. - Improved query string support in Mojo::Parameters. - Fixed Windows restart issues in Morbo. (lammel) - Fixed missing plugin error message. 1.45 2011-06-20 - Fixed an exception with layout rendering bug. - Fixed small Mojo::Parameters bug. 1.44 2011-06-18 - Added EXPERIMENTAL self-restarting Morbo development web server and removed old "--reload" support since there have been too many negative side effects. This also improves overall performance by about 5-10% and reduces memory usage by about 10%. - Added EXPERIMENTAL application mount plugin. - Added EXPERIMENTAL --help support for all commands. - Updated prettify.js to version 1-Jun-2011. - Updated WebSocket diagnostics test in Mojo::HelloWorld for latest Firefox Aurora. - Improved inline template and static file performance. - Improved whitespace trimming in Mojo::DOM. (sri, DaTa) - Fixed Morbo file discovery bug. (crab) - Fixed a few application embedding bugs. - Fixed link generation bug in Mojolicious::Plugin::PodRenderer. - Fixed small embedding bug in Mojolicious::Plugin::RequestTimer. 1.43 2011-06-13 - Improved after_dispatch hook by allowing it to change session data. - Fixed a bug in Mojo::Template that caused template blocks to be auto escaped. 1.42 2011-06-09 - Added EXPERIMENTAL support for unquoted wildcard placeholders in Mojolicious::Routes::Pattern. - Added EXPERIMENTAL status code support to rendred method in Mojolicious::Controller. - Updated WebSocket implementation to ietf-08. - Fixed a bug that prevented Mojo::Base subclasses from using the "-base" flag. - Fixed a few small default status code bugs. - Fixed route suggestion bug in "not_found.development.html.ep". 1.41 2011-06-03 - Fixed param list bug in Mojolicious::Controller. - Fixed overload bug in Mojo::DOM. (yko) 1.4 2011-06-02 - Code name "Smiling Face With Sunglasses", this is a major release. - Deprecated Mojo::DOM add_after method in favor of the append method. - Deprecated Mojo::DOM add_before method in favor of the prepend method. - Deprecated all methods containing the word "inner" in favor of ones containing the word "content". - Added EXPERIMENTAL direct hash access for attributes and child element accessor support to Mojo::DOM. - Added EXPERIMENTAL support for collections to children method and element accessors in Mojo::DOM. - Added EXPERIMENTAL to_xml method to Mojo::DOM collections. - Added EXPERIMENTAL eval command. - Added EXPERIMENTAL load_app method to Mojo::Server. - Added append_content and prepend_content methods to Mojo::DOM. - Added HTTP method support to routes command. (trone) - Improved long poll support. - Improved compatibility with Feersum PSGI web servers. (audreyt) - Switched from Storable to JSON serialization for Mojolicious sessions to increase efficiency. - Reduced memory usage of Hypnotoad workers by at least 1MB (each). - Fixed a small Mojo::Loader bug. - Fixed small Windows line ending problem in Mojo::Command. (Akron) - Fixed a UTF-8 bug in Mojo::Exception. (jamadam) - Fixed "Can't locate object method x via package y" error messages. - Fixed woff MIME type. 1.34 2011-05-22 - Fixed nested selector bug in Mojo::DOM. - Fixed small Mojo::DOM HTML5 bug. 1.33 2011-05-20 - Added EXPERIMENTAL helper function to Mojolicious::Lite. - Updated jQuery to version 1.6.1. - Improved Mojo::JSON string escaping to make JSONP easier. - Improved reloader slightly. - Moved all bundled templates to "lib/Mojolicious/templates". - Fixed reserved GET/POST param handling in Mojolicious::Controller. - Fixed small XML semantics bug in Mojo::DOM. - Fixed all blocking server bindings to default to a 404 status code. 1.32 2011-05-11 - Added EXPERIMENTAL name support for template exceptions. - Updated IO::Socket::SSL requirement to 1.43 due to bugs in older versions. Note that the version requirement will keep getting updated until we encounter a version that is not broken most of the time. - Improved reloading slightly by allowing it to clean up the main namespace. - Fixed enabling of Perl 5.10 features in Mojo::Base and Mojolicious::Lite. (garu, sri) - Fixed render_later to prevent delayed rendering warning. 1.31 2011-05-08 - Reverted deprecation of Perl 5.8.x support, by popular demand. - Added FAQ entry to clarify the Perl 5.8.x situation. - Fixed case sensitivity of Mojo::DOM in XML mode. - Fixed pseudo class case handling in Mojo::DOM. (Akron) 1.3 2011-05-05 - Code name "Tropical Drink", this is a major release. - Deprecated Perl 5.8.x support. - Deprecated Mojolicious::Renderer get_inline_template method in favor of the get_data_template method. - Added EXPERIMENTAL before_render hook. - Added EXPERIMENTAL hook function to Mojolicious::Lite. - Added workaround for uWSGI bug. (miyagawa) - Improved Mojo::Template and Mojolicious::Routes exception handling. - Improved debug log messages for template rendering. - Updated Mojo::Base and Mojolicious::Lite to enable Perl 5.10 features if available. - Updated jQuery to version 1.6. - Fixed PSGI read error handling. - Fixed 64bit WebSocket message bug. - Fixed small Windows bug. 1.22 2011-05-02 - Added opposite tests to Test::Mojo. - Deprecated Mojo::IOLoop on_tick method in favor of the recurring method. (sbertrang) - Deprecated Mojo::IOLoop on_hup method in favor of the on_close method. - Deprecated on_build_tx methods in favor of on_transaction methods. - Deprecated on_handler methods in favor of on_request methods. - Updated WebSocket implementation to ietf-07. - Renamed on_idle method in Mojo::IOLoop to idle. - Reduced memory requirements of cached templates by up to 50%. - Fixed controller specific render_exception and render_not_found methods. - Fixed Mojo::JSON string size limit. (henryykt) - Fixed Windows bug in Mojo::Asset::File. (kimoto) - Fixed small memory leak. - Fixed small stack localization bug. - Fixed small tag helper escaping bug. (cheese) 1.21 2011-04-20 - Improved temporary file handling to avoid a very unlikely race condition. (crab) - Fixed "multipart/form-data" generation bug in Mojo::UserAgent. (sugar, sharifulin, sri) 1.20 2011-04-20 - Improved size limit handling. 1.19 2011-04-20 - Fixed size limits in message parser. 1.18 2011-04-19 - Added support for "X-Forwarded-HTTPS" and "X-Forwarded-Host" headers. - Added argument localization to the include helper. (crab, moritz, sri) - Fixed test case. 1.17 2011-04-18 - Deprecated Mojolicious process method in favor of the on_process attribute. - Added Failraptor. - Added support for MOJO_CERT_FILE and MOJO_KEY_FILE environment variables. - Added EXPERIMENTAL xml attribute to Mojo::DOM. - Added EXPERIMENTAL build_url method to Test::Mojo. - Added EXPERIMENTAL dnt (Do Not Track) method to Mojo::Headers. - Added WOFF MIME type. (reezer) - Updated WebSocket implementation to ietf-06. (sri, crab) - Updated jQuery to version 1.5.2. - Improved HTML healing capabilities of Mojo::DOM. - Improved Mojo::DOM to ignore useless end tags. - Improved Mojo::DOM inline DTD support. (Akron) - Improved Mojo::DOM text extraction. - Improved Mojolicious::Plugin::I18n default lexicon handling. (yko) - Improved a Mojo::IOLoop workaround. - Moved all bundled static files to "lib/Mojolicious/public". - Made Test::Mojo a little more user-friendly. - Fixed small CGI/FastCGI header generation bug. - Fixed readonly handle support in Mojo::IOLoop. - Fixed a Mojo::IOLoop resolver bug. (Charlie Brady) - Fixed small Mojo::Asset::File bug. (crab) - Fixed small Mojo::DOM selector bug. (tempire) - Fixed small Mojo::DOM namespace detection bug. (Akron) - Fixed small route pattern escaping bug. - Fixed small reload bug. - Fixed small documentation browser bug. (kberov) - Fixed cookbook recipe. (moritz) 1.16 2011-04-15 - Emergency release for a critical security issue that can expose files on your system, everybody should update! (perlninja, sri) 1.15 2011-03-18 - Changed default log level in "production" mode from "error" to "info". - Improved lookup method in Mojo::IOLoop. - Fixed small Mojo::Util bug. - Fixed a serious Mojo::DOM bug. (moritz) 1.14 2011-03-17 - Added support for multiple DNS servers to Mojo::IOLoop. - Added config helper to Mojolicious::Plugin::Config. - Changed resolv.conf parser in Mojo::IOLoop to use the first nameserver. - Changed lookup method in Mojo::IOLoop to pick records randomly. - Fixed small optional tag bugs in Mojo::DOM. - Fixed JavaScript/CSS bug in Mojo::DOM. - Fixed Windows home directory detection bug. (Akron) - Fixed a few warnings. 1.13 2011-03-14 - Deprecated Mojo::Client in favor of the much sleeker Mojo::UserAgent. - Made the most common Mojo::IOLoop methods easier to access for the singleton instance. 1.12 2011-03-10 - Relicensed all artwork to CC-SA, so the whole distribution can be considered "open" again. - Deprecated MOJO_JSON_CONFIG environment variable in favor of MOJO_CONFIG. (crab) - Added EXPERIMENTAL support for IPv6. - Added more Perl-ish configuration plugin. - Added drain callback support for WebSockets. - Added line numbers to Mojo::JSON error messages. (marcus) - Removed experimental status from Hypnotoad and Mojolicious::Plugin::TagHelpers. - Removed experimental status from many attributes and methods all over Mojolicious. - Improved attribute support of the select_field tag helper. (yko) - Improved text_field tag helper. - Improved tag helper attribute escaping. - Improved attrs method in Mojo::DOM. - Updated jQuery to version 1.5.1. - Fixed XSS issue in link_to helper. - Fixed route unescaping bug. - Fixed small Mojo::DOM bug. (yko) - Fixed small documentation bug. 1.11 2011-02-18 - Deprecated Mojo::Client async method in favor of the managed attribute. - Added TTL support to resolve in Mojo::IOLoop. (und3f) - Relaxed charset handling in and around Mojo::DOM a bit. - Fixed Mojo::Client async mode. - Fixed session cookie encoding bug. - Fixed small route bug. - Fixed small Hypnotoad bug. (bduggan) 1.1 2011-02-14 - Code name "Smiling Cat Face With Heart-Shaped Eyes", this is a major release. - Deprecated wildcard route names in favor of automatically generated default names for all routes. - Removed native IIS support since it has become unmaintainable. - Added EXPERIMENTAL much prettier attribute generator to Mojo::Base. - Added EXPERIMENTAL on_start attribute to Mojo::Client. - Added EXPERIMENTAL support for route shortcuts. - Added EXPERIMENTAL support for NO_PROXY. (l0b0) - Added EXPERIMENTAL user_agent attribute to Mojo::Client. - Added EXPERIMENTAL support for mode specific not_found and exception templates. - Added EXPERIMENTAL support for route caching. - Added EXPERIMENTAL support for CSS3 selectors to the get command. - Added image helper to Mojolicious::Plugin::TagHelpers. - Added support for secure session cookies. (crab) - Improved HTML5 compatibility of Mojo::DOM. - Replaced Mojo::JSON parser with a much faster and stricter implementation. (chansen) - Improved Mojo::JSON string encoding. (chansen) - Updated to jQuery to version 1.5. - Removed experimental status from Mojo::DOM and ojo. - Removed experimental status from many attributes and methods all over Mojolicious. - Renamed after and before in Mojo::DOM to add_after and add_before. - Improved documentation browser slightly. - Improved CSS3 support in Mojo::DOM. - Changed Mojolicious::Plugin::EplRenderer to not render 404 errors for missing templates. - Changed exception template to use pre instead of h1 tags for error messages. (vaneska) - Made Simpsons and Futurama quotes easier to distinguish from normal comments. - Made routes reusable outside of Mojolicious. (forwardever) - Fixed a few home detection bugs. - Fixed a complicated application embedding bug. - Fixed a Apache mod_rewrite compatibility bug in Mojo::Message::Request. (dekimsey) - Fixed a small bug in the relaxed HTTP parser. - Fixed a small bug in Mojolicious::Command::Get. - Fixed a small bug in Mojolicious::Plugin::JsonConfig. - Fixed support for broken redirects. - Fixed --reload delay problem. - Fixed shagadelic function of Mojolicious::Lite. - Fixed optgroup support in select_field helper. - Fixed tests that can't run on Windows. - Fixed delayed rendering bug. (yko) - Fixed nested route bug. - Fixed a small multipart parser bug. - Fixed small any route bug. - Fixed small empty route bug. - Fixed URL merging in Mojo::URL. - Fixed version detection in Mojolicious::Command::Version. - Fixed Mojo::Client cloning. 1.01 2011-01-06 - Relicensed some of the images to make sure Mojolicious can be shipped with commercial products. - Updated IO::Socket::SSL requirement to 1.37 due to bugs in older versions. - Added EXPERIMENTAL TLS certificate authentication support. (tempire) - Added EXPERIMENTAL title helper. - Added EXPERIMENTAL render_later method to Mojolicious::Controller. - Improved test. (Charlie Brady) - Improved charset handling in Mojolicious slightly. - Updated application generators with base tags. - Fixed relative path handling in Mojo::URL. - Fixed punycode bug. (kits) - Fixed a bug where the static dispatcher would eat the flash. 1.0 2010-12-26 - Code name "Snowflake", this is a major release. - Deprecated session method in Mojolicious. - Deprecated handler and helper attributes in Mojolicious::Renderer. - Added new exception and not_found templates. - Added documentation browser to Mojolicious::Plugin::PodRenderer. - Added EXPERIMENTAL content_for helper. - Disabled debug log messages for static files. - Improved Hypnotoad web server to restart workers regularly. - Improved query manipulation in Mojo::URL. (yko) - Improved TLS exception handling. - Improved nested exception handling. (spleenjack) - Fixed relative path handling. - Fixed application generator. (yko) - Fixed support for multiline expressions in Mojo::Template. - Fixed multiple --reload related leaks and reduced overall memory usage. - Fixed exception handling for included templates. - Fixed a small Mojo::Server::PSGI header bug. - Fixed a small Mojo::DOM selector bug. 0.999950 2010-11-30 - Added EXPERIMENTAL Hypnotoad web server. - Added EXPERIMENTAL built-in exception and not_found templates. - Added put and del functions to Mojolicious::Lite. - Added on_idle and on_tick event handlers to Mojo::IOLoop. - Added "*" query support to the Mojo::IOLoop resolver. - Added ability to pass plain connection ids to Mojo::Client. - Added ability to call Mojo::Base::attr as an instance method. (charsbar) - Improved Mojolicious::Lite ability to recover from syntax errors. - Improved number detection in Mojo::JSON. - Improved Mojo::ByteStream encode/decode. (marcus) - Fixed a bug where an empty Mojo::IOLoop would never block. - Fixed a possible Mojo::IOLoop descriptor leak. - Fixed a small route condition bug. - Fixed a small test glitch on some Linux distributions. 0.999941 2010-11-19 - Allow Mojolicious::Lite style routes in Mojolicious. - Added base_tag helper to Mojolicious::Plugin::TagHelpers. - Added CNAME and NS record type support to the Mojo::IOLoop resolver. - Improved Mojo::IOLoop responsiveness. - Made Mojo::IOLoop resolver results more useful. 0.999940 2010-11-15 - Fixed IO::Socket::SSL 1.34 compatibility. 0.999939 2010-11-15 - Removed IPv6 support until Perl itself gets better support for it. - Added MX and PTR record type support to the Mojo::IOLoop resolver. (und3f) - Fixed a Mojolicious::Static rendering bug. - Fixed a bug that forced connect in Mojo::IOLoop to block. - Fixed a bug that prevented on_finish to be triggered for interrupted connections. - Fixed a TLS accept bug in Mojo::IOLoop. - Fixed a small bug in Mojo::Parameters. (spleenjack) - Fixed javascript and stylesheet helper. (sshaw) - Fixed IPv4 address detection bug in Mojo::URL. - Fixed a Mojo::Client bug where interrupted transactions were still successful. - Fixed a small reloader bug. 0.999938 2010-11-09 - Moved all commands into the Mojolicious namespace. - Fixed typo. - Removed OS X resource fork files. 0.999937 2010-11-09 - Deprecated the MojoX namespace and merged affected modules into the Mojolicious namespace, this will make reference documentation a lot more accessible. - Added important module overview to Mojolicious. (rhaen) - Improved Mojo::Loader to allow Mojolicious recovering from tricky syntax errors in Controllers. - Improved param method in MojoX::Dispatcher::Routes::Controller. - Fixed escaping in Mojo::Parameters to work better in the real world. - Fixed a small inflate command bug. 0.999936 2010-11-03 - Improved Mojo::Template performance slightly. (kimoto) - Fixed a serious WebSocket bug. - Fixed non-blocking DNS resolver bug. - Fixed connection reset handling in Mojo::IOLoop. 0.999935 2010-11-03 - Added EXPERIMENTAL module Mojo::Util as a faster low level alternative to Mojo::ByteStream and rewrote many internals to use it instead. - Improved Mojo::IOLoop performance by about 20%. - Made automatic file storage upgrade smarter. - Fixed overload stringification and improved overall performance by about 25%. - Fixed start line/header buffering and improved performance by 8%. 0.999934 2010-11-01 - Fixed relaxed HTTP parsing. 0.999933 2010-10-30 - Fixed small connect bug in Mojo::IOLoop. - Fixed WebSocket handshake. 0.999932 2010-10-29 - Deprecated the old plugin hook calling convention and added EXPERIMENTAL hook method to Mojolicious. - Fixed a few small connect bugs in Mojo::IOLoop. 0.999931 2010-10-25 - Removed tag helpers label and img. - Renamed tag helper script to javascript and added CDATA support. - Renamed tag helper input to input_tag. - Added EXPERIMENTAL non-blocking DNS support to Mojo::IOLoop. (und3f) - Added EXPERIMENTAL support for IPv4 and IPv6 address checks to Mojo::URL. - Added stylesheet tag helper. - Added before and after methods to Mojo::DOM. - Hide command overview from prove. (omega) - Default to silent tests in Test::Mojo. - Fixed optional value support in Mojo::Cookie. - Fixed shortcut methods in Mojo::Headers to not be context aware. - Fixed url_for to not inherit captures for new endpoints. 0.999930 2010-10-18 - Code name "Hot Beverage", this is a major release. - Removed Mojo::Server::Daemon::Prefork due to unfixable design flaws regarding WebSocket support, please use a PSGI server instead for HTTP production setups. For scalable WebSocket deployment we will introduce a whole new server in one of the next releases! - Deprecated old Mojo::Template block syntax and added a very pretty replacement. (See documentation for more) - Deprecated helper method in Mojolicious::Controller. - Deprecated all *_cb methods (and finished/receive_message) in favor of on_* methods. - Deprecated process method in Mojo::Client and added new start method. - Replaced the "mojolicious" command with "mojo", for convenience. - Removed Mojo::Command::Generate::App. - Renamed the methods name and replace_content to type and replace_inner in Mojo::DOM. - Added EXPERIMENTAL support for indented Perl lines in Mojo::Template. - Added EXPERIMENTAL support for --mode and --home options to all Mojolicious commands. - Added EXPERIMENTAL support for helper methods. - Added EXPERIMENTAL helper method to Mojolicious. - Added EXPERIMENTAL support for inline rendering to Mojolicious. - Added EXPERIMENTAL memorize helper to Mojolicious::Plugin::DefaultHelpers. (ptomli) - Added EXPERIMENTAL write, write_chunk and rendered methods to Mojolicious::Controller. - Added EXPERIMENTAL support for loading of plugins by full module name. - Added EXPERIMENTAL tag helpers to Mojolicious. - Added EXPERIMENTAL support for radio buttons and select fields to Mojolicious::Plugin::TagHelpers. (kvorg) - Added EXPERIMENTAL is_limit_exceeded, max_line_size and max_message_size methods to Mojo::Message. - Added EXPERIMENTAL automatic relaxed parsing support for HTTP responses. - Added while, until and inner_xml methods for Mojo::DOM collections. (vti) - Added b function to all Mojo::Template templates. - Added selector support to the dom method of Mojo::Message. (marcus) - Added x function to ojo. (DaTa) - Added failed request warnings to ojo. (marcus) - Added support for selector groups to Mojo::DOM. - Added more attribute selectors, pseudo classes and combinators to Mojo::DOM. - Added support for mode specific configuration files to Mojolicious::Plugin::JsonConfig. (marcus) - Added reserved route name current. - Simplified transaction pausing by replacing it with an automatism. - Improved RFC 3986 compliance of Mojo::Path. (janus) - Improved Mojo::Server::PSGI to preload applications. - Improved FastCGI detection for Dreamhost. (garu) - Improved keep-alive timeout handling in Mojo::Client. - Improved Mojo::ByteStream performance. (mons) - Improved Mojo::Parameters performance. (kimoto) - Improved Mojo::Message::Response parser resilience. - Improved template class handling in MojoX::Renderer. (vti) - Fixed a serious design flaw in Mojo::Message and made long poll much easier. - Fixed a bug where Mojo::IOLoop connections could be closed too early. - Fixed a bug where a broken renderer could cause a fatal exception. - Fixed HTTPS support for CGI environments. - Fixed a auto rendering bug related to bridges. - Fixed Mojo::IOLoop Windows support. - Fixed Mojo::DOM class selector bug. (tempire) - Fixed small render bug. (skaurus) - Fixed a small renderer bug. - Fixed automatic reloading for external templates. - Fixed after_build_tx plugin hook callback order. - Fixed a small under bug in Mojolicious::Lite. - Fixed logging of UTF-8 errors. (und3f) - Fixed Mojo::DOM parser bug. (esskar) - Fixed TLS handshake bug in Mojo::IOLoop. (und3f) - Fixed a small Test::Mojo bug. - Fixed multiple route condition bugs. (esskar) - Fixed a small relative path bug in Mojo::URL. - Fixed POD renderer bug. (vti) - Fixed a multipart parser bug affecting mostly file uploads. - Fixed input tag helper escaping. (vti) - Fixed url_for WebSocket support. - Fixed url_for format handling. 0.999929 2010-08-17 - Removed OS X resource fork files. 0.999928 2010-08-15 - Fixed a security problem with CGI environment detection. - Fixed redirect_to without content and render_static bug. - Fixed nested partial rendering bug. (yko) - Fixed multiple small Mojo::DOM bugs. (yko) 0.999927 2010-08-15 - Code name "Comet", this is a major release. - Added EXPERIMENTAL method defaults to Mojolicious. - Added EXPERIMENTAL method detour to MojoX::Dispatcher::Routes. - Added EXPERIMENTAL attribute partial to MojoX::Routes. - Added EXPERIMENTAL CSS3 selector tests to Test::Mojo. - Added EXPERIMENTAL method test_server to Mojo::Client. - Added EXPERIMENTAL one-liner module ojo. - Added EXPERIMENTAL support for static files in the DATA section of Mojolicious applications. - Added EXPERIMENTAL Bonjour support. - Added EXPERIMENTAL support for route name generation. - Added graceful shutdown support to Mojo::Server::Daemon. - Added multiple guides and improved documentation substantially. - Added finished callback support for HTTP transactions. - Added relative path support to Mojo::URL. (marcus) - Added simple iterator support to Mojo::DOM. - Added XML namespace support to Mojo::DOM. - Added is_xhr method to Mojo::Message::Request. - Added detect_proxy method to Mojo::Client. (DaTa) - Added say and trim methods to Mojo::ByteStream. - Added custom socket support to Mojo::Client. - Added SHA1 support to Mojo::ByteStream. (vti) - Added app helper. - Renamed attributes method in Mojo::DOM to attrs. - Renamed search method in Mojo::DOM to find. - Cleaned up tests. (memowe) - Cleaned up regular expressions in Mojo::DOM. (mpu) - Improved Mojo::Client error logging. - Improved Mojo::Template error messages. - Improved generated multipart messages to be 2 bytes shorter. (John Kingsley) - Improved conditions by allowing them to access the stash. - Fixed memory and file descriptor leaks in Mojo::Client. - Fixed Mojo::Server::Daemon::Prefork to use a random lock file by default. - Fixed Mojo::DOM to support escaped selectors. - Fixed Mojo::DOM parser bugs. - Fixed Mojo::DOM child listing bug. (evt) - Fixed Mojo::DOM multiline attribute bug. (tempire) - Fixed charset detection of the dom builder in Mojo::Message. (und3f) - Fixed json/data rendering with layouts in MojoX::Renderer. - Fixed Mojo::IOLoop to not stop unexpectedly. - Fixed graceful shutdown in Mojo::Server::Daemon::Prefork. - Fixed Mojo::Server::CGI and Mojo::Server::FastCGI to be more portable. - Fixed poll + tls support. - Fixed language switching in Mojolicious::Plugin::I18n. - Fixed async Mojo::Client tests. - Fixed HTML1 and HTML5 compatibility of Mojo::DOM. - Fixed a selector bug in Mojo::DOM. - Fixed environment detection. - Fixed Mojolicious application embedding. - Fixed a tutorial bug. (zoul) - Fixed tests to not use any optional modules. - Fixed small Mojolicious::Lite bug. (sharifulin) - Fixed Mojo application generator. (zakame) - Fixed edgy stringified return value bug in MojoX::Dispatcher::Routes. (DaTa) - Fixed route rendering bug. (koban) - Fixed route without namespace bug. - Fixed route with mixed format bug. (sharifulin) - Fixed small url_for bug. - Fixed Mojo::IOLoop to not connect to TLS hosts without checking TLS support first. (ashleydev) - Fixed multiple WebSocket bugs. - Fixed Test::Mojo::Server to be more portable. (afresh1) - Fixed url_for to not expose userinfo in absolute URLs. - Fixed path detection bug in generated scripts. (merlyn) - Fixed a small redirect bug in Mojo::Client. - Fixed a route callback inheritance bug. - Fixed a security problem in the HMAC-MD5 implementation. (vti) 0.999926 2010-06-07 - Added version requirement for all optional dependencies. - Fixed async client processing. - Fixed small renderer bug. 0.999925 2010-06-07 - Updated WebSocket implementation to draft 76, NOTE THAT THIS CHANGE IS NOT BACKWARDS COMPATIBLE!!! (sadly we have no choice when the spec changes) - Increased Perl version requirement to 5.8.7 due to Unicode bugs in earlier releases. - Switched to app->start instead of shagadelic as default way to start Mojolicious::Lite apps in the documentation. - Made tutorial examples more business friendly. - Added the ability to use Mojolicious::Lite apps as Mojolicious controllers. - Added EXPERIMENTAL XML DOM parser with CSS3 selector support. - Added EXPERIMENTAL tag_helper plugin to Mojolicious. (vti) - Added EXPERIMENTAL success method to Mojo::Transaction. - Added EXPERIMENTAL json method and json_class attribute to Mojo::Message. - Added EXPERIMENTAL idle_cb attribute to Mojo::IOLoop. - Added more Perl-ish block syntax to Mojo::Template. - Added non-blocking TLS handshake support to Mojo::IOLoop. - Added proxy support to Mojo::Client. - Added the ability to have dispatch plugins. - Added "under" to Mojolicious::Lite. - Added file upload support to Mojo::Client. (yko) - Added higher precision timers to Mojo::IOLoop. (vti) - Improved exception handling. - Improved IIS compatibility of the CGI implementation. - Improved routes by making the leading slash optional and storing route names in the stash. - Converted README to markdown. (memowe) - Fixed connection keep-alive with epoll. - Fixed bridge bug in MojoX::Routes::Match. (Oleg Zhelo, Dmitry Konstantinov) - Fixed argument handling of Mojo::Template blocks. (afresh1) - Fixed a stash localization bug. (und3f) - Fixed Mojo::Log to use flock to sync log file writing. - Fixed daemons to listen on "::" for IPv6 and "0.0.0.0" for IPv4 with a wildcard address. - Fixed lock_cb and unlock_cb exceptions to be fatal in Mojo::IOLoop, this makes Mojo::Server::Daemon::Prefork much more solid. (ask) - Fixed a bug that prevented undef values in the stash. (garu) - Fixed Mojo::Message::headers chaining. (markstos) - Fixed a bug in Mojo::JSON that prevented BOM characters in strings. (chansen) - Fixed Mojo::JSON to not unescape broken surrogates. (chansen) - Fixed UTF-8 bug in Mojolicious::Plugin::JsonConfig. (vti) - Fixed Mojo::Parameters to accept array values. (konstantinov) - Fixed IRI routes in Mojolicious. - Fixed multiple path encoding bugs. - Fixed a loader bug. - Fixed reloading of inflated Mojolicious::Lite templates. - Fixed the client transaction builder. (Curt Tilmes) - Fixed unix domain socket support. (sharifulin) - Fixed a few regex bugs. (vti) - Fixed POD. (memowe) 0.999924 2010-03-08 - Added default TLS cert and key to Mojo::IOLoop to make HTTPS testing easier, so "mojo daemon --listen https://*:3000" now just works. - Added request limit support to the daemons. - Added basic authentication and proxy authentication support to Mojo::Message::Request. (esskar) - Added tick callback to Mojo::IOLoop to make mixing multiple event loops trivial. - Added the ability to pass arguments to Mojo::Template blocks. - Added layout support for partial rendering, in addition all render arguments are now localized. - Relaxed Mojo::Server::CGI read timeout. - Fixed ioloop timers to actually work. - Fixed PSGI environment auto detection and removed .psgi file generator since it has become obsolete. - Fixed Mojolicious sessions to remove the session cookie immediately if it's not needed anymore. (ask) - Fixed routes method condition to consider GET and HEAD equal. - Fixed test requiring Perl 5.10. - Fixed a loader bug. (mvuets) - Fixed layout and extends scope in MojoX::Renderer. (korshak) - Fixed daemons to create listen sockets before changing user and group. (xantus) 0.999923 2010-03-07 - Made Mojo::Client sync by default with optional async support, this massively improves usability! my $tx = $client->get('http://mojolicious.org'); print $client->get('http://search.cpan.org')->res->body; my $tx = $client->post_form('http://kraih.com', {q => 'mojo'}); - Made plugins much more configurable. - Improved PSGI support and added "psgi" command. - Added automatic environment detection for Plack based servers, there is no technical way to detect all PSGI compliant servers yet though. That means "plackup myapp.pl" and "plackup script/myapp" should just work. - Added session and flash helpers. - Added finished callback to WebSocket client and server. - Added referrer method to Mojo::Headers. (esskar) - Added finish_cb callback to Mojo::Message. - Added render_data method to Mojolicious::Controller. - Added form-data tests for multiple browsers. (koban) - Changed Mojolicious default secret to a slightly more secure value. (xantus) - Allow parser errors to be handled by frameworks. - Removed bundled RFCs. - Fixed multiple Mojo::Template parser bugs. - Fixed epl rendering bug. - Fixed multipart form encoding and decoding. - Fixed IRI handling. (sharifulin) - Fixed mixed IRI/IDNA handling. - Fixed tmpdir detection. 0.999922 2010-02-11 - Added session support. - Added signed cookie support. - Added I18N support. (vti, memowe) - Added template detection again, you can now just mix multiple template engines and the renderer will automatically pick the right template. So you don't have to use the "handler" argument anymore, even though it's still available and overrides auto detection. - Added Flash Policy Server example. (xantus) - Added more reference docs. - Added ".gitignore" generator command. (marcus) - Added automatic CGI/FastCGI environment detection to Mojo::Commands. - Renamed Mojolicious::Book to Mojolicious::Guides. - Removed hot deployment support for Windows because of incompatibilities between Active Perl and Strawberry Perl. - Made process id and lock file defaults more user-friendly in Mojo::Server::Daemon. - Updated for Perl 5.12, not using the bytes pragma anymore. - Fixed a bug where WebSocket servers could not directly start sending messages. - Fixed connection id handling in Mojo::Client. - Fixed multiple epoll bugs. - Fixed Mojo::IOLoop connection check. - Fixed identification headers. - Fixed a bug where exception pages would be rendered multiple times. - Fixed reverse proxy support. (vti) - Fixed error state in Mojo::Stateful. (vti) - Fixed seek bug. (lee7) - Fixed a PSGI header bug. (lee7) 0.999921 2010-02-11 - Fixed a small kqueue bug. 0.999920 2010-02-11 - Code name "Snowman", this is a major release, which means deprecation policies apply. (See also "perldoc Mojolicious::Book::CodingGuidelines") - Renamed distribution from Mojo to Mojolicious. - Deprecated $VERSION in Mojo, new $VERSION lives in Mojolicious. Make sure to update your modules depending on Mojo to depend on Mojolicious in the future. - Deprecated Mojo::Transaction::Single, make sure to update all old code to use Mojo::Transaction::HTTP instead. - MOJO_RELOAD=1 now works with Mojolicious::Lite, have fun! - Allow reloading to be triggered once by a USR1 or WINCH (Windows) signal. - Added --reload flag to all server bindings as an alternative to MOJO_RELOAD=1. - Added WebSocket support. - Added IPv6 support. - Added SSL/TLS support. - Added IDNA support. - Added UNIX domain socket support to daemons. - Added transparent kqueue and epoll support to daemons and client. - Added support for listening to multiple locations to the daemons. mojo daemon --listen http://127.0.0.1:3000 mojo daemon --listen http://*:3000,http://*:3001,http://*:3002 mojo daemon --listen http://[::1]:3000 mojo daemon --listen https://*:443:/x/server.crt:/x/server.key - Added routes captures to params in Mojolicious. - Added native PSGI support. - Added the ability to have multiple Mojolicious::Lite apps at once. (Mojolicious::Lite is not a singleton anymore!) - Added charset plugin to Mojolicious. (charsbar) - Added simple reverse proxy support. - Added simpler way to define default controller and action for a route. $r->route('/foo')->to('mycontroller#myaction'); - Added simple way to define default controller or action for a route. (mvuets) $r->route('/foo/:controller')->to('#myaction'); $r->route('/foo/:action')->to('mycontroller#'); - Added multipart post support to Test::Mojo. (yuki-kimoto) - Added env attribute to Mojo::Message::Request. - Added range support to MojoX::Dispatcher::Static. (xantus) - Added version command. - Added after_build_tx plugin hook. - Added timer support to Mojo::IOLoop. - Added the ability to run multiple parallel ioloops that block each other. - Added default_template_class attribute to MojoX::Renderer. - Added render_static method to Mojolicious::Controller. - Added support for embedded Mojolicious applications. - Added json_config plugin to Mojolicious. (vti) - Added the ability to reload the application and (graceful) restart all children to the prefork daemon. - Added to_hash and from_hash methods to Mojo::Headers. (vti) - Added post_form method to Mojo::Client. - Added find_route method to MojoX::Routes. - Added buffer size limits to the message parser. - Added child_status method to Mojo::Server::Daemon::Prefork. (und3f) - Added header_condition plugin to Mojolicious. (xantus) - Added finish method to Mojolicious::Controller. - Added WebSocket support to Mojolicious and Mojolicious::Lite. - Added message body support to Mojo::Client API. (tempire) - Added stash helper. - Added POD renderer plugin to Mojolicious. (vti) - Added inflate command to Mojolicious. (vti, korshak) - Added singleton support to Mojo::Client. - Started working on the Mojolicious book. - Started adding reference documentation. (marcus) - Improved HTTP 1.1 state machine. - Improved exception handling in Mojo::Client, Mojo::Server::Daemon and Mojo::IOLoop. - Disabled Nagle's algorithm in Mojo::IOLoop. - Changed the testing framework to always run real world tests with daemon and TCP connections. - Changed exceptions to stay out of your way as much as possible. - Made all Mojolicious after_* plugin hooks run in reverse order. - Made param decoding more defensive and allow malformed data to pass through for debugging. - Made Mojo::IOLoop very hard to kill. - Reduced Mojolicious log output outside of development mode. - Polished Mojo::Client API. - Fixed connect error handling in Mojo::Client. - Fixed double encoding of JSON data with charset plugin. (yuki-kimoto) - Fixed prefork daemon signal handling. - Fixed backslash encoding bug in Mojo::JSON. - Fixed memory leaks in Mojolicious plugins. (sharifulin) - Fixed memory leaks in .ep templates. (vti) - Fixed makefile and app generators. - Fixed a case where an ending tag would be interpreted as a line start in Mojo::Template. - Fixed multipart charset handling and added the ability to disable param decoding. - Fixed format detection bug. (marcus) - Fixed named url_for. (marcus) - Fixed decamelize of multiple uppercase characters. - Fixed plugins and commands to work with multiple namespaces and reloading. - Fixed multiple process calls in Mojo::Client. - Fixed a routes parser bug. - Fixed a bug that caused waypoint actions to run twice. - Fixed a bug where to_abs and to_rel could not be called multiple times on a Mojo::URL object. (vti) - Fixed development mode log level. (ka2u) - Fixed query string support in Mojo::URL. (vti) - Fixed rendering without template name. - Fixed large file upload bug. (vti, sharifulin) - Fixed a small inconsistency between relaxed and wildcared plaeholders. 0.999914 2009-11-24 - Added the Mojolicious plugin system. - Added helper method to Mojolicious::Controller. - Added encoding support to post_form_ok in Test::Mojo. - Made cookies easier to set. - Fixed body_contains in Mojo::Content::Single. (yuki-kimoto) - Fixed utf8 output in STDERR log. (vti) 0.999913 2009-11-24 - Added automatic content decoding to content helpers in Test::Mojo. - Added json test helper to Test::Mojo. - Added the ability to reset a test session in Test::Mojo. (yuki-kimoto) - Fixed Mojolicious::Renderer to always default to rendering a 404 error. - Fixed a cookiejar bug. (yuki-kimoto) 0.999912 2009-11-24 - Improved ioloop performance. (gbarr) 0.999911 2009-11-14 - Added template inheritance to Mojolicious. - Added block and capturing support to Mojo::Template. - Added trimming support to Mojo::Template. - Added new testing framework for Mojo and Mojolicious applications. (yuki-kimoto) - Added redirect support to Mojo::Client. (acajou) - Added cookie jar to Mojo::Client. (acajou) - Excluded Mojo::ByteStream objects from auto escaping. - Updated Mojolicious::Lite tutorial. - Fixed a case where routes captures got false positives. - Fixed literal name handling in Mojo::JSON. (rsp) - Fixed Unicode detection in Mojo::JSON. (rsp) - Fixed multiple small bugs in Mojo::JSON. (rsp) - Fixed Mojolicious default app tests. (yuki-kimoto) - Fixed Mojo::Server::FCGI compatibility. 0.999910 2009-11-14 - Fixed url_for without endpoint bug. - Fixed BOM handling in Mojo::JSON. (rsp) - Fixed named redirect_to with arguments. - Improved Mojo::Exception. (yuki-kimoto) 0.999909 2009-11-11 - Cleaned up tutorial. - FIxed renderer exception bug. (yuki-kimoto) 0.999908 2009-11-11 - Fixed bridges/ladders. 0.999907 2009-11-11 - Fixed another connection close bug in ioloop. - Fixed relaxed placeholder format handling in MojoX::Routes::Pattern. 0.999906 2009-11-11 - Fixed connection close bug in ioloop. 0.999905 2009-11-11 - Fixed routes bug that prevented the root from having formats. 0.999904 2009-11-10 - Cleaned up examples. 0.999903 2009-11-10 - Added ladders to Mojolicious::Lite, they are like bridges but lite. - Added encoding support to renderer. (likhatskiy) - Added dumper helper. - Made tmpdir in Mojo::Asset::File configurable. 0.999902 2009-11-01 - Added include helper. - Optimized buffering a bit. - Fixed a case where multiple clients would taint the shared ioloop. (ferreira) - Fixed a case where non existing actions were considered a server error. (Andre Vieth) 0.999901 2009-09-01 - Added new Mojo::Client, because the old one had bugs that prevented proper scaling and could not be fixed otherwise. Note that this change is not backwards compatible, the decision to make it so close to the 1.0 release was not easy but the bugs were simply too serious. - Added native JSON support. - Added more designer friendly .ep templates to Mojolicious. The default template format for your application can be controlled with the default_handler attribute of the mojolicious renderer. Mojolicious (in the startup method): $self->renderer->default_handler('epl'); $self->renderer->default_handler('ep'); Mojolicious::Lite: app->renderer->default_handler('epl'); app->renderer->default_handler('ep'); - Added helper support for .ep templates. - Added support for MOJO_CHUNK_SIZE=1. (melo) - Added not_found.html.* templates. - Added input streaming support to Mojo::Content. - Added client, param, pause, redirect_to and resume to Mojolicious::Controller. - Renamed Mojo::Manual to Mojolicious::Book. - Updated Mojolicious lite_app generator to use .ep templates. - Fixed many bugs in the HTTP 1.1 state machine and added the ability to pause transactions. - Fixed param to be CGI.pm compatible. - Fixed a few cases where exceptions and not found events would result in empty pages. - Fixed layouts with partial templates. - Fixed encoding of non utf8 form-data. - Fixed body callbacks to get automatic buffering. - Fixed a case where Mojo::Server::Daemon and Mojo::Client were too defensive and made them in turn 20 times faster. - Fixed keep-alive problem in Mojo::Transaction::Pipeline. - Fixed and simplified Mojo::Parameters. (gbarr) - Fixed xml_escape to use character semantics. (vti) - Fixed utf8 handling of routes captures. (vti) - Fixed body helper in Mojo::Message. (vti) - Fixed padding byte handling in Mojo::Server::FastCGI. (Jaroslav Muhin) - Fixed a few small parser bugs in MojoX::Routes. - Fixed Mojo::Asset::File. (Yuki Kimoto) - Fixed generated scripts. (Yuki Kimoto) - Fixed CHLD signal handler for prefork children. (sharifulin) - Fixed typo. 0.991251 2009-08-18 - Fixed continue timeout handling in Mojo::Transaction::Simple. - Fixed undefined value in If-Modified-Since check in MojoX::Dispatcher::Routes. - Fixed MojoX::Routes::Pattern::match. (trendels) - Fixed default_handler in MojoX::Renderer. (sharifulin) - Fixed HTML5 tags. (xantus) - Fixed special Apache CGI environment cases. - Fixed Mojo::Log to work with older versions of Perl. - Fixed typo. 0.991250 2009-08-18 - This release contains many substantial changes that are not backwards compatible, but good news is that it's also the last major feature breaking release before 1.0. ;) Older releases of Mojo did contain additional Mojo::Script::* and Mojolicious::Script::* modules that are obsolete now and might break this version if they are still present on your system. Because of this we highly suggest that you DELETE ALL MODULES IN THE "Mojo", "MojoX" AND "Mojolicious" NAMESPACES MANUALLY!!! - Mojo::Script has been renamed to Mojo::Command, this change is not backwards compatible! You will have to regenerate application scripts or replace "Mojo(licious)::Script" with "Mojo(licious)::Command" manually. - Removed unused features from Mojo::Base and simplified API, this change is not backwards compatible! __PACKAGE__->attr('foo', default => 'bar'); becomes __PACKAGE__->attr(foo => 'bar'); - Merged eplite and epl, this change is not backwards compatible, you will have to rename all your eplite templates to epl. - Simplified MojoX::Renderer, this change is not backwards compatible! Handler can no longer be detected, that means "default_handler" or the "handler" argument are required. The template argument can no longer contain format or handler. $self->render(template => 'foo.html.epl') becomes $self->render('foo', format => 'html', handler => 'epl') The following forms are available now. $self->render; $self->render(controller => 'foo', action => 'bar'); $self->render({controller => 'foo', action => 'bar'}); $self->render(text => 'Hello!'); $self->render(template => 'index'); $self->render(template => 'foo/index'); $self->render( template => 'index', format => 'html', handler => 'epl' ); $self->render(handler => 'something'); $self->render('foo/bar'); $self->render('foo/bar', format => 'html'); $self->render('foo/bar', {format => 'html'}); For renderers the stash will no longer get an updated template, instead a new argument will be passed along. {template => 'foo/bar', format => 'html', handler => 'epl'} - Simplified context and controller in Mojolicious, this change is not backwards compatible! If you've been using a custom context object you'll now have to use a custom controller base class. The new controller_class attribute can now be used to set the default controller in Mojolicious. There is also no $c argument anymore actions get called with, since everything is in $self now. - Refactored and renamed Mojo::Transaction and Mojo::Pipeline, this change is not backwards compatible! Mojo::Transaction -> Mojo::Transaction::Single Mojo::Pipeline -> Mojo::Transaction::Pipeline - Refactored and renamed Mojo::File and Mojo::File::Memory, this change is not backwards compatible! Mojo::File -> Mojo::Asset::File Mojo::File::Memory -> Mojo::Asset::Memory - Refactored and renamed Mojo::Content, this change is not backwards compatible! Mojo::Content -> Mojo::Content::Single - Added conditions to MojoX::Routes. - Added routes script to Mojolicious. - Simplified Mojo::Base. - Simplified exceptions. - Changed Mojo::Log to default to utf8 when writing to a file. - Made build_tx a callback named build_tx_cb in Mojo. - Made the exception template a bit more fault tolerant. - Made controller base class configurable in MojoX::Dispatcher::Routes. - Removed address, password and user methods from Mojo::URL. - Fixed Microsoft IIS CGI and FastCGI environment support. - Fixed prefix handling in MojoX::Dispatcher::Static. - Fixed max_age in Mojo::Cookie. - Fixed cloning of urls with base in Mojo::URL. - Fixed parsing of multiple headers and cookies with same name. - Fixed pipeline support in Mojo::Client. (acajou) - Fixed utf8 handling in Mojo::Parameters. (vti) - Fixed Mojo::Scripts to only allow word characters in script names. - Fixed security problem in MojoX::Dispatcher::Static. (trendels) 0.991246 2009-08-01 - Fixed typo. 0.991245 2009-07-31 - Added spin_app to Mojo::Client and simplified API. - Added port support to Mojo::Cookie. - Made chunk size configurable with MOJO_CHUNK_SIZE environment variable. - Simplified script system startup. - Fixed Windows bug where eplite templates would not be detected right. 0.991244 2009-07-30 - Fixed package. 0.991243 2009-07-28 - Made eplite ignore everything after __END__. - Made proxy support more portable. - Simplified progress callbacks. - Added local host bin address support to Mojo::Server::Daemon. - Fixed layouts on Windows and made templates portable, "/" is now the separator on all platforms. (charsbar) - Fixed dependency on Getopt::Long 2.38. (kevinold) - Fixed Perl 5.8.1 prereqs. (alias) 0.991242 2009-07-27 - Cleaned up the whole script system, this change is mostly backwards compatible except for a few cases. "daemon $port" now becomes "daemon -p $port" "mojolicious mojo $script" becomes "mojolicious $script" - Added HTML escape expression marks "<%==" and "%==" to Mojo::Template. - Added more Mojolicious::Lite examples and reformatted them into a tutorial. - Fixed a bridge bug in MojoX::Dispatcher. 0.991241 2009-07-20 - Mojolicious::Lite has been introduced as a new entry level web framework example. - Mojo::Message::Response will now default to response code 200, this change is not backwards compatible. In Mojolicious you should use ->render(text => 'Hello!') instead of ->res->body('Hello!') now. - Changed routes syntax again, this change is not entirely backwards compatible but will only affect you if you are using the relaxed and wildcard variations. "/((foo))" becomes "/(.foo)" "/(((foo)))" becomes "/(*foo)" - Updated Mojolicious to support ->render(text => 'Hello World!'). - Updated Mojo::Script::get_data to use "@@ $name" instead of "__$name__". - Updated our routes implementation to support HTTP request methods. - Updated Mojo::Home to fallback to FindBin for detection. - Made Mojolicious much more fault tolerant. - Fixed PATH_INFO handling of the CGI environment parser in Mojo::Message::Request. - Added url_for and render_partial to Mojolicious::Controller. - Added namespace support to Mojo::Template. - Added eplite handler to Mojolicious::Renderer. - Added generator for lite apps. - Allow log level override via environment variable in Mojo::Log. - Code cleanup. 0.991240 2009-07-19 - Turned Mojolicious layout rendering inside out for better exception handling and to make layouts configurable from templates. - Added debug helpers to Mojo::Server::FastCGI. - Fixed detection bug in Mojo::Home. - Fixed generator bug in Mojo::Script. - Fixed Windows related parser bug in Mojo::Loader::Exception. 0.991239 2009-07-16 - Renamed bin directory to script, old apps should not break but you are still encouraged to rename the directory yourself. - Simplified Mojo::Template, this will only affect you if you are using Mojo::Template directly. - Added setuid/setgid support to Mojo::Server::Daemon and Mojo::Server::Daemon::Prefork. (James Duncan) - Updated Mojo::Server::FastCGI and Mojo::Server::Daemon::Prefork to use the application logger. - Fixed import problem in Mojo::Server::Daemon::Prefork. (James Duncan) - Fixed warning in "template.t". 0.991238 2009-07-16 - Fixed all shebang lines. 0.991237 2009-07-15 - Renamed process_local to process_app in Mojo::Client, this change is not backwards compatible and you might have to change some of your tests. - Simplified MojoX::Renderer. - Simplified Mojo::Loader. - Simplified Mojo::ByteStream. - Simplified exceptions. - Updated all modules to use IO::Poll instead of IO::Select. - Updated exception handling in Mojolicious to work with exceptions in epl templates. - Updated Mojo and Mojolicious to log to STDERR if log directory isn't writable. - Updated Mojo and Mojolicious to work without boilerplate and a single MyApp.pm file. - Added html_encode and html_decode methods to Mojo::ByteStream. - Improved 100 Continue handling. (acajou) - Improved Mojo::Template exception handling. - Cleaned up exception code. - Fixed possible infinite loop in Mojo::Server::FastCGI. 0.991236 2009-07-05 - Simplified Mojo::Home. - Moved executable detection to Test::Mojo::Server. - Improved Mojo::Loader::Exception. - Fixed at_least_version. (yuki-kimoto) 0.991235 2009-07-05 - Removed prepare/finalize methods from Mojolicious. 0.991234 2009-07-03 - Added name and value filters to Mojo::Headers. (acajou) - Added clean multiline value handling to Mojo::Headers. - Added prepare/finalize methods to Mojolicious. - Added some additional MIME types to MojoX::Types. - Renamed method add_line to add in Mojo::Headers. - Updated generator scripts to play nice with MM->parse_version. 0.991233 2009-07-01 - Rewrote Mojo::Client::process_local to use the new state machine. - Added Server and X-Powered-By headers. - Fixed external server tests. - Fixed Mojo::Date handling of negative epoch values. 0.991232 2009-06-29 - Fixed tarball. 0.991231 2009-06-29 - Rewrote MojoX::Renderer, it is not backwards compatible and templates need to be renamed in the following 3 part format "index.html.tt"! - Added exception support to MojoX::Dispatcher::Routes, this change is not backwards compatible and "dispatch" calls now return exception objects for errors and false otherwise. - Changed routes syntax, this change is not backwards compatible and you need to change all your existing routes. "/:foo" becomes "/(foo)" "/^foo" becomes "/((foo))" "/*foo" becomes "/(((foo)))" - Added full HTTP 1.1 pipelining support to all Mojo layers. - Added layout support to MojoX::Renderer. - Made render call optional. - Added format support to MojoX::Routes. - Added Mojo::Loader::Exception. - Added wildcard symbol support to MojoX::Routes and rewrote many routes internals. - Added Makefile.PL generator. - Added HttpOnly support to Mojo::Cookie. (burak) - Support more CGI implementations. - Added support for namespaces only dispatching in MojoX::Dispatcher::Routes. - Added encoding support to Mojo::Template and made "utf8" the default. - Added HEAD support to Mojo::Server::Daemon. (acajou) - Added new relaxed placeholder to MojoX::Routes::Pattern. - Added Mojo::Template::Exception. - Added HEAD support to the Mojo::Transaction state machine and related modules. (acajou) - Added safe_post option to Mojo::Pipeline. (acajou) - Made chained => 1 the default in Mojo::Base. - Fixed compiler bug in Mojo::Template that prevented more advanced control structures, you might have to add additional semicolons to some of your templates. - Fixed Mojo::Date to not crash on invalid dates. (vti) - Fixed chunked support in Mojo::Server::Daemon and Mojo::Client. - Fixed tokenizer in MojoX::Routes::Pattern to support "0" values. (Anatoly Sharifulin) - Fixed parsing of "0" in Mojo::Path. (charsbar) - Fix server tests on Windows. (charsbar) - Fixed leading whitespace problem in the request parser. (acajou) - Fixed broken pipe problem in Mojo::Server::CGI. (vti) - Added more diagnostics options to Mojo::HelloWorld. (uwe) - Fixed empty cookie parsing. (vti) - Fixed a case where child processes migth hang in Mojo::Server::Daemon::Prefork. (gbarr) - Fixed a bug in MojoX::Dispatcher::Routes where the renderer would be called with an empty stack. (melo) - Fixed a escaping problem in Mojo::Parameters. (vti) - Updated Mojo::URL to be more template friendly. - Improved Solaris compatibility. 0.9002 2009-02-16 - Added local_address(), local_port(), remote_address() and remote_port() to Mojo::Transaction. 0.9001 2009-01-28 - Added proper home detection to Mojo itself. (charsbar) - Fixed a bug where errors got cached in the router. (charsbar) - Updated error handling in MojoX::Dispatcher::Static. - Fixed Mojo::Message::Request::cookies() to always return an array reference. - Fixed url_for to support references. (vti) - Fixed unescaping of captures. (vti) 0.9 2008-12-01 - Added modes to Mojolicious. - Added Mojo::Log and log support for Mojo/Mojolicious. - Changed MojoX::Renderer and Mojo::Template API to make catching errors easier, we now use a scalar ref for results like most template engines. - Added MojoX::Context. - Added multi level controller class support to Mojolicious. - MojoX::Dispatcher::Routes should be able to fail. - Added diagnostics functions to Mojo::HelloWorld. - Made the env parser Apache compatible. - Made Mojo::Server::FastCGI Apache compatible. - Added namespace, class and method captures to MojoX::Dispatcher::Routes. - Made url_for work for rebased applications. - Added ctx, render, req, res and stash methods to Mojolicious controllers. - Changed cookie, param and upload in Mojo::Parameters to return a list. - Added support for templateless renderers to MojoX::Renderer. - Added blacklist to MojoX::Dispatcher::Routes. - Fixed Mojo::Date bugs. (vti) - Fixed / routes matching too much. - New Windows workaround in Mojo::Client and Mojo::Server::Daemon. - Added ".perltidyrc". (Ask Bjoern Hansen) - Allow chains to be broken with return values in MojoX::Dispatcher::Routes. - The stack in MojoX::Routes resets now. - Renamed default_handler to default_format in MojoX::Renderer. - Disallow actions beginning with _ in MojoX::Dispatcher::Routes. - Preload application in servers. (Graham Barr) - Renamed is_version to at_least_version. (Mark Stosberg) - Added documentation for Mojo::Log. (Mark Stosberg) - Add test for MojoX::Renderer. (Mark Stosberg) - When testing, allow servers a few seconds to stop. (Leon Brocard) 0.8009 2008-11-07 - Fixed escaping in Mojo::URL. - Fixed query string support and escaping in Mojo::Parameters. - Optimized randomness in Mojo::Client. (Leon Brocard) - Randomized handle order in Mojo::Client - Mojo::Client now prefers writes over reads. - Added copy_to and move_to to Mojo::File. - Made the daemons about 20% faster. - Fallback to default renderer in MojoX::Renderer. (Ask Bjoern Hansen) - Made Mojo::Base instantiation a little bit faster. - Added documentation to Mojo::Base. (Marcus Ramberg) - Moved the home attribute from Mojolicious to Mojo. - Fixed MojoX::Renderer to pass options through to the handler. (Ask Bjoern Hansen) - Fixed Mojo::Server::FastCGI according to the spec. - Dispatchers now return true or false. - Added documentation to Mojo::Home. (Mark Stosberg) - Added documentation to Mojo::Buffer. (Mark Stosberg) - Removed replace from Mojo::Buffer. (Mark Stosberg) 0.8008 2008-11-07 - Fixed multipart parsing for short requests. - Fixed content file storage to specific file. - Fixed lowercase appclasses. 0.8007 2008-11-07 - Cleaned up the API some more. - Added param to Mojo::Message. - Added "server.t". (Mark Stosberg) - Fixed infinite loop in Mojo::File. (Leon Brocard) 0.8006 2008-11-06 - Simplified API by removing aliases, this will help with subclassing annoyances but might break some existing code if you are using long versions of formerly aliased attributes. - Fixed application/x-www-form-urlencoded. - Fixed support for query strings. - Fixed multi query parameter support. - Added a context class to the Mojolicious generator. - Cleaned up Mojo::Server API. (Mark Stosberg) - Increased Mojo::Template performance. (Pedro Melo) 0.8.5 2008-11-04 - Fixed version. (Andreas Koenig) 0.8.4 2008-11-04 - Improved caching in Mojo::Message. - Added upload and cookie method to Mojo::Message. - Changed uploads behavior in Mojo::Message to bring it in line with cookies. 0.8.3 2008-11-03 - Removed filter from Mojo::Base and added warnings. - Added caching to uploads in Mojo::Message. (Mark Stosberg) 0.8.2 2008-11-01 - Removed OS X resource fork files. 0.8.1 2008-11-01 - Made "daemon.t" developer only. 0.8 2008-10-21 - Fixed Mojo::Server::Daemon Windows support. - Generated applications now have individually named executables. - Changed Mojolicious default application templates to something more sane. - Mojo::Base accessors don't take multiple arguments anymore, this results in a 25% speed increase. - Added MOJO_MAX_MEMORY_SIZE environment variable. - Added prepare_parser and prepare_builder callbacks to Mojo::Message. - Added done and is_done to Mojo::Stateful. - Fixed many Windows related bugs. - Fixed keep-alive related bugs in daemon and client. (Pedro Melo) - Allow default in Mojo::Base to have false values. (Pedro Melo) - Fixed chmod_rel_file in Mojo::Script. (Shu Cho). - Mojo::Base attributes can't start with a digit. (Shu Cho). - Fixed Content-Length header for empty messages. - Removed warning from Mojo.pm. - Renamed gate to bridge in MojoX::Routes. - Added waypoint() to MojoX::Routes. - Added named url_for to MojoX::Routes and Mojolicious. - Fixed documentation links. 0.7 2008-10-11 - Added the Mojolicious web framework example. - Added upload and GET/POST parameter helpers to Mojo::Message. - Hooks for upload progress and stuff added. - Refactored transfer encoding code into Mojo::Filter and Mojo::Filter::Chunked. - Added callbacks for start line and header generators. - Added workaround for missing IO::Seekable support in older versions of File::Temp (Perl 5.8). - script/mojo.pl got renamed to bin/mojo. - Mojo::Cache got renamed to Mojo::File because there will be a cache module named MojoX::Cache, and that could cause confusion later on. - Fixed many escaping related bugs around Mojo::URL. - Fixed 100-Continue support in Mojo::Server::Daemon and Mojo::Client. - Countless small bugs fixed and tests added. 0.6 2008-09-24 - Many more bug fixes. 0.5 2008-09-24 - Many small bug fixes. 0.4 2008-09-24 - Moved everything into the Mojo namespace. 0.3 2008-09-24 - Fixed documentation. 0.2 2008-09-24 - First release. libmojolicious-perl-4.63+dfsg.orig/CONTRIBUTING.md0000644000175000017500000000016612123073215021407 0ustar cstamascstamasPlease read the guide for [contributing to Mojolicious](http://mojolicio.us/perldoc/Mojolicious/Guides/Contributing). libmojolicious-perl-4.63+dfsg.orig/examples/0000755000175000017500000000000012256126533021002 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/examples/connect-proxy.pl0000644000175000017500000000504112231330130024126 0ustar cstamascstamasuse FindBin; use lib "$FindBin::Bin/../lib"; use Mojo::Base -strict; use Mojo::IOLoop; # Minimal CONNECT proxy server to test TLS tunneling my %buffer; Mojo::IOLoop->server( {port => 3000} => sub { my ($loop, $stream, $client) = @_; # Connection to client $stream->on( read => sub { my ($stream, $chunk) = @_; # Write chunk from client to server my $server = $buffer{$client}{connection}; return Mojo::IOLoop->stream($server)->write($chunk) if $server; # Read connect request from client my $buffer = $buffer{$client}{client} .= $chunk; if ($buffer =~ /\x0d?\x0a\x0d?\x0a$/) { $buffer{$client}{client} = ''; if ($buffer =~ /CONNECT (\S+):(\d+)?/) { my $address = $1; my $port = $2 || 80; # Connection to server $buffer{$client}{connection} = Mojo::IOLoop->client( {address => $address, port => $port} => sub { my ($loop, $err, $stream) = @_; # Connection to server failed if ($err) { say "Connection error for $address:$port: $err"; Mojo::IOLoop->remove($client); return delete $buffer{$client}; } # Start forwarding data in both directions say "Forwarding to $address:$port."; Mojo::IOLoop->stream($client) ->write("HTTP/1.1 200 OK\x0d\x0a" . "Connection: keep-alive\x0d\x0a\x0d\x0a"); $stream->on( read => sub { my ($stream, $chunk) = @_; Mojo::IOLoop->stream($client)->write($chunk); } ); # Server closed connection $stream->on( close => sub { Mojo::IOLoop->remove($client); delete $buffer{$client}; } ); } ); } } # Invalid request from client else { Mojo::IOLoop->remove($client) } } ); # Client closed connection $stream->on( close => sub { my $buffer = delete $buffer{$client}; Mojo::IOLoop->remove($buffer->{connection}) if $buffer->{connection}; } ); } ) or die "Couldn't create listen socket!\n"; print <<'EOF'; Starting CONNECT proxy on port 3000. For testing use something like "HTTPS_PROXY=http://127.0.0.1:3000". EOF # Start event loop Mojo::IOLoop->start; 1; libmojolicious-perl-4.63+dfsg.orig/examples/entities.pl0000644000175000017500000000064412224745317023171 0ustar cstamascstamasuse FindBin; use lib "$FindBin::Bin/../lib"; use Mojo::Base -strict; use Mojo::ByteStream 'b'; use Mojo::UserAgent; # Extract named character references from HTML spec my $tx = Mojo::UserAgent->new->get( 'http://www.whatwg.org/specs/web-apps/current-work/'); b($_->at('td > code')->text . ' ' . $_->children('td')->[1]->text)->trim->say for $tx->res->dom('#named-character-references-table tbody > tr')->each; 1; libmojolicious-perl-4.63+dfsg.orig/examples/fast.pl0000644000175000017500000000040012171461066022265 0ustar cstamascstamasuse FindBin; use lib "$FindBin::Bin/../lib"; use Mojo::Base 'Mojolicious'; sub handler { my $tx = pop; $tx->res->code(200)->body('Hello World!'); $tx->resume; } # Fast "Hello World" application for profiling the HTTP stack __PACKAGE__->new->start; libmojolicious-perl-4.63+dfsg.orig/examples/hello.pl0000644000175000017500000000025112171461064022435 0ustar cstamascstamasuse FindBin; use lib "$FindBin::Bin/../lib"; use Mojolicious::Lite; get '/' => {data => 'Hello World!'}; # Minimal "Hello World" application for profiling app->start; libmojolicious-perl-4.63+dfsg.orig/examples/microhttpd.pl0000644000175000017500000000225512171461063023514 0ustar cstamascstamasuse FindBin; use lib "$FindBin::Bin/../lib"; use Mojo::Base -strict; use Mojo::IOLoop; # Minimal ioloop example demonstrating how to cheat at HTTP benchmarks :) my %buffer; Mojo::IOLoop->server( {port => 8080} => sub { my ($loop, $stream, $id) = @_; $buffer{$id} = ''; $stream->on( read => sub { my ($stream, $chunk) = @_; # Append chunk to buffer $buffer{$id} .= $chunk; # Check if we got start line and headers (no body support) if (index($buffer{$id}, "\x0d\x0a\x0d\x0a") >= 0) { # Clean buffer delete $buffer{$id}; # Write a minimal HTTP response # (the "Hello World!" message has been optimized away!) $stream->write("HTTP/1.1 200 OK\x0d\x0aContent-Length: 0\x0d\x0a" . "Connection: keep-alive\x0d\x0a\x0d\x0a"); } } ); $stream->on(close => sub { delete $buffer{$id} }); } ) or die "Couldn't create listen socket!\n"; print <<'EOF'; Starting server on port 8080. Try something like "wrk -c 100 -d 10s http://127.0.0.1:8080/" for testing. On a MacBook Air this results in about 18k req/s. EOF # Start event loop Mojo::IOLoop->start; 1; libmojolicious-perl-4.63+dfsg.orig/examples/websocket.pl0000644000175000017500000000203312245676512023330 0ustar cstamascstamasuse FindBin; use lib "$FindBin::Bin/../lib"; use Mojolicious::Lite; websocket '/test' => sub { my $self = shift; $self->on( json => sub { my ($self, $hash) = @_; $hash->{test} = "♥ $hash->{test}"; $self->send({json => $hash}); } ); }; get '/' => 'websocket'; # Minimal WebSocket application for browser testing app->start; __DATA__ @@ websocket.html.ep WebSocket Test %= javascript begin var ws; if ("WebSocket" in window) { ws = new WebSocket('<%= url_for('test')->to_abs %>'); } if(typeof(ws) !== 'undefined') { ws.onmessage = function (event) { document.body.innerHTML += JSON.parse(event.data).test; }; ws.onopen = function (event) { ws.send(JSON.stringify({test: 'WebSocket support works! ♥'})); }; } else { document.body.innerHTML += 'Browser does not support WebSockets.'; } % end Testing WebSockets: libmojolicious-perl-4.63+dfsg.orig/lib/0000755000175000017500000000000012256126533017732 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/0000755000175000017500000000000012256126533020636 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Asset/0000755000175000017500000000000012256126533021715 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Asset/File.pm0000644000175000017500000001276412254163736023150 0ustar cstamascstamaspackage Mojo::Asset::File; use Mojo::Base 'Mojo::Asset'; use Carp 'croak'; use Errno 'EEXIST'; use Fcntl qw(O_CREAT O_EXCL O_RDWR); use File::Copy 'move'; use File::Spec::Functions 'catfile'; use IO::File; use Mojo::Util 'md5_sum'; has [qw(cleanup path)]; has handle => sub { my $self = shift; # Open existing file my $handle = IO::File->new; my $path = $self->path; if (defined $path && -f $path) { $handle->open($path, '<') or croak qq{Can't open file "$path": $!}; return $handle; } # Open new or temporary file my $base = catfile $self->tmpdir, 'mojo.tmp'; 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 999); } $self->path($name); # Enable automatic cleanup $self->cleanup(1) unless defined $self->cleanup; return $handle; }; has tmpdir => sub { $ENV{MOJO_TMPDIR} || File::Spec::Functions::tmpdir }; sub DESTROY { my $self = shift; return unless $self->cleanup && defined(my $path = $self->path); close $self->handle; unlink $path if -w $path; } sub add_chunk { my ($self, $chunk) = @_; my $handle = $self->handle; $handle->sysseek(0, SEEK_END); $chunk //= ''; croak "Can't write to asset: $!" unless defined $handle->syswrite($chunk, length $chunk); return $self; } sub contains { my ($self, $str) = @_; my $handle = $self->handle; $handle->sysseek($self->start_range, SEEK_SET); # Calculate window size my $end = $self->end_range // $self->size; my $len = length $str; my $size = $len > 131072 ? $len : 131072; $size = $end - $self->start_range if $size > $end - $self->start_range; # Sliding window search my $offset = 0; my $start = $handle->sysread(my $window, $len); while ($offset < $end) { # Read as much as possible my $diff = $end - ($start + $offset); my $read = $handle->sysread(my $buffer, $diff < $size ? $diff : $size); $window .= $buffer; # Search window my $pos = index $window, $str; return $offset + $pos if $pos >= 0; $offset += $read; return -1 if $read == 0 || $offset == $end; # Resize window substr $window, 0, $read, ''; } return -1; } sub get_chunk { my ($self, $offset, $max) = @_; $max //= 131072; $offset += $self->start_range; my $handle = $self->handle; $handle->sysseek($offset, SEEK_SET); my $buffer; if (defined(my $end = $self->end_range)) { my $chunk = $end + 1 - $offset; return '' if $chunk <= 0; $handle->sysread($buffer, $chunk > $max ? $max : $chunk); } else { $handle->sysread($buffer, $max) } return $buffer; } sub is_file {1} sub move_to { my ($self, $to) = @_; # Windows requires that the handle is closed close $self->handle; delete $self->{handle}; # Move file and prevent clean up my $from = $self->path; move($from, $to) or croak qq{Can't move file "$from" to "$to": $!}; return $self->path($to)->cleanup(0); } sub size { return 0 unless defined(my $file = shift->path); return -s $file; } sub slurp { my $handle = shift->handle; $handle->sysseek(0, SEEK_SET); my $content = ''; while ($handle->sysread(my $buffer, 131072)) { $content .= $buffer } return $content; } 1; =encoding utf8 =head1 NAME Mojo::Asset::File - File storage for HTTP content =head1 SYNOPSIS use Mojo::Asset::File; # Temporary file my $file = Mojo::Asset::File->new; $file->add_chunk('foo bar baz'); say 'File contains "bar"' if $file->contains('bar') >= 0; say $file->slurp; # Existing file my $file = Mojo::Asset::File->new(path => '/home/sri/foo.txt'); $file->move_to('/yada.txt'); say $file->slurp; =head1 DESCRIPTION L is a file storage backend for HTTP content. =head1 EVENTS L inherits all events from L. =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 cleanup my $bool = $file->cleanup; $file = $file->cleanup($bool); Delete file automatically once it's not used anymore. =head2 handle my $handle = $file->handle; $file = $file->handle(IO::File->new); Filehandle, created on demand. =head2 path my $path = $file->path; $file = $file->path('/home/sri/foo.txt'); File path used to create L, can also be automatically generated if necessary. =head2 tmpdir my $tmpdir = $file->tmpdir; $file = $file->tmpdir('/tmp'); Temporary directory used to generate L, defaults to the value of the MOJO_TMPDIR environment variable or auto detection. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 add_chunk $file = $file->add_chunk('foo bar baz'); Add chunk of data. =head2 contains my $position = $file->contains('bar'); Check if asset contains a specific string. =head2 get_chunk my $bytes = $file->get_chunk($offset); my $bytes = $file->get_chunk($offset, $max); Get chunk of data starting from a specific position, defaults to a maximum chunk size of C<131072> bytes. =head2 is_file my $true = $file->is_file; True. =head2 move_to $file = $file->move_to('/home/sri/bar.txt'); Move asset data into a specific file and disable L. =head2 size my $size = $file->size; Size of asset data in bytes. =head2 slurp my $bytes = $file->slurp; Read all asset data at once. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Asset/Memory.pm0000644000175000017500000000701012254121523023511 0ustar cstamascstamaspackage Mojo::Asset::Memory; use Mojo::Base 'Mojo::Asset'; use Mojo::Asset::File; use Mojo::Util 'spurt'; has 'auto_upgrade'; has max_memory_size => sub { $ENV{MOJO_MAX_MEMORY_SIZE} || 262144 }; sub new { shift->SUPER::new(@_, content => '') } sub add_chunk { my ($self, $chunk) = @_; # Upgrade if necessary $self->{content} .= $chunk // ''; return $self if !$self->auto_upgrade || $self->size <= $self->max_memory_size; my $file = Mojo::Asset::File->new; return $file->add_chunk($self->emit(upgrade => $file)->slurp); } sub contains { my ($self, $str) = @_; my $start = $self->start_range; my $pos = index $self->{content}, $str, $start; $pos -= $start if $start && $pos >= 0; my $end = $self->end_range; return $end && ($pos + length $str) >= $end ? -1 : $pos; } sub get_chunk { my ($self, $offset, $max) = @_; $max //= 131072; $offset += $self->start_range; if (my $end = $self->end_range) { $max = $end + 1 - $offset if ($offset + $max) > $end; } return substr shift->{content}, $offset, $max; } sub move_to { my ($self, $to) = @_; spurt $self->{content}, $to; return $self; } sub size { length shift->{content} } sub slurp { shift->{content} } 1; =encoding utf8 =head1 NAME Mojo::Asset::Memory - In-memory storage for HTTP content =head1 SYNOPSIS use Mojo::Asset::Memory; my $mem = Mojo::Asset::Memory->new; $mem->add_chunk('foo bar baz'); say $mem->slurp; =head1 DESCRIPTION L is an in-memory storage backend for HTTP content. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 upgrade $mem->on(upgrade => sub { my ($mem, $file) = @_; ... }); Emitted when asset gets upgraded to a L object. $mem->on(upgrade => sub { my ($mem, $file) = @_; $file->tmpdir('/tmp'); }); =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 auto_upgrade my $bool = $mem->auto_upgrade; $mem = $mem->auto_upgrade($bool); Try to detect if content size exceeds L limit and automatically upgrade to a L object. =head2 max_memory_size my $size = $mem->max_memory_size; $mem = $mem->max_memory_size(1024); Maximum size in bytes of data to keep in memory before automatically upgrading to a L object, defaults to the value of the MOJO_MAX_MEMORY_SIZE environment variable or C<262144>. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $mem = Mojo::Asset::Memory->new; Construct a new L object. =head2 add_chunk $mem = $mem->add_chunk('foo bar baz'); my $file = $mem->add_chunk('abc' x 262144); Add chunk of data and upgrade to L object if necessary. =head2 contains my $position = $mem->contains('bar'); Check if asset contains a specific string. =head2 get_chunk my $bytes = $mem->get_chunk($offset); my $bytes = $mem->get_chunk($offset, $max); Get chunk of data starting from a specific position, defaults to a maximum chunk size of C<131072> bytes. =head2 move_to $mem = $mem->move_to('/home/sri/foo.txt'); Move asset data into a specific file. =head2 size my $size = $mem->size; Size of asset data in bytes. =head2 slurp my $bytes = mem->slurp; Read all asset data at once. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Asset.pm0000644000175000017500000000513412242771470022257 0ustar cstamascstamaspackage Mojo::Asset; use Mojo::Base 'Mojo::EventEmitter'; use Carp 'croak'; has 'end_range'; has start_range => 0; sub add_chunk { croak 'Method "add_chunk" not implemented by subclass' } sub contains { croak 'Method "contains" not implemented by subclass' } sub get_chunk { croak 'Method "get_chunk" not implemented by subclass' } sub is_file {undef} sub is_range { !!($_[0]->end_range || $_[0]->start_range) } sub move_to { croak 'Method "move_to" not implemented by subclass' } sub size { croak 'Method "size" not implemented by subclass' } sub slurp { croak 'Method "slurp" not implemented by subclass' } 1; =encoding utf8 =head1 NAME Mojo::Asset - HTTP content storage base class =head1 SYNOPSIS package Mojo::Asset::MyAsset; use Mojo::Base 'Mojo::Asset'; sub add_chunk {...} sub contains {...} sub get_chunk {...} sub move_to {...} sub size {...} sub slurp {...} =head1 DESCRIPTION L is an abstract base class for HTTP content storage. =head1 EVENTS L inherits all events from L. =head1 ATTRIBUTES L implements the following attributes. =head2 end_range my $end = $asset->end_range; $asset = $asset->end_range(8); Pretend file ends earlier. =head2 start_range my $start = $asset->start_range; $asset = $asset->start_range(3); Pretend file starts later. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 add_chunk $asset = $asset->add_chunk('foo bar baz'); Add chunk of data to asset. Meant to be overloaded in a subclass. =head2 contains my $position = $asset->contains('bar'); Check if asset contains a specific string. Meant to be overloaded in a subclass. =head2 get_chunk my $bytes = $asset->get_chunk($offset); my $bytes = $asset->get_chunk($offset, $max); Get chunk of data starting from a specific position, defaults to a maximum chunk size of C<131072> bytes. Meant to be overloaded in a subclass. =head2 is_file my $false = $asset->is_file; False. =head2 is_range my $bool = $asset->is_range; Check if asset has a L or L. =head2 move_to $asset = $asset->move_to('/home/sri/foo.txt'); Move asset data into a specific file. Meant to be overloaded in a subclass. =head2 size my $size = $asset->size; Size of asset data in bytes. Meant to be overloaded in a subclass. =head2 slurp my $bytes = $asset->slurp; Read all asset data at once. Meant to be overloaded in a subclass. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Base.pm0000644000175000017500000001243512246232147022051 0ustar cstamascstamaspackage Mojo::Base; use strict; use warnings; use utf8; use feature (); # No imports because we get subclassed, a lot! use Carp (); # Only Perl 5.14+ requires it on demand use IO::Handle (); sub import { my $class = shift; return unless my $flag = shift; # Base if ($flag eq '-base') { $flag = $class } # Strict elsif ($flag eq '-strict') { $flag = undef } # Module elsif ((my $file = $flag) && !$flag->can('new')) { $file =~ s!::|'!/!g; require "$file.pm"; } # ISA if ($flag) { my $caller = caller; no strict 'refs'; push @{"${caller}::ISA"}, $flag; *{"${caller}::has"} = sub { attr($caller, @_) }; } # Mojo modules are strict! $_->import for qw(strict warnings utf8); feature->import(':5.10'); } sub new { my $class = shift; bless @_ ? @_ > 1 ? {@_} : {%{$_[0]}} : {}, ref $class || $class; } sub attr { my ($class, $attrs, $default) = @_; return unless ($class = ref $class || $class) && $attrs; Carp::croak 'Default has to be a code reference or constant value' if ref $default && ref $default ne 'CODE'; for my $attr (@{ref $attrs eq 'ARRAY' ? $attrs : [$attrs]}) { Carp::croak qq{Attribute "$attr" invalid} unless $attr =~ /^[a-zA-Z_]\w*$/; # Header (check arguments) my $code = "package $class;\nsub $attr {\n if (\@_ == 1) {\n"; # No default value (return value) unless (defined $default) { $code .= " return \$_[0]{'$attr'};" } # Default value else { # Return value $code .= " return \$_[0]{'$attr'} if exists \$_[0]{'$attr'};\n"; # Return default value $code .= " return \$_[0]{'$attr'} = "; $code .= ref $default eq 'CODE' ? '$default->($_[0]);' : '$default;'; } # Store value $code .= "\n }\n \$_[0]{'$attr'} = \$_[1];\n"; # Footer (return invocant) $code .= " \$_[0];\n}"; warn "-- Attribute $attr in $class\n$code\n\n" if $ENV{MOJO_BASE_DEBUG}; Carp::croak "Mojo::Base error: $@" unless eval "$code;1"; } } sub tap { my ($self, $cb) = @_; $_->$cb for $self; return $self; } 1; =encoding utf8 =head1 NAME Mojo::Base - Minimal base class for Mojo projects =head1 SYNOPSIS package Cat; use Mojo::Base -base; has name => 'Nyan'; has [qw(birds mice)] => 2; package Tiger; use Mojo::Base 'Cat'; has friend => sub { Cat->new }; has stripes => 42; package main; use Mojo::Base -strict; my $mew = Cat->new(name => 'Longcat'); say $mew->mice; say $mew->mice(3)->birds(4)->mice; my $rawr = Tiger->new(stripes => 23, mice => 0); say $rawr->tap(sub { $_->friend->name('Tacgnol') })->mice; =head1 DESCRIPTION L is a simple base class for L projects. # Automatically enables "strict", "warnings", "utf8" and Perl 5.10 features use Mojo::Base -strict; use Mojo::Base -base; use Mojo::Base 'SomeBaseClass'; All three forms save a lot of typing. # use Mojo::Base -strict; use strict; use warnings; use utf8; use feature ':5.10'; use IO::Handle (); # use Mojo::Base -base; use strict; use warnings; use utf8; use feature ':5.10'; use IO::Handle (); use Mojo::Base; push @ISA, 'Mojo::Base'; sub has { Mojo::Base::attr(__PACKAGE__, @_) } # use Mojo::Base 'SomeBaseClass'; use strict; use warnings; use utf8; use feature ':5.10'; use IO::Handle (); require SomeBaseClass; push @ISA, 'SomeBaseClass'; use Mojo::Base; sub has { Mojo::Base::attr(__PACKAGE__, @_) } =head1 FUNCTIONS L exports the following functions if imported with the C<-base> flag or a base class. =head2 has has 'name'; has [qw(name1 name2 name3)]; has name => 'foo'; has name => sub {...}; has [qw(name1 name2 name3)] => 'foo'; has [qw(name1 name2 name3)] => sub {...}; Create attributes for hash-based objects, just like the L method. =head1 METHODS L implements the following methods. =head2 new my $object = BaseSubClass->new; my $object = BaseSubClass->new(name => 'value'); my $object = BaseSubClass->new({name => 'value'}); This base class provides a basic constructor for hash-based objects. You can pass it either a hash or a hash reference with attribute values. =head2 attr $object->attr('name'); BaseSubClass->attr('name'); BaseSubClass->attr([qw(name1 name2 name3)]); BaseSubClass->attr(name => 'foo'); BaseSubClass->attr(name => sub {...}); BaseSubClass->attr([qw(name1 name2 name3)] => 'foo'); BaseSubClass->attr([qw(name1 name2 name3)] => sub {...}); Create attribute accessor for hash-based objects, an array reference can be used to create more than one at a time. Pass an optional second argument to set a default value, it should be a constant or a callback. The callback will be executed at accessor read time if there's no set value. Accessors can be chained, that means they return their invocant when they are called with an argument. =head2 tap $object = $object->tap(sub {...}); K combinator, tap into a method chain to perform operations on an object within the chain. The object will be the first argument passed to the callback and is also available as C<$_>. =head1 DEBUGGING You can set the MOJO_BASE_DEBUG environment variable to get some advanced diagnostics information printed to C. MOJO_BASE_DEBUG=1 =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/ByteStream.pm0000644000175000017500000001575512242771463023273 0ustar cstamascstamaspackage Mojo::ByteStream; use Mojo::Base -strict; use overload '""' => sub { shift->to_string }, fallback => 1; use Exporter 'import'; use Mojo::Collection; use Mojo::Util; our @EXPORT_OK = ('b'); # Turn most functions from Mojo::Util into methods my @UTILS = ( qw(b64_decode b64_encode camelize decamelize hmac_sha1_sum html_unescape), qw(md5_bytes md5_sum punycode_decode punycode_encode quote sha1_bytes), qw(sha1_sum slurp spurt squish trim unquote url_escape url_unescape), qw(xml_escape xor_encode) ); for my $name (@UTILS) { my $sub = Mojo::Util->can($name); Mojo::Util::monkey_patch __PACKAGE__, $name, sub { my $self = shift; $$self = $sub->($$self, @_); return $self; }; } sub new { my $class = shift; return bless \(my $dummy = join '', @_), ref $class || $class; } sub b { __PACKAGE__->new(@_) } sub clone { $_[0]->new(${$_[0]}) } sub decode { my $self = shift; $$self = Mojo::Util::decode shift || 'UTF-8', $$self; return $self; } sub encode { my $self = shift; $$self = Mojo::Util::encode shift || 'UTF-8', $$self; return $self; } sub say { my ($self, $handle) = @_; $handle ||= \*STDOUT; say $handle $$self; } sub secure_compare { Mojo::Util::secure_compare ${shift()}, @_ } sub size { length ${$_[0]} } sub split { my ($self, $pattern) = @_; return Mojo::Collection->new(map { $self->new($_) } split $pattern, $$self); } sub tap { shift->Mojo::Base::tap(@_) } sub to_string { ${$_[0]} } 1; =encoding utf8 =head1 NAME Mojo::ByteStream - ByteStream =head1 SYNOPSIS use Mojo::ByteStream; # Manipulate bytestream my $stream = Mojo::ByteStream->new('foo_bar_baz'); say $stream->camelize; # Chain methods my $stream = Mojo::ByteStream->new('foo bar baz')->quote; $stream = $stream->unquote->encode('UTF-8')->b64_encode(''); say "$stream"; # Use the alternative constructor use Mojo::ByteStream 'b'; my $stream = b('foobarbaz')->b64_encode('')->say; =head1 DESCRIPTION L provides a more friendly API for the bytestream manipulation functions in L. =head1 FUNCTIONS L implements the following functions. =head2 b my $stream = b('test123'); Construct a new scalar-based L object. =head1 METHODS L implements the following methods. =head2 new my $stream = Mojo::ByteStream->new('test123'); Construct a new scalar-based L object. =head2 b64_decode $stream = $stream->b64_decode; Base64 decode bytestream with L. =head2 b64_encode $stream = $stream->b64_encode; $stream = $stream->b64_encode("\n"); Base64 encode bytestream with L. b('foo bar baz')->b64_encode('')->say; =head2 camelize $stream = $stream->camelize; Camelize bytestream with L. =head2 clone my $stream2 = $stream->clone; Clone bytestream. =head2 decamelize $stream = $stream->decamelize; Decamelize bytestream with L. =head2 decode $stream = $stream->decode; $stream = $stream->decode('iso-8859-1'); Decode bytestream with L, defaults to C. $stream->decode('UTF-16LE')->unquote->trim->say; =head2 encode $stream = $stream->encode; $stream = $stream->encode('iso-8859-1'); Encode bytestream with L, defaults to C. $stream->trim->quote->encode->say; =head2 hmac_sha1_sum $stream = $stream->hmac_sha1_sum('passw0rd'); Generate HMAC-SHA1 checksum for bytestream with L. b('foo bar baz')->hmac_sha1_sum('secr3t')->quote->say; =head2 html_unescape $stream = $stream->html_unescape; Unescape all HTML entities in bytestream with L. b('<html>')->html_unescape->url_escape->say; =head2 md5_bytes $stream = $stream->md5_bytes; Generate binary MD5 checksum for bytestream with L. =head2 md5_sum $stream = $stream->md5_sum; Generate MD5 checksum for bytestream with L. =head2 punycode_decode $stream = $stream->punycode_decode; Punycode decode bytestream with L. =head2 punycode_encode $stream = $stream->punycode_encode; Punycode encode bytestream with L. =head2 quote $stream = $stream->quote; Quote bytestream with L. =head2 say $stream->say; $stream->say(*STDERR); Print bytestream to handle and append a newline, defaults to C. =head2 secure_compare my $bool = $stream->secure_compare($str); Compare bytestream with L. say 'Match!' if b('foo')->secure_compare('foo'); =head2 sha1_bytes $stream = $stream->sha1_bytes; Generate binary SHA1 checksum for bytestream with L. =head2 sha1_sum $stream = $stream->sha1_sum; Generate SHA1 checksum for bytestream with L. =head2 size my $size = $stream->size; Size of bytestream. =head2 slurp $stream = $stream->slurp; Read all data at once from file into bytestream with L. b('/home/sri/myapp.pl')->slurp->split("\n")->shuffle->join("\n")->say; =head2 spurt $stream = $stream->spurt('/home/sri/myapp.pl'); Write all data from bytestream at once to file with L. b('/home/sri/foo.txt')->slurp->squish->spurt('/home/sri/bar.txt'); =head2 split my $collection = $stream->split(','); Turn bytestream into L object containing L objects. b('a,b,c')->split(',')->quote->join(',')->say; =head2 squish $stream = $stream->squish; Trim whitespace characters from both ends of bytestream and then change all consecutive groups of whitespace into one space each with L. =head2 tap $stream = $stream->tap(sub {...}); Alias for L. =head2 to_string my $str = $stream->to_string; my $str = "$stream"; Stringify bytestream. =head2 trim $stream = $stream->trim; Trim whitespace characters from both ends of bytestream with L. =head2 unquote $stream = $stream->unquote; Unquote bytestream with L. =head2 url_escape $stream = $stream->url_escape; $stream = $stream->url_escape('^A-Za-z0-9\-._~'); Percent encode all unsafe characters in bytestream with L. b('foo bar baz')->url_escape->say; =head2 url_unescape $stream = $stream->url_unescape; Decode percent encoded characters in bytestream with L. b('%3Chtml%3E')->url_unescape->xml_escape->say; =head2 xml_escape $stream = $stream->xml_escape; Escape only the characters C<&>, C>, C>, C<"> and C<'> in bytestream with L. =head2 xor_encode $stream = $stream->xor_encode($key); XOR encode bytestream with L. =head1 BYTESTREAM Direct scalar reference access to the bytestream is also possible. $$stream .= 'foo'; =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Cache.pm0000644000175000017500000000232012242771462022176 0ustar cstamascstamaspackage Mojo::Cache; use Mojo::Base -base; has 'max_keys' => 100; sub get { (shift->{cache} || {})->{shift()} } sub set { my ($self, $key, $value) = @_; my $cache = $self->{cache} ||= {}; my $queue = $self->{queue} ||= []; delete $cache->{shift @$queue} if @$queue >= $self->max_keys; push @$queue, $key unless exists $cache->{$key}; $cache->{$key} = $value; return $self; } 1; =encoding utf8 =head1 NAME Mojo::Cache - Naive in-memory cache =head1 SYNOPSIS use Mojo::Cache; my $cache = Mojo::Cache->new(max_keys => 50); $cache->set(foo => 'bar'); my $foo = $cache->get('foo'); =head1 DESCRIPTION L is a naive in-memory cache with size limits. =head1 ATTRIBUTES L implements the following attributes. =head2 max_keys my $max = $cache->max_keys; $cache = $cache->max_keys(50); Maximum number of cache keys, defaults to C<100>. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 get my $value = $cache->get('foo'); Get cached value. =head2 set $cache = $cache->set(foo => 'bar'); Set cached value. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Collection.pm0000644000175000017500000001531412253225521023265 0ustar cstamascstamaspackage Mojo::Collection; use Mojo::Base -strict; use overload bool => sub {1}, '""' => sub { shift->join("\n") }, fallback => 1; use Carp 'croak'; use Exporter 'import'; use List::Util; use Mojo::ByteStream; use Scalar::Util 'blessed'; our @EXPORT_OK = ('c'); sub AUTOLOAD { my $self = shift; my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/; croak "Undefined subroutine &${package}::$method called" unless blessed $self && $self->isa(__PACKAGE__); croak qq{Can't locate object method "$method" via package "$package"} unless @$self; return $self->pluck($method, @_); } sub DESTROY { } sub new { my $class = shift; return bless [@_], ref $class || $class; } sub c { __PACKAGE__->new(@_) } sub compact { shift->grep(sub { length($_ // '') }); } sub each { my ($self, $cb) = @_; return @$self unless $cb; my $i = 1; $_->$cb($i++) for @$self; return $self; } sub first { my ($self, $cb) = @_; return $self->[0] unless $cb; return List::Util::first { $cb->($_) } @$self if ref $cb eq 'CODE'; return List::Util::first { $_ =~ $cb } @$self; } sub flatten { $_[0]->new(_flatten(@{$_[0]})) } sub grep { my ($self, $cb) = @_; return $self->new(grep { $cb->($_) } @$self) if ref $cb eq 'CODE'; return $self->new(grep { $_ =~ $cb } @$self); } sub join { Mojo::ByteStream->new(join $_[1] // '', map({"$_"} @{$_[0]})) } sub map { my ($self, $cb) = @_; return $self->new(map { $_->$cb } @$self); } sub pluck { my ($self, $method, @args) = @_; return $self->map(sub { $_->$method(@args) }); } sub reverse { $_[0]->new(reverse @{$_[0]}) } sub shuffle { $_[0]->new(List::Util::shuffle @{$_[0]}) } sub size { scalar @{$_[0]} } sub slice { my $self = shift; return $self->new(@$self[@_]); } sub sort { my ($self, $cb) = @_; return $self->new($cb ? sort { $a->$cb($b) } @$self : sort @$self); } sub tap { shift->Mojo::Base::tap(@_) } sub uniq { my $self = shift; my %seen; return $self->grep(sub { !$seen{$_}++ }); } sub _flatten { map { _ref($_) ? _flatten(@$_) : $_ } @_; } sub _ref { ref $_[0] && (ref $_[0] eq 'ARRAY' || $_[0]->isa(__PACKAGE__)) } 1; =encoding utf8 =head1 NAME Mojo::Collection - Collection =head1 SYNOPSIS use Mojo::Collection; # Manipulate collection my $collection = Mojo::Collection->new(qw(just works)); unshift @$collection, 'it'; # 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; =head1 DESCRIPTION L is a container for collections. =head1 FUNCTIONS L implements the following functions. =head2 c my $collection = c(1, 2, 3); Construct a new array-based L object. =head1 METHODS L implements the following methods. =head2 new my $collection = Mojo::Collection->new(1, 2, 3); Construct a new array-based L object. =head2 compact my $new = $collection->compact; Create a new collection with all elements that are defined and not an empty string. =head2 each my @elements = $collection->each; $collection = $collection->each(sub {...}); Evaluate callback for each element in collection or return all elements as a list if none has been provided. The element will be the first argument passed to the callback and is also available as C<$_>. $collection->each(sub { my ($e, $count) = @_; say "$count: $e"; }); =head2 first my $first = $collection->first; my $first = $collection->first(qr/foo/); my $first = $collection->first(sub {...}); Evaluate regular expression or callback for each element in collection and return the first one that matched the regular expression, or for which the callback returned true. The element will be the first argument passed to the callback and is also available as C<$_>. my $five = $collection->first(sub { $_ == 5 }); =head2 flatten my $new = $collection->flatten; Flatten nested collections/arrays recursively and create a new collection with all elements. =head2 grep my $new = $collection->grep(qr/foo/); my $new = $collection->grep(sub {...}); Evaluate regular expression or callback for each element in collection and create a new collection with all elements that matched the regular expression, or for which the callback returned true. The element will be the first argument passed to the callback and is also available as C<$_>. my $interesting = $collection->grep(qr/mojo/i); =head2 join my $stream = $collection->join; my $stream = $collection->join("\n"); Turn collection into L. $collection->join("\n")->say; =head2 map my $new = $collection->map(sub {...}); Evaluate callback for each element in collection and create a new collection from the results. The element will be the first argument passed to the callback and is also available as C<$_>. my $doubled = $collection->map(sub { $_ * 2 }); =head2 pluck my $new = $collection->pluck($method); my $new = $collection->pluck($method, @args); Call method on each element in collection and create a new collection from the results. # Equal to but more convenient than my $new = $collection->map(sub { $_->$method(@args) }); =head2 reverse my $new = $collection->reverse; Create a new collection with all elements in reverse order. =head2 slice my $new = $collection->slice(4 .. 7); Create a new collection with all selected elements. =head2 shuffle my $new = $collection->shuffle; Create a new collection with all elements in random order. =head2 size my $size = $collection->size; Number of elements in collection. =head2 sort my $new = $collection->sort; my $new = $collection->sort(sub {...}); Sort elements based on return value of callback and create a new collection from the results. my $insensitive = $collection->sort(sub { uc(shift) cmp uc(shift) }); =head2 tap $collection = $collection->tap(sub {...}); Alias for L. =head2 uniq my $new = $collection->uniq; Create a new collection without duplicate elements. =head1 ELEMENT METHODS In addition to the methods above, you can also call methods provided by all elements in the collection directly and create a new collection from the results, similar to L. push @$collection, Mojo::DOM->new("

$_

") for 1 .. 9; say $collection->find('h1')->type('h2')->prepend_content('Test ')->root; =head1 ELEMENTS Direct array reference access to elements is also possible. say $collection->[23]; say for @$collection; =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Content/0000755000175000017500000000000012256126533022250 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Content/MultiPart.pm0000644000175000017500000001613212242771755024541 0ustar cstamascstamaspackage Mojo::Content::MultiPart; use Mojo::Base 'Mojo::Content'; use Mojo::Util 'b64_encode'; has parts => sub { [] }; sub new { my $self = shift->SUPER::new(@_); $self->on(read => \&_read); return $self; } sub body_contains { my ($self, $chunk) = @_; for my $part (@{$self->parts}) { return 1 if index($part->build_headers, $chunk) >= 0; return 1 if $part->body_contains($chunk); } return undef; } sub body_size { my $self = shift; # Check for existing Content-Lenght header my $content_len = $self->headers->content_length; return $content_len if $content_len; # Calculate length of whole body my $boundary_len = length($self->build_boundary) + 6; my $len = $boundary_len - 2; $len += $_->header_size + $_->body_size + $boundary_len for @{$self->parts}; return $len; } sub build_boundary { my $self = shift; # Check for existing boundary if (defined(my $boundary = $self->boundary)) { return $boundary } # Generate and check boundary my $boundary; my $size = 1; while (1) { $boundary = b64_encode join('', map chr(rand 256), 1 .. $size++ * 3); $boundary =~ s/\W/X/g; last unless $self->body_contains($boundary); } # Add boundary to Content-Type header my $headers = $self->headers; ($headers->content_type // '') =~ m!^(.*multipart/[^;]+)(.*)$!; my $before = $1 || 'multipart/mixed'; my $after = $2 || ''; $headers->content_type("$before; boundary=$boundary$after"); return $boundary; } sub clone { my $self = shift; return undef unless my $clone = $self->SUPER::clone(); return $clone->parts($self->parts); } sub get_body_chunk { my ($self, $offset) = @_; # Body generator return $self->generate_body_chunk($offset) if $self->{dynamic}; # First boundary my $boundary = $self->build_boundary; my $boundary_len = length($boundary) + 6; my $len = $boundary_len - 2; return substr "--$boundary\x0d\x0a", $offset if $len > $offset; # Prepare content part by part my $parts = $self->parts; for (my $i = 0; $i < @$parts; $i++) { my $part = $parts->[$i]; # Headers my $header_len = $part->header_size; return $part->get_header_chunk($offset - $len) if ($len + $header_len) > $offset; $len += $header_len; # Content my $content_len = $part->body_size; return $part->get_body_chunk($offset - $len) if ($len + $content_len) > $offset; $len += $content_len; # Boundary if (($len + $boundary_len) > $offset) { # Last boundary return substr "\x0d\x0a--$boundary--", $offset - $len if $#{$parts} == $i; # Middle boundary return substr "\x0d\x0a--$boundary\x0d\x0a", $offset - $len; } $len += $boundary_len; } } sub is_multipart {1} sub _parse_multipart_body { my ($self, $boundary) = @_; # Whole part in buffer my $pos = index $self->{multipart}, "\x0d\x0a--$boundary"; if ($pos < 0) { my $len = length($self->{multipart}) - (length($boundary) + 8); return undef unless $len > 0; # Store chunk my $chunk = substr $self->{multipart}, 0, $len, ''; $self->parts->[-1] = $self->parts->[-1]->parse($chunk); return undef; } # Store chunk my $chunk = substr $self->{multipart}, 0, $pos, ''; $self->parts->[-1] = $self->parts->[-1]->parse($chunk); return !!($self->{multi_state} = 'multipart_boundary'); } sub _parse_multipart_boundary { my ($self, $boundary) = @_; # Boundary begins if ((index $self->{multipart}, "\x0d\x0a--$boundary\x0d\x0a") == 0) { substr $self->{multipart}, 0, length($boundary) + 6, ''; # New part my $part = Mojo::Content::Single->new(relaxed => 1); $self->emit(part => $part); push @{$self->parts}, $part; return !!($self->{multi_state} = 'multipart_body'); } # Boundary ends my $end = "\x0d\x0a--$boundary--"; if ((index $self->{multipart}, $end) == 0) { substr $self->{multipart}, 0, length $end, ''; $self->{multi_state} = 'finished'; } return undef; } sub _parse_multipart_preamble { my ($self, $boundary) = @_; # No boundary yet return undef if (my $pos = index $self->{multipart}, "--$boundary") < 0; # Replace preamble with carriage return and line feed substr $self->{multipart}, 0, $pos, "\x0d\x0a"; # Parse boundary return !!($self->{multi_state} = 'multipart_boundary'); } sub _read { my ($self, $chunk) = @_; $self->{multipart} .= $chunk; my $boundary = $self->boundary; until (($self->{multi_state} //= 'multipart_preamble') eq 'finished') { # Preamble if ($self->{multi_state} eq 'multipart_preamble') { last unless $self->_parse_multipart_preamble($boundary); } # Boundary elsif ($self->{multi_state} eq 'multipart_boundary') { last unless $self->_parse_multipart_boundary($boundary); } # Body elsif ($self->{multi_state} eq 'multipart_body') { last unless $self->_parse_multipart_body($boundary); } } # Check buffer size $self->{limit} = $self->{state} = 'finished' if length($self->{multipart} // '') > $self->max_buffer_size; } 1; =encoding utf8 =head1 NAME Mojo::Content::MultiPart - HTTP multipart content =head1 SYNOPSIS use Mojo::Content::MultiPart; my $multi = Mojo::Content::MultiPart->new; $multi->parse('Content-Type: multipart/mixed; boundary=---foobar'); my $single = $multi->parts->[4]; =head1 DESCRIPTION L is a container for HTTP multipart content as described in RFC 2616. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 part $multi->on(part => sub { my ($multi, $single) = @_; ... }); Emitted when a new L part starts. $multi->on(part => sub { my ($multi, $single) = @_; return unless $single->headers->content_disposition =~ /name="([^"]+)"/; say "Field: $1"; }); =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 parts my $parts = $multi->parts; $multi = $multi->parts([]); Content parts embedded in this multipart content, usually L objects. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $multi = Mojo::Content::MultiPart->new; Construct a new L object and subscribe to L event with default content parser. =head2 body_contains my $bool = $multi->body_contains('foobarbaz'); Check if content parts contain a specific string. =head2 body_size my $size = $multi->body_size; Content size in bytes. =head2 build_boundary my $boundary = $multi->build_boundary; Generate a suitable boundary for content and add it to C header. =head2 clone my $clone = $multi->clone; Clone content if possible, otherwise return C. =head2 get_body_chunk my $bytes = $multi->get_body_chunk(0); Get a chunk of content starting from a specific position. =head2 is_multipart my $true = $multi->is_multipart; True. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Content/Single.pm0000644000175000017500000000715112254163744024036 0ustar cstamascstamaspackage Mojo::Content::Single; use Mojo::Base 'Mojo::Content'; use Mojo::Asset::Memory; use Mojo::Content::MultiPart; has asset => sub { Mojo::Asset::Memory->new(auto_upgrade => 1) }; has auto_upgrade => 1; sub new { my $self = shift->SUPER::new(@_); $self->{read} = $self->on(read => sub { $_[0]->asset($_[0]->asset->add_chunk($_[1])) }); return $self; } sub body_contains { shift->asset->contains(shift) >= 0 } sub body_size { my $self = shift; return ($self->headers->content_length || 0) if $self->{dynamic}; return $self->asset->size; } sub clone { my $self = shift; return undef unless my $clone = $self->SUPER::clone(); return $clone->asset($self->asset); } sub get_body_chunk { my ($self, $offset) = @_; return $self->generate_body_chunk($offset) if $self->{dynamic}; return $self->asset->get_chunk($offset); } sub parse { my $self = shift; # Parse headers $self->_parse_until_body(@_); # Parse body return $self->SUPER::parse unless $self->auto_upgrade && defined $self->boundary; # Content needs to be upgraded to multipart $self->unsubscribe(read => $self->{read}); my $multi = Mojo::Content::MultiPart->new(%$self); $self->emit(upgrade => $multi); return $multi->parse; } 1; =encoding utf8 =head1 NAME Mojo::Content::Single - HTTP content =head1 SYNOPSIS use Mojo::Content::Single; my $single = Mojo::Content::Single->new; $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!"); say $single->headers->content_length; =head1 DESCRIPTION L is a container for HTTP content as described in RFC 2616. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 upgrade $single->on(upgrade => sub { my ($single, $multi) = @_; ... }); Emitted when content gets upgraded to a L object. $single->on(upgrade => sub { my ($single, $multi) = @_; return unless $multi->headers->content_type =~ /multipart\/([^;]+)/i; say "Multipart: $1"; }); =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 asset my $asset = $single->asset; $single = $single->asset(Mojo::Asset::Memory->new); The actual content, defaults to a L object with C enabled. =head2 auto_upgrade my $upgrade = $single->auto_upgrade; $single = $single->auto_upgrade(0); Try to detect multipart content and automatically upgrade to a L object, defaults to C<1>. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $single = Mojo::Content::Single->new; Construct a new L object and subscribe to L event with default content parser. =head2 body_contains my $bool = $single->body_contains('1234567'); Check if content contains a specific string. =head2 body_size my $size = $single->body_size; Content size in bytes. =head2 clone my $clone = $single->clone; Clone content if possible, otherwise return C. =head2 get_body_chunk my $bytes = $single->get_body_chunk(0); Get a chunk of content starting from a specific position. =head2 parse $single = $single->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!"); my $multi = $single->parse("Content-Type: multipart/form-data\x0d\x0a\x0d\x0a"); Parse content chunk and upgrade to L object if necessary. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Content.pm0000644000175000017500000003261612254163533022615 0ustar cstamascstamaspackage Mojo::Content; use Mojo::Base 'Mojo::EventEmitter'; use Carp 'croak'; use Compress::Raw::Zlib qw(WANT_GZIP Z_STREAM_END); use Mojo::Headers; has [qw(auto_relax relaxed skip_body)]; has headers => sub { Mojo::Headers->new }; has max_buffer_size => sub { $ENV{MOJO_MAX_BUFFER_SIZE} || 262144 }; has max_leftover_size => sub { $ENV{MOJO_MAX_LEFTOVER_SIZE} || 262144 }; sub body_contains { croak 'Method "body_contains" not implemented by subclass'; } sub body_size { croak 'Method "body_size" not implemented by subclass' } sub boundary { return undef unless my $type = shift->headers->content_type; $type =~ m!multipart.*boundary\s*=\s*(?:"([^"]+)"|([\w'(),.:?\-+/]+))!i and return $1 // $2; return undef; } sub build_body { shift->_build('get_body_chunk') } sub build_headers { shift->_build('get_header_chunk') } sub charset { my $type = shift->headers->content_type // ''; return $type =~ /charset\s*=\s*"?([^"\s;]+)"?/i ? $1 : undef; } sub clone { my $self = shift; return undef if $self->is_dynamic; return $self->new(headers => $self->headers->clone); } sub generate_body_chunk { my ($self, $offset) = @_; $self->emit(drain => $offset) if !delete $self->{delay} && !length($self->{body_buffer} // ''); my $chunk = delete $self->{body_buffer} // ''; return $self->{eof} ? '' : undef unless length $chunk; return $chunk; } sub get_body_chunk { croak 'Method "get_body_chunk" not implemented by subclass'; } sub get_header_chunk { my ($self, $offset) = @_; unless (defined $self->{header_buffer}) { my $headers = $self->headers->to_string; $self->{header_buffer} = $headers ? "$headers\x0d\x0a\x0d\x0a" : "\x0d\x0a"; } return substr $self->{header_buffer}, $offset, 131072; } sub header_size { length shift->build_headers } sub is_chunked { !!shift->headers->transfer_encoding } sub is_compressed { (shift->headers->content_encoding // '') =~ /^gzip$/i } sub is_dynamic { $_[0]{dynamic} && !defined $_[0]->headers->content_length } sub is_finished { (shift->{state} // '') eq 'finished' } sub is_limit_exceeded { !!shift->{limit} } sub is_multipart {undef} sub is_parsing_body { (shift->{state} // '') eq 'body' } sub leftovers { shift->{buffer} } sub parse { my $self = shift; # Headers $self->_parse_until_body(@_); return $self if $self->{state} eq 'headers'; $self->emit('body') unless $self->{body}++; # Chunked content $self->{real_size} //= 0; if ($self->is_chunked && $self->{state} ne 'headers') { $self->_parse_chunked; $self->{state} = 'finished' if ($self->{chunk_state} // '') eq 'finished'; } # Not chunked, pass through to second buffer else { $self->{real_size} += length $self->{pre_buffer}; my $limit = $self->is_finished && length($self->{buffer}) > $self->max_leftover_size; $self->{buffer} .= $self->{pre_buffer} unless $limit; $self->{pre_buffer} = ''; } # No content if ($self->skip_body) { $self->{state} = 'finished'; return $self; } # Relaxed parsing my $headers = $self->headers; if ($self->auto_relax) { my $connection = $headers->connection // ''; my $len = $headers->content_length // ''; $self->relaxed(1) if !length $len && ($connection =~ /close/i || $headers->content_type); } # Chunked or relaxed content if ($self->is_chunked || $self->relaxed) { $self->{size} += length($self->{buffer} //= ''); $self->_uncompress($self->{buffer}); $self->{buffer} = ''; } # Normal content else { my $len = $headers->content_length || 0; $self->{size} ||= 0; if ((my $need = $len - $self->{size}) > 0) { my $len = length $self->{buffer}; my $chunk = substr $self->{buffer}, 0, $need > $len ? $len : $need, ''; $self->_uncompress($chunk); $self->{size} += length $chunk; } $self->{state} = 'finished' if $len <= $self->progress; } return $self; } sub parse_body { my $self = shift; $self->{state} = 'body'; return $self->parse(@_); } sub progress { my $self = shift; return 0 unless my $state = $self->{state}; return 0 unless $state eq 'body' || $state eq 'finished'; return $self->{raw_size} - ($self->{header_size} || 0); } sub write { my ($self, $chunk, $cb) = @_; $self->{dynamic} = 1; if (defined $chunk) { $self->{body_buffer} .= $chunk } else { $self->{delay} = 1 } $self->once(drain => $cb) if $cb; $self->{eof} = 1 if defined $chunk && $chunk eq ''; return $self; } sub write_chunk { my ($self, $chunk, $cb) = @_; $self->headers->transfer_encoding('chunked') unless $self->is_chunked; $self->write(defined $chunk ? $self->_build_chunk($chunk) : $chunk, $cb); $self->{eof} = 1 if defined $chunk && $chunk eq ''; return $self; } sub _build { my ($self, $method) = @_; my $buffer = ''; my $offset = 0; while (1) { # No chunk yet, try again next unless defined(my $chunk = $self->$method($offset)); # End of part last unless my $len = length $chunk; $offset += $len; $buffer .= $chunk; } return $buffer; } sub _build_chunk { my ($self, $chunk) = @_; # End return "\x0d\x0a0\x0d\x0a\x0d\x0a" if length $chunk == 0; # First chunk has no leading CRLF my $crlf = $self->{chunks}++ ? "\x0d\x0a" : ''; return $crlf . sprintf('%x', length $chunk) . "\x0d\x0a$chunk"; } sub _parse_chunked { my $self = shift; # Trailing headers return $self->_parse_chunked_trailing_headers if ($self->{chunk_state} // '') eq 'trailing_headers'; while (my $len = length $self->{pre_buffer}) { # Start new chunk (ignore the chunk extension) unless ($self->{chunk_len}) { last unless $self->{pre_buffer} =~ s/^(?:\x0d?\x0a)?([0-9a-fA-F]+).*\x0a//; next if $self->{chunk_len} = hex $1; # Last chunk $self->{chunk_state} = 'trailing_headers'; last; } # Remove as much as possible from payload $len = $self->{chunk_len} if $self->{chunk_len} < $len; $self->{buffer} .= substr $self->{pre_buffer}, 0, $len, ''; $self->{real_size} += $len; $self->{chunk_len} -= $len; } # Trailing headers $self->_parse_chunked_trailing_headers if ($self->{chunk_state} // '') eq 'trailing_headers'; # Check buffer size $self->{limit} = $self->{state} = 'finished' if length($self->{pre_buffer} // '') > $self->max_buffer_size; } sub _parse_chunked_trailing_headers { my $self = shift; my $headers = $self->headers->parse(delete $self->{pre_buffer}); return unless $headers->is_finished; $self->{chunk_state} = 'finished'; # Replace Transfer-Encoding with Content-Length $headers->remove('Transfer-Encoding'); $headers->content_length($self->{real_size}) unless $headers->content_length; } sub _parse_headers { my $self = shift; my $headers = $self->headers->parse(delete $self->{pre_buffer}); return unless $headers->is_finished; $self->{state} = 'body'; # Take care of leftovers my $leftovers = $self->{pre_buffer} = $headers->leftovers; $self->{header_size} = $self->{raw_size} - length $leftovers; $self->emit('body') unless $self->{body}++; } sub _parse_until_body { my ($self, $chunk) = @_; $self->{raw_size} += length($chunk //= ''); $self->{pre_buffer} .= $chunk; unless ($self->{state}) { $self->{header_size} = $self->{raw_size} - length $self->{pre_buffer}; $self->{state} = 'headers'; } $self->_parse_headers if ($self->{state} // '') eq 'headers'; } sub _uncompress { my ($self, $chunk) = @_; # No compression return $self->emit(read => $chunk) unless $self->is_compressed; # Uncompress $self->{post_buffer} .= $chunk; my $gz = $self->{gz} //= Compress::Raw::Zlib::Inflate->new(WindowBits => WANT_GZIP); my $status = $gz->inflate(\$self->{post_buffer}, my $out); $self->emit(read => $out) if defined $out; # Replace Content-Encoding with Content-Length $self->headers->content_length($gz->total_out)->remove('Content-Encoding') if $status == Z_STREAM_END; # Check buffer size $self->{limit} = $self->{state} = 'finished' if length($self->{post_buffer} // '') > $self->max_buffer_size; } 1; =encoding utf8 =head1 NAME Mojo::Content - HTTP content base class =head1 SYNOPSIS package Mojo::Content::MyContent; use Mojo::Base 'Mojo::Content'; sub body_contains {...} sub body_size {...} sub get_body_chunk {...} =head1 DESCRIPTION L is an abstract base class for HTTP content as described in RFC 2616. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 body $content->on(body => sub { my $content = shift; ... }); Emitted once all headers have been parsed and the body starts. $content->on(body => sub { my $content = shift; $content->auto_upgrade(0) if $content->headers->header('X-No-MultiPart'); }); =head2 drain $content->on(drain => sub { my ($content, $offset) = @_; ... }); Emitted once all data has been written. $content->on(drain => sub { my $content = shift; $content->write_chunk(time); }); =head2 read $content->on(read => sub { my ($content, $bytes) = @_; ... }); Emitted when a new chunk of content arrives. $content->unsubscribe('read'); $content->on(read => sub { my ($content, $bytes) = @_; say "Streaming: $bytes"; }); =head1 ATTRIBUTES L implements the following attributes. =head2 auto_relax my $bool = $content->auto_relax; $content = $content->auto_relax($bool); Try to detect when relaxed parsing is necessary. =head2 headers my $headers = $content->headers; $content = $content->headers(Mojo::Headers->new); Content headers, defaults to a L object. =head2 max_buffer_size my $size = $content->max_buffer_size; $content = $content->max_buffer_size(1024); Maximum size in bytes of buffer for content parser, defaults to the value of the MOJO_MAX_BUFFER_SIZE environment variable or C<262144>. =head2 max_leftover_size my $size = $content->max_leftover_size; $content = $content->max_leftover_size(1024); Maximum size in bytes of buffer for pipelined HTTP requests, defaults to the value of the MOJO_MAX_LEFTOVER_SIZE environment variable or C<262144>. =head2 relaxed my $bool = $content->relaxed; $content = $content->relaxed($bool); Activate relaxed parsing for responses that are terminated with a connection close. =head2 skip_body my $bool = $content->skip_body; $content = $content->skip_body($bool); Skip body parsing and finish after headers. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 body_contains my $bool = $content->body_contains('foo bar baz'); Check if content contains a specific string. Meant to be overloaded in a subclass. =head2 body_size my $size = $content->body_size; Content size in bytes. Meant to be overloaded in a subclass. =head2 boundary my $boundary = $content->boundary; Extract multipart boundary from C header. =head2 build_body my $str = $content->build_body; Render whole body. =head2 build_headers my $str = $content->build_headers; Render all headers. =head2 charset my $charset = $content->charset; Extract charset from C header. =head2 clone my $clone = $content->clone; Clone content if possible, otherwise return C. =head2 generate_body_chunk my $bytes = $content->generate_body_chunk(0); Generate dynamic content. =head2 get_body_chunk my $bytes = $content->get_body_chunk(0); Get a chunk of content starting from a specific position. Meant to be overloaded in a subclass. =head2 get_header_chunk my $bytes = $content->get_header_chunk(13); Get a chunk of the headers starting from a specific position. =head2 header_size my $size = $content->header_size; Size of headers in bytes. =head2 is_chunked my $bool = $content->is_chunked; Check if content is chunked. =head2 is_compressed my $bool = $content->is_compressed; Check if content is C compressed. =head2 is_dynamic my $bool = $content->is_dynamic; Check if content will be dynamically generated, which prevents L from working. =head2 is_finished my $bool = $content->is_finished; Check if parser is finished. =head2 is_limit_exceeded my $bool = $content->is_limit_exceeded; Check if buffer has exceeded L. =head2 is_multipart my $false = $content->is_multipart; False. =head2 is_parsing_body my $bool = $content->is_parsing_body; Check if body parsing started yet. =head2 leftovers my $bytes = $content->leftovers; Get leftover data from content parser. =head2 parse $content = $content->parse("Content-Length: 12\x0d\x0a\x0d\x0aHello World!"); Parse content chunk. =head2 parse_body $content = $content->parse_body('Hi!'); Parse body chunk and skip headers. =head2 progress my $size = $content->progress; Size of content already received from message in bytes. =head2 write $content = $content->write($bytes); $content = $content->write($bytes => sub {...}); Write dynamic content non-blocking, the optional drain callback will be invoked once all data has been written. =head2 write_chunk $content = $content->write_chunk($bytes); $content = $content->write_chunk($bytes => sub {...}); Write dynamic content non-blocking with C transfer encoding, the optional drain callback will be invoked once all data has been written. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Cookie/0000755000175000017500000000000012256126533022047 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Cookie/Request.pm0000644000175000017500000000260512242771751024043 0ustar cstamascstamaspackage Mojo::Cookie::Request; use Mojo::Base 'Mojo::Cookie'; use Mojo::Util qw(quote split_header); sub parse { my ($self, $str) = @_; my @cookies; my @pairs = map {@$_} @{split_header($str // '')}; while (@pairs) { my ($name, $value) = (shift @pairs, shift @pairs); next if $name =~ /^\$/; push @cookies, $self->new(name => $name, value => $value // ''); } return \@cookies; } sub to_string { my $self = shift; return '' unless length(my $name = $self->name // ''); my $value = $self->value // ''; return join '=', $name, $value =~ /[,;" ]/ ? quote($value) : $value; } 1; =encoding utf8 =head1 NAME Mojo::Cookie::Request - HTTP request cookie =head1 SYNOPSIS use Mojo::Cookie::Request; my $cookie = Mojo::Cookie::Request->new; $cookie->name('foo'); $cookie->value('bar'); say "$cookie"; =head1 DESCRIPTION L is a container for HTTP request cookies as described in RFC 6265. =head1 ATTRIBUTES L inherits all attributes from L. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 parse my $cookies = Mojo::Cookie::Request->parse('f=b; g=a'); Parse cookies. =head2 to_string my $str = $cookie->to_string; Render cookie. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Cookie/Response.pm0000644000175000017500000000751712242771747024225 0ustar cstamascstamaspackage Mojo::Cookie::Response; use Mojo::Base 'Mojo::Cookie'; use Mojo::Date; use Mojo::Util qw(quote split_header); has [qw(domain httponly max_age origin path secure)]; sub expires { my $self = shift; # Upgrade my $e = $self->{expires}; return $self->{expires} = defined $e && !ref $e ? Mojo::Date->new($e) : $e unless @_; $self->{expires} = shift; return $self; } sub parse { my ($self, $str) = @_; my @cookies; my $tree = split_header($str // ''); while (my $pairs = shift @$tree) { my $i = 0; while (@$pairs) { my ($name, $value) = (shift @$pairs, shift @$pairs); # "expires" is a special case, thank you Netscape... if ($name =~ /^expires$/i) { push @$pairs, @{shift @$tree // []}; my $len = ($pairs->[0] // '') =~ /-/ ? 6 : 10; $value .= join ' ', ',', grep {defined} splice @$pairs, 0, $len; } # This will only run once push @cookies, $self->new(name => $name, value => $value // '') and next unless $i++; # Attributes (Netscape and RFC 6265) next unless $name =~ /^(expires|domain|path|secure|max-age|httponly)$/i; my $attr = lc $1; $attr = 'max_age' if $attr eq 'max-age'; $cookies[-1] ->$attr($attr eq 'secure' || $attr eq 'httponly' ? 1 : $value); } } return \@cookies; } sub to_string { my $self = shift; # Name and value (Netscape) return '' unless length(my $name = $self->name // ''); my $value = $self->value // ''; my $cookie = join '=', $name, $value =~ /[,;" ]/ ? quote($value) : $value; # "expires" (Netscape) if (defined(my $e = $self->expires)) { $cookie .= "; expires=$e" } # "domain" (Netscape) if (my $domain = $self->domain) { $cookie .= "; domain=$domain" } # "path" (Netscape) if (my $path = $self->path) { $cookie .= "; path=$path" } # "secure" (Netscape) $cookie .= "; secure" if $self->secure; # "Max-Age" (RFC 6265) if (defined(my $max = $self->max_age)) { $cookie .= "; Max-Age=$max" } # "HttpOnly" (RFC 6265) $cookie .= "; HttpOnly" if $self->httponly; return $cookie; } 1; =encoding utf8 =head1 NAME Mojo::Cookie::Response - HTTP response cookie =head1 SYNOPSIS use Mojo::Cookie::Response; my $cookie = Mojo::Cookie::Response->new; $cookie->name('foo'); $cookie->value('bar'); say "$cookie"; =head1 DESCRIPTION L is a container for HTTP response cookies as described in RFC 6265. =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 domain my $domain = $cookie->domain; $cookie = $cookie->domain('localhost'); Cookie domain. =head2 httponly my $bool = $cookie->httponly; $cookie = $cookie->httponly($bool); HttpOnly flag, which can prevent client-side scripts from accessing this cookie. =head2 max_age my $max_age = $cookie->max_age; $cookie = $cookie->max_age(60); Max age for cookie. =head2 origin my $origin = $cookie->origin; $cookie = $cookie->origin('mojolicio.us'); Origin of the cookie. =head2 path my $path = $cookie->path; $cookie = $cookie->path('/test'); Cookie path. =head2 secure my $bool = $cookie->secure; $cookie = $cookie->secure($bool); Secure flag, which instructs browsers to only send this cookie over HTTPS connections. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 expires my $expires = $cookie->expires; $cookie = $cookie->expires(time + 60); $cookie = $cookie->expires(Mojo::Date->new(time + 60)); Expiration for cookie. =head2 parse my $cookies = Mojo::Cookie::Response->parse('f=b; path=/'); Parse cookies. =head2 to_string my $str = $cookie->to_string; Render cookie. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Cookie.pm0000644000175000017500000000244212242771453022411 0ustar cstamascstamaspackage Mojo::Cookie; use Mojo::Base -base; use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1; use Carp 'croak'; has [qw(name value)]; sub parse { croak 'Method "parse" not implemented by subclass' } sub to_string { croak 'Method "to_string" not implemented by subclass' } 1; =encoding utf8 =head1 NAME Mojo::Cookie - HTTP cookie base class =head1 SYNOPSIS package Mojo::Cookie::MyCookie; use Mojo::Base 'Mojo::Cookie'; sub parse {...} sub to_string {...} =head1 DESCRIPTION L is an abstract base class for HTTP cookies as described in RFC 6265. =head1 ATTRIBUTES L implements the following attributes. =head2 name my $name = $cookie->name; $cookie = $cookie->name('foo'); Cookie name. =head2 value my $value = $cookie->value; $cookie = $cookie->value('/test'); Cookie value. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 parse my $cookies = $cookie->parse($str); Parse cookies. Meant to be overloaded in a subclass. =head2 to_string my $str = $cookie->to_string; my $str = "$cookie"; Render cookie. Meant to be overloaded in a subclass. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Date.pm0000644000175000017500000000623412242771451022056 0ustar cstamascstamaspackage Mojo::Date; use Mojo::Base -base; use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1; use Time::Local 'timegm'; has 'epoch'; my @DAYS = qw(Sun Mon Tue Wed Thu Fri Sat); my @MONTHS = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); my %MONTHS; @MONTHS{@MONTHS} = (0 .. 11); sub new { shift->SUPER::new->parse(@_) } sub parse { my ($self, $date) = @_; # Invalid return $self unless defined $date; # epoch (784111777) return $self->epoch($date) if $date =~ /^\d+$/; # RFC 822/1123 (Sun, 06 Nov 1994 08:49:37 GMT) my ($day, $month, $year, $h, $m, $s); if ($date =~ /^\w+\,\s+(\d+)\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+GMT$/) { ($day, $month, $year, $h, $m, $s) = ($1, $MONTHS{$2}, $3, $4, $5, $6); } # RFC 850/1036 (Sunday, 06-Nov-94 08:49:37 GMT) elsif ($date =~ /^\w+\,\s+(\d+)-(\w+)-(\d+)\s+(\d+):(\d+):(\d+)\s+GMT$/) { ($day, $month, $year, $h, $m, $s) = ($1, $MONTHS{$2}, $3, $4, $5, $6); } # ANSI C asctime() (Sun Nov 6 08:49:37 1994) elsif ($date =~ /^\w+\s+(\w+)\s+(\d+)\s+(\d+):(\d+):(\d+)\s+(\d+)$/) { ($month, $day, $h, $m, $s, $year) = ($MONTHS{$1}, $2, $3, $4, $5, $6); } # Invalid else { return $self } # Prevent crash my $epoch = eval { timegm($s, $m, $h, $day, $month, $year) }; return defined $epoch && $epoch >= 0 ? $self->epoch($epoch) : $self; } sub to_string { my $self = shift; # RFC 2616 (Sun, 06 Nov 1994 08:49:37 GMT) my ($s, $m, $h, $mday, $month, $year, $wday) = gmtime($self->epoch // time); return sprintf '%s, %02d %s %04d %02d:%02d:%02d GMT', $DAYS[$wday], $mday, $MONTHS[$month], $year + 1900, $h, $m, $s; } 1; =encoding utf8 =head1 NAME Mojo::Date - HTTP date =head1 SYNOPSIS use Mojo::Date; # Parse my $date = Mojo::Date->new('Sun, 06 Nov 1994 08:49:37 GMT'); say $date->epoch; # Build my $date = Mojo::Date->new(time); say "$date"; =head1 DESCRIPTION L implements HTTP date and time functions as described in RFC 2616. Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format =head1 ATTRIBUTES L implements the following attributes. =head2 epoch my $epoch = $date->epoch; $date = $date->epoch(784111777); Epoch seconds. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $date = Mojo::Date->new; my $date = Mojo::Date->new('Sun Nov 6 08:49:37 1994'); Construct a new L object and L date if necessary. =head2 parse $date = $date->parse('Sun Nov 6 08:49:37 1994'); Parse date. # Epoch say Mojo::Date->new('784111777')->epoch; # RFC 822/1123 say Mojo::Date->new('Sun, 06 Nov 1994 08:49:37 GMT')->epoch; # RFC 850/1036 say Mojo::Date->new('Sunday, 06-Nov-94 08:49:37 GMT')->epoch; # Ansi C asctime() say Mojo::Date->new('Sun Nov 6 08:49:37 1994')->epoch; =head2 to_string my $str = $date->to_string; my $str = "$date"; Render date suitable for HTTP messages. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/DOM/0000755000175000017500000000000012256126533021255 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/DOM/CSS.pm0000644000175000017500000003460312254656166022261 0ustar cstamascstamaspackage Mojo::DOM::CSS; use Mojo::Base -base; has 'tree'; my $ESCAPE_RE = qr/\\[^0-9a-fA-F]|\\[0-9a-fA-F]{1,6}/; my $ATTR_RE = qr/ \[ ((?:$ESCAPE_RE|[\w\-])+) # Key (?: (\W)? # Operator = (?:"((?:\\"|[^"])*)"|([^\]]+)) # Value )? \] /x; my $CLASS_ID_RE = qr/ (?: (?:\.((?:\\\.|[^\#.])+)) # Class | (?:\#((?:\\\#|[^.\#])+)) # ID ) /x; my $PSEUDO_CLASS_RE = qr/(?::([\w\-]+)(?:\(((?:\([^)]+\)|[^)])+)\))?)/; my $TOKEN_RE = qr/ (\s*,\s*)? # Separator ((?:[^[\\:\s,]|$ESCAPE_RE\s?)+)? # Element ($PSEUDO_CLASS_RE*)? # Pseudoclass ((?:$ATTR_RE)*)? # Attributes (?: \s* ([>+~]) # Combinator )? /x; sub match { my $self = shift; my $tree = $self->tree; return undef if $tree->[0] eq 'root'; return $self->_match($self->_compile(shift), $tree, $tree); } sub select { shift->_select(0, @_) } sub select_one { shift->_select(1, @_) } sub _ancestor { my ($self, $selectors, $current, $tree) = @_; while ($current = $current->[3]) { return undef if $current->[0] eq 'root' || $current eq $tree; return 1 if $self->_combinator($selectors, $current, $tree); } return undef; } sub _attr { my ($self, $key, $regex, $current) = @_; # Ignore namespace prefix my $attrs = $current->[2]; for my $name (keys %$attrs) { next unless $name =~ /(?:^|:)$key$/; return 1 unless defined $attrs->{$name} && defined $regex; return 1 if $attrs->{$name} =~ $regex; } return undef; } sub _combinator { my ($self, $selectors, $current, $tree) = @_; # Selector my @s = @$selectors; return undef unless my $combinator = shift @s; if ($combinator->[0] ne 'combinator') { return undef unless $self->_selector($combinator, $current); return 1 unless $combinator = shift @s; } # " " (ancestor) my $c = $combinator->[1]; if ($c eq ' ') { return undef unless $self->_ancestor(\@s, $current, $tree) } # ">" (parent only) elsif ($c eq '>') { return undef unless $self->_parent(\@s, $current, $tree); } # "~" (preceding siblings) elsif ($c eq '~') { return undef unless $self->_sibling(\@s, $current, $tree, 0); } # "+" (immediately preceding siblings) elsif ($c eq '+') { return undef unless $self->_sibling(\@s, $current, $tree, 1); } return 1; } sub _compile { my ($self, $css) = @_; my $pattern = [[]]; while ($css =~ /$TOKEN_RE/g) { my ($separator, $element, $pc, $attrs, $combinator) = ($1, $2 // '', $3, $6, $11); next unless $separator || $element || $pc || $attrs || $combinator; # New selector push @$pattern, [] if $separator; my $part = $pattern->[-1]; # Empty combinator push @$part, [combinator => ' '] if $part->[-1] && $part->[-1][0] ne 'combinator'; # Selector push @$part, ['element']; my $selector = $part->[-1]; # Element my $tag = '*'; $element =~ s/^((?:\\\.|\\\#|[^.#])+)// and $tag = $self->_unescape($1); # Tag push @$selector, ['tag', $tag]; # Class or ID while ($element =~ /$CLASS_ID_RE/g) { push @$selector, ['attr', 'class', $self->_regex('~', $1)] if defined $1; push @$selector, ['attr', 'id', $self->_regex('', $2)] if defined $2; } # Pseudo classes while ($pc =~ /$PSEUDO_CLASS_RE/g) { # "not" if ($1 eq 'not') { my $subpattern = $self->_compile($2)->[-1][-1]; push @$selector, ['pc', 'not', $subpattern]; } # Everything else else { push @$selector, ['pc', $1, $2] } } # Attributes while ($attrs =~ /$ATTR_RE/g) { my ($key, $op, $value) = ($self->_unescape($1), $2 // '', $3 // $4); push @$selector, ['attr', $key, $self->_regex($op, $value)]; } # Combinator push @$part, [combinator => $combinator] if $combinator; } return $pattern; } sub _equation { my ($self, $equation) = @_; # "even" return [2, 2] if $equation =~ /^even$/i; # "odd" return [2, 1] if $equation =~ /^odd$/i; # Equation my $num = [1, 1]; return $num if $equation !~ /(?:(-?(?:\d+)?)?(n))?\s*\+?\s*(-?\s*\d+)?\s*$/i; $num->[0] = defined($1) && length($1) ? $1 : $2 ? 1 : 0; $num->[0] = -1 if $num->[0] eq '-'; $num->[1] = $3 // 0; $num->[1] =~ s/\s+//g; return $num; } sub _match { my ($self, $pattern, $current, $tree) = @_; $self->_combinator([reverse @$_], $current, $tree) and return 1 for @$pattern; return undef; } sub _parent { my ($self, $selectors, $current, $tree) = @_; return undef unless my $parent = $current->[3]; return undef if $parent->[0] eq 'root'; return $self->_combinator($selectors, $parent, $tree); } sub _pc { my ($self, $class, $args, $current) = @_; # ":first-*" if ($class =~ /^first-(?:(child)|of-type)$/) { $class = defined $1 ? 'nth-child' : 'nth-of-type'; $args = 1; } # ":last-*" elsif ($class =~ /^last-(?:(child)|of-type)$/) { $class = defined $1 ? 'nth-last-child' : 'nth-last-of-type'; $args = '-n+1'; } # ":checked" if ($class eq 'checked') { my $attrs = $current->[2]; return 1 if exists $attrs->{checked} || exists $attrs->{selected}; } # ":empty" elsif ($class eq 'empty') { return 1 unless defined $current->[4] } # ":root" elsif ($class eq 'root') { if (my $parent = $current->[3]) { return 1 if $parent->[0] eq 'root' } } # ":not" elsif ($class eq 'not') { return 1 if !$self->_selector($args, $current) } # ":nth-*" elsif ($class =~ /^nth-/) { # Numbers $args = $self->_equation($args) unless ref $args; # Siblings my $parent = $current->[3]; my @siblings; my $type = $class =~ /of-type$/ ? $current->[1] : undef; for my $i (($parent->[0] eq 'root' ? 1 : 4) .. $#$parent) { my $sibling = $parent->[$i]; next unless $sibling->[0] eq 'tag'; next if defined $type && $type ne $sibling->[1]; push @siblings, $sibling; } # Reverse @siblings = reverse @siblings if $class =~ /^nth-last/; # Find for my $i (0 .. $#siblings) { my $result = $args->[0] * $i + $args->[1]; next if $result < 1; last unless my $sibling = $siblings[$result - 1]; return 1 if $sibling eq $current; } } # ":only-*" elsif ($class =~ /^only-(?:child|(of-type))$/) { my $type = $1 ? $current->[1] : undef; # Siblings my $parent = $current->[3]; for my $i (($parent->[0] eq 'root' ? 1 : 4) .. $#$parent) { my $sibling = $parent->[$i]; next if $sibling->[0] ne 'tag' || $sibling eq $current; return undef unless defined $type && $sibling->[1] ne $type; } # No siblings return 1; } return undef; } sub _regex { my ($self, $op, $value) = @_; return undef unless defined $value; $value = quotemeta $self->_unescape($value); # "~=" (word) return qr/(?:^|.*\s+)$value(?:\s+.*|$)/ if $op eq '~'; # "*=" (contains) return qr/$value/ if $op eq '*'; # "^=" (begins with) return qr/^$value/ if $op eq '^'; # "$=" (ends with) return qr/$value$/ if $op eq '$'; # Everything else 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) = @_; for my $s (@$selector[1 .. $#$selector]) { my $type = $s->[0]; # Tag (ignore namespace prefix) if ($type eq 'tag') { my $tag = $s->[1]; return undef unless $tag eq '*' || $current->[1] =~ /(?:^|:)$tag$/; } # Attribute elsif ($type eq 'attr') { return undef unless $self->_attr(@$s[1, 2], $current); } # Pseudo class elsif ($type eq 'pc') { return undef unless $self->_pc(lc $s->[1], $s->[2], $current); } } return 1; } sub _sibling { my ($self, $selectors, $current, $tree, $immediate) = @_; my $parent = $current->[3]; my $found; for my $e (@$parent[($parent->[0] eq 'root' ? 1 : 4) .. $#$parent]) { return $found if $e eq $current; next unless $e->[0] eq 'tag'; # "+" (immediately preceding sibling) if ($immediate) { $found = $self->_combinator($selectors, $e, $tree) } # "~" (preceding sibling) else { return 1 if $self->_combinator($selectors, $e, $tree) } } return undef; } sub _unescape { my ($self, $value) = @_; # Remove escaped newlines $value =~ s/\\\n//g; # Unescape Unicode characters $value =~ s/\\([0-9a-fA-F]{1,6})\s?/pack('U', hex $1)/ge; # Remove backslash $value =~ s/\\//g; return $value; } 1; =encoding utf8 =head1 NAME Mojo::DOM::CSS - CSS selector engine =head1 SYNOPSIS use Mojo::DOM::CSS; # Select elements from DOM tree my $css = Mojo::DOM::CSS->new(tree => $tree); my $elements = $css->select('h1, h2, h3'); =head1 DESCRIPTION L is the CSS selector engine used by L. =head1 SELECTORS All CSS selectors that make sense for a standalone parser are supported. =head2 * Any element. my $all = $css->select('*'); =head2 E An element of type C. my $title = $css->select('title'); =head2 E[foo] An C element with a C attribute. my $links = $css->select('a[href]'); =head2 E[foo="bar"] An C element whose C attribute value is exactly equal to C. my $fields = $css->select('input[name="foo"]'); =head2 E[foo~="bar"] An C element whose C attribute value is a list of whitespace-separated values, one of which is exactly equal to C. my $fields = $css->select('input[name~="foo"]'); =head2 E[foo^="bar"] An C element whose C attribute value begins exactly with the string C. my $fields = $css->select('input[name^="f"]'); =head2 E[foo$="bar"] An C element whose C attribute value ends exactly with the string C. my $fields = $css->select('input[name$="o"]'); =head2 E[foo*="bar"] An C element whose C attribute value contains the substring C. my $fields = $css->select('input[name*="fo"]'); =head2 E:root An C element, root of the document. my $root = $css->select(':root'); =head2 E:checked A user interface element C which is checked (for instance a radio-button or checkbox). my $input = $css->select(':checked'); =head2 E:empty An C element that has no children (including text nodes). my $empty = $css->select(':empty'); =head2 E:nth-child(n) An C element, the C child of its parent. my $third = $css->select('div:nth-child(3)'); my $odd = $css->select('div:nth-child(odd)'); my $even = $css->select('div:nth-child(even)'); my $top3 = $css->select('div:nth-child(-n+3)'); =head2 E:nth-last-child(n) An C element, the C child of its parent, counting from the last one. my $third = $css->select('div:nth-last-child(3)'); my $odd = $css->select('div:nth-last-child(odd)'); my $even = $css->select('div:nth-last-child(even)'); my $bottom3 = $css->select('div:nth-last-child(-n+3)'); =head2 E:nth-of-type(n) An C element, the C sibling of its type. my $third = $css->select('div:nth-of-type(3)'); my $odd = $css->select('div:nth-of-type(odd)'); my $even = $css->select('div:nth-of-type(even)'); my $top3 = $css->select('div:nth-of-type(-n+3)'); =head2 E:nth-last-of-type(n) An C element, the C sibling of its type, counting from the last one. my $third = $css->select('div:nth-last-of-type(3)'); my $odd = $css->select('div:nth-last-of-type(odd)'); my $even = $css->select('div:nth-last-of-type(even)'); my $bottom3 = $css->select('div:nth-last-of-type(-n+3)'); =head2 E:first-child An C element, first child of its parent. my $first = $css->select('div p:first-child'); =head2 E:last-child An C element, last child of its parent. my $last = $css->select('div p:last-child'); =head2 E:first-of-type An C element, first sibling of its type. my $first = $css->select('div p:first-of-type'); =head2 E:last-of-type An C element, last sibling of its type. my $last = $css->select('div p:last-of-type'); =head2 E:only-child An C element, only child of its parent. my $lonely = $css->select('div p:only-child'); =head2 E:only-of-type An C element, only sibling of its type. my $lonely = $css->select('div p:only-of-type'); =head2 E.warning my $warning = $css->select('div.warning'); An C element whose class is "warning". =head2 E#myid my $foo = $css->select('div#foo'); An C element with C equal to "myid". =head2 E:not(s) An C element that does not match simple selector C. my $others = $css->select('div p:not(:first-child)'); =head2 E F An C element descendant of an C element. my $headlines = $css->select('div h1'); =head2 E E F An C element child of an C element. my $headlines = $css->select('html > body > div > h1'); =head2 E + F An C element immediately preceded by an C element. my $second = $css->select('h1 + h2'); =head2 E ~ F An C element preceded by an C element. my $second = $css->select('h1 ~ h2'); =head2 E, F, G Elements of type C, C and C. my $headlines = $css->select('h1, h2, h3'); =head2 E[foo=bar][bar=baz] An C element whose attributes match all following attribute selectors. my $links = $css->select('a[foo^=b][foo$=ar]'); =head1 ATTRIBUTES L implements the following attributes. =head2 tree my $tree = $css->tree; $css = $css->tree(['root', ['text', 'foo']]); Document Object Model. Note that this structure should only be used very carefully since it is very dynamic. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 match my $bool = $css->match('head > title'); Match CSS selector against first node in L. =head2 select my $results = $css->select('head > title'); 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. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/DOM/HTML.pm0000644000175000017500000002065512246232147022365 0ustar cstamascstamaspackage Mojo::DOM::HTML; use Mojo::Base -base; use Mojo::Util qw(html_unescape xml_escape); use Scalar::Util 'weaken'; has 'xml'; has tree => sub { ['root'] }; my $ATTR_RE = qr/ ([^<>=\s]+) # Key (?: \s*=\s* (?: "([^"]*?)" # Quotation marks | '([^']*?)' # Apostrophes | ([^>\s]*) # Unquoted ) )? \s* /x; my $END_RE = qr!^\s*/\s*(.+)\s*!; my $TOKEN_RE = qr/ ([^<]*) # Text (?: <\?(.*?)\?> # Processing Instruction | ' if $e eq 'comment'; # CDATA return '[1] . ']]>' if $e eq 'cdata'; # Processing instruction return '[1] . '?>' if $e eq 'pi'; # Start tag my $start = 1; my $content = ''; if ($e eq 'tag') { $start = 4; # Open tag my $tag = $tree->[1]; $content .= "<$tag"; # Attributes my @attrs; for my $key (sort keys %{$tree->[2]}) { my $value = $tree->[2]{$key}; # No value push @attrs, $key and next unless defined $value; # Key and value push @attrs, qq{$key="} . xml_escape($value) . '"'; } my $attrs = join ' ', @attrs; $content .= " $attrs" if $attrs; # Element without end tag return $self->xml || $VOID{$tag} ? "$content />" : "$content>" unless $tree->[4]; # Close tag $content .= '>'; } # Render whole tree $content .= $self->_render($tree->[$_]) for $start .. $#$tree; # End tag $content .= '[1] . '>' if $e eq 'tag'; return $content; } sub _start { my ($self, $start, $attrs, $current) = @_; # Autoclose optional HTML elements if (!$self->xml && $$current->[0] ne 'root') { if (my $end = $END{$start}) { $self->_end($_, $current) for @$end } # "li" elsif ($start eq 'li') { $self->_close($current, {li => 1}, 'ul') } # "colgroup", "thead", "tbody" and "tfoot" elsif (grep { $_ eq $start } qw(colgroup thead tbody tfoot)) { $self->_close($current, \%TABLE, 'table'); } # "tr" elsif ($start eq 'tr') { $self->_close($current, {tr => 1}, 'table') } # "th" and "td" elsif ($start eq 'th' || $start eq 'td') { $self->_close($current, {$_ => 1}, 'table') for qw(th td); } } # New tag my $new = ['tag', $start, $attrs, $$current]; weaken $new->[3]; push @$$current, $new; $$current = $new; } 1; =encoding utf8 =head1 NAME Mojo::DOM::HTML - HTML/XML engine =head1 SYNOPSIS use Mojo::DOM::HTML; # Turn HTML into DOM tree my $html = Mojo::DOM::HTML->new; $html->parse('

A

B

'); my $tree = $html->tree; =head1 DESCRIPTION L is the HTML/XML engine used by L. =head1 ATTRIBUTES L implements the following attributes. =head2 tree my $tree = $html->tree; $html = $html->tree(['root', ['text', 'foo']]); Document Object Model. Note that this structure should only be used very carefully since it is very dynamic. =head2 xml my $bool = $html->xml; $html = $html->xml($bool); Disable HTML semantics in parser and activate case sensitivity, defaults to auto detection based on processing instructions. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 parse $html = $html->parse('test'); Parse HTML/XML fragment. =head2 render my $xml = $html->render; Render DOM to XML. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/DOM.pm0000644000175000017500000004450212253463326021621 0ustar cstamascstamaspackage Mojo::DOM; use Mojo::Base -strict; use overload '%{}' => sub { shift->attr }, bool => sub {1}, '""' => sub { shift->to_xml }, fallback => 1; # "Fry: This snow is beautiful. I'm glad global warming never happened. # Leela: Actually, it did. But thank God nuclear winter canceled it out." use Carp 'croak'; use Mojo::Collection; use Mojo::DOM::CSS; use Mojo::DOM::HTML; use Mojo::Util 'squish'; use Scalar::Util qw(blessed weaken); sub AUTOLOAD { my $self = shift; my ($package, $method) = our $AUTOLOAD =~ /^([\w:]+)::(\w+)$/; croak "Undefined subroutine &${package}::$method called" unless blessed $self && $self->isa(__PACKAGE__); # Search children of current element my $children = $self->children($method); return @$children > 1 ? $children : $children->[0] if @$children; croak qq{Can't locate object method "$method" via package "$package"}; } sub DESTROY { } sub new { my $class = shift; my $self = bless [Mojo::DOM::HTML->new], ref $class || $class; return @_ ? $self->parse(@_) : $self; } sub all_text { shift->_content(1, @_) } sub ancestors { _select($_[0]->_collect(_ancestors($_[0]->tree)), $_[1]) } sub append { shift->_add(1, @_) } sub append_content { my ($self, $new) = @_; my $tree = $self->tree; push @$tree, _link($self->_parse("$new"), $tree); return $self; } 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; # Hash my $tree = $self->tree; my $attrs = $tree->[0] eq 'root' ? {} : $tree->[2]; return $attrs unless @_; # Get return $attrs->{$_[0]} // '' unless @_ > 1 || ref $_[0]; # Set %$attrs = (%$attrs, %{ref $_[0] ? $_[0] : {@_}}); return $self; } sub children { my $self = shift; return _select( $self->_collect(grep { $_->[0] eq 'tag' } _nodes($self->tree)), @_); } sub content_xml { my $self = shift; my $xml = $self->xml; return join '', map { _render($_, $xml) } _nodes($self->tree); } sub find { $_[0]->_collect(@{$_[0]->_css->select($_[1])}) } sub match { $_[0]->_css->match($_[1]) ? $_[0] : undef } sub namespace { my $self = shift; return '' if (my $current = $self->tree)->[0] eq 'root'; # Extract namespace prefix and search parents my $ns = $current->[1] =~ /^(.*?):/ ? "xmlns:$1" : undef; while ($current->[0] ne 'root') { # Namespace for prefix my $attrs = $current->[2]; if ($ns) { /^\Q$ns\E$/ and return $attrs->{$_} for keys %$attrs } # Namespace attribute elsif (defined $attrs->{xmlns}) { return $attrs->{xmlns} } $current = $current->[3]; } return ''; } sub next { shift->_siblings->[1][0] } sub parent { my $self = shift; return undef if (my $tree = $self->tree)->[0] eq 'root'; return $self->new->tree($tree->[3])->xml($self->xml); } sub parse { shift->_delegate(parse => shift) } sub prepend { shift->_add(0, @_) } sub prepend_content { my ($self, $new) = @_; my $tree = $self->tree; splice @$tree, _offset($tree), 0, _link($self->_parse("$new"), $tree); return $self; } sub previous { shift->_siblings->[0][-1] } sub remove { shift->replace('') } sub replace { my ($self, $new) = @_; my $tree = $self->tree; return $self->xml(undef)->parse($new) if $tree->[0] eq 'root'; return $self->_replace($tree, $self->_parse("$new")); } sub replace_content { my ($self, $new) = @_; my $tree = $self->tree; splice @$tree, _offset($tree), $#$tree, _link($self->_parse("$new"), $tree); return $self; } sub root { my $self = shift; return $self unless my $tree = _ancestors($self->tree, 1); return $self->new->tree($tree)->xml($self->xml); } sub siblings { _select(Mojo::Collection->new(@{_siblings($_[0], 1)}), $_[1]) } sub strip { my $self = shift; my $tree = $self->tree; return $self if $tree->[0] eq 'root'; return $self->_replace($tree, ['root', _nodes($tree)]); } sub tap { shift->Mojo::Base::tap(@_) } sub text { shift->_content(0, @_) } sub text_after { my ($self, $trim) = @_; return '' if (my $tree = $self->tree)->[0] eq 'root'; my (@nodes, $started); for my $n (_nodes($tree->[3])) { ++$started and next if $n eq $tree; next unless $started; last if $n->[0] eq 'tag'; push @nodes, $n; } return _text(\@nodes, 0, _trim($tree->[3], $trim)); } sub text_before { my ($self, $trim) = @_; return '' if (my $tree = $self->tree)->[0] eq 'root'; my @nodes; for my $n (_nodes($tree->[3])) { last if $n eq $tree; push @nodes, $n; @nodes = () if $n->[0] eq 'tag'; } return _text(\@nodes, 0, _trim($tree->[3], $trim)); } sub to_xml { shift->[0]->render } sub tree { shift->_delegate(tree => @_) } sub type { my ($self, $type) = @_; return '' if (my $tree = $self->tree)->[0] eq 'root'; return $tree->[1] unless $type; $tree->[1] = $type; return $self; } sub xml { shift->_delegate(xml => @_) } sub _add { my ($self, $offset, $new) = @_; return $self if (my $tree = $self->tree)->[0] eq 'root'; my $parent = $tree->[3]; splice @$parent, _parent($parent, $tree) + $offset, 0, _link($self->_parse("$new"), $parent); return $self; } sub _ancestors { my ($tree, $root) = @_; my @ancestors; push @ancestors, $tree while ($tree->[0] eq 'tag') && ($tree = $tree->[3]); return $root ? $ancestors[-1] : @ancestors[0 .. $#ancestors - 1]; } sub _collect { my $self = shift; my $xml = $self->xml; return Mojo::Collection->new(@_) ->map(sub { $self->new->tree($_)->xml($xml) }); } sub _content { my $tree = shift->tree; 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 @_; $self->[0]->$method(@_); return $self; } sub _link { my ($children, $parent) = @_; # Link parent to children my @new; for my $n (@$children[1 .. $#$children]) { push @new, $n; next unless $n->[0] eq 'tag'; $n->[3] = $parent; weaken $n->[3]; } return @new; } sub _nodes { return unless my $n = shift; return @$n[_offset($n) .. $#$n]; } sub _offset { $_[0][0] eq 'root' ? 1 : 4 } sub _parent { my ($parent, $child) = @_; # Find parent offset for child my $i = _offset($parent); for my $n (@$parent[$i .. $#$parent]) { last if $n == $child; $i++; } return $i; } sub _parse { Mojo::DOM::HTML->new(xml => shift->xml)->parse(shift)->tree } sub _render { Mojo::DOM::HTML->new(tree => shift, xml => shift)->render } sub _replace { my ($self, $tree, $new) = @_; my $parent = $tree->[3]; splice @$parent, _parent($parent, $tree), 1, _link($new, $parent); return $self->parent; } sub _select { my ($self, $selector) = @_; return defined $selector ? $self->grep(sub { $_->match($selector) }) : $self; } sub _siblings { my ($self, $merge) = @_; return $merge ? [] : [[], []] unless my $parent = $self->parent; my $tree = $self->tree; my (@before, @after, $match); for my $child ($parent->children->each) { ++$match and next if $child->tree eq $tree; $match ? push @after, $child : push @before, $child; } return $merge ? [@before, @after] : [\@before, \@after]; } sub _text { my ($nodes, $recurse, $trim) = @_; # Merge successive text nodes my $i = 0; while (my $next = $nodes->[$i + 1]) { ++$i and next unless $nodes->[$i][0] eq 'text' && $next->[0] eq 'text'; splice @$nodes, $i, 2, ['text', $nodes->[$i][1] . $next->[1]]; } my $text = ''; for my $n (@$nodes) { my $type = $n->[0]; # Nested tag my $content = ''; if ($type eq 'tag' && $recurse) { $content = _text([_nodes($n)], 1, _trim($n, $trim)); } # Text elsif ($type eq 'text') { $content = $trim ? squish($n->[1]) : $n->[1] } # CDATA or raw text elsif ($type eq 'cdata' || $type eq 'raw') { $content = $n->[1] } # Add leading whitespace if punctuation allows it $content = " $content" if $text =~ /\S\z/ && $content =~ /^[^.!?,;:\s]+/; # Trim whitespace blocks $text .= $content if $content =~ /\S+/ || !$trim; } return $text; } sub _trim { my ($e, $trim) = @_; # Disabled return 0 unless $e && ($trim = defined $trim ? $trim : 1); # Detect "pre" tag while ($e->[0] eq 'tag') { return 0 if $e->[1] eq 'pre'; last unless $e = $e->[3]; } return 1; } 1; =encoding utf8 =head1 NAME Mojo::DOM - Minimalistic HTML/XML DOM parser with CSS selectors =head1 SYNOPSIS use Mojo::DOM; # Parse my $dom = Mojo::DOM->new('

A

B

'); # Find say $dom->at('#b')->text; say $dom->find('p')->text; say $dom->find('[id]')->attr('id'); # Walk say $dom->div->p->[0]->text; say $dom->div->children('p')->first->{id}; # Iterate $dom->find('p[id]')->each(sub { say shift->{id} }); # Loop for my $e ($dom->find('p[id]')->each) { say $e->text; } # Modify $dom->div->p->[1]->append('

C

'); $dom->find(':not(p)')->strip; # Render say "$dom"; =head1 DESCRIPTION L is a minimalistic and relaxed HTML/XML DOM parser with CSS selector support. It will even try to interpret broken XML, so you should not use it for validation. =head1 CASE SENSITIVITY L defaults to HTML semantics, that means all tags and attributes are lowercased and selectors need to be lowercase as well. my $dom = Mojo::DOM->new('

Hi!

'); say $dom->at('p')->text; say $dom->p->{id}; If XML processing instructions are found, the parser will automatically switch into XML mode and everything becomes case sensitive. my $dom = Mojo::DOM->new('

Hi!

'); say $dom->at('P')->text; say $dom->P->{ID}; XML detection can also be disabled with the L method. # Force XML semantics $dom->xml(1); # Force HTML semantics $dom->xml(0); =head1 METHODS L implements the following methods. =head2 new my $dom = Mojo::DOM->new; my $dom = Mojo::DOM->new('test'); Construct a new array-based L object and L HTML/XML fragment if necessary. =head2 all_text my $trimmed = $dom->all_text; my $untrimmed = $dom->all_text(0); Extract all text content from DOM structure, smart whitespace trimming is enabled by default. # "foo bar baz" $dom->parse("
foo\n

bar

baz\n
")->div->all_text; # "foo\nbarbaz\n" $dom->parse("
foo\n

bar

baz\n
")->div->all_text(0); =head2 ancestors my $collection = $dom->ancestors; my $collection = $dom->ancestors('div'); Find all ancestors of this element matching the CSS selector and return a L object containing these elements as L objects. All selectors from L are supported. # List types of ancestor elements say $dom->ancestors->type; =head2 append $dom = $dom->append('

Hi!

'); Append HTML/XML fragment to element. # "

A

B

" $dom->parse('

A

')->at('h1')->append('

B

')->root; =head2 append_content $dom = $dom->append_content('

Hi!

'); Append HTML/XML fragment to element content. # "

AB

" $dom->parse('

A

')->at('h1')->append_content('B')->root; =head2 at my $result = $dom->at('html title'); Find first element matching the CSS selector and return it as a L object or return C if none could be found. All selectors from L are supported. # Find first element with "svg" namespace definition my $namespace = $dom->at('[xmlns\:svg]')->{'xmlns:svg'}; =head2 attr my $attrs = $dom->attr; my $foo = $dom->attr('foo'); $dom = $dom->attr({foo => 'bar'}); $dom = $dom->attr(foo => 'bar'); Element attributes. # List id attributes say $dom->find('*')->attr('id')->compact; =head2 children my $collection = $dom->children; my $collection = $dom->children('div'); Find all children of this element matching the CSS selector and return a L object containing these elements as L objects. All selectors from L are supported. # Show type of random child element say $dom->children->shuffle->first->type; =head2 content_xml my $xml = $dom->content_xml; Render content of this element to XML. # "test" $dom->parse('
test
')->div->content_xml; =head2 find my $collection = $dom->find('html title'); Find all elements matching the CSS selector and return a L object containing these elements as L objects. All selectors from L are supported. # Find a specific element and extract information my $id = $dom->find('div')->[23]{id}; # Extract information from multiple elements my @headers = $dom->find('h1, h2, h3')->text->each; my @links = $dom->find('a[href]')->attr('href')->each; =head2 match my $result = $dom->match('html title'); Match the CSS selector against this element and return it as a L object or return C if it didn't match. All selectors from L are supported. =head2 namespace my $namespace = $dom->namespace; Find element namespace. # Find namespace for an element with namespace prefix my $namespace = $dom->at('svg > svg\:circle')->namespace; # Find namespace for an element that may or may not have a namespace prefix my $namespace = $dom->at('svg > circle')->namespace; =head2 next my $sibling = $dom->next; Return L object for next sibling of element or C if there are no more siblings. # "

B

" $dom->parse('

A

B

')->at('h1')->next; =head2 parent my $parent = $dom->parent; Return L object for parent of element or C if this element has no parent. =head2 parse $dom = $dom->parse('test'); Parse HTML/XML fragment with L. # Parse XML my $dom = Mojo::DOM->new->xml(1)->parse($xml); =head2 prepend $dom = $dom->prepend('

Hi!

'); Prepend HTML/XML fragment to element. # "

A

B

" $dom->parse('

B

')->at('h2')->prepend('

A

')->root; =head2 prepend_content $dom = $dom->prepend_content('

Hi!

'); Prepend HTML/XML fragment to element content. # "

AB

" $dom->parse('

B

')->at('h2')->prepend_content('A')->root; =head2 previous my $sibling = $dom->previous; Return L object for previous sibling of element or C if there are no more siblings. # "

A

" $dom->parse('

A

B

')->at('h2')->previous; =head2 remove my $parent = $dom->remove; Remove element and return L object for parent of element. # "
" $dom->parse('

A

')->at('h1')->remove; =head2 replace my $parent = $dom->replace('
test
'); Replace element with HTML/XML fragment and return L object for parent of element. # "

B

" $dom->parse('

A

')->at('h1')->replace('

B

'); # "
" $dom->parse('

A

')->at('h1')->replace(''); =head2 replace_content $dom = $dom->replace_content('

test

'); Replace element content with HTML/XML fragment. # "

B

" $dom->parse('

A

')->at('h1')->replace_content('B')->root; # "

" $dom->parse('

A

')->at('h1')->replace_content('')->root; =head2 root my $root = $dom->root; Return L object for root node. =head2 siblings my $collection = $dom->siblings; my $collection = $dom->siblings('div'); Find all siblings of this element matching the CSS selector and return a L object containing these elements as L objects. All selectors from L are supported. # List types of sibling elements say $dom->siblings->type; =head2 strip my $parent = $dom->strip; Remove element while preserving its content and return L object for parent of element. # "
A
" $dom->parse('

A

')->at('h1')->strip; =head2 tap $dom = $dom->tap(sub {...}); Alias for L. =head2 text my $trimmed = $dom->text; my $untrimmed = $dom->text(0); Extract text content from element only (not including child elements), smart whitespace trimming is enabled by default. # "foo baz" $dom->parse("
foo\n

bar

baz\n
")->div->text; # "foo\nbaz\n" $dom->parse("
foo\n

bar

baz\n
")->div->text(0); =head2 text_after my $trimmed = $dom->text_after; my $untrimmed = $dom->text_after(0); Extract text content immediately following element, smart whitespace trimming is enabled by default. # "baz" $dom->parse("
foo\n

bar

baz\n
")->div->p->text_after; # "baz\n" $dom->parse("
foo\n

bar

baz\n
")->div->p->text_after(0); =head2 text_before my $trimmed = $dom->text_before; my $untrimmed = $dom->text_before(0); Extract text content immediately preceding element, smart whitespace trimming is enabled by default. # "foo" $dom->parse("
foo\n

bar

baz\n
")->div->p->text_before; # "foo\n" $dom->parse("
foo\n

bar

baz\n
")->div->p->text_before(0); =head2 to_xml my $xml = $dom->to_xml; my $xml = "$dom"; Render this element and its content to XML. # "test" $dom->parse('
test
')->div->b->to_xml; =head2 tree my $tree = $dom->tree; $dom = $dom->tree(['root', ['text', 'foo']]); Document Object Model. Note that this structure should only be used very carefully since it is very dynamic. =head2 type my $type = $dom->type; $dom = $dom->type('div'); Element type. # List types of child elements say $dom->children->type; =head2 xml my $bool = $dom->xml; $dom = $dom->xml($bool); Disable HTML semantics in parser and activate case sensitivity, defaults to auto detection based on processing instructions. =head1 CHILD ELEMENTS In addition to the methods above, many child elements are also automatically available as object methods, which return a L or L object, depending on number of children. say $dom->p->text; say $dom->div->[23]->text; say $dom->div->text; =head1 ELEMENT ATTRIBUTES Direct hash reference access to element attributes is also possible. say $dom->{foo}; say $dom->div->{id}; =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/entities.txt0000644000175000017500000011113012254124671023217 0ustar cstamascstamasAacute; U+000C1 Aacute U+000C1 aacute; U+000E1 aacute U+000E1 Abreve; U+00102 abreve; U+00103 ac; U+0223E acd; U+0223F acE; U+0223E U+00333 Acirc; U+000C2 Acirc U+000C2 acirc; U+000E2 acirc U+000E2 acute; U+000B4 acute U+000B4 Acy; U+00410 acy; U+00430 AElig; U+000C6 AElig U+000C6 aelig; U+000E6 aelig U+000E6 af; U+02061 Afr; U+1D504 afr; U+1D51E Agrave; U+000C0 Agrave U+000C0 agrave; U+000E0 agrave U+000E0 alefsym; U+02135 aleph; U+02135 Alpha; U+00391 alpha; U+003B1 Amacr; U+00100 amacr; U+00101 amalg; U+02A3F AMP; U+00026 AMP U+00026 amp; U+00026 amp U+00026 And; U+02A53 and; U+02227 andand; U+02A55 andd; U+02A5C andslope; U+02A58 andv; U+02A5A ang; U+02220 ange; U+029A4 angle; U+02220 angmsd; U+02221 angmsdaa; U+029A8 angmsdab; U+029A9 angmsdac; U+029AA angmsdad; U+029AB angmsdae; U+029AC angmsdaf; U+029AD angmsdag; U+029AE angmsdah; U+029AF angrt; U+0221F angrtvb; U+022BE angrtvbd; U+0299D angsph; U+02222 angst; U+000C5 angzarr; U+0237C Aogon; U+00104 aogon; U+00105 Aopf; U+1D538 aopf; U+1D552 ap; U+02248 apacir; U+02A6F apE; U+02A70 ape; U+0224A apid; U+0224B apos; U+00027 ApplyFunction; U+02061 approx; U+02248 approxeq; U+0224A Aring; U+000C5 Aring U+000C5 aring; U+000E5 aring U+000E5 Ascr; U+1D49C ascr; U+1D4B6 Assign; U+02254 ast; U+0002A asymp; U+02248 asympeq; U+0224D Atilde; U+000C3 Atilde U+000C3 atilde; U+000E3 atilde U+000E3 Auml; U+000C4 Auml U+000C4 auml; U+000E4 auml U+000E4 awconint; U+02233 awint; U+02A11 backcong; U+0224C backepsilon; U+003F6 backprime; U+02035 backsim; U+0223D backsimeq; U+022CD Backslash; U+02216 Barv; U+02AE7 barvee; U+022BD Barwed; U+02306 barwed; U+02305 barwedge; U+02305 bbrk; U+023B5 bbrktbrk; U+023B6 bcong; U+0224C Bcy; U+00411 bcy; U+00431 bdquo; U+0201E becaus; U+02235 Because; U+02235 because; U+02235 bemptyv; U+029B0 bepsi; U+003F6 bernou; U+0212C Bernoullis; U+0212C Beta; U+00392 beta; U+003B2 beth; U+02136 between; U+0226C Bfr; U+1D505 bfr; U+1D51F bigcap; U+022C2 bigcirc; U+025EF bigcup; U+022C3 bigodot; U+02A00 bigoplus; U+02A01 bigotimes; U+02A02 bigsqcup; U+02A06 bigstar; U+02605 bigtriangledown; U+025BD bigtriangleup; U+025B3 biguplus; U+02A04 bigvee; U+022C1 bigwedge; U+022C0 bkarow; U+0290D blacklozenge; U+029EB blacksquare; U+025AA blacktriangle; U+025B4 blacktriangledown; U+025BE blacktriangleleft; U+025C2 blacktriangleright; U+025B8 blank; U+02423 blk12; U+02592 blk14; U+02591 blk34; U+02593 block; U+02588 bne; U+0003D U+020E5 bnequiv; U+02261 U+020E5 bNot; U+02AED bnot; U+02310 Bopf; U+1D539 bopf; U+1D553 bot; U+022A5 bottom; U+022A5 bowtie; U+022C8 boxbox; U+029C9 boxDL; U+02557 boxDl; U+02556 boxdL; U+02555 boxdl; U+02510 boxDR; U+02554 boxDr; U+02553 boxdR; U+02552 boxdr; U+0250C boxH; U+02550 boxh; U+02500 boxHD; U+02566 boxHd; U+02564 boxhD; U+02565 boxhd; U+0252C boxHU; U+02569 boxHu; U+02567 boxhU; U+02568 boxhu; U+02534 boxminus; U+0229F boxplus; U+0229E boxtimes; U+022A0 boxUL; U+0255D boxUl; U+0255C boxuL; U+0255B boxul; U+02518 boxUR; U+0255A boxUr; U+02559 boxuR; U+02558 boxur; U+02514 boxV; U+02551 boxv; U+02502 boxVH; U+0256C boxVh; U+0256B boxvH; U+0256A boxvh; U+0253C boxVL; U+02563 boxVl; U+02562 boxvL; U+02561 boxvl; U+02524 boxVR; U+02560 boxVr; U+0255F boxvR; U+0255E boxvr; U+0251C bprime; U+02035 Breve; U+002D8 breve; U+002D8 brvbar; U+000A6 brvbar U+000A6 Bscr; U+0212C bscr; U+1D4B7 bsemi; U+0204F bsim; U+0223D bsime; U+022CD bsol; U+0005C bsolb; U+029C5 bsolhsub; U+027C8 bull; U+02022 bullet; U+02022 bump; U+0224E bumpE; U+02AAE bumpe; U+0224F Bumpeq; U+0224E bumpeq; U+0224F Cacute; U+00106 cacute; U+00107 Cap; U+022D2 cap; U+02229 capand; U+02A44 capbrcup; U+02A49 capcap; U+02A4B capcup; U+02A47 capdot; U+02A40 CapitalDifferentialD; U+02145 caps; U+02229 U+0FE00 caret; U+02041 caron; U+002C7 Cayleys; U+0212D ccaps; U+02A4D Ccaron; U+0010C ccaron; U+0010D Ccedil; U+000C7 Ccedil U+000C7 ccedil; U+000E7 ccedil U+000E7 Ccirc; U+00108 ccirc; U+00109 Cconint; U+02230 ccups; U+02A4C ccupssm; U+02A50 Cdot; U+0010A cdot; U+0010B cedil; U+000B8 cedil U+000B8 Cedilla; U+000B8 cemptyv; U+029B2 cent; U+000A2 cent U+000A2 CenterDot; U+000B7 centerdot; U+000B7 Cfr; U+0212D cfr; U+1D520 CHcy; U+00427 chcy; U+00447 check; U+02713 checkmark; U+02713 Chi; U+003A7 chi; U+003C7 cir; U+025CB circ; U+002C6 circeq; U+02257 circlearrowleft; U+021BA circlearrowright; U+021BB circledast; U+0229B circledcirc; U+0229A circleddash; U+0229D CircleDot; U+02299 circledR; U+000AE circledS; U+024C8 CircleMinus; U+02296 CirclePlus; U+02295 CircleTimes; U+02297 cirE; U+029C3 cire; U+02257 cirfnint; U+02A10 cirmid; U+02AEF cirscir; U+029C2 ClockwiseContourIntegral; U+02232 CloseCurlyDoubleQuote; U+0201D CloseCurlyQuote; U+02019 clubs; U+02663 clubsuit; U+02663 Colon; U+02237 colon; U+0003A Colone; U+02A74 colone; U+02254 coloneq; U+02254 comma; U+0002C commat; U+00040 comp; U+02201 compfn; U+02218 complement; U+02201 complexes; U+02102 cong; U+02245 congdot; U+02A6D Congruent; U+02261 Conint; U+0222F conint; U+0222E ContourIntegral; U+0222E Copf; U+02102 copf; U+1D554 coprod; U+02210 Coproduct; U+02210 COPY; U+000A9 COPY U+000A9 copy; U+000A9 copy U+000A9 copysr; U+02117 CounterClockwiseContourIntegral; U+02233 crarr; U+021B5 Cross; U+02A2F cross; U+02717 Cscr; U+1D49E cscr; U+1D4B8 csub; U+02ACF csube; U+02AD1 csup; U+02AD0 csupe; U+02AD2 ctdot; U+022EF cudarrl; U+02938 cudarrr; U+02935 cuepr; U+022DE cuesc; U+022DF cularr; U+021B6 cularrp; U+0293D Cup; U+022D3 cup; U+0222A cupbrcap; U+02A48 CupCap; U+0224D cupcap; U+02A46 cupcup; U+02A4A cupdot; U+0228D cupor; U+02A45 cups; U+0222A U+0FE00 curarr; U+021B7 curarrm; U+0293C curlyeqprec; U+022DE curlyeqsucc; U+022DF curlyvee; U+022CE curlywedge; U+022CF curren; U+000A4 curren U+000A4 curvearrowleft; U+021B6 curvearrowright; U+021B7 cuvee; U+022CE cuwed; U+022CF cwconint; U+02232 cwint; U+02231 cylcty; U+0232D Dagger; U+02021 dagger; U+02020 daleth; U+02138 Darr; U+021A1 dArr; U+021D3 darr; U+02193 dash; U+02010 Dashv; U+02AE4 dashv; U+022A3 dbkarow; U+0290F dblac; U+002DD Dcaron; U+0010E dcaron; U+0010F Dcy; U+00414 dcy; U+00434 DD; U+02145 dd; U+02146 ddagger; U+02021 ddarr; U+021CA DDotrahd; U+02911 ddotseq; U+02A77 deg; U+000B0 deg U+000B0 Del; U+02207 Delta; U+00394 delta; U+003B4 demptyv; U+029B1 dfisht; U+0297F Dfr; U+1D507 dfr; U+1D521 dHar; U+02965 dharl; U+021C3 dharr; U+021C2 DiacriticalAcute; U+000B4 DiacriticalDot; U+002D9 DiacriticalDoubleAcute; U+002DD DiacriticalGrave; U+00060 DiacriticalTilde; U+002DC diam; U+022C4 Diamond; U+022C4 diamond; U+022C4 diamondsuit; U+02666 diams; U+02666 die; U+000A8 DifferentialD; U+02146 digamma; U+003DD disin; U+022F2 div; U+000F7 divide; U+000F7 divide U+000F7 divideontimes; U+022C7 divonx; U+022C7 DJcy; U+00402 djcy; U+00452 dlcorn; U+0231E dlcrop; U+0230D dollar; U+00024 Dopf; U+1D53B dopf; U+1D555 Dot; U+000A8 dot; U+002D9 DotDot; U+020DC doteq; U+02250 doteqdot; U+02251 DotEqual; U+02250 dotminus; U+02238 dotplus; U+02214 dotsquare; U+022A1 doublebarwedge; U+02306 DoubleContourIntegral; U+0222F DoubleDot; U+000A8 DoubleDownArrow; U+021D3 DoubleLeftArrow; U+021D0 DoubleLeftRightArrow; U+021D4 DoubleLeftTee; U+02AE4 DoubleLongLeftArrow; U+027F8 DoubleLongLeftRightArrow; U+027FA DoubleLongRightArrow; U+027F9 DoubleRightArrow; U+021D2 DoubleRightTee; U+022A8 DoubleUpArrow; U+021D1 DoubleUpDownArrow; U+021D5 DoubleVerticalBar; U+02225 DownArrow; U+02193 Downarrow; U+021D3 downarrow; U+02193 DownArrowBar; U+02913 DownArrowUpArrow; U+021F5 DownBreve; U+00311 downdownarrows; U+021CA downharpoonleft; U+021C3 downharpoonright; U+021C2 DownLeftRightVector; U+02950 DownLeftTeeVector; U+0295E DownLeftVector; U+021BD DownLeftVectorBar; U+02956 DownRightTeeVector; U+0295F DownRightVector; U+021C1 DownRightVectorBar; U+02957 DownTee; U+022A4 DownTeeArrow; U+021A7 drbkarow; U+02910 drcorn; U+0231F drcrop; U+0230C Dscr; U+1D49F dscr; U+1D4B9 DScy; U+00405 dscy; U+00455 dsol; U+029F6 Dstrok; U+00110 dstrok; U+00111 dtdot; U+022F1 dtri; U+025BF dtrif; U+025BE duarr; U+021F5 duhar; U+0296F dwangle; U+029A6 DZcy; U+0040F dzcy; U+0045F dzigrarr; U+027FF Eacute; U+000C9 Eacute U+000C9 eacute; U+000E9 eacute U+000E9 easter; U+02A6E Ecaron; U+0011A ecaron; U+0011B ecir; U+02256 Ecirc; U+000CA Ecirc U+000CA ecirc; U+000EA ecirc U+000EA ecolon; U+02255 Ecy; U+0042D ecy; U+0044D eDDot; U+02A77 Edot; U+00116 eDot; U+02251 edot; U+00117 ee; U+02147 efDot; U+02252 Efr; U+1D508 efr; U+1D522 eg; U+02A9A Egrave; U+000C8 Egrave U+000C8 egrave; U+000E8 egrave U+000E8 egs; U+02A96 egsdot; U+02A98 el; U+02A99 Element; U+02208 elinters; U+023E7 ell; U+02113 els; U+02A95 elsdot; U+02A97 Emacr; U+00112 emacr; U+00113 empty; U+02205 emptyset; U+02205 EmptySmallSquare; U+025FB emptyv; U+02205 EmptyVerySmallSquare; U+025AB emsp; U+02003 emsp13; U+02004 emsp14; U+02005 ENG; U+0014A eng; U+0014B ensp; U+02002 Eogon; U+00118 eogon; U+00119 Eopf; U+1D53C eopf; U+1D556 epar; U+022D5 eparsl; U+029E3 eplus; U+02A71 epsi; U+003B5 Epsilon; U+00395 epsilon; U+003B5 epsiv; U+003F5 eqcirc; U+02256 eqcolon; U+02255 eqsim; U+02242 eqslantgtr; U+02A96 eqslantless; U+02A95 Equal; U+02A75 equals; U+0003D EqualTilde; U+02242 equest; U+0225F Equilibrium; U+021CC equiv; U+02261 equivDD; U+02A78 eqvparsl; U+029E5 erarr; U+02971 erDot; U+02253 Escr; U+02130 escr; U+0212F esdot; U+02250 Esim; U+02A73 esim; U+02242 Eta; U+00397 eta; U+003B7 ETH; U+000D0 ETH U+000D0 eth; U+000F0 eth U+000F0 Euml; U+000CB Euml U+000CB euml; U+000EB euml U+000EB euro; U+020AC excl; U+00021 exist; U+02203 Exists; U+02203 expectation; U+02130 ExponentialE; U+02147 exponentiale; U+02147 fallingdotseq; U+02252 Fcy; U+00424 fcy; U+00444 female; U+02640 ffilig; U+0FB03 fflig; U+0FB00 ffllig; U+0FB04 Ffr; U+1D509 ffr; U+1D523 filig; U+0FB01 FilledSmallSquare; U+025FC FilledVerySmallSquare; U+025AA fjlig; U+00066 U+0006A flat; U+0266D fllig; U+0FB02 fltns; U+025B1 fnof; U+00192 Fopf; U+1D53D fopf; U+1D557 ForAll; U+02200 forall; U+02200 fork; U+022D4 forkv; U+02AD9 Fouriertrf; U+02131 fpartint; U+02A0D frac12; U+000BD frac12 U+000BD frac13; U+02153 frac14; U+000BC frac14 U+000BC frac15; U+02155 frac16; U+02159 frac18; U+0215B frac23; U+02154 frac25; U+02156 frac34; U+000BE frac34 U+000BE frac35; U+02157 frac38; U+0215C frac45; U+02158 frac56; U+0215A frac58; U+0215D frac78; U+0215E frasl; U+02044 frown; U+02322 Fscr; U+02131 fscr; U+1D4BB gacute; U+001F5 Gamma; U+00393 gamma; U+003B3 Gammad; U+003DC gammad; U+003DD gap; U+02A86 Gbreve; U+0011E gbreve; U+0011F Gcedil; U+00122 Gcirc; U+0011C gcirc; U+0011D Gcy; U+00413 gcy; U+00433 Gdot; U+00120 gdot; U+00121 gE; U+02267 ge; U+02265 gEl; U+02A8C gel; U+022DB geq; U+02265 geqq; U+02267 geqslant; U+02A7E ges; U+02A7E gescc; U+02AA9 gesdot; U+02A80 gesdoto; U+02A82 gesdotol; U+02A84 gesl; U+022DB U+0FE00 gesles; U+02A94 Gfr; U+1D50A gfr; U+1D524 Gg; U+022D9 gg; U+0226B ggg; U+022D9 gimel; U+02137 GJcy; U+00403 gjcy; U+00453 gl; U+02277 gla; U+02AA5 glE; U+02A92 glj; U+02AA4 gnap; U+02A8A gnapprox; U+02A8A gnE; U+02269 gne; U+02A88 gneq; U+02A88 gneqq; U+02269 gnsim; U+022E7 Gopf; U+1D53E gopf; U+1D558 grave; U+00060 GreaterEqual; U+02265 GreaterEqualLess; U+022DB GreaterFullEqual; U+02267 GreaterGreater; U+02AA2 GreaterLess; U+02277 GreaterSlantEqual; U+02A7E GreaterTilde; U+02273 Gscr; U+1D4A2 gscr; U+0210A gsim; U+02273 gsime; U+02A8E gsiml; U+02A90 GT; U+0003E GT U+0003E Gt; U+0226B gt; U+0003E gt U+0003E gtcc; U+02AA7 gtcir; U+02A7A gtdot; U+022D7 gtlPar; U+02995 gtquest; U+02A7C gtrapprox; U+02A86 gtrarr; U+02978 gtrdot; U+022D7 gtreqless; U+022DB gtreqqless; U+02A8C gtrless; U+02277 gtrsim; U+02273 gvertneqq; U+02269 U+0FE00 gvnE; U+02269 U+0FE00 Hacek; U+002C7 hairsp; U+0200A half; U+000BD hamilt; U+0210B HARDcy; U+0042A hardcy; U+0044A hArr; U+021D4 harr; U+02194 harrcir; U+02948 harrw; U+021AD Hat; U+0005E hbar; U+0210F Hcirc; U+00124 hcirc; U+00125 hearts; U+02665 heartsuit; U+02665 hellip; U+02026 hercon; U+022B9 Hfr; U+0210C hfr; U+1D525 HilbertSpace; U+0210B hksearow; U+02925 hkswarow; U+02926 hoarr; U+021FF homtht; U+0223B hookleftarrow; U+021A9 hookrightarrow; U+021AA Hopf; U+0210D hopf; U+1D559 horbar; U+02015 HorizontalLine; U+02500 Hscr; U+0210B hscr; U+1D4BD hslash; U+0210F Hstrok; U+00126 hstrok; U+00127 HumpDownHump; U+0224E HumpEqual; U+0224F hybull; U+02043 hyphen; U+02010 Iacute; U+000CD Iacute U+000CD iacute; U+000ED iacute U+000ED ic; U+02063 Icirc; U+000CE Icirc U+000CE icirc; U+000EE icirc U+000EE Icy; U+00418 icy; U+00438 Idot; U+00130 IEcy; U+00415 iecy; U+00435 iexcl; U+000A1 iexcl U+000A1 iff; U+021D4 Ifr; U+02111 ifr; U+1D526 Igrave; U+000CC Igrave U+000CC igrave; U+000EC igrave U+000EC ii; U+02148 iiiint; U+02A0C iiint; U+0222D iinfin; U+029DC iiota; U+02129 IJlig; U+00132 ijlig; U+00133 Im; U+02111 Imacr; U+0012A imacr; U+0012B image; U+02111 ImaginaryI; U+02148 imagline; U+02110 imagpart; U+02111 imath; U+00131 imof; U+022B7 imped; U+001B5 Implies; U+021D2 in; U+02208 incare; U+02105 infin; U+0221E infintie; U+029DD inodot; U+00131 Int; U+0222C int; U+0222B intcal; U+022BA integers; U+02124 Integral; U+0222B intercal; U+022BA Intersection; U+022C2 intlarhk; U+02A17 intprod; U+02A3C InvisibleComma; U+02063 InvisibleTimes; U+02062 IOcy; U+00401 iocy; U+00451 Iogon; U+0012E iogon; U+0012F Iopf; U+1D540 iopf; U+1D55A Iota; U+00399 iota; U+003B9 iprod; U+02A3C iquest; U+000BF iquest U+000BF Iscr; U+02110 iscr; U+1D4BE isin; U+02208 isindot; U+022F5 isinE; U+022F9 isins; U+022F4 isinsv; U+022F3 isinv; U+02208 it; U+02062 Itilde; U+00128 itilde; U+00129 Iukcy; U+00406 iukcy; U+00456 Iuml; U+000CF Iuml U+000CF iuml; U+000EF iuml U+000EF Jcirc; U+00134 jcirc; U+00135 Jcy; U+00419 jcy; U+00439 Jfr; U+1D50D jfr; U+1D527 jmath; U+00237 Jopf; U+1D541 jopf; U+1D55B Jscr; U+1D4A5 jscr; U+1D4BF Jsercy; U+00408 jsercy; U+00458 Jukcy; U+00404 jukcy; U+00454 Kappa; U+0039A kappa; U+003BA kappav; U+003F0 Kcedil; U+00136 kcedil; U+00137 Kcy; U+0041A kcy; U+0043A Kfr; U+1D50E kfr; U+1D528 kgreen; U+00138 KHcy; U+00425 khcy; U+00445 KJcy; U+0040C kjcy; U+0045C Kopf; U+1D542 kopf; U+1D55C Kscr; U+1D4A6 kscr; U+1D4C0 lAarr; U+021DA Lacute; U+00139 lacute; U+0013A laemptyv; U+029B4 lagran; U+02112 Lambda; U+0039B lambda; U+003BB Lang; U+027EA lang; U+027E8 langd; U+02991 langle; U+027E8 lap; U+02A85 Laplacetrf; U+02112 laquo; U+000AB laquo U+000AB Larr; U+0219E lArr; U+021D0 larr; U+02190 larrb; U+021E4 larrbfs; U+0291F larrfs; U+0291D larrhk; U+021A9 larrlp; U+021AB larrpl; U+02939 larrsim; U+02973 larrtl; U+021A2 lat; U+02AAB lAtail; U+0291B latail; U+02919 late; U+02AAD lates; U+02AAD U+0FE00 lBarr; U+0290E lbarr; U+0290C lbbrk; U+02772 lbrace; U+0007B lbrack; U+0005B lbrke; U+0298B lbrksld; U+0298F lbrkslu; U+0298D Lcaron; U+0013D lcaron; U+0013E Lcedil; U+0013B lcedil; U+0013C lceil; U+02308 lcub; U+0007B Lcy; U+0041B lcy; U+0043B ldca; U+02936 ldquo; U+0201C ldquor; U+0201E ldrdhar; U+02967 ldrushar; U+0294B ldsh; U+021B2 lE; U+02266 le; U+02264 LeftAngleBracket; U+027E8 LeftArrow; U+02190 Leftarrow; U+021D0 leftarrow; U+02190 LeftArrowBar; U+021E4 LeftArrowRightArrow; U+021C6 leftarrowtail; U+021A2 LeftCeiling; U+02308 LeftDoubleBracket; U+027E6 LeftDownTeeVector; U+02961 LeftDownVector; U+021C3 LeftDownVectorBar; U+02959 LeftFloor; U+0230A leftharpoondown; U+021BD leftharpoonup; U+021BC leftleftarrows; U+021C7 LeftRightArrow; U+02194 Leftrightarrow; U+021D4 leftrightarrow; U+02194 leftrightarrows; U+021C6 leftrightharpoons; U+021CB leftrightsquigarrow; U+021AD LeftRightVector; U+0294E LeftTee; U+022A3 LeftTeeArrow; U+021A4 LeftTeeVector; U+0295A leftthreetimes; U+022CB LeftTriangle; U+022B2 LeftTriangleBar; U+029CF LeftTriangleEqual; U+022B4 LeftUpDownVector; U+02951 LeftUpTeeVector; U+02960 LeftUpVector; U+021BF LeftUpVectorBar; U+02958 LeftVector; U+021BC LeftVectorBar; U+02952 lEg; U+02A8B leg; U+022DA leq; U+02264 leqq; U+02266 leqslant; U+02A7D les; U+02A7D lescc; U+02AA8 lesdot; U+02A7F lesdoto; U+02A81 lesdotor; U+02A83 lesg; U+022DA U+0FE00 lesges; U+02A93 lessapprox; U+02A85 lessdot; U+022D6 lesseqgtr; U+022DA lesseqqgtr; U+02A8B LessEqualGreater; U+022DA LessFullEqual; U+02266 LessGreater; U+02276 lessgtr; U+02276 LessLess; U+02AA1 lesssim; U+02272 LessSlantEqual; U+02A7D LessTilde; U+02272 lfisht; U+0297C lfloor; U+0230A Lfr; U+1D50F lfr; U+1D529 lg; U+02276 lgE; U+02A91 lHar; U+02962 lhard; U+021BD lharu; U+021BC lharul; U+0296A lhblk; U+02584 LJcy; U+00409 ljcy; U+00459 Ll; U+022D8 ll; U+0226A llarr; U+021C7 llcorner; U+0231E Lleftarrow; U+021DA llhard; U+0296B lltri; U+025FA Lmidot; U+0013F lmidot; U+00140 lmoust; U+023B0 lmoustache; U+023B0 lnap; U+02A89 lnapprox; U+02A89 lnE; U+02268 lne; U+02A87 lneq; U+02A87 lneqq; U+02268 lnsim; U+022E6 loang; U+027EC loarr; U+021FD lobrk; U+027E6 LongLeftArrow; U+027F5 Longleftarrow; U+027F8 longleftarrow; U+027F5 LongLeftRightArrow; U+027F7 Longleftrightarrow; U+027FA longleftrightarrow; U+027F7 longmapsto; U+027FC LongRightArrow; U+027F6 Longrightarrow; U+027F9 longrightarrow; U+027F6 looparrowleft; U+021AB looparrowright; U+021AC lopar; U+02985 Lopf; U+1D543 lopf; U+1D55D loplus; U+02A2D lotimes; U+02A34 lowast; U+02217 lowbar; U+0005F LowerLeftArrow; U+02199 LowerRightArrow; U+02198 loz; U+025CA lozenge; U+025CA lozf; U+029EB lpar; U+00028 lparlt; U+02993 lrarr; U+021C6 lrcorner; U+0231F lrhar; U+021CB lrhard; U+0296D lrm; U+0200E lrtri; U+022BF lsaquo; U+02039 Lscr; U+02112 lscr; U+1D4C1 Lsh; U+021B0 lsh; U+021B0 lsim; U+02272 lsime; U+02A8D lsimg; U+02A8F lsqb; U+0005B lsquo; U+02018 lsquor; U+0201A Lstrok; U+00141 lstrok; U+00142 LT; U+0003C LT U+0003C Lt; U+0226A lt; U+0003C lt U+0003C ltcc; U+02AA6 ltcir; U+02A79 ltdot; U+022D6 lthree; U+022CB ltimes; U+022C9 ltlarr; U+02976 ltquest; U+02A7B ltri; U+025C3 ltrie; U+022B4 ltrif; U+025C2 ltrPar; U+02996 lurdshar; U+0294A luruhar; U+02966 lvertneqq; U+02268 U+0FE00 lvnE; U+02268 U+0FE00 macr; U+000AF macr U+000AF male; U+02642 malt; U+02720 maltese; U+02720 Map; U+02905 map; U+021A6 mapsto; U+021A6 mapstodown; U+021A7 mapstoleft; U+021A4 mapstoup; U+021A5 marker; U+025AE mcomma; U+02A29 Mcy; U+0041C mcy; U+0043C mdash; U+02014 mDDot; U+0223A measuredangle; U+02221 MediumSpace; U+0205F Mellintrf; U+02133 Mfr; U+1D510 mfr; U+1D52A mho; U+02127 micro; U+000B5 micro U+000B5 mid; U+02223 midast; U+0002A midcir; U+02AF0 middot; U+000B7 middot U+000B7 minus; U+02212 minusb; U+0229F minusd; U+02238 minusdu; U+02A2A MinusPlus; U+02213 mlcp; U+02ADB mldr; U+02026 mnplus; U+02213 models; U+022A7 Mopf; U+1D544 mopf; U+1D55E mp; U+02213 Mscr; U+02133 mscr; U+1D4C2 mstpos; U+0223E Mu; U+0039C mu; U+003BC multimap; U+022B8 mumap; U+022B8 nabla; U+02207 Nacute; U+00143 nacute; U+00144 nang; U+02220 U+020D2 nap; U+02249 napE; U+02A70 U+00338 napid; U+0224B U+00338 napos; U+00149 napprox; U+02249 natur; U+0266E natural; U+0266E naturals; U+02115 nbsp; U+000A0 nbsp U+000A0 nbump; U+0224E U+00338 nbumpe; U+0224F U+00338 ncap; U+02A43 Ncaron; U+00147 ncaron; U+00148 Ncedil; U+00145 ncedil; U+00146 ncong; U+02247 ncongdot; U+02A6D U+00338 ncup; U+02A42 Ncy; U+0041D ncy; U+0043D ndash; U+02013 ne; U+02260 nearhk; U+02924 neArr; U+021D7 nearr; U+02197 nearrow; U+02197 nedot; U+02250 U+00338 NegativeMediumSpace; U+0200B NegativeThickSpace; U+0200B NegativeThinSpace; U+0200B NegativeVeryThinSpace; U+0200B nequiv; U+02262 nesear; U+02928 nesim; U+02242 U+00338 NestedGreaterGreater; U+0226B NestedLessLess; U+0226A NewLine; U+0000A nexist; U+02204 nexists; U+02204 Nfr; U+1D511 nfr; U+1D52B ngE; U+02267 U+00338 nge; U+02271 ngeq; U+02271 ngeqq; U+02267 U+00338 ngeqslant; U+02A7E U+00338 nges; U+02A7E U+00338 nGg; U+022D9 U+00338 ngsim; U+02275 nGt; U+0226B U+020D2 ngt; U+0226F ngtr; U+0226F nGtv; U+0226B U+00338 nhArr; U+021CE nharr; U+021AE nhpar; U+02AF2 ni; U+0220B nis; U+022FC nisd; U+022FA niv; U+0220B NJcy; U+0040A njcy; U+0045A nlArr; U+021CD nlarr; U+0219A nldr; U+02025 nlE; U+02266 U+00338 nle; U+02270 nLeftarrow; U+021CD nleftarrow; U+0219A nLeftrightarrow; U+021CE nleftrightarrow; U+021AE nleq; U+02270 nleqq; U+02266 U+00338 nleqslant; U+02A7D U+00338 nles; U+02A7D U+00338 nless; U+0226E nLl; U+022D8 U+00338 nlsim; U+02274 nLt; U+0226A U+020D2 nlt; U+0226E nltri; U+022EA nltrie; U+022EC nLtv; U+0226A U+00338 nmid; U+02224 NoBreak; U+02060 NonBreakingSpace; U+000A0 Nopf; U+02115 nopf; U+1D55F Not; U+02AEC not; U+000AC not U+000AC NotCongruent; U+02262 NotCupCap; U+0226D NotDoubleVerticalBar; U+02226 NotElement; U+02209 NotEqual; U+02260 NotEqualTilde; U+02242 U+00338 NotExists; U+02204 NotGreater; U+0226F NotGreaterEqual; U+02271 NotGreaterFullEqual; U+02267 U+00338 NotGreaterGreater; U+0226B U+00338 NotGreaterLess; U+02279 NotGreaterSlantEqual; U+02A7E U+00338 NotGreaterTilde; U+02275 NotHumpDownHump; U+0224E U+00338 NotHumpEqual; U+0224F U+00338 notin; U+02209 notindot; U+022F5 U+00338 notinE; U+022F9 U+00338 notinva; U+02209 notinvb; U+022F7 notinvc; U+022F6 NotLeftTriangle; U+022EA NotLeftTriangleBar; U+029CF U+00338 NotLeftTriangleEqual; U+022EC NotLess; U+0226E NotLessEqual; U+02270 NotLessGreater; U+02278 NotLessLess; U+0226A U+00338 NotLessSlantEqual; U+02A7D U+00338 NotLessTilde; U+02274 NotNestedGreaterGreater; U+02AA2 U+00338 NotNestedLessLess; U+02AA1 U+00338 notni; U+0220C notniva; U+0220C notnivb; U+022FE notnivc; U+022FD NotPrecedes; U+02280 NotPrecedesEqual; U+02AAF U+00338 NotPrecedesSlantEqual; U+022E0 NotReverseElement; U+0220C NotRightTriangle; U+022EB NotRightTriangleBar; U+029D0 U+00338 NotRightTriangleEqual; U+022ED NotSquareSubset; U+0228F U+00338 NotSquareSubsetEqual; U+022E2 NotSquareSuperset; U+02290 U+00338 NotSquareSupersetEqual; U+022E3 NotSubset; U+02282 U+020D2 NotSubsetEqual; U+02288 NotSucceeds; U+02281 NotSucceedsEqual; U+02AB0 U+00338 NotSucceedsSlantEqual; U+022E1 NotSucceedsTilde; U+0227F U+00338 NotSuperset; U+02283 U+020D2 NotSupersetEqual; U+02289 NotTilde; U+02241 NotTildeEqual; U+02244 NotTildeFullEqual; U+02247 NotTildeTilde; U+02249 NotVerticalBar; U+02224 npar; U+02226 nparallel; U+02226 nparsl; U+02AFD U+020E5 npart; U+02202 U+00338 npolint; U+02A14 npr; U+02280 nprcue; U+022E0 npre; U+02AAF U+00338 nprec; U+02280 npreceq; U+02AAF U+00338 nrArr; U+021CF nrarr; U+0219B nrarrc; U+02933 U+00338 nrarrw; U+0219D U+00338 nRightarrow; U+021CF nrightarrow; U+0219B nrtri; U+022EB nrtrie; U+022ED nsc; U+02281 nsccue; U+022E1 nsce; U+02AB0 U+00338 Nscr; U+1D4A9 nscr; U+1D4C3 nshortmid; U+02224 nshortparallel; U+02226 nsim; U+02241 nsime; U+02244 nsimeq; U+02244 nsmid; U+02224 nspar; U+02226 nsqsube; U+022E2 nsqsupe; U+022E3 nsub; U+02284 nsubE; U+02AC5 U+00338 nsube; U+02288 nsubset; U+02282 U+020D2 nsubseteq; U+02288 nsubseteqq; U+02AC5 U+00338 nsucc; U+02281 nsucceq; U+02AB0 U+00338 nsup; U+02285 nsupE; U+02AC6 U+00338 nsupe; U+02289 nsupset; U+02283 U+020D2 nsupseteq; U+02289 nsupseteqq; U+02AC6 U+00338 ntgl; U+02279 Ntilde; U+000D1 Ntilde U+000D1 ntilde; U+000F1 ntilde U+000F1 ntlg; U+02278 ntriangleleft; U+022EA ntrianglelefteq; U+022EC ntriangleright; U+022EB ntrianglerighteq; U+022ED Nu; U+0039D nu; U+003BD num; U+00023 numero; U+02116 numsp; U+02007 nvap; U+0224D U+020D2 nVDash; U+022AF nVdash; U+022AE nvDash; U+022AD nvdash; U+022AC nvge; U+02265 U+020D2 nvgt; U+0003E U+020D2 nvHarr; U+02904 nvinfin; U+029DE nvlArr; U+02902 nvle; U+02264 U+020D2 nvlt; U+0003C U+020D2 nvltrie; U+022B4 U+020D2 nvrArr; U+02903 nvrtrie; U+022B5 U+020D2 nvsim; U+0223C U+020D2 nwarhk; U+02923 nwArr; U+021D6 nwarr; U+02196 nwarrow; U+02196 nwnear; U+02927 Oacute; U+000D3 Oacute U+000D3 oacute; U+000F3 oacute U+000F3 oast; U+0229B ocir; U+0229A Ocirc; U+000D4 Ocirc U+000D4 ocirc; U+000F4 ocirc U+000F4 Ocy; U+0041E ocy; U+0043E odash; U+0229D Odblac; U+00150 odblac; U+00151 odiv; U+02A38 odot; U+02299 odsold; U+029BC OElig; U+00152 oelig; U+00153 ofcir; U+029BF Ofr; U+1D512 ofr; U+1D52C ogon; U+002DB Ograve; U+000D2 Ograve U+000D2 ograve; U+000F2 ograve U+000F2 ogt; U+029C1 ohbar; U+029B5 ohm; U+003A9 oint; U+0222E olarr; U+021BA olcir; U+029BE olcross; U+029BB oline; U+0203E olt; U+029C0 Omacr; U+0014C omacr; U+0014D Omega; U+003A9 omega; U+003C9 Omicron; U+0039F omicron; U+003BF omid; U+029B6 ominus; U+02296 Oopf; U+1D546 oopf; U+1D560 opar; U+029B7 OpenCurlyDoubleQuote; U+0201C OpenCurlyQuote; U+02018 operp; U+029B9 oplus; U+02295 Or; U+02A54 or; U+02228 orarr; U+021BB ord; U+02A5D order; U+02134 orderof; U+02134 ordf; U+000AA ordf U+000AA ordm; U+000BA ordm U+000BA origof; U+022B6 oror; U+02A56 orslope; U+02A57 orv; U+02A5B oS; U+024C8 Oscr; U+1D4AA oscr; U+02134 Oslash; U+000D8 Oslash U+000D8 oslash; U+000F8 oslash U+000F8 osol; U+02298 Otilde; U+000D5 Otilde U+000D5 otilde; U+000F5 otilde U+000F5 Otimes; U+02A37 otimes; U+02297 otimesas; U+02A36 Ouml; U+000D6 Ouml U+000D6 ouml; U+000F6 ouml U+000F6 ovbar; U+0233D OverBar; U+0203E OverBrace; U+023DE OverBracket; U+023B4 OverParenthesis; U+023DC par; U+02225 para; U+000B6 para U+000B6 parallel; U+02225 parsim; U+02AF3 parsl; U+02AFD part; U+02202 PartialD; U+02202 Pcy; U+0041F pcy; U+0043F percnt; U+00025 period; U+0002E permil; U+02030 perp; U+022A5 pertenk; U+02031 Pfr; U+1D513 pfr; U+1D52D Phi; U+003A6 phi; U+003C6 phiv; U+003D5 phmmat; U+02133 phone; U+0260E Pi; U+003A0 pi; U+003C0 pitchfork; U+022D4 piv; U+003D6 planck; U+0210F planckh; U+0210E plankv; U+0210F plus; U+0002B plusacir; U+02A23 plusb; U+0229E pluscir; U+02A22 plusdo; U+02214 plusdu; U+02A25 pluse; U+02A72 PlusMinus; U+000B1 plusmn; U+000B1 plusmn U+000B1 plussim; U+02A26 plustwo; U+02A27 pm; U+000B1 Poincareplane; U+0210C pointint; U+02A15 Popf; U+02119 popf; U+1D561 pound; U+000A3 pound U+000A3 Pr; U+02ABB pr; U+0227A prap; U+02AB7 prcue; U+0227C prE; U+02AB3 pre; U+02AAF prec; U+0227A precapprox; U+02AB7 preccurlyeq; U+0227C Precedes; U+0227A PrecedesEqual; U+02AAF PrecedesSlantEqual; U+0227C PrecedesTilde; U+0227E preceq; U+02AAF precnapprox; U+02AB9 precneqq; U+02AB5 precnsim; U+022E8 precsim; U+0227E Prime; U+02033 prime; U+02032 primes; U+02119 prnap; U+02AB9 prnE; U+02AB5 prnsim; U+022E8 prod; U+0220F Product; U+0220F profalar; U+0232E profline; U+02312 profsurf; U+02313 prop; U+0221D Proportion; U+02237 Proportional; U+0221D propto; U+0221D prsim; U+0227E prurel; U+022B0 Pscr; U+1D4AB pscr; U+1D4C5 Psi; U+003A8 psi; U+003C8 puncsp; U+02008 Qfr; U+1D514 qfr; U+1D52E qint; U+02A0C Qopf; U+0211A qopf; U+1D562 qprime; U+02057 Qscr; U+1D4AC qscr; U+1D4C6 quaternions; U+0210D quatint; U+02A16 quest; U+0003F questeq; U+0225F QUOT; U+00022 QUOT U+00022 quot; U+00022 quot U+00022 rAarr; U+021DB race; U+0223D U+00331 Racute; U+00154 racute; U+00155 radic; U+0221A raemptyv; U+029B3 Rang; U+027EB rang; U+027E9 rangd; U+02992 range; U+029A5 rangle; U+027E9 raquo; U+000BB raquo U+000BB Rarr; U+021A0 rArr; U+021D2 rarr; U+02192 rarrap; U+02975 rarrb; U+021E5 rarrbfs; U+02920 rarrc; U+02933 rarrfs; U+0291E rarrhk; U+021AA rarrlp; U+021AC rarrpl; U+02945 rarrsim; U+02974 Rarrtl; U+02916 rarrtl; U+021A3 rarrw; U+0219D rAtail; U+0291C ratail; U+0291A ratio; U+02236 rationals; U+0211A RBarr; U+02910 rBarr; U+0290F rbarr; U+0290D rbbrk; U+02773 rbrace; U+0007D rbrack; U+0005D rbrke; U+0298C rbrksld; U+0298E rbrkslu; U+02990 Rcaron; U+00158 rcaron; U+00159 Rcedil; U+00156 rcedil; U+00157 rceil; U+02309 rcub; U+0007D Rcy; U+00420 rcy; U+00440 rdca; U+02937 rdldhar; U+02969 rdquo; U+0201D rdquor; U+0201D rdsh; U+021B3 Re; U+0211C real; U+0211C realine; U+0211B realpart; U+0211C reals; U+0211D rect; U+025AD REG; U+000AE REG U+000AE reg; U+000AE reg U+000AE ReverseElement; U+0220B ReverseEquilibrium; U+021CB ReverseUpEquilibrium; U+0296F rfisht; U+0297D rfloor; U+0230B Rfr; U+0211C rfr; U+1D52F rHar; U+02964 rhard; U+021C1 rharu; U+021C0 rharul; U+0296C Rho; U+003A1 rho; U+003C1 rhov; U+003F1 RightAngleBracket; U+027E9 RightArrow; U+02192 Rightarrow; U+021D2 rightarrow; U+02192 RightArrowBar; U+021E5 RightArrowLeftArrow; U+021C4 rightarrowtail; U+021A3 RightCeiling; U+02309 RightDoubleBracket; U+027E7 RightDownTeeVector; U+0295D RightDownVector; U+021C2 RightDownVectorBar; U+02955 RightFloor; U+0230B rightharpoondown; U+021C1 rightharpoonup; U+021C0 rightleftarrows; U+021C4 rightleftharpoons; U+021CC rightrightarrows; U+021C9 rightsquigarrow; U+0219D RightTee; U+022A2 RightTeeArrow; U+021A6 RightTeeVector; U+0295B rightthreetimes; U+022CC RightTriangle; U+022B3 RightTriangleBar; U+029D0 RightTriangleEqual; U+022B5 RightUpDownVector; U+0294F RightUpTeeVector; U+0295C RightUpVector; U+021BE RightUpVectorBar; U+02954 RightVector; U+021C0 RightVectorBar; U+02953 ring; U+002DA risingdotseq; U+02253 rlarr; U+021C4 rlhar; U+021CC rlm; U+0200F rmoust; U+023B1 rmoustache; U+023B1 rnmid; U+02AEE roang; U+027ED roarr; U+021FE robrk; U+027E7 ropar; U+02986 Ropf; U+0211D ropf; U+1D563 roplus; U+02A2E rotimes; U+02A35 RoundImplies; U+02970 rpar; U+00029 rpargt; U+02994 rppolint; U+02A12 rrarr; U+021C9 Rrightarrow; U+021DB rsaquo; U+0203A Rscr; U+0211B rscr; U+1D4C7 Rsh; U+021B1 rsh; U+021B1 rsqb; U+0005D rsquo; U+02019 rsquor; U+02019 rthree; U+022CC rtimes; U+022CA rtri; U+025B9 rtrie; U+022B5 rtrif; U+025B8 rtriltri; U+029CE RuleDelayed; U+029F4 ruluhar; U+02968 rx; U+0211E Sacute; U+0015A sacute; U+0015B sbquo; U+0201A Sc; U+02ABC sc; U+0227B scap; U+02AB8 Scaron; U+00160 scaron; U+00161 sccue; U+0227D scE; U+02AB4 sce; U+02AB0 Scedil; U+0015E scedil; U+0015F Scirc; U+0015C scirc; U+0015D scnap; U+02ABA scnE; U+02AB6 scnsim; U+022E9 scpolint; U+02A13 scsim; U+0227F Scy; U+00421 scy; U+00441 sdot; U+022C5 sdotb; U+022A1 sdote; U+02A66 searhk; U+02925 seArr; U+021D8 searr; U+02198 searrow; U+02198 sect; U+000A7 sect U+000A7 semi; U+0003B seswar; U+02929 setminus; U+02216 setmn; U+02216 sext; U+02736 Sfr; U+1D516 sfr; U+1D530 sfrown; U+02322 sharp; U+0266F SHCHcy; U+00429 shchcy; U+00449 SHcy; U+00428 shcy; U+00448 ShortDownArrow; U+02193 ShortLeftArrow; U+02190 shortmid; U+02223 shortparallel; U+02225 ShortRightArrow; U+02192 ShortUpArrow; U+02191 shy; U+000AD shy U+000AD Sigma; U+003A3 sigma; U+003C3 sigmaf; U+003C2 sigmav; U+003C2 sim; U+0223C simdot; U+02A6A sime; U+02243 simeq; U+02243 simg; U+02A9E simgE; U+02AA0 siml; U+02A9D simlE; U+02A9F simne; U+02246 simplus; U+02A24 simrarr; U+02972 slarr; U+02190 SmallCircle; U+02218 smallsetminus; U+02216 smashp; U+02A33 smeparsl; U+029E4 smid; U+02223 smile; U+02323 smt; U+02AAA smte; U+02AAC smtes; U+02AAC U+0FE00 SOFTcy; U+0042C softcy; U+0044C sol; U+0002F solb; U+029C4 solbar; U+0233F Sopf; U+1D54A sopf; U+1D564 spades; U+02660 spadesuit; U+02660 spar; U+02225 sqcap; U+02293 sqcaps; U+02293 U+0FE00 sqcup; U+02294 sqcups; U+02294 U+0FE00 Sqrt; U+0221A sqsub; U+0228F sqsube; U+02291 sqsubset; U+0228F sqsubseteq; U+02291 sqsup; U+02290 sqsupe; U+02292 sqsupset; U+02290 sqsupseteq; U+02292 squ; U+025A1 Square; U+025A1 square; U+025A1 SquareIntersection; U+02293 SquareSubset; U+0228F SquareSubsetEqual; U+02291 SquareSuperset; U+02290 SquareSupersetEqual; U+02292 SquareUnion; U+02294 squarf; U+025AA squf; U+025AA srarr; U+02192 Sscr; U+1D4AE sscr; U+1D4C8 ssetmn; U+02216 ssmile; U+02323 sstarf; U+022C6 Star; U+022C6 star; U+02606 starf; U+02605 straightepsilon; U+003F5 straightphi; U+003D5 strns; U+000AF Sub; U+022D0 sub; U+02282 subdot; U+02ABD subE; U+02AC5 sube; U+02286 subedot; U+02AC3 submult; U+02AC1 subnE; U+02ACB subne; U+0228A subplus; U+02ABF subrarr; U+02979 Subset; U+022D0 subset; U+02282 subseteq; U+02286 subseteqq; U+02AC5 SubsetEqual; U+02286 subsetneq; U+0228A subsetneqq; U+02ACB subsim; U+02AC7 subsub; U+02AD5 subsup; U+02AD3 succ; U+0227B succapprox; U+02AB8 succcurlyeq; U+0227D Succeeds; U+0227B SucceedsEqual; U+02AB0 SucceedsSlantEqual; U+0227D SucceedsTilde; U+0227F succeq; U+02AB0 succnapprox; U+02ABA succneqq; U+02AB6 succnsim; U+022E9 succsim; U+0227F SuchThat; U+0220B Sum; U+02211 sum; U+02211 sung; U+0266A Sup; U+022D1 sup; U+02283 sup1; U+000B9 sup1 U+000B9 sup2; U+000B2 sup2 U+000B2 sup3; U+000B3 sup3 U+000B3 supdot; U+02ABE supdsub; U+02AD8 supE; U+02AC6 supe; U+02287 supedot; U+02AC4 Superset; U+02283 SupersetEqual; U+02287 suphsol; U+027C9 suphsub; U+02AD7 suplarr; U+0297B supmult; U+02AC2 supnE; U+02ACC supne; U+0228B supplus; U+02AC0 Supset; U+022D1 supset; U+02283 supseteq; U+02287 supseteqq; U+02AC6 supsetneq; U+0228B supsetneqq; U+02ACC supsim; U+02AC8 supsub; U+02AD4 supsup; U+02AD6 swarhk; U+02926 swArr; U+021D9 swarr; U+02199 swarrow; U+02199 swnwar; U+0292A szlig; U+000DF szlig U+000DF Tab; U+00009 target; U+02316 Tau; U+003A4 tau; U+003C4 tbrk; U+023B4 Tcaron; U+00164 tcaron; U+00165 Tcedil; U+00162 tcedil; U+00163 Tcy; U+00422 tcy; U+00442 tdot; U+020DB telrec; U+02315 Tfr; U+1D517 tfr; U+1D531 there4; U+02234 Therefore; U+02234 therefore; U+02234 Theta; U+00398 theta; U+003B8 thetasym; U+003D1 thetav; U+003D1 thickapprox; U+02248 thicksim; U+0223C ThickSpace; U+0205F U+0200A thinsp; U+02009 ThinSpace; U+02009 thkap; U+02248 thksim; U+0223C THORN; U+000DE THORN U+000DE thorn; U+000FE thorn U+000FE Tilde; U+0223C tilde; U+002DC TildeEqual; U+02243 TildeFullEqual; U+02245 TildeTilde; U+02248 times; U+000D7 times U+000D7 timesb; U+022A0 timesbar; U+02A31 timesd; U+02A30 tint; U+0222D toea; U+02928 top; U+022A4 topbot; U+02336 topcir; U+02AF1 Topf; U+1D54B topf; U+1D565 topfork; U+02ADA tosa; U+02929 tprime; U+02034 TRADE; U+02122 trade; U+02122 triangle; U+025B5 triangledown; U+025BF triangleleft; U+025C3 trianglelefteq; U+022B4 triangleq; U+0225C triangleright; U+025B9 trianglerighteq; U+022B5 tridot; U+025EC trie; U+0225C triminus; U+02A3A TripleDot; U+020DB triplus; U+02A39 trisb; U+029CD tritime; U+02A3B trpezium; U+023E2 Tscr; U+1D4AF tscr; U+1D4C9 TScy; U+00426 tscy; U+00446 TSHcy; U+0040B tshcy; U+0045B Tstrok; U+00166 tstrok; U+00167 twixt; U+0226C twoheadleftarrow; U+0219E twoheadrightarrow; U+021A0 Uacute; U+000DA Uacute U+000DA uacute; U+000FA uacute U+000FA Uarr; U+0219F uArr; U+021D1 uarr; U+02191 Uarrocir; U+02949 Ubrcy; U+0040E ubrcy; U+0045E Ubreve; U+0016C ubreve; U+0016D Ucirc; U+000DB Ucirc U+000DB ucirc; U+000FB ucirc U+000FB Ucy; U+00423 ucy; U+00443 udarr; U+021C5 Udblac; U+00170 udblac; U+00171 udhar; U+0296E ufisht; U+0297E Ufr; U+1D518 ufr; U+1D532 Ugrave; U+000D9 Ugrave U+000D9 ugrave; U+000F9 ugrave U+000F9 uHar; U+02963 uharl; U+021BF uharr; U+021BE uhblk; U+02580 ulcorn; U+0231C ulcorner; U+0231C ulcrop; U+0230F ultri; U+025F8 Umacr; U+0016A umacr; U+0016B uml; U+000A8 uml U+000A8 UnderBar; U+0005F UnderBrace; U+023DF UnderBracket; U+023B5 UnderParenthesis; U+023DD Union; U+022C3 UnionPlus; U+0228E Uogon; U+00172 uogon; U+00173 Uopf; U+1D54C uopf; U+1D566 UpArrow; U+02191 Uparrow; U+021D1 uparrow; U+02191 UpArrowBar; U+02912 UpArrowDownArrow; U+021C5 UpDownArrow; U+02195 Updownarrow; U+021D5 updownarrow; U+02195 UpEquilibrium; U+0296E upharpoonleft; U+021BF upharpoonright; U+021BE uplus; U+0228E UpperLeftArrow; U+02196 UpperRightArrow; U+02197 Upsi; U+003D2 upsi; U+003C5 upsih; U+003D2 Upsilon; U+003A5 upsilon; U+003C5 UpTee; U+022A5 UpTeeArrow; U+021A5 upuparrows; U+021C8 urcorn; U+0231D urcorner; U+0231D urcrop; U+0230E Uring; U+0016E uring; U+0016F urtri; U+025F9 Uscr; U+1D4B0 uscr; U+1D4CA utdot; U+022F0 Utilde; U+00168 utilde; U+00169 utri; U+025B5 utrif; U+025B4 uuarr; U+021C8 Uuml; U+000DC Uuml U+000DC uuml; U+000FC uuml U+000FC uwangle; U+029A7 vangrt; U+0299C varepsilon; U+003F5 varkappa; U+003F0 varnothing; U+02205 varphi; U+003D5 varpi; U+003D6 varpropto; U+0221D vArr; U+021D5 varr; U+02195 varrho; U+003F1 varsigma; U+003C2 varsubsetneq; U+0228A U+0FE00 varsubsetneqq; U+02ACB U+0FE00 varsupsetneq; U+0228B U+0FE00 varsupsetneqq; U+02ACC U+0FE00 vartheta; U+003D1 vartriangleleft; U+022B2 vartriangleright; U+022B3 Vbar; U+02AEB vBar; U+02AE8 vBarv; U+02AE9 Vcy; U+00412 vcy; U+00432 VDash; U+022AB Vdash; U+022A9 vDash; U+022A8 vdash; U+022A2 Vdashl; U+02AE6 Vee; U+022C1 vee; U+02228 veebar; U+022BB veeeq; U+0225A vellip; U+022EE Verbar; U+02016 verbar; U+0007C Vert; U+02016 vert; U+0007C VerticalBar; U+02223 VerticalLine; U+0007C VerticalSeparator; U+02758 VerticalTilde; U+02240 VeryThinSpace; U+0200A Vfr; U+1D519 vfr; U+1D533 vltri; U+022B2 vnsub; U+02282 U+020D2 vnsup; U+02283 U+020D2 Vopf; U+1D54D vopf; U+1D567 vprop; U+0221D vrtri; U+022B3 Vscr; U+1D4B1 vscr; U+1D4CB vsubnE; U+02ACB U+0FE00 vsubne; U+0228A U+0FE00 vsupnE; U+02ACC U+0FE00 vsupne; U+0228B U+0FE00 Vvdash; U+022AA vzigzag; U+0299A Wcirc; U+00174 wcirc; U+00175 wedbar; U+02A5F Wedge; U+022C0 wedge; U+02227 wedgeq; U+02259 weierp; U+02118 Wfr; U+1D51A wfr; U+1D534 Wopf; U+1D54E wopf; U+1D568 wp; U+02118 wr; U+02240 wreath; U+02240 Wscr; U+1D4B2 wscr; U+1D4CC xcap; U+022C2 xcirc; U+025EF xcup; U+022C3 xdtri; U+025BD Xfr; U+1D51B xfr; U+1D535 xhArr; U+027FA xharr; U+027F7 Xi; U+0039E xi; U+003BE xlArr; U+027F8 xlarr; U+027F5 xmap; U+027FC xnis; U+022FB xodot; U+02A00 Xopf; U+1D54F xopf; U+1D569 xoplus; U+02A01 xotime; U+02A02 xrArr; U+027F9 xrarr; U+027F6 Xscr; U+1D4B3 xscr; U+1D4CD xsqcup; U+02A06 xuplus; U+02A04 xutri; U+025B3 xvee; U+022C1 xwedge; U+022C0 Yacute; U+000DD Yacute U+000DD yacute; U+000FD yacute U+000FD YAcy; U+0042F yacy; U+0044F Ycirc; U+00176 ycirc; U+00177 Ycy; U+0042B ycy; U+0044B yen; U+000A5 yen U+000A5 Yfr; U+1D51C yfr; U+1D536 YIcy; U+00407 yicy; U+00457 Yopf; U+1D550 yopf; U+1D56A Yscr; U+1D4B4 yscr; U+1D4CE YUcy; U+0042E yucy; U+0044E Yuml; U+00178 yuml; U+000FF yuml U+000FF Zacute; U+00179 zacute; U+0017A Zcaron; U+0017D zcaron; U+0017E Zcy; U+00417 zcy; U+00437 Zdot; U+0017B zdot; U+0017C zeetrf; U+02128 ZeroWidthSpace; U+0200B Zeta; U+00396 zeta; U+003B6 Zfr; U+02128 zfr; U+1D537 ZHcy; U+00416 zhcy; U+00436 zigrarr; U+021DD Zopf; U+02124 zopf; U+1D56B Zscr; U+1D4B5 zscr; U+1D4CF zwj; U+0200D zwnj; U+0200C libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/EventEmitter.pm0000644000175000017500000000736312254653176023626 0ustar cstamascstamaspackage Mojo::EventEmitter; use Mojo::Base -base; use Scalar::Util qw(blessed weaken); use constant DEBUG => $ENV{MOJO_EVENTEMITTER_DEBUG} || 0; sub emit { my ($self, $name) = (shift, shift); if (my $s = $self->{events}{$name}) { warn "-- Emit $name in @{[blessed $self]} (@{[scalar @$s]})\n" if DEBUG; for my $cb (@$s) { $self->$cb(@_) } } else { warn "-- Emit $name in @{[blessed $self]} (0)\n" if DEBUG; die "@{[blessed $self]}: $_[0]" if $name eq 'error'; } return $self; } sub emit_safe { my ($self, $name) = (shift, shift); if (my $s = $self->{events}{$name}) { warn "-- Emit $name in @{[blessed $self]} safely (@{[scalar @$s]})\n" if DEBUG; for my $cb (@$s) { $self->emit(error => qq{Event "$name" failed: $@}) unless eval { $self->$cb(@_); 1 }; } } else { warn "-- Emit $name in @{[blessed $self]} safely (0)\n" if DEBUG; die "@{[blessed $self]}: $_[0]" if $name eq 'error'; } return $self; } sub has_subscribers { !!@{shift->subscribers(shift)} } sub on { my ($self, $name, $cb) = @_; push @{$self->{events}{$name} ||= []}, $cb; return $cb; } sub once { my ($self, $name, $cb) = @_; weaken $self; my $wrapper; $wrapper = sub { $self->unsubscribe($name => $wrapper); $cb->(@_); }; $self->on($name => $wrapper); weaken $wrapper; return $wrapper; } sub subscribers { shift->{events}{shift()} || [] } sub unsubscribe { my ($self, $name, $cb) = @_; # One if ($cb) { $self->{events}{$name} = [grep { $cb ne $_ } @{$self->{events}{$name}}]; delete $self->{events}{$name} unless @{$self->{events}{$name}}; } # All else { delete $self->{events}{$name} } return $self; } 1; =encoding utf8 =head1 NAME Mojo::EventEmitter - Event emitter base class =head1 SYNOPSIS package Cat; use Mojo::Base 'Mojo::EventEmitter'; # Emit events sub poke { my $self = shift; $self->emit(roar => 3); } package main; # Subscribe to events my $tiger = Cat->new; $tiger->on(roar => sub { my ($tiger, $times) = @_; say 'RAWR!' for 1 .. $times; }); $tiger->poke; =head1 DESCRIPTION L is a simple base class for event emitting objects. =head1 EVENTS L can emit the following events. =head2 error $e->on(error => sub { my ($e, $err) = @_; ... }); Emitted for event errors, fatal if unhandled. $e->on(error => sub { my ($e, $err) = @_; say "This looks bad: $err"; }); =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 emit $e = $e->emit('foo'); $e = $e->emit('foo', 123); Emit event. =head2 emit_safe $e = $e->emit_safe('foo'); $e = $e->emit_safe('foo', 123); Emit event safely and emit L event on failure. =head2 has_subscribers my $bool = $e->has_subscribers('foo'); Check if event has subscribers. =head2 on my $cb = $e->on(foo => sub {...}); Subscribe to event. $e->on(foo => sub { my ($e, @args) = @_; ... }); =head2 once my $cb = $e->once(foo => sub {...}); Subscribe to event and unsubscribe again after it has been emitted once. $e->once(foo => sub { my ($e, @args) = @_; ... }); =head2 subscribers my $subscribers = $e->subscribers('foo'); All subscribers for event. # Unsubscribe last subscriber $e->unsubscribe(foo => $e->subscribers('foo')->[-1]); =head2 unsubscribe $e = $e->unsubscribe('foo'); $e = $e->unsubscribe(foo => $cb); Unsubscribe from event. =head1 DEBUGGING You can set the MOJO_EVENTEMITTER_DEBUG environment variable to get some advanced diagnostics information printed to C. MOJO_EVENTEMITTER_DEBUG=1 =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Exception.pm0000644000175000017500000001044312245761253023136 0ustar cstamascstamaspackage Mojo::Exception; use Mojo::Base -base; use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1; use Scalar::Util 'blessed'; has [qw(frames line lines_before lines_after)] => sub { [] }; has message => 'Exception!'; has 'verbose'; sub new { my $self = shift->SUPER::new; return @_ ? $self->_detect(@_) : $self; } sub throw { die shift->new->trace(2)->_detect(@_) } sub to_string { my $self = shift; return $self->message unless $self->verbose; my $str = $self->message ? $self->message : ''; # Before $str .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_before}; # Line $str .= ($self->line->[0] . ': ' . $self->line->[1] . "\n") if $self->line->[0]; # After $str .= $_->[0] . ': ' . $_->[1] . "\n" for @{$self->lines_after}; return $str; } sub trace { my ($self, $start) = @_; $start //= 1; my @frames; while (my @trace = caller($start++)) { push @frames, \@trace } return $self->frames(\@frames); } sub _context { my ($self, $num, $lines) = @_; # Line return unless defined $lines->[0][$num - 1]; $self->line([$num]); for my $line (@$lines) { chomp(my $code = $line->[$num - 1]); push @{$self->line}, $code; } # Before for my $i (2 .. 6) { last if ((my $previous = $num - $i) < 0); next unless defined $lines->[0][$previous]; unshift @{$self->lines_before}, [$previous + 1]; for my $line (@$lines) { chomp(my $code = $line->[$previous]); push @{$self->lines_before->[0]}, $code; } } # After for my $i (0 .. 4) { next if ((my $next = $num + $i) < 0); next unless defined $lines->[0][$next]; push @{$self->lines_after}, [$next + 1]; for my $line (@$lines) { last unless defined(my $code = $line->[$next]); chomp $code; push @{$self->lines_after->[-1]}, $code; } } } sub _detect { my ($self, $msg, $files) = @_; return $msg if blessed $msg && $msg->isa('Mojo::Exception'); $self->message($msg); # Extract file and line from message my @trace; while ($msg =~ /at\s+(.+?)\s+line\s+(\d+)/g) { unshift @trace, [$1, $2] } # Extract file and line from stacktrace my $first = $self->frames->[0]; unshift @trace, [$first->[1], $first->[2]] if $first; # Search for context in files for my $frame (@trace) { next unless -r $frame->[0] && open my $handle, '<:utf8', $frame->[0]; $self->_context($frame->[1], [[<$handle>]]); return $self; } # More context $self->_context($trace[0][1], [map { [split /\n/] } @$files]) if $files; return $self; } 1; =encoding utf8 =head1 NAME Mojo::Exception - Exceptions with context =head1 SYNOPSIS use Mojo::Exception; # Throw exception Mojo::Exception->throw('Not again!'); # Customize exception die Mojo::Exception->new('Not again!')->trace(2)->verbose(1); =head1 DESCRIPTION L is a container for exceptions with context information. =head1 ATTRIBUTES L implements the following attributes. =head2 frames my $frames = $e->frames; $e = $e->frames($frames); Stacktrace. =head2 line my $line = $e->line; $e = $e->line([3 => 'foo']); The line where the exception occurred. =head2 lines_after my $lines = $e->lines_after; $e = $e->lines_after([[1 => 'bar'], [2 => 'baz']]); Lines after the line where the exception occurred. =head2 lines_before my $lines = $e->lines_before; $e = $e->lines_before([[4 => 'bar'], [5 => 'baz']]); Lines before the line where the exception occurred. =head2 message my $msg = $e->message; $e = $e->message('Oops!'); Exception message. =head2 verbose my $bool = $e->verbose; $e = $e->verbose($bool); Render exception with context. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $e = Mojo::Exception->new('Oops!'); my $e = Mojo::Exception->new('Oops!', $files); Construct a new L object. =head2 throw Mojo::Exception->throw('Oops!'); Mojo::Exception->throw('Oops!', $files); Throw exception with stacktrace. =head2 to_string my $str = $e->to_string; my $str = "$e"; Render exception. =head2 trace $e = $e->trace; $e = $e->trace(2); Store stacktrace. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Headers.pm0000644000175000017500000003441112242771603022551 0ustar cstamascstamaspackage Mojo::Headers; use Mojo::Base -base; use Mojo::Util qw(get_line monkey_patch); has max_line_size => sub { $ENV{MOJO_MAX_LINE_SIZE} || 10240 }; # Common headers my @HEADERS = ( qw(Accept Accept-Charset Accept-Encoding Accept-Language Accept-Ranges), qw(Allow Authorization Cache-Control Connection Content-Disposition), qw(Content-Encoding Content-Length Content-Range Content-Type Cookie DNT), qw(Date ETag Expect Expires Host If-Modified-Since Last-Modified Link), qw(Location Origin Proxy-Authenticate Proxy-Authorization Range), qw(Sec-WebSocket-Accept Sec-WebSocket-Extensions Sec-WebSocket-Key), qw(Sec-WebSocket-Protocol Sec-WebSocket-Version Server Set-Cookie Status), qw(TE Trailer Transfer-Encoding Upgrade User-Agent Vary WWW-Authenticate) ); for my $header (@HEADERS) { my $name = lc $header; $name =~ s/-/_/g; monkey_patch __PACKAGE__, $name, sub { scalar shift->header($header => @_) }; } # Lowercase headers my %NORMALCASE = map { lc($_) => $_ } @HEADERS; sub add { my ($self, $name) = (shift, shift); # Make sure we have a normal case entry for name my $key = lc $name; $self->{normalcase}{$key} //= $name unless $NORMALCASE{$key}; # Add lines push @{$self->{headers}{$key}}, map { ref $_ eq 'ARRAY' ? $_ : [$_] } @_; return $self; } sub append { my ($self, $name, $value) = @_; my $old = $self->header($name); return $self->header($name => defined $old ? "$old, $value" : $value); } sub clone { my $self = shift; return $self->new->from_hash($self->to_hash(1)); } sub from_hash { my ($self, $hash) = @_; # Empty hash deletes all headers delete $self->{headers} if keys %{$hash} == 0; # Merge while (my ($header, $value) = each %$hash) { $self->add($header => ref $value eq 'ARRAY' ? @$value : $value); } return $self; } sub header { my ($self, $name) = (shift, shift); # Replace return $self->remove($name)->add($name, @_) if @_; # String return unless my $headers = $self->{headers}{lc $name}; return join ', ', map { join ', ', @$_ } @$headers unless wantarray; # Array return @$headers; } sub is_finished { (shift->{state} // '') eq 'finished' } sub is_limit_exceeded { !!shift->{limit} } sub leftovers { delete shift->{buffer} } sub names { my $self = shift; return [map { $NORMALCASE{$_} || $self->{normalcase}{$_} || $_ } keys %{$self->{headers}}]; } sub parse { my $self = shift; $self->{state} = 'headers'; $self->{buffer} .= shift // ''; my $headers = $self->{cache} ||= []; my $max = $self->max_line_size; while (defined(my $line = get_line \$self->{buffer})) { # Check line size limit if (length $line > $max) { $self->{limit} = $self->{state} = 'finished'; return $self; } # New header if ($line =~ /^(\S+)\s*:\s*(.*)$/) { push @$headers, $1, [$2] } # Multiline elsif (@$headers && $line =~ s/^\s+//) { push @{$headers->[-1]}, $line } # Empty line else { $self->add(splice @$headers, 0, 2) while @$headers; $self->{state} = 'finished'; return $self; } } # Check line size limit $self->{limit} = $self->{state} = 'finished' if length $self->{buffer} > $max; return $self; } sub referrer { scalar shift->header(Referer => @_) } sub remove { my ($self, $name) = @_; delete $self->{headers}{lc $name}; return $self; } sub to_hash { my ($self, $multi) = @_; my %hash; $hash{$_} = $multi ? [$self->header($_)] : scalar $self->header($_) for @{$self->names}; return \%hash; } sub to_string { my $self = shift; # Make sure multiline values are formatted correctly my @headers; for my $name (@{$self->names}) { push @headers, "$name: " . join("\x0d\x0a ", @$_) for $self->header($name); } return join "\x0d\x0a", @headers; } 1; =encoding utf8 =head1 NAME Mojo::Headers - Headers =head1 SYNOPSIS use Mojo::Headers; # Parse my $headers = Mojo::Headers->new; $headers->parse("Content-Length: 42\x0d\x0a"); $headers->parse("Content-Type: text/html\x0d\x0a\x0d\x0a"); say $headers->content_length; say $headers->content_type; # Build my $headers = Mojo::Headers->new; $headers->content_length(42); $headers->content_type('text/plain'); say $headers->to_string; =head1 DESCRIPTION L is a container for HTTP headers as described in RFC 2616. =head1 ATTRIBUTES L implements the following attributes. =head2 max_line_size my $size = $headers->max_line_size; $headers = $headers->max_line_size(1024); Maximum header line size in bytes, defaults to the value of the MOJO_MAX_LINE_SIZE environment variable or C<10240>. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 accept my $accept = $headers->accept; $headers = $headers->accept('application/json'); Shortcut for the C header. =head2 accept_charset my $charset = $headers->accept_charset; $headers = $headers->accept_charset('UTF-8'); Shortcut for the C header. =head2 accept_encoding my $encoding = $headers->accept_encoding; $headers = $headers->accept_encoding('gzip'); Shortcut for the C header. =head2 accept_language my $language = $headers->accept_language; $headers = $headers->accept_language('de, en'); Shortcut for the C header. =head2 accept_ranges my $ranges = $headers->accept_ranges; $headers = $headers->accept_ranges('bytes'); Shortcut for the C header. =head2 add $headers = $headers->add(Foo => 'one value'); $headers = $headers->add(Foo => 'first value', 'second value'); $headers = $headers->add(Foo => ['first line', 'second line']); Add one or more header values with one or more lines. # "Vary: Accept" # "Vary: Accept-Encoding" $headers->vary('Accept')->add(Vary => 'Accept-Encoding')->to_string; =head2 allow my $allow = $headers->allow; $headers = $headers->allow('GET, POST'); Shortcut for the C header. =head2 append $headers = $headers->append(Vary => 'Accept-Encoding'); Append value to header and flatten it if necessary. # "Vary: Accept" $headers->append(Vary => 'Accept')->to_string; # "Vary: Accept, Accept-Encoding" $headers->vary('Accept')->append(Vary => 'Accept-Encoding')->to_string; =head2 authorization my $authorization = $headers->authorization; $headers = $headers->authorization('Basic Zm9vOmJhcg=='); Shortcut for the C header. =head2 cache_control my $cache_control = $headers->cache_control; $headers = $headers->cache_control('max-age=1, no-cache'); Shortcut for the C header. =head2 clone my $clone = $headers->clone; Clone headers. =head2 connection my $connection = $headers->connection; $headers = $headers->connection('close'); Shortcut for the C header. =head2 content_disposition my $disposition = $headers->content_disposition; $headers = $headers->content_disposition('foo'); Shortcut for the C header. =head2 content_encoding my $encoding = $headers->content_encoding; $headers = $headers->content_encoding('gzip'); Shortcut for the C header. =head2 content_length my $len = $headers->content_length; $headers = $headers->content_length(4000); Shortcut for the C header. =head2 content_range my $range = $headers->content_range; $headers = $headers->content_range('bytes 2-8/100'); Shortcut for the C header. =head2 content_type my $type = $headers->content_type; $headers = $headers->content_type('text/plain'); Shortcut for the C header. =head2 cookie my $cookie = $headers->cookie; $headers = $headers->cookie('f=b'); Shortcut for the C header from RFC 6265. =head2 date my $date = $headers->date; $headers = $headers->date('Sun, 17 Aug 2008 16:27:35 GMT'); Shortcut for the C header. =head2 dnt my $dnt = $headers->dnt; $headers = $headers->dnt(1); Shortcut for the C (Do Not Track) header, which has no specification yet, but is very commonly used. =head2 etag my $etag = $headers->etag; $headers = $headers->etag('abc321'); Shortcut for the C header. =head2 expect my $expect = $headers->expect; $headers = $headers->expect('100-continue'); Shortcut for the C header. =head2 expires my $expires = $headers->expires; $headers = $headers->expires('Thu, 01 Dec 1994 16:00:00 GMT'); Shortcut for the C header. =head2 from_hash $headers = $headers->from_hash({'Content-Type' => 'text/html'}); $headers = $headers->from_hash({}); Parse headers from a hash reference, an empty hash removes all headers. =head2 header my $value = $headers->header('Foo'); my @values = $headers->header('Foo'); $headers = $headers->header(Foo => 'one value'); $headers = $headers->header(Foo => 'first value', 'second value'); $headers = $headers->header(Foo => ['first line', 'second line']); Get or replace the current header values. # Multiple headers with the same name for my $header ($headers->header('Set-Cookie')) { say 'Set-Cookie:'; # Multiple lines per header say for @$header; } =head2 host my $host = $headers->host; $headers = $headers->host('127.0.0.1'); Shortcut for the C header. =head2 if_modified_since my $date = $headers->if_modified_since; $headers = $headers->if_modified_since('Sun, 17 Aug 2008 16:27:35 GMT'); Shortcut for the C header. =head2 is_finished my $bool = $headers->is_finished; Check if header parser is finished. =head2 is_limit_exceeded my $bool = $headers->is_limit_exceeded; Check if a header has exceeded C. =head2 last_modified my $date = $headers->last_modified; $headers = $headers->last_modified('Sun, 17 Aug 2008 16:27:35 GMT'); Shortcut for the C header. =head2 leftovers my $bytes = $headers->leftovers; Get leftover data from header parser. =head2 link my $link = $headers->link; $headers = $headers->link('; rel="next"'); Shortcut for the C header from RFC 5988. =head2 location my $location = $headers->location; $headers = $headers->location('http://127.0.0.1/foo'); Shortcut for the C header. =head2 names my $names = $headers->names; Return a list of all currently defined headers. # Names of all headers say for @{$headers->names}; =head2 origin my $origin = $headers->origin; $headers = $headers->origin('http://example.com'); Shortcut for the C header from RFC 6454. =head2 parse $headers = $headers->parse("Content-Type: text/plain\x0d\x0a\x0d\x0a"); Parse formatted headers. =head2 proxy_authenticate my $authenticate = $headers->proxy_authenticate; $headers = $headers->proxy_authenticate('Basic "realm"'); Shortcut for the C header. =head2 proxy_authorization my $authorization = $headers->proxy_authorization; $headers = $headers->proxy_authorization('Basic Zm9vOmJhcg=='); Shortcut for the C header. =head2 range my $range = $headers->range; $headers = $headers->range('bytes=2-8'); Shortcut for the C header. =head2 referrer my $referrer = $headers->referrer; $headers = $headers->referrer('http://example.com'); Shortcut for the C header, there was a typo in RFC 2068 which resulted in C becoming an official header. =head2 remove $headers = $headers->remove('Foo'); Remove a header. =head2 sec_websocket_accept my $accept = $headers->sec_websocket_accept; $headers = $headers->sec_websocket_accept('s3pPLMBiTxaQ9kYGzzhZRbK+xOo='); Shortcut for the C header from RFC 6455. =head2 sec_websocket_extensions my $extensions = $headers->sec_websocket_extensions; $headers = $headers->sec_websocket_extensions('foo'); Shortcut for the C header from RFC 6455. =head2 sec_websocket_key my $key = $headers->sec_websocket_key; $headers = $headers->sec_websocket_key('dGhlIHNhbXBsZSBub25jZQ=='); Shortcut for the C header from RFC 6455. =head2 sec_websocket_protocol my $proto = $headers->sec_websocket_protocol; $headers = $headers->sec_websocket_protocol('sample'); Shortcut for the C header from RFC 6455. =head2 sec_websocket_version my $version = $headers->sec_websocket_version; $headers = $headers->sec_websocket_version(13); Shortcut for the C header from RFC 6455. =head2 server my $server = $headers->server; $headers = $headers->server('Mojo'); Shortcut for the C header. =head2 set_cookie my $cookie = $headers->set_cookie; $headers = $headers->set_cookie('f=b; path=/'); Shortcut for the C header from RFC 6265. =head2 status my $status = $headers->status; $headers = $headers->status('200 OK'); Shortcut for the C header from RFC 3875. =head2 te my $te = $headers->te; $headers = $headers->te('chunked'); Shortcut for the C header. =head2 to_hash my $single = $headers->to_hash; my $multi = $headers->to_hash(1); Turn headers into hash reference, nested array references to represent multiline values are disabled by default. say $headers->to_hash->{DNT}; =head2 to_string my $str = $headers->to_string; Turn headers into a string, suitable for HTTP messages. =head2 trailer my $trailer = $headers->trailer; $headers = $headers->trailer('X-Foo'); Shortcut for the C header. =head2 transfer_encoding my $encoding = $headers->transfer_encoding; $headers = $headers->transfer_encoding('chunked'); Shortcut for the C header. =head2 upgrade my $upgrade = $headers->upgrade; $headers = $headers->upgrade('websocket'); Shortcut for the C header. =head2 user_agent my $agent = $headers->user_agent; $headers = $headers->user_agent('Mojo/1.0'); Shortcut for the C header. =head2 vary my $vary = $headers->vary; $headers = $headers->vary('*'); Shortcut for the C header. =head2 www_authenticate my $authenticate = $headers->www_authenticate; $headers = $headers->www_authenticate('Basic realm="realm"'); Shortcut for the C header. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/HelloWorld.pm0000644000175000017500000000101112242771601023235 0ustar cstamascstamaspackage Mojo::HelloWorld; use Mojolicious::Lite; app->log->level('error')->path(undef); any '/*whatever' => {whatever => '', text => 'Your Mojo is working!'}; 1; =encoding utf8 =head1 NAME Mojo::HelloWorld - Hello World! =head1 SYNOPSIS use Mojo::HelloWorld; my $hello = Mojo::HelloWorld->new; $hello->start; =head1 DESCRIPTION L is the default L application, used mostly for testing. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Home.pm0000644000175000017500000000734312242771577022104 0ustar cstamascstamaspackage Mojo::Home; use Mojo::Base -base; use overload bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1; use Cwd 'abs_path'; use File::Basename 'dirname'; use File::Find 'find'; use File::Spec::Functions qw(abs2rel catdir catfile splitdir); use FindBin; use Mojo::Util qw(class_to_path slurp); has parts => sub { [] }; sub new { shift->SUPER::new->parse(@_) } sub detect { my $self = shift; # Environment variable return $self->parts([splitdir(abs_path $ENV{MOJO_HOME})]) if $ENV{MOJO_HOME}; # Try to find home from lib directory if (my $class = @_ ? shift : 'Mojo::HelloWorld') { my $file = class_to_path $class; if (my $path = $INC{$file}) { $path =~ s/$file$//; my @home = splitdir $path; # Remove "lib" and "blib" pop @home while @home && ($home[-1] =~ /^b?lib$/ || $home[-1] eq ''); # Turn into absolute path return $self->parts([splitdir(abs_path(catdir(@home) || '.'))]); } } # FindBin fallback return $self->parts([split /\//, $FindBin::Bin]); } sub lib_dir { my $path = catdir @{shift->parts}, 'lib'; return -d $path ? $path : undef; } sub list_files { my ($self, $dir) = @_; $dir = catdir @{$self->parts}, split '/', ($dir // ''); return [] unless -d $dir; my @files; find { wanted => sub { my @parts = splitdir(abs2rel($File::Find::name, $dir)); push @files, join '/', @parts unless grep {/^\./} @parts; }, no_chdir => 1 }, $dir; return [sort @files]; } sub mojo_lib_dir { catdir(dirname(__FILE__), '..') } sub parse { my ($self, $path) = @_; return defined $path ? $self->parts([splitdir $path]) : $self; } sub rel_dir { catdir(@{shift->parts}, split '/', shift) } sub rel_file { catfile(@{shift->parts}, split '/', shift) } sub to_string { catdir(@{shift->parts}) } 1; =encoding utf8 =head1 NAME Mojo::Home - Home sweet home! =head1 SYNOPSIS use Mojo::Home; # Find and manage the project root directory my $home = Mojo::Home->new; $home->detect; say $home->lib_dir; say $home->rel_file('templates/layouts/default.html.ep'); say "$home"; =head1 DESCRIPTION L is a container for home directories. =head1 ATTRIBUTES L implements the following attributes. =head2 parts my $parts = $home->parts; $home = $home->parts([]); Home directory parts. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $home = Mojo::Home->new; my $home = Mojo::Home->new('/home/sri/myapp'); Construct a new L object and L home directory if necessary. =head2 detect $home = $home->detect; $home = $home->detect('My::App'); Detect home directory from the value of the MOJO_HOME environment variable or application class. =head2 lib_dir my $path = $home->lib_dir; Path to C directory of application. =head2 list_files my $files = $home->list_files; my $files = $home->list_files('foo/bar'); Portably list all files recursively in directory relative to the home directory. say $home->rel_file($home->list_files('templates/layouts')->[1]); =head2 mojo_lib_dir my $path = $home->mojo_lib_dir; Path to C directory in which L is installed. =head2 parse $home = $home->parse('/home/sri/myapp'); Parse home directory. =head2 rel_dir my $path = $home->rel_dir('foo/bar'); Portably generate an absolute path for a directory relative to the home directory. =head2 rel_file my $path = $home->rel_file('foo/bar.html'); Portably generate an absolute path for a file relative to the home directory. =head2 to_string my $str = $home->to_string; my $str = "$home"; Home directory. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop/0000755000175000017500000000000012256126533021777 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop/Client.pm0000644000175000017500000001457112254163751023564 0ustar cstamascstamaspackage Mojo::IOLoop::Client; use Mojo::Base 'Mojo::EventEmitter'; use Errno 'EINPROGRESS'; use IO::Socket::INET; use Scalar::Util 'weaken'; use Socket qw(IPPROTO_TCP SO_ERROR TCP_NODELAY); # IPv6 support requires IO::Socket::IP use constant IPV6 => $ENV{MOJO_NO_IPV6} ? 0 : eval 'use IO::Socket::IP 0.16 (); 1'; # TLS support requires IO::Socket::SSL use constant TLS => $ENV{MOJO_NO_TLS} ? 0 : eval(IPV6 ? 'use IO::Socket::SSL 1.75 (); 1' : 'use IO::Socket::SSL 1.75 "inet4"; 1'); use constant TLS_READ => TLS ? IO::Socket::SSL::SSL_WANT_READ() : 0; use constant TLS_WRITE => TLS ? IO::Socket::SSL::SSL_WANT_WRITE() : 0; has reactor => sub { require Mojo::IOLoop; Mojo::IOLoop->singleton->reactor; }; sub DESTROY { shift->_cleanup } sub connect { my $self = shift; my $args = ref $_[0] ? $_[0] : {@_}; weaken $self; $self->{delay} = $self->reactor->timer(0 => sub { $self->_connect($args) }); } sub _cleanup { my $self = shift; return $self unless my $reactor = $self->reactor; $self->{$_} && $reactor->remove(delete $self->{$_}) for qw(delay timer handle); return $self; } sub _connect { my ($self, $args) = @_; my $handle; my $reactor = $self->reactor; my $address = $args->{address} ||= 'localhost'; unless ($handle = $self->{handle} = $args->{handle}) { my %options = ( Blocking => 0, PeerAddr => $address eq 'localhost' ? '127.0.0.1' : $address, PeerPort => $args->{port} || ($args->{tls} ? 443 : 80) ); $options{LocalAddr} = $args->{local_address} if $args->{local_address}; $options{PeerAddr} =~ s/[\[\]]//g if $options{PeerAddr}; my $class = IPV6 ? 'IO::Socket::IP' : 'IO::Socket::INET'; return $self->emit(error => "Couldn't connect: $@") unless $self->{handle} = $handle = $class->new(%options); # Timeout $self->{timer} = $reactor->timer($args->{timeout} || 10, sub { $self->emit(error => 'Connect timeout') }); } $handle->blocking(0); # Wait for handle to become writable weaken $self; $reactor->io($handle => sub { $self->_try($args) })->watch($handle, 0, 1); } sub _tls { my $self = shift; # Connected my $handle = $self->{handle}; return $self->_cleanup->emit_safe(connect => $handle) if $handle->connect_SSL; # Switch between reading and writing my $err = $IO::Socket::SSL::SSL_ERROR; if ($err == TLS_READ) { $self->reactor->watch($handle, 1, 0) } elsif ($err == TLS_WRITE) { $self->reactor->watch($handle, 1, 1) } } sub _try { my ($self, $args) = @_; # Retry or handle exceptions my $handle = $self->{handle}; return $! == EINPROGRESS ? undef : $self->emit(error => $!) if IPV6 && !$handle->connect; return $self->emit(error => $! = $handle->sockopt(SO_ERROR)) if !IPV6 && !$handle->connected; # Disable Nagle's algorithm setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1; return $self->_cleanup->emit_safe(connect => $handle) if !$args->{tls} || $handle->isa('IO::Socket::SSL'); return $self->emit(error => 'IO::Socket::SSL 1.75 required for TLS support') unless TLS; # Upgrade weaken $self; my %options = ( SSL_ca_file => $args->{tls_ca} && -T $args->{tls_ca} ? $args->{tls_ca} : undef, SSL_cert_file => $args->{tls_cert}, SSL_error_trap => sub { $self->_cleanup->emit(error => $_[1]) }, SSL_hostname => $args->{address}, SSL_key_file => $args->{tls_key}, SSL_startHandshake => 0, SSL_verify_mode => $args->{tls_ca} ? 0x01 : 0x00, SSL_verifycn_name => $args->{address}, SSL_verifycn_scheme => $args->{tls_ca} ? 'http' : undef ); my $reactor = $self->reactor; $reactor->remove($handle); return $self->emit(error => 'TLS upgrade failed') unless $handle = IO::Socket::SSL->start_SSL($handle, %options); $reactor->io($handle => sub { $self->_tls })->watch($handle, 0, 1); } 1; =encoding utf8 =head1 NAME Mojo::IOLoop::Client - Non-blocking TCP client =head1 SYNOPSIS use Mojo::IOLoop::Client; # Create socket connection my $client = Mojo::IOLoop::Client->new; $client->on(connect => sub { my ($client, $handle) = @_; ... }); $client->on(error => sub { my ($client, $err) = @_; ... }); $client->connect(address => 'example.com', port => 80); # Start reactor if necessary $client->reactor->start unless $client->reactor->is_running; =head1 DESCRIPTION L opens TCP connections for L. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 connect $client->on(connect => sub { my ($client, $handle) = @_; ... }); Emitted safely once the connection is established. =head2 error $client->on(error => sub { my ($client, $err) = @_; ... }); Emitted if an error occurs on the connection, fatal if unhandled. =head1 ATTRIBUTES L implements the following attributes. =head2 reactor my $reactor = $client->reactor; $client = $client->reactor(Mojo::Reactor::Poll->new); Low level event reactor, defaults to the C attribute value of the global L singleton. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 connect $client->connect(address => '127.0.0.1', port => 3000); Open a socket connection to a remote host. Note that TLS support depends on L (1.75+) and IPv6 support on L (0.16+). These options are currently available: =over 2 =item address address => 'mojolicio.us' Address or host name of the peer to connect to, defaults to C. =item handle handle => $handle Use an already prepared handle. =item local_address local_address => '127.0.0.1' Local address to bind to. =item port port => 80 Port to connect to, defaults to C<80> or C<443> with C option. =item timeout timeout => 15 Maximum amount of time in seconds establishing connection may take before getting canceled, defaults to C<10>. =item tls tls => 1 Enable TLS. =item tls_ca tls_ca => '/etc/tls/ca.crt' Path to TLS certificate authority file. Also activates hostname verification. =item tls_cert tls_cert => '/etc/tls/client.crt' Path to the TLS certificate file. =item tls_key tls_key => '/etc/tls/client.key' Path to the TLS key file. =back =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop/Delay.pm0000644000175000017500000001104512254163760023375 0ustar cstamascstamaspackage Mojo::IOLoop::Delay; use Mojo::Base 'Mojo::EventEmitter'; use Mojo::IOLoop; has ioloop => sub { Mojo::IOLoop->singleton }; sub begin { my ($self, $ignore) = @_; $self->{pending}++; my $id = $self->{counter}++; return sub { $ignore // 1 and shift; $self->_step($id, @_) }; } sub steps { my $self = shift; $self->{steps} = [@_]; $self->ioloop->timer(0 => $self->begin); return $self; } sub wait { my $self = shift; my @args; $self->once(error => \&_die); $self->once(finish => sub { shift->ioloop->stop; @args = @_ }); $self->ioloop->start; return wantarray ? @args : $args[0]; } sub _die { $_[0]->has_subscribers('error') ? $_[0]->ioloop->stop : die $_[1] } sub _step { my ($self, $id) = (shift, shift); $self->{args}[$id] = [@_]; return if $self->{fail} || --$self->{pending} || $self->{lock}; local $self->{lock} = 1; my @args = map {@$_} @{delete $self->{args}}; $self->{counter} = 0; if (my $cb = shift @{$self->{steps} ||= []}) { eval { $self->$cb(@args); 1 } or return $self->emit(error => $@)->{fail}++; } return $self->emit(finish => @args) unless $self->{counter}; $self->ioloop->timer(0 => $self->begin) unless $self->{pending}; } 1; =encoding utf8 =head1 NAME Mojo::IOLoop::Delay - Manage callbacks and control the flow of events =head1 SYNOPSIS use Mojo::IOLoop::Delay; # Synchronize multiple events my $delay = Mojo::IOLoop::Delay->new; $delay->on(finish => sub { say 'BOOM!' }); for my $i (1 .. 10) { my $end = $delay->begin; Mojo::IOLoop->timer($i => sub { say 10 - $i; $end->(); }); } $delay->wait unless Mojo::IOLoop->is_running; # Sequentialize multiple events my $delay = Mojo::IOLoop::Delay->new; $delay->steps( # First step (simple timer) sub { my $delay = shift; Mojo::IOLoop->timer(2 => $delay->begin); say 'Second step in 2 seconds.'; }, # Second step (parallel timers) sub { my ($delay, @args) = @_; Mojo::IOLoop->timer(1 => $delay->begin); Mojo::IOLoop->timer(3 => $delay->begin); say 'Third step in 3 seconds.'; }, # Third step (the end) sub { my ($delay, @args) = @_; say 'And done after 5 seconds total.'; } ); $delay->wait unless Mojo::IOLoop->is_running; =head1 DESCRIPTION L manages callbacks and controls the flow of events for L. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 error $delay->on(error => sub { my ($delay, $err) = @_; ... }); Emitted if an error occurs in one of the steps, breaking the chain, fatal if unhandled. =head2 finish $delay->on(finish => sub { my ($delay, @args) = @_; ... }); Emitted once the active event counter reaches zero and there are no more steps. =head1 ATTRIBUTES L implements the following attributes. =head2 ioloop my $ioloop = $delay->ioloop; $delay = $delay->ioloop(Mojo::IOLoop->new); Event loop object to control, defaults to the global L singleton. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 begin my $without_first_arg = $delay->begin; my $with_first_arg = $delay->begin(0); Increment active event counter, the returned callback can be used to decrement the active event counter again. Arguments passed to the callback are queued in the right order for the next step or L event and L method, the first argument will be ignored by default. # Capture all arguments my $delay = Mojo::IOLoop->delay; Mojo::IOLoop->client({port => 3000} => $delay->begin(0)); my ($loop, $err, $stream) = $delay->wait; =head2 steps $delay = $delay->steps(sub {...}, sub {...}); Sequentialize multiple events, the first callback will run right away, and the next one once the active event counter reaches zero. This chain will continue until there are no more callbacks, a callback does not increment the active event counter or an error occurs in a callback. =head2 wait my $arg = $delay->wait; my @args = $delay->wait; Start L and stop it again once an L or L event gets emitted, only works when L is not running already. # Use the "finish" event to synchronize portably $delay->on(finish => sub { my ($delay, @args) = @_; ... }); $delay->wait unless $delay->ioloop->is_running; =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop/server.crt0000644000175000017500000000233512054604347024022 0ustar cstamascstamas-----BEGIN CERTIFICATE----- MIIDaTCCAtKgAwIBAgIJAI+AzotR68CTMA0GCSqGSIb3DQEBBQUAMIGAMQswCQYD VQQGEwJERTEWMBQGA1UECBMNTmllZGVyc2FjaHNlbjESMBAGA1UEBxMJSGFtYmVy Z2VuMRQwEgYDVQQKEwtNb2pvbGljaW91czESMBAGA1UEAxMJbG9jYWxob3N0MRsw GQYJKoZIhvcNAQkBFgxzcmlAY3Bhbi5vcmcwHhcNMTIwNDE4MTczOTU5WhcNMzIw NDEzMTczOTU5WjCBgDELMAkGA1UEBhMCREUxFjAUBgNVBAgTDU5pZWRlcnNhY2hz ZW4xEjAQBgNVBAcTCUhhbWJlcmdlbjEUMBIGA1UEChMLTW9qb2xpY2lvdXMxEjAQ BgNVBAMTCWxvY2FsaG9zdDEbMBkGCSqGSIb3DQEJARYMc3JpQGNwYW4ub3JnMIGf MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCohcU0qG+hHn6JK8XdygAJo7EuRqG2 5GSHaRRMyYgd89tEluInMH86tVcktJ1s/0VVvr5anAp8L7Pgu01Wr13OfgIzBxCz 51ZIFxq4DtimBftXs9Z9M0sui2NuIPDrMEjkYUhUsxMEZcDSp2KJjDosZjSYUiiF G2ACvVGXSrS16QIDAQABo4HoMIHlMB0GA1UdDgQWBBSrZ+hIlPTgV7xx2O9wzdIO /d4osDCBtQYDVR0jBIGtMIGqgBSrZ+hIlPTgV7xx2O9wzdIO/d4osKGBhqSBgzCB gDELMAkGA1UEBhMCREUxFjAUBgNVBAgTDU5pZWRlcnNhY2hzZW4xEjAQBgNVBAcT CUhhbWJlcmdlbjEUMBIGA1UEChMLTW9qb2xpY2lvdXMxEjAQBgNVBAMTCWxvY2Fs aG9zdDEbMBkGCSqGSIb3DQEJARYMc3JpQGNwYW4ub3JnggkAj4DOi1HrwJMwDAYD VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQAq6MXA7ZeO7B7vAcWxQKeLPKSy Jzkb1bC/agaISDbOwuZ1AoQSj6OQHKhNIdY5v/oLQJ0B8wB0dIigqn1WVacDtPgu PKSrxpqieDCh2bJ7+dyQIzQHgtZqPHi5k1PyNNXQxC94kPWdFp6PpF0M/y97aCxC ZQjKgDfncFWY3FHqUw== -----END CERTIFICATE----- libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop/server.key0000644000175000017500000000156712054604347024030 0ustar cstamascstamas-----BEGIN RSA PRIVATE KEY----- MIICXAIBAAKBgQCohcU0qG+hHn6JK8XdygAJo7EuRqG25GSHaRRMyYgd89tEluIn MH86tVcktJ1s/0VVvr5anAp8L7Pgu01Wr13OfgIzBxCz51ZIFxq4DtimBftXs9Z9 M0sui2NuIPDrMEjkYUhUsxMEZcDSp2KJjDosZjSYUiiFG2ACvVGXSrS16QIDAQAB AoGALSdqp6lZ/7nD/c0Uv1CYofySROv3+KFJrl6hadG1/xCP99jVz9pWvMxKBTO/ 2qyrT0ZEitK0nIHLmLOXDVr/rxzbxP/kHmkOLKj45jW31BSap89tUpFjFQXFfjwT YnOgOB4+eqQuGwigCqabcQPtFC4fU7Qzk7pdz/kO4FjR0GECQQDdXthCKgS7E5Zy qqzjepxYvKgkWPD3G9H6I8LOtiVBdcehflF8Y61OGsEST3pbOhrijhY281VnD1AG pNL1rOhDAkEAwuKKTN+2GF3m1mPtGW9jpkP8gU2zcO945U0jxpn2srjQ9oIoB45Y gqtE6yybRY4BBd+hMdgeH5dXSwsZW+FMYwJASrFy5LhKylisndoq5cJ8OJDHZyQ/ ghF4Ax/H3nmlDnZQOpRlqEP1uPHcDXKVxWxQn/rzUe0+9rw681Lv/4ctAwJAfyLO 2muvHaJUr1QtH0S9m4AKwEfyYiC3m8+BIVTbzagoGki62IMSVtxob4uAGBYVsME9 JYk5zZ4rgndRKdGGxQJBAIpbdLBKArvnpbYIqNJGG83mUZ/VZaQl0G+S3zGkgre9 KjIuz10nNMNAKmGRrTbClLtvAQ9MVa3Xjnp+XmxPFho= -----END RSA PRIVATE KEY----- libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop/Server.pm0000644000175000017500000001633512254163766023622 0ustar cstamascstamaspackage Mojo::IOLoop::Server; use Mojo::Base 'Mojo::EventEmitter'; use Carp 'croak'; use File::Basename 'dirname'; use File::Spec::Functions 'catfile'; use IO::Socket::INET; use Scalar::Util 'weaken'; use Socket qw(IPPROTO_TCP TCP_NODELAY); # IPv6 support requires IO::Socket::IP use constant IPV6 => $ENV{MOJO_NO_IPV6} ? 0 : eval 'use IO::Socket::IP 0.16 (); 1'; # TLS support requires IO::Socket::SSL use constant TLS => $ENV{MOJO_NO_TLS} ? 0 : eval(IPV6 ? 'use IO::Socket::SSL 1.75 (); 1' : 'use IO::Socket::SSL 1.75 "inet4"; 1'); use constant TLS_READ => TLS ? IO::Socket::SSL::SSL_WANT_READ() : 0; use constant TLS_WRITE => TLS ? IO::Socket::SSL::SSL_WANT_WRITE() : 0; # To regenerate the certificate run this command (18.04.2012) # openssl req -new -x509 -keyout server.key -out server.crt -nodes -days 7300 my $CERT = catfile dirname(__FILE__), 'server.crt'; my $KEY = catfile dirname(__FILE__), 'server.key'; has multi_accept => 50; has reactor => sub { require Mojo::IOLoop; Mojo::IOLoop->singleton->reactor; }; sub DESTROY { my $self = shift; if (my $port = $self->{port}) { $ENV{MOJO_REUSE} =~ s/(?:^|\,)${port}:\d+// } return unless my $reactor = $self->reactor; $self->stop if $self->{handle}; $reactor->remove($_) for values %{$self->{handles}}; } sub generate_port { IO::Socket::INET->new(Listen => 5, LocalAddr => '127.0.0.1')->sockport; } sub handle { shift->{handle} } sub listen { my $self = shift; my $args = ref $_[0] ? $_[0] : {@_}; # Look for reusable file descriptor my $reuse = my $port = $self->{port} = $args->{port} || 3000; $ENV{MOJO_REUSE} ||= ''; my $fd; if ($ENV{MOJO_REUSE} =~ /(?:^|\,)${reuse}:(\d+)/) { $fd = $1 } # Allow file descriptor inheritance local $^F = 1000; # Reuse file descriptor my $handle; my $class = IPV6 ? 'IO::Socket::IP' : 'IO::Socket::INET'; if (defined $fd) { $handle = $class->new_from_fd($fd, 'r') or croak "Can't open file descriptor $fd: $!"; } # New socket else { my %options = ( Listen => $args->{backlog} // SOMAXCONN, LocalAddr => $args->{address} || '0.0.0.0', LocalPort => $port, ReuseAddr => 1, ReusePort => $args->{reuse}, Type => SOCK_STREAM ); $options{LocalAddr} =~ s/[\[\]]//g; $handle = $class->new(%options) or croak "Can't create listen socket: $@"; $fd = fileno $handle; $ENV{MOJO_REUSE} .= length $ENV{MOJO_REUSE} ? ",$reuse:$fd" : "$reuse:$fd"; } $handle->blocking(0); $self->{handle} = $handle; return unless $args->{tls}; croak "IO::Socket::SSL 1.75 required for TLS support" unless TLS; # Prioritize RC4 to mitigate BEAST attack $self->{tls} = { SSL_ca_file => $args->{tls_ca} && -T $args->{tls_ca} ? $args->{tls_ca} : undef, SSL_cert_file => $args->{tls_cert} || $CERT, SSL_cipher_list => $args->{tls_ciphers} // 'ECDHE-RSA-AES128-SHA256:AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH', SSL_honor_cipher_order => 1, SSL_key_file => $args->{tls_key} || $KEY, SSL_startHandshake => 0, SSL_verify_mode => $args->{tls_verify} // $args->{tls_ca} ? 0x03 : 0x00 }; } sub start { my $self = shift; weaken $self; $self->reactor->io( $self->{handle} => sub { $self->_accept for 1 .. $self->multi_accept }); } sub stop { $_[0]->reactor->remove($_[0]{handle}) } sub _accept { my $self = shift; return unless my $handle = $self->{handle}->accept; $handle->blocking(0); # Disable Nagle's algorithm setsockopt $handle, IPPROTO_TCP, TCP_NODELAY, 1; # Start TLS handshake return $self->emit_safe(accept => $handle) unless my $tls = $self->{tls}; weaken $self; $tls->{SSL_error_trap} = sub { return unless my $handle = delete $self->{handles}{shift()}; $self->reactor->remove($handle); close $handle; }; return unless $handle = IO::Socket::SSL->start_SSL($handle, %$tls); $self->reactor->io($handle => sub { $self->_tls($handle) }); $self->{handles}{$handle} = $handle; } sub _tls { my ($self, $handle) = @_; # Accepted if ($handle->accept_SSL) { $self->reactor->remove($handle); return $self->emit_safe(accept => delete $self->{handles}{$handle}); } # Switch between reading and writing my $err = $IO::Socket::SSL::SSL_ERROR; if ($err == TLS_READ) { $self->reactor->watch($handle, 1, 0) } elsif ($err == TLS_WRITE) { $self->reactor->watch($handle, 1, 1) } } 1; =encoding utf8 =head1 NAME Mojo::IOLoop::Server - Non-blocking TCP server =head1 SYNOPSIS use Mojo::IOLoop::Server; # Create listen socket my $server = Mojo::IOLoop::Server->new; $server->on(accept => sub { my ($server, $handle) = @_; ... }); $server->listen(port => 3000); # Start and stop accepting connections $server->start; $server->stop; # Start reactor if necessary $server->reactor->start unless $server->reactor->is_running; =head1 DESCRIPTION L accepts TCP connections for L. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 accept $server->on(accept => sub { my ($server, $handle) = @_; ... }); Emitted safely for each accepted connection. =head1 ATTRIBUTES L implements the following attributes. =head2 multi_accept my $multi = $server->multi_accept; $server = $server->multi_accept(100); Number of connections to accept at once, defaults to C<50>. =head2 reactor my $reactor = $server->reactor; $server = $server->reactor(Mojo::Reactor::Poll->new); Low level event reactor, defaults to the C attribute value of the global L singleton. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 generate_port my $port = $server->generate_port; Find a free TCP port, this is a utility function primarily used for tests. =head2 handle my $handle = $server->handle; Get handle for server. =head2 listen $server->listen(port => 3000); Create a new listen socket. Note that TLS support depends on L (1.75+) and IPv6 support on L (0.16+). These options are currently available: =over 2 =item address address => '127.0.0.1' Local address to listen on, defaults to all. =item backlog backlog => 128 Maximum backlog size, defaults to C. =item port port => 80 Port to listen on. =item reuse reuse => 1 Allow multiple servers to use the same port with the C socket option. =item tls tls => 1 Enable TLS. =item tls_ca tls_ca => '/etc/tls/ca.crt' Path to TLS certificate authority file. =item tls_cert tls_cert => '/etc/tls/server.crt' Path to the TLS cert file, defaults to a built-in test certificate. =item tls_ciphers tls_ciphers => 'AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH' Cipher specification string. =item tls_key tls_key => '/etc/tls/server.key' Path to the TLS key file, defaults to a built-in test key. =item tls_verify tls_verify => 0x00 TLS verification mode, defaults to C<0x03>. =back =head2 start $server->start; Start accepting connections. =head2 stop $server->stop; Stop accepting connections. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop/Stream.pm0000644000175000017500000001512512254163774023602 0ustar cstamascstamaspackage Mojo::IOLoop::Stream; use Mojo::Base 'Mojo::EventEmitter'; use Errno qw(EAGAIN ECONNRESET EINTR EPIPE EWOULDBLOCK); use Scalar::Util 'weaken'; has reactor => sub { require Mojo::IOLoop; Mojo::IOLoop->singleton->reactor; }; sub DESTROY { shift->close } sub new { shift->SUPER::new(handle => shift, buffer => '', timeout => 15) } sub close { my $self = shift; return unless my $reactor = $self->reactor; return unless my $handle = delete $self->timeout(0)->{handle}; $reactor->remove($handle); close $handle; $self->emit_safe('close'); } sub close_gracefully { my $self = shift; return $self->{graceful} = 1 if $self->is_writing; $self->close; } sub handle { shift->{handle} } sub is_readable { my $self = shift; $self->_again; return $self->{handle} && $self->reactor->is_readable($self->{handle}); } sub is_writing { my $self = shift; return undef unless $self->{handle}; return !!length($self->{buffer}) || $self->has_subscribers('drain'); } sub start { my $self = shift; # Resume my $reactor = $self->reactor; return $reactor->watch($self->{handle}, 1, $self->is_writing) if delete $self->{paused}; weaken $self; my $cb = sub { pop() ? $self->_write : $self->_read }; $reactor->io($self->timeout($self->{timeout})->{handle} => $cb); } sub stop { my $self = shift; $self->reactor->watch($self->{handle}, 0, $self->is_writing) unless $self->{paused}++; } sub steal_handle { my $self = shift; $self->reactor->remove($self->{handle}); return delete $self->{handle}; } sub timeout { my $self = shift; return $self->{timeout} unless @_; my $reactor = $self->reactor; $reactor->remove(delete $self->{timer}) if $self->{timer}; return $self unless my $timeout = $self->{timeout} = shift; weaken $self; $self->{timer} = $reactor->timer($timeout => sub { $self->emit_safe('timeout')->close }); return $self; } sub write { my ($self, $chunk, $cb) = @_; $self->{buffer} .= $chunk; if ($cb) { $self->once(drain => $cb) } else { return $self unless length $self->{buffer} } $self->reactor->watch($self->{handle}, !$self->{paused}, 1) if $self->{handle}; return $self; } sub _again { $_[0]->reactor->again($_[0]{timer}) if $_[0]{timer} } sub _error { my $self = shift; # Retry return if $! == EAGAIN || $! == EINTR || $! == EWOULDBLOCK; # Closed return $self->close if $! == ECONNRESET || $! == EPIPE; # Error $self->emit(error => $!)->close; } sub _read { my $self = shift; my $read = $self->{handle}->sysread(my $buffer, 131072, 0); return $self->_error unless defined $read; return $self->close if $read == 0; $self->emit_safe(read => $buffer)->_again; } sub _write { my $self = shift; my $handle = $self->{handle}; if (length $self->{buffer}) { my $written = $handle->syswrite($self->{buffer}); return $self->_error unless defined $written; $self->emit_safe(write => substr($self->{buffer}, 0, $written, '')); $self->_again; } $self->emit_safe('drain') unless length $self->{buffer}; return if $self->is_writing; return $self->close if $self->{graceful}; $self->reactor->watch($handle, !$self->{paused}, 0) if $self->{handle}; } 1; =encoding utf8 =head1 NAME Mojo::IOLoop::Stream - Non-blocking I/O stream =head1 SYNOPSIS use Mojo::IOLoop::Stream; # Create stream my $stream = Mojo::IOLoop::Stream->new($handle); $stream->on(read => sub { my ($stream, $bytes) = @_; ... }); $stream->on(close => sub { my $stream = shift; ... }); $stream->on(error => sub { my ($stream, $err) = @_; ... }); # Start and stop watching for new data $stream->start; $stream->stop; # Start reactor if necessary $stream->reactor->start unless $stream->reactor->is_running; =head1 DESCRIPTION L is a container for I/O streams used by L. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 close $stream->on(close => sub { my $stream = shift; ... }); Emitted safely if the stream gets closed. =head2 drain $stream->on(drain => sub { my $stream = shift; ... }); Emitted safely once all data has been written. =head2 error $stream->on(error => sub { my ($stream, $err) = @_; ... }); Emitted if an error occurs on the stream, fatal if unhandled. =head2 read $stream->on(read => sub { my ($stream, $bytes) = @_; ... }); Emitted safely if new data arrives on the stream. =head2 timeout $stream->on(timeout => sub { my $stream = shift; ... }); Emitted safely if the stream has been inactive for too long and will get closed automatically. =head2 write $stream->on(write => sub { my ($stream, $bytes) = @_; ... }); Emitted safely if new data has been written to the stream. =head1 ATTRIBUTES L implements the following attributes. =head2 reactor my $reactor = $stream->reactor; $stream = $stream->reactor(Mojo::Reactor::Poll->new); Low level event reactor, defaults to the C attribute value of the global L singleton. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $stream = Mojo::IOLoop::Stream->new($handle); Construct a new L object. =head2 close $stream->close; Close stream immediately. =head2 close_gracefully $stream->close_gracefully; Close stream gracefully. =head2 handle my $handle = $stream->handle; Get handle for stream. =head2 is_readable my $bool = $stream->is_readable; Quick non-blocking check if stream is readable, useful for identifying tainted sockets. =head2 is_writing my $bool = $stream->is_writing; Check if stream is writing. =head2 start $stream->start; Start watching for new data on the stream. =head2 stop $stream->stop; Stop watching for new data on the stream. =head2 steal_handle my $handle = $stream->steal_handle; Steal handle from stream and prevent it from getting closed automatically. =head2 timeout my $timeout = $stream->timeout; $stream = $stream->timeout(45); Maximum amount of time in seconds stream can be inactive before getting closed automatically, defaults to C<15>. Setting the value to C<0> will allow this stream to be inactive indefinitely. =head2 write $stream = $stream->write($bytes); $stream = $stream->write($bytes => sub {...}); Write data to stream, the optional drain callback will be invoked once all data has been written. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/IOLoop.pm0000644000175000017500000003720112254163556022344 0ustar cstamascstamaspackage Mojo::IOLoop; use Mojo::Base -base; # "Professor: Amy, technology isn't intrinsically good or evil. It's how it's # used. Like the death ray." use Carp 'croak'; use Mojo::IOLoop::Client; use Mojo::IOLoop::Delay; use Mojo::IOLoop::Server; use Mojo::IOLoop::Stream; use Mojo::Reactor::Poll; use Mojo::Util qw(md5_sum steady_time); use Scalar::Util qw(blessed weaken); use constant DEBUG => $ENV{MOJO_IOLOOP_DEBUG} || 0; has accept_interval => 0.025; has [qw(lock unlock)]; has max_accepts => 0; has max_connections => 1000; has multi_accept => 50; has reactor => sub { my $class = Mojo::Reactor::Poll->detect; warn "-- Reactor initialized ($class)\n" if DEBUG; my $reactor = $class->new; $reactor->on(error => sub { warn "@{[blessed $_[0]]}: $_[1]" }); return $reactor; }; # Ignore PIPE signal $SIG{PIPE} = 'IGNORE'; # Initialize singleton reactor early __PACKAGE__->singleton->reactor; sub acceptor { my ($self, $acceptor) = (_instance(shift), @_); # Find acceptor for id return $self->{acceptors}{$acceptor} unless ref $acceptor; # Connect acceptor with reactor my $id = $self->_id; $self->{acceptors}{$id} = $acceptor; weaken $acceptor->reactor($self->reactor)->{reactor}; $self->{accepts} = $self->max_accepts if $self->max_accepts; # Allow new acceptor to get picked up $self->_not_accepting; return $id; } sub client { my ($self, $cb) = (_instance(shift), pop); # Make sure timers are running $self->_recurring; my $id = $self->_id; my $client = $self->{connections}{$id}{client} = Mojo::IOLoop::Client->new; weaken $client->reactor($self->reactor)->{reactor}; weaken $self; $client->on( connect => sub { delete $self->{connections}{$id}{client}; my $stream = Mojo::IOLoop::Stream->new(pop); $self->_stream($stream => $id); $self->$cb(undef, $stream); } ); $client->on( error => sub { $self->_remove($id); $self->$cb(pop, undef); } ); $client->connect(@_); return $id; } sub delay { my $self = _instance(shift); my $delay = Mojo::IOLoop::Delay->new; weaken $delay->ioloop($self)->{ioloop}; @_ > 1 ? $delay->steps(@_) : $delay->once(finish => shift) if @_; return $delay; } sub generate_port { Mojo::IOLoop::Server->generate_port } sub is_running { (ref $_[0] ? $_[0] : $_[0]->singleton)->reactor->is_running } sub one_tick { (ref $_[0] ? $_[0] : $_[0]->singleton)->reactor->one_tick } sub recurring { shift->_timer(recurring => @_) } sub remove { my ($self, $id) = (_instance(shift), @_); my $c = $self->{connections}{$id}; if ($c && (my $stream = $c->{stream})) { return $stream->close_gracefully } $self->_remove($id); } sub server { my ($self, $cb) = (_instance(shift), pop); my $server = Mojo::IOLoop::Server->new; weaken $self; $server->on( accept => sub { my $stream = Mojo::IOLoop::Stream->new(pop); $self->$cb($stream, $self->stream($stream)); } ); $server->listen(@_); return $self->acceptor($server); } sub singleton { state $loop = shift->SUPER::new } sub start { my $self = shift; croak 'Mojo::IOLoop already running' if $self->is_running; (ref $self ? $self : $self->singleton)->reactor->start; } sub stop { (ref $_[0] ? $_[0] : $_[0]->singleton)->reactor->stop } sub stream { my ($self, $stream) = (_instance(shift), @_); # Find stream for id return ($self->{connections}{$stream} || {})->{stream} unless ref $stream; # Release accept mutex $self->_not_accepting; # Enforce connection limit (randomize to improve load balancing) $self->max_connections(0) if defined $self->{accepts} && ($self->{accepts} -= int(rand 2) + 1) <= 0; return $self->_stream($stream, $self->_id); } sub timer { shift->_timer(timer => @_) } sub _accepting { my $self = shift; # Check if we have acceptors my $acceptors = $self->{acceptors} ||= {}; return $self->_remove(delete $self->{accept}) unless keys %$acceptors; # Check connection limit my $i = keys %{$self->{connections}}; my $max = $self->max_connections; return unless $i < $max; # Acquire accept mutex if (my $cb = $self->lock) { return unless $self->$cb(!$i) } $self->_remove(delete $self->{accept}); # Check if multi-accept is desirable my $multi = $self->multi_accept; $_->multi_accept($max < $multi ? 1 : $multi)->start for values %$acceptors; $self->{accepting}++; } sub _id { my $self = shift; my $id; do { $id = md5_sum('c' . steady_time . rand 999) } while $self->{connections}{$id} || $self->{acceptors}{$id}; return $id; } sub _instance { ref $_[0] ? $_[0] : $_[0]->singleton } sub _not_accepting { my $self = shift; # Make sure timers are running $self->_recurring; # Release accept mutex return unless delete $self->{accepting}; return unless my $cb = $self->unlock; $self->$cb; $_->stop for values %{$self->{acceptors} || {}}; } sub _recurring { my $self = shift; $self->{accept} ||= $self->recurring($self->accept_interval => \&_accepting); $self->{stop} ||= $self->recurring(1 => \&_stop); } sub _remove { my ($self, $id) = @_; # Timer return unless my $reactor = $self->reactor; return if $reactor->remove($id); # Acceptor if (delete $self->{acceptors}{$id}) { $self->_not_accepting } # Connection else { delete $self->{connections}{$id} } } sub _stop { my $self = shift; return if keys %{$self->{connections}}; $self->stop if $self->max_connections == 0; return if keys %{$self->{acceptors}}; $self->{$_} && $self->_remove(delete $self->{$_}) for qw(accept stop); } sub _stream { my ($self, $stream, $id) = @_; # Make sure timers are running $self->_recurring; # Connect stream with reactor $self->{connections}{$id}{stream} = $stream; weaken $stream->reactor($self->reactor)->{reactor}; weaken $self; $stream->on(close => sub { $self && $self->_remove($id) }); $stream->start; return $id; } sub _timer { my ($self, $method, $after, $cb) = (_instance(shift), @_); weaken $self; return $self->reactor->$method($after => sub { $self->$cb }); } 1; =encoding utf8 =head1 NAME Mojo::IOLoop - Minimalistic event loop =head1 SYNOPSIS use Mojo::IOLoop; # Listen on port 3000 Mojo::IOLoop->server({port => 3000} => sub { my ($loop, $stream) = @_; $stream->on(read => sub { my ($stream, $bytes) = @_; # Process input chunk say $bytes; # Write response $stream->write('HTTP/1.1 200 OK'); }); }); # Connect to port 3000 my $id = Mojo::IOLoop->client({port => 3000} => sub { my ($loop, $err, $stream) = @_; $stream->on(read => sub { my ($stream, $bytes) = @_; # Process input say "Input: $bytes"; }); # Write request $stream->write("GET / HTTP/1.1\x0d\x0a\x0d\x0a"); }); # Add a timer Mojo::IOLoop->timer(5 => sub { my $loop = shift; $loop->remove($id); }); # Start event loop if necessary Mojo::IOLoop->start unless Mojo::IOLoop->is_running; =head1 DESCRIPTION L is a very minimalistic event loop based on L, it has been reduced to the absolute minimal feature set required to build solid and scalable non-blocking TCP clients and servers. The event loop will be resilient to time jumps if a monotonic clock is available through L. A TLS certificate and key are also built right in, to make writing test servers as easy as possible. Also note that for convenience the C signal will be set to C when L is loaded. For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS support, the optional modules L (4.0+), L (0.16+) and L (1.75+) will be used automatically if they are installed. Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables. See L for more. =head1 ATTRIBUTES L implements the following attributes. =head2 accept_interval my $interval = $loop->accept_interval; $loop = $loop->accept_interval(0.5); Interval in seconds for trying to reacquire the accept mutex, defaults to C<0.025>. Note that changing this value can affect performance and idle CPU usage. =head2 lock my $cb = $loop->lock; $loop = $loop->lock(sub {...}); A callback for acquiring the accept mutex, used to sync multiple server processes. The callback should return true or false. Note that exceptions in this callback are not captured. $loop->lock(sub { my ($loop, $blocking) = @_; # Got the accept mutex, start accepting new connections return 1; }); =head2 max_accepts my $max = $loop->max_accepts; $loop = $loop->max_accepts(1000); The maximum number of connections this event loop is allowed to accept before shutting down gracefully without interrupting existing connections, defaults to C<0>. Setting the value to C<0> will allow this event loop to accept new connections indefinitely. Note that up to half of this value can be subtracted randomly to improve load balancing between multiple server processes. =head2 max_connections my $max = $loop->max_connections; $loop = $loop->max_connections(1000); The maximum number of parallel connections this event loop is allowed to handle before stopping to accept new incoming connections, defaults to C<1000>. Setting the value to C<0> will make this event loop stop accepting new connections and allow it to shut down gracefully without interrupting existing connections. =head2 multi_accept my $multi = $loop->multi_accept; $loop = $loop->multi_accept(100); Number of connections to accept at once, defaults to C<50>. =head2 reactor my $reactor = $loop->reactor; $loop = $loop->reactor(Mojo::Reactor->new); Low level event reactor, usually a L or L object with a default C event. # Watch if handle becomes readable or writable $loop->reactor->io($handle => sub { my ($reactor, $writable) = @_; say $writable ? 'Handle is writable' : 'Handle is readable'; }); # Change to watching only if handle becomes writable $loop->reactor->watch($handle, 0, 1); =head2 unlock my $cb = $loop->unlock; $loop = $loop->unlock(sub {...}); A callback for releasing the accept mutex, used to sync multiple server processes. Note that exceptions in this callback are not captured. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 acceptor my $server = Mojo::IOLoop->acceptor($id); my $server = $loop->acceptor($id); my $id = $loop->acceptor(Mojo::IOLoop::Server->new); Get L object for id or turn object into an acceptor. =head2 client my $id = Mojo::IOLoop->client(address => '127.0.0.1', port => 3000, sub {...}); my $id = $loop->client(address => '127.0.0.1', port => 3000, sub {...}); my $id = $loop->client({address => '127.0.0.1', port => 3000} => sub {...}); Open TCP connection with L, takes the same arguments as L. # Connect to localhost on port 3000 Mojo::IOLoop->client({port => 3000} => sub { my ($loop, $err, $stream) = @_; ... }); =head2 delay my $delay = Mojo::IOLoop->delay; my $delay = $loop->delay; my $delay = $loop->delay(sub {...}); my $delay = $loop->delay(sub {...}, sub {...}); Get L object to manage callbacks and control the flow of events. A single callback will be treated as a subscriber to the C event, and multiple ones as a chain of steps. # Synchronize multiple events my $delay = Mojo::IOLoop->delay(sub { say 'BOOM!' }); for my $i (1 .. 10) { my $end = $delay->begin; Mojo::IOLoop->timer($i => sub { say 10 - $i; $end->(); }); } $delay->wait unless Mojo::IOLoop->is_running; # Sequentialize multiple events my $delay = Mojo::IOLoop->delay( # First step (simple timer) sub { my $delay = shift; Mojo::IOLoop->timer(2 => $delay->begin); say 'Second step in 2 seconds.'; }, # Second step (parallel timers) sub { my $delay = shift; Mojo::IOLoop->timer(1 => $delay->begin); Mojo::IOLoop->timer(3 => $delay->begin); say 'Third step in 3 seconds.'; }, # Third step (the end) sub { say 'And done after 5 seconds total.' } ); $delay->wait unless Mojo::IOLoop->is_running; =head2 generate_port my $port = Mojo::IOLoop->generate_port; my $port = $loop->generate_port; Find a free TCP port, this is a utility function primarily used for tests. =head2 is_running my $bool = Mojo::IOLoop->is_running; my $bool = $loop->is_running; Check if event loop is running. exit unless Mojo::IOLoop->is_running; =head2 one_tick Mojo::IOLoop->one_tick; $loop->one_tick; Run event loop until an event occurs. Note that this method can recurse back into the reactor, so you need to be careful. # Don't block longer than 0.5 seconds my $id = Mojo::IOLoop->timer(0.5 => sub {}); Mojo::IOLoop->one_tick; Mojo::IOLoop->remove($id); =head2 recurring my $id = Mojo::IOLoop->recurring(0.5 => sub {...}); my $id = $loop->recurring(3 => sub {...}); Create a new recurring timer, invoking the callback repeatedly after a given amount of time in seconds. # Invoke as soon as possible Mojo::IOLoop->recurring(0 => sub { say 'Reactor tick.' }); =head2 remove Mojo::IOLoop->remove($id); $loop->remove($id); Remove anything with an id, connections will be dropped gracefully by allowing them to finish writing all data in their write buffers. =head2 server my $id = Mojo::IOLoop->server(port => 3000, sub {...}); my $id = $loop->server(port => 3000, sub {...}); my $id = $loop->server({port => 3000} => sub {...}); Accept TCP connections with L, takes the same arguments as L. # Listen on port 3000 Mojo::IOLoop->server({port => 3000} => sub { my ($loop, $stream, $id) = @_; ... }); =head2 singleton my $loop = Mojo::IOLoop->singleton; The global L singleton, used to access a single shared event loop object from everywhere inside the process. # Many methods also allow you to take shortcuts Mojo::IOLoop->timer(2 => sub { Mojo::IOLoop->stop }); Mojo::IOLoop->start; # Restart active timer my $id = Mojo::IOLoop->timer(3 => sub { say 'Timeout!' }); Mojo::IOLoop->singleton->reactor->again($id); =head2 start Mojo::IOLoop->start; $loop->start; Start the event loop, this will block until L is called. Note that some reactors stop automatically if there are no events being watched anymore. # Start event loop only if it is not running already Mojo::IOLoop->start unless Mojo::IOLoop->is_running; =head2 stop Mojo::IOLoop->stop; $loop->stop; Stop the event loop, this will not interrupt any existing connections and the event loop can be restarted by running L again. =head2 stream my $stream = Mojo::IOLoop->stream($id); my $stream = $loop->stream($id); my $id = $loop->stream(Mojo::IOLoop::Stream->new); Get L object for id or turn object into a connection. # Increase inactivity timeout for connection to 300 seconds Mojo::IOLoop->stream($id)->timeout(300); =head2 timer my $id = Mojo::IOLoop->timer(5 => sub {...}); my $id = $loop->timer(5 => sub {...}); my $id = $loop->timer(0.25 => sub {...}); Create a new timer, invoking the callback after a given amount of time in seconds. # Invoke as soon as possible Mojo::IOLoop->timer(0 => sub { say 'Next tick.' }); =head1 DEBUGGING You can set the MOJO_IOLOOP_DEBUG environment variable to get some advanced diagnostics information printed to C. MOJO_IOLOOP_DEBUG=1 =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/JSON/0000755000175000017500000000000012256126533021407 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/JSON/Pointer.pm0000644000175000017500000000406412242771727023377 0ustar cstamascstamaspackage Mojo::JSON::Pointer; use Mojo::Base -base; use Scalar::Util 'looks_like_number'; sub contains { shift->_pointer(1, @_) } sub get { shift->_pointer(0, @_) } sub _pointer { my ($self, $contains, $data, $pointer) = @_; return $data unless $pointer =~ s!^/!!; for my $p ($pointer eq '' ? ($pointer) : (split '/', $pointer)) { $p =~ s/~0/~/g; $p =~ s!~1!/!g; # Hash if (ref $data eq 'HASH' && exists $data->{$p}) { $data = $data->{$p} } # Array elsif (ref $data eq 'ARRAY' && looks_like_number($p) && @$data > $p) { $data = $data->[$p]; } # Nothing else { return undef } } return $contains ? 1 : $data; } 1; =encoding utf8 =head1 NAME Mojo::JSON::Pointer - JSON Pointers =head1 SYNOPSIS use Mojo::JSON::Pointer; my $pointer = Mojo::JSON::Pointer->new; say $pointer->get({foo => [23, 'bar']}, '/foo/1'); say 'Contains "/foo".' if $pointer->contains({foo => [23, 'bar']}, '/foo'); =head1 DESCRIPTION L is a relaxed implementation of RFC 6901. =head1 METHODS =head2 contains my $bool = $pointer->contains($data, '/foo/1'); Check if data structure contains a value that can be identified with the given JSON Pointer. # True $pointer->contains({'♥' => 'mojolicious'}, '/♥'); $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/foo'); $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/baz/2'); # False $pointer->contains({'♥' => 'mojolicious'}, '/☃'); $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/bar'); $pointer->contains({foo => 'bar', baz => [4, 5, 6]}, '/baz/9'); =head2 get my $value = $pointer->get($data, '/foo/bar'); Extract value identified by the given JSON Pointer. # "mojolicious" $pointer->get({'♥' => 'mojolicious'}, '/♥'); # "bar" $pointer->get({foo => 'bar', baz => [4, 5, 6]}, '/foo'); # "4" $pointer->get({foo => 'bar', baz => [4, 5, 6]}, '/baz/0'); # "6" $pointer->get({foo => 'bar', baz => [4, 5, 6]}, '/baz/2'); =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/JSON.pm0000644000175000017500000002331412242771570021752 0ustar cstamascstamaspackage Mojo::JSON; use Mojo::Base -base; use B; use Exporter 'import'; use Mojo::Util; use Scalar::Util 'blessed'; has 'error'; our @EXPORT_OK = ('j'); # Literal names my $FALSE = bless \(my $false = 0), 'Mojo::JSON::_Bool'; my $TRUE = bless \(my $true = 1), 'Mojo::JSON::_Bool'; # Escaped special character map (with u2028 and u2029) my %ESCAPE = ( '"' => '"', '\\' => '\\', '/' => '/', 'b' => "\x08", 'f' => "\x0c", 'n' => "\x0a", 'r' => "\x0d", 't' => "\x09", 'u2028' => "\x{2028}", 'u2029' => "\x{2029}" ); my %REVERSE = map { $ESCAPE{$_} => "\\$_" } keys %ESCAPE; for (0x00 .. 0x1f, 0x7f) { $REVERSE{pack 'C', $_} //= sprintf '\u%.4X', $_ } # Unicode encoding detection my $UTF_PATTERNS = { 'UTF-32BE' => qr/^\x00{3}[^\x00]/, 'UTF-32LE' => qr/^[^\x00]\x00{3}/, 'UTF-16BE' => qr/^(?:\x00[^\x00]){2}/, 'UTF-16LE' => qr/^(?:[^\x00]\x00){2}/ }; my $WHITESPACE_RE = qr/[\x20\x09\x0a\x0d]*/; sub decode { my ($self, $bytes) = @_; # Clean start $self->error(undef); # Missing input $self->error('Missing or empty input') and return undef unless $bytes; # Remove BOM $bytes =~ s/^(?:\357\273\277|\377\376\0\0|\0\0\376\377|\376\377|\377\376)//g; # Wide characters $self->error('Wide character in input') and return undef unless utf8::downgrade($bytes, 1); # Detect and decode Unicode my $encoding = 'UTF-8'; $bytes =~ $UTF_PATTERNS->{$_} and $encoding = $_ for keys %$UTF_PATTERNS; $bytes = Mojo::Util::decode $encoding, $bytes; # Object or array my $res = eval { local $_ = $bytes; # Leading whitespace m/\G$WHITESPACE_RE/gc; # Array my $ref; if (m/\G\[/gc) { $ref = _decode_array() } # Object elsif (m/\G\{/gc) { $ref = _decode_object() } # Invalid character else { _exception('Expected array or object') } # Leftover data unless (m/\G$WHITESPACE_RE\z/gc) { my $got = ref $ref eq 'ARRAY' ? 'array' : 'object'; _exception("Unexpected data after $got"); } $ref; }; # Exception if (!$res && (my $e = $@)) { chomp $e; $self->error($e); } return $res; } sub encode { my ($self, $ref) = @_; return Mojo::Util::encode 'UTF-8', _encode_value($ref); } sub false {$FALSE} sub j { my $d = shift; return __PACKAGE__->new->encode($d) if ref $d eq 'ARRAY' || ref $d eq 'HASH'; return __PACKAGE__->new->decode($d); } sub true {$TRUE} sub _decode_array { my @array; until (m/\G$WHITESPACE_RE\]/gc) { # Value push @array, _decode_value(); # Separator redo if m/\G$WHITESPACE_RE,/gc; # End last if m/\G$WHITESPACE_RE\]/gc; # Invalid character _exception('Expected comma or right square bracket while parsing array'); } return \@array; } sub _decode_object { my %hash; until (m/\G$WHITESPACE_RE\}/gc) { # Quote m/\G$WHITESPACE_RE"/gc or _exception('Expected string while parsing object'); # Key my $key = _decode_string(); # Colon m/\G$WHITESPACE_RE:/gc or _exception('Expected colon while parsing object'); # Value $hash{$key} = _decode_value(); # Separator redo if m/\G$WHITESPACE_RE,/gc; # End last if m/\G$WHITESPACE_RE\}/gc; # Invalid character _exception('Expected comma or right curly bracket while parsing object'); } return \%hash; } sub _decode_string { my $pos = pos; # Extract string with escaped characters m!\G((?:(?:[^\x00-\x1f\\"]|\\(?:["\\/bfnrt]|u[0-9a-fA-F]{4})){0,32766})*)!gc; my $str = $1; # Invalid character unless (m/\G"/gc) { _exception('Unexpected character or invalid escape while parsing string') if m/\G[\x00-\x1f\\]/; _exception('Unterminated string'); } # Unescape popular characters if (index($str, '\\u') < 0) { $str =~ s!\\(["\\/bfnrt])!$ESCAPE{$1}!gs; return $str; } # Unescape everything else my $buffer = ''; while ($str =~ m/\G([^\\]*)\\(?:([^u])|u(.{4}))/gc) { $buffer .= $1; # Popular character if ($2) { $buffer .= $ESCAPE{$2} } # Escaped else { my $ord = hex $3; # Surrogate pair if (($ord & 0xf800) == 0xd800) { # High surrogate ($ord & 0xfc00) == 0xd800 or pos($_) = $pos + pos($str), _exception('Missing high-surrogate'); # Low surrogate $str =~ m/\G\\u([Dd][C-Fc-f]..)/gc or pos($_) = $pos + pos($str), _exception('Missing low-surrogate'); $ord = 0x10000 + ($ord - 0xd800) * 0x400 + (hex($1) - 0xdc00); } # Character $buffer .= pack 'U', $ord; } } # The rest return $buffer . substr $str, pos($str), length($str); } sub _decode_value { # Leading whitespace m/\G$WHITESPACE_RE/gc; # String return _decode_string() if m/\G"/gc; # Array return _decode_array() if m/\G\[/gc; # Object return _decode_object() if m/\G\{/gc; # Number return 0 + $1 if m/\G([-]?(?:0|[1-9][0-9]*)(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?)/gc; # True return $TRUE if m/\Gtrue/gc; # False return $FALSE if m/\Gfalse/gc; # Null return undef if m/\Gnull/gc; # Invalid character _exception('Expected string, array, object, number, boolean or null'); } sub _encode_array { my $array = shift; return '[' . join(',', map { _encode_value($_) } @$array) . ']'; } sub _encode_object { my $object = shift; my @pairs = map { _encode_string($_) . ':' . _encode_value($object->{$_}) } keys %$object; return '{' . join(',', @pairs) . '}'; } sub _encode_string { my $str = shift; $str =~ s!([\x00-\x1f\x7f\x{2028}\x{2029}\\"/\b\f\n\r\t])!$REVERSE{$1}!gs; return "\"$str\""; } sub _encode_value { my $value = shift; # Reference if (my $ref = ref $value) { # Array return _encode_array($value) if $ref eq 'ARRAY'; # Object return _encode_object($value) if $ref eq 'HASH'; # True or false return $$value ? 'true' : 'false' if $ref eq 'SCALAR'; return $value ? 'true' : 'false' if $ref eq 'Mojo::JSON::_Bool'; # Blessed reference with TO_JSON method if (blessed $value && (my $sub = $value->can('TO_JSON'))) { return _encode_value($value->$sub); } } # Null return 'null' unless defined $value; # Number my $flags = B::svref_2object(\$value)->FLAGS; return 0 + $value if $flags & (B::SVp_IOK | B::SVp_NOK) && $value * 0 == 0; # String return _encode_string($value); } sub _exception { # Leading whitespace m/\G$WHITESPACE_RE/gc; # Context my $context = 'Malformed JSON: ' . shift; if (m/\G\z/gc) { $context .= ' before end of data' } else { my @lines = split /\n/, substr($_, 0, pos); $context .= ' at line ' . @lines . ', offset ' . length(pop @lines || ''); } die "$context\n"; } # Emulate boolean type package Mojo::JSON::_Bool; use overload '0+' => sub { ${$_[0]} }, '""' => sub { ${$_[0]} }, fallback => 1; 1; =encoding utf8 =head1 NAME Mojo::JSON - Minimalistic JSON =head1 SYNOPSIS 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); # Check for errors my $json = Mojo::JSON->new; if (defined(my $hash = $json->decode($bytes))) { say $hash->{message} } else { say 'Error: ', $json->error } # Use the alternative interface use Mojo::JSON 'j'; my $bytes = j({foo => [1, 2], bar => 'hello!', baz => \1}); my $hash = j($bytes); =head1 DESCRIPTION L is a minimalistic and possibly the fastest pure-Perl implementation of RFC 4627. It supports normal Perl data types like C, C reference, C reference and will try to call the C method on blessed references, or stringify them if it doesn't exist. Differentiating between strings and numbers in Perl is hard, depending on how it has been used, a C can be both at the same time. Since numeric comparisons on strings are very unlikely to happen intentionally, the numeric value always gets priority, so any C that has been used in numeric context is considered a number. [1, -2, 3] -> [1, -2, 3] {"foo": "bar"} -> {foo => 'bar'} Literal names will be translated to and from L constants or a similar native Perl value. true -> Mojo::JSON->true false -> Mojo::JSON->false null -> undef In addition C references will be used to generate booleans, based on if their values are true or false. \1 -> true \0 -> false Decoding UTF-16 (LE/BE) and UTF-32 (LE/BE) will be handled transparently, encoding will only generate UTF-8. The two Unicode whitespace characters C and C will always be escaped to make JSONP easier. =head1 FUNCTIONS L implements the following functions. =head2 j my $bytes = j([1, 2, 3]); my $bytes = j({foo => 'bar'}); my $array = j($bytes); my $hash = j($bytes); Encode Perl data structure or decode JSON and return C if decoding fails. =head1 ATTRIBUTES L implements the following attributes. =head2 error my $err = $json->error; $json = $json->error('Parser error'); Parser errors. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 decode my $array = $json->decode($bytes); my $hash = $json->decode($bytes); Decode JSON to Perl data structure and return C if decoding fails. =head2 encode my $bytes = $json->encode([1, 2, 3]); my $bytes = $json->encode({foo => 'bar'}); Encode Perl data structure to JSON. =head2 false my $false = Mojo::JSON->false; my $false = $json->false; False value, used because Perl has no native equivalent. =head2 true my $true = Mojo::JSON->true; my $true = $json->true; True value, used because Perl has no native equivalent. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Loader.pm0000644000175000017500000000652012242771547022413 0ustar cstamascstamaspackage Mojo::Loader; use Mojo::Base -base; use File::Basename 'fileparse'; use File::Spec::Functions qw(catdir catfile splitdir); use Mojo::Exception; use Mojo::Util qw(b64_decode class_to_path); my (%BIN, %CACHE); sub data { $_[1] ? $_[2] ? _all($_[1])->{$_[2]} : _all($_[1]) : undef } sub is_binary { keys %{_all($_[1])} ? !!$BIN{$_[1]}{$_[2]} : undef } sub load { my ($self, $module) = @_; # Check module name return 1 if !$module || $module !~ /^\w(?:[\w:']*\w)?$/; # Load return undef if $module->can('new') || eval "require $module; 1"; # Exists return 1 if $@ =~ /^Can't locate \Q@{[class_to_path $module]}\E in \@INC/; # Real error return Mojo::Exception->new($@); } sub search { my ($self, $namespace) = @_; my (@modules, %found); for my $directory (@INC) { next unless -d (my $path = catdir $directory, split(/::|'/, $namespace)); # List "*.pm" files in directory opendir(my $dir, $path); for my $file (grep /\.pm$/, readdir $dir) { next if -d catfile splitdir($path), $file; my $class = "${namespace}::" . fileparse $file, qr/\.pm/; push @modules, $class unless $found{$class}++; } } return \@modules; } sub _all { my $class = shift; my $handle = do { no strict 'refs'; \*{"${class}::DATA"} }; return $CACHE{$class} || {} if $CACHE{$class} || !fileno $handle; seek $handle, 0, 0; my $data = join '', <$handle>; # Ignore everything before __DATA__ (Windows will seek to start of file) $data =~ s/^.*\n__DATA__\r?\n/\n/s; # Ignore everything after __END__ $data =~ s/\n__END__\r?\n.*$/\n/s; # Split files (undef, my @files) = split /^@@\s*(.+?)\s*\r?\n/m, $data; # Find data my $all = $CACHE{$class} = {}; while (@files) { my ($name, $data) = splice @files, 0, 2; $all->{$name} = $name =~ s/\s*\(\s*base64\s*\)$// && ++$BIN{$class}{$name} ? b64_decode($data) : $data; } return $all; } 1; =encoding utf8 =head1 NAME Mojo::Loader - Loader =head1 SYNOPSIS use Mojo::Loader; # Find modules in a namespace my $loader = Mojo::Loader->new; for my $module (@{$loader->search('Some::Namespace')}) { # Load them safely my $e = $loader->load($module); warn qq{Loading "$module" failed: $e} and next if ref $e; # And extract files from the DATA section say $loader->data($module, 'some_file.txt'); } =head1 DESCRIPTION L is a class loader and plugin framework. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 data my $all = $loader->data('Foo::Bar'); my $index = $loader->data('Foo::Bar', 'index.html'); Extract embedded file from the C section of a class. say for keys %{$loader->data('Foo::Bar')}; =head2 is_binary my $bool = $loader->is_binary('Foo::Bar', 'test.png'); Check if embedded file from the C section of a class was Base64 encoded. =head2 load my $e = $loader->load('Foo::Bar'); Load a class and catch exceptions. Note that classes are checked for a C method to see if they are already loaded. if (my $e = $loader->load('Foo::Bar')) { die ref $e ? "Exception: $e" : 'Not found!'; } =head2 search my $modules = $loader->search('MyApp::Namespace'); Search for modules in a namespace non-recursively. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Log.pm0000644000175000017500000001132112254163565021717 0ustar cstamascstamaspackage Mojo::Log; use Mojo::Base 'Mojo::EventEmitter'; use Carp 'croak'; use Fcntl ':flock'; use Mojo::Util 'encode'; has handle => sub { # File if (my $path = shift->path) { croak qq{Can't open log file "$path": $!} unless open my $file, '>>', $path; return $file; } # STDERR return \*STDERR; }; has level => 'debug'; has 'path'; # Supported log level my $LEVEL = {debug => 1, info => 2, warn => 3, error => 4, fatal => 5}; sub new { my $self = shift->SUPER::new(@_); $self->on(message => \&_message); return $self; } sub debug { shift->log(debug => @_) } sub error { shift->log(error => @_) } sub fatal { shift->log(fatal => @_) } sub format { my ($self, $level, @lines) = @_; return encode 'UTF-8', '[' . localtime(time) . "] [$level] " . join("\n", @lines, ''); } sub info { shift->log(info => @_) } sub is_debug { shift->is_level('debug') } sub is_error { shift->is_level('error') } sub is_fatal { shift->is_level('fatal') } sub is_info { shift->is_level('info') } sub is_level { my ($self, $level) = @_; return $LEVEL->{lc $level} >= $LEVEL->{$ENV{MOJO_LOG_LEVEL} || $self->level}; } sub is_warn { shift->is_level('warn') } sub log { shift->emit('message', lc(shift), @_) } sub warn { shift->log(warn => @_) } sub _message { my ($self, $level) = (shift, shift); return unless $self->is_level($level) && (my $handle = $self->handle); flock $handle, LOCK_EX; $handle->print($self->format($level, @_)) or croak "Can't write to log: $!"; flock $handle, LOCK_UN; } 1; =encoding utf8 =head1 NAME Mojo::Log - Simple logger =head1 SYNOPSIS use Mojo::Log; # Log to STDERR my $log = Mojo::Log->new; # Customize log file location and minimum log level my $log = Mojo::Log->new(path => '/var/log/mojo.log', level => 'warn'); # Log messages $log->debug('Why is this not working?'); $log->info('FYI: it happened again.'); $log->warn('This might be a problem.'); $log->error('Garden variety error.'); $log->fatal('Boom!'); =head1 DESCRIPTION L is a simple logger for L projects. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 message $log->on(message => sub { my ($log, $level, @lines) = @_; ... }); Emitted when a new message gets logged. $log->unsubscribe('message'); $log->on(message => sub { my ($log, $level, @lines) = @_; say "$level: ", @lines; }); =head1 ATTRIBUTES L implements the following attributes. =head2 handle my $handle = $log->handle; $log = $log->handle(IO::Handle->new); Log filehandle used by default L event, defaults to opening L or C. =head2 level my $level = $log->level; $log = $log->level('debug'); Active log level, defaults to C. Available log levels are C, C, C, C and C, in that order. Note that the MOJO_LOG_LEVEL environment variable can override this value. =head2 path my $path = $log->path $log = $log->path('/var/log/mojo.log'); Log file path used by L. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $log = Mojo::Log->new; Construct a new L object and subscribe to L event with default logger. =head2 debug $log = $log->debug('You screwed up, but that is ok.'); $log = $log->debug('All', 'cool!'); Log debug message. =head2 error $log = $log->error('You really screwed up this time.'); $log = $log->error('Wow', 'seriously!'); Log error message. =head2 fatal $log = $log->fatal('Its over...'); $log = $log->fatal('Bye', 'bye!'); Log fatal message. =head2 format my $msg = $log->format(debug => 'Hi there!'); my $msg = $log->format(debug => 'Hi', 'there!'); Format log message. =head2 info $log = $log->info('You are bad, but you prolly know already.'); $log = $log->info('Ok', 'then!'); Log info message. =head2 is_level my $bool = $log->is_level('debug'); Check log level. =head2 is_debug my $bool = $log->is_debug; Check for debug log level. =head2 is_error my $bool = $log->is_error; Check for error log level. =head2 is_fatal my $bool = $log->is_fatal; Check for fatal log level. =head2 is_info my $bool = $log->is_info; Check for info log level. =head2 is_warn my $bool = $log->is_warn; Check for warn log level. =head2 log $log = $log->log(debug => 'This should work.'); $log = $log->log(debug => 'This', 'too!'); Emit L event. =head2 warn $log = $log->warn('Dont do that Dave...'); $log = $log->warn('No', 'really!'); Log warn message. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Message/0000755000175000017500000000000012256126533022222 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Message/Request.pm0000644000175000017500000002524712254164005024214 0ustar cstamascstamaspackage Mojo::Message::Request; use Mojo::Base 'Mojo::Message'; use Mojo::Cookie::Request; use Mojo::Util qw(b64_encode b64_decode get_line); use Mojo::URL; has env => sub { {} }; has method => 'GET'; has url => sub { Mojo::URL->new }; my $START_LINE_RE = qr/ ^ ([a-zA-Z]+) # Method \s+ ([0-9a-zA-Z!#\$\%&'()*+,\-.\/:;=?\@[\\\]^_`\{|\}~]+) # URL (?:\s+HTTP\/(\d\.\d))? # Version $ /x; sub clone { my $self = shift; # Dynamic requests cannot be cloned return undef unless my $content = $self->content->clone; my $clone = $self->new( content => $content, method => $self->method, url => $self->url->clone, version => $self->version ); $clone->{proxy} = $self->{proxy}->clone if $self->{proxy}; return $clone; } sub cookies { my $self = shift; # Parse cookies my $headers = $self->headers; return [map { @{Mojo::Cookie::Request->parse($_)} } $headers->cookie] unless @_; # Add cookies my @cookies = $headers->cookie || (); for my $cookie (@_) { $cookie = Mojo::Cookie::Request->new($cookie) if ref $cookie eq 'HASH'; push @cookies, $cookie; } $headers->cookie(join('; ', @cookies)); return $self; } sub extract_start_line { my ($self, $bufref) = @_; # Ignore any leading empty lines $$bufref =~ s/^\s+//; return undef unless defined(my $line = get_line $bufref); # We have a (hopefully) full request line $self->error('Bad request start line', 400) and return undef unless $line =~ $START_LINE_RE; my $url = $self->method($1)->version($3)->url; return !!($1 eq 'CONNECT' ? $url->authority($2) : $url->parse($2)); } sub fix_headers { my $self = shift; $self->{fix} ? return $self : $self->SUPER::fix_headers(@_); # Basic authentication my $url = $self->url; my $headers = $self->headers; my $auth = $url->userinfo; $headers->authorization('Basic ' . b64_encode($auth, '')) if $auth && !$headers->authorization; # Basic proxy authentication if (my $proxy = $self->proxy) { my $proxy_auth = $proxy->userinfo; $headers->proxy_authorization('Basic ' . b64_encode($proxy_auth, '')) if $proxy_auth && !$headers->proxy_authorization; } # Host my $host = $url->ihost; my $port = $url->port; $headers->host($port ? "$host:$port" : $host) unless $headers->host; return $self; } sub get_start_line_chunk { my ($self, $offset) = @_; unless (defined $self->{start_buffer}) { # Path my $url = $self->url; my $path = $url->path->to_string; my $query = $url->query->to_string; $path .= "?$query" if $query; $path = "/$path" unless $path =~ m!^/!; # CONNECT my $method = uc $self->method; if ($method eq 'CONNECT') { my $port = $url->port || ($url->protocol eq 'https' ? '443' : '80'); $path = $url->host . ":$port"; } # Proxy elsif ($self->proxy) { my $clone = $url = $url->clone->userinfo(undef); my $upgrade = lc($self->headers->upgrade // ''); $path = $clone unless $upgrade eq 'websocket' || $url->protocol eq 'https'; } $self->{start_buffer} = "$method $path HTTP/@{[$self->version]}\x0d\x0a"; } $self->emit(progress => 'start_line', $offset); return substr $self->{start_buffer}, $offset, 131072; } sub is_secure { my $url = shift->url; return ($url->protocol || $url->base->protocol) eq 'https'; } sub is_xhr { (shift->headers->header('X-Requested-With') // '') =~ /XMLHttpRequest/i; } sub param { shift->params->param(@_) } sub params { my $self = shift; return $self->{params} ||= $self->body_params->clone->merge($self->query_params); } sub parse { my $self = shift; # Parse CGI environment my $env = @_ > 1 ? {@_} : ref $_[0] eq 'HASH' ? $_[0] : undef; $self->env($env)->_parse_env($env) if $env; # Parse normal message my @args = $env ? () : @_; if (($self->{state} // '') ne 'cgi') { $self->SUPER::parse(@args) } # Parse CGI content else { $self->content($self->content->parse_body(@args))->SUPER::parse } # Check if we can fix things that require all headers return $self unless $self->is_finished; # Base URL my $base = $self->url->base; $base->scheme('http') unless $base->scheme; my $headers = $self->headers; if (!$base->host && (my $host = $headers->host)) { $base->authority($host) } # Basic authentication my $auth = _parse_basic_auth($headers->authorization); $base->userinfo($auth) if $auth; # Basic proxy authentication my $proxy_auth = _parse_basic_auth($headers->proxy_authorization); $self->proxy(Mojo::URL->new->userinfo($proxy_auth)) if $proxy_auth; # "X-Forwarded-HTTPS" $base->scheme('https') if $ENV{MOJO_REVERSE_PROXY} && $headers->header('X-Forwarded-HTTPS'); return $self; } sub proxy { my $self = shift; return $self->{proxy} unless @_; $self->{proxy} = !$_[0] || ref $_[0] ? shift : Mojo::URL->new(shift); return $self; } sub query_params { shift->url->query } sub _parse_basic_auth { return undef unless my $header = shift; return $header =~ /Basic (.+)$/ ? b64_decode($1) : undef; } sub _parse_env { my ($self, $env) = @_; # Extract headers my $headers = $self->headers; my $url = $self->url; my $base = $url->base; while (my ($name, $value) = each %$env) { next unless $name =~ s/^HTTP_//i; $name =~ s/_/-/g; $headers->header($name => $value); # Host/Port if ($name eq 'HOST') { my ($host, $port) = ($value, undef); ($host, $port) = ($1, $2) if $host =~ /^([^:]*):?(.*)$/; $base->host($host)->port($port); } } # Content-Type is a special case on some servers $headers->content_type($env->{CONTENT_TYPE}) if $env->{CONTENT_TYPE}; # Content-Length is a special case on some servers $headers->content_length($env->{CONTENT_LENGTH}) if $env->{CONTENT_LENGTH}; # Query $url->query->parse($env->{QUERY_STRING}) if $env->{QUERY_STRING}; # Method $self->method($env->{REQUEST_METHOD}) if $env->{REQUEST_METHOD}; # Scheme/Version if (($env->{SERVER_PROTOCOL} // '') =~ m!^([^/]+)/([^/]+)$!) { $base->scheme($1); $self->version($2); } # HTTPS $base->scheme('https') if uc($env->{HTTPS} // '') eq 'ON'; # Path my $path = $url->path->parse($env->{PATH_INFO} ? $env->{PATH_INFO} : ''); # Base path if (my $value = $env->{SCRIPT_NAME}) { # Make sure there is a trailing slash (important for merging) $base->path->parse($value =~ m!/$! ? $value : "$value/"); # Remove SCRIPT_NAME prefix if necessary my $buffer = $path->to_string; $value =~ s!^/|/$!!g; $buffer =~ s!^/?\Q$value\E/?!!; $buffer =~ s!^/!!; $path->parse($buffer); } # Bypass normal message parser $self->{state} = 'cgi'; } 1; =encoding utf8 =head1 NAME Mojo::Message::Request - HTTP request =head1 SYNOPSIS use Mojo::Message::Request; # Parse my $req = Mojo::Message::Request->new; $req->parse("GET /foo HTTP/1.0\x0d\x0a"); $req->parse("Content-Length: 12\x0d\x0a"); $req->parse("Content-Type: text/plain\x0d\x0a\x0d\x0a"); $req->parse('Hello World!'); say $req->method; say $req->headers->content_type; say $req->body; # Build my $req = Mojo::Message::Request->new; $req->url->parse('http://127.0.0.1/foo/bar'); $req->method('GET'); say $req->to_string; =head1 DESCRIPTION L is a container for HTTP requests as described in RFC 2616 and RFC 2817. =head1 EVENTS L inherits all events from L. =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 env my $env = $req->env; $req = $req->env({}); Direct access to the C or C environment hash if available. # Check CGI version my $version = $req->env->{GATEWAY_INTERFACE}; # Check PSGI version my $version = $req->env->{'psgi.version'}; =head2 method my $method = $req->method; $req = $req->method('POST'); HTTP request method, defaults to C. =head2 url my $url = $req->url; $req = $req->url(Mojo::URL->new); HTTP request URL, defaults to a L object. # Get request information say $req->url->to_abs->userinfo; say $req->url->to_abs->host; say $req->url->to_abs->path; =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 clone my $clone = $req->clone; Clone request if possible, otherwise return C. =head2 cookies my $cookies = $req->cookies; $req = $req->cookies(Mojo::Cookie::Request->new); $req = $req->cookies({name => 'foo', value => 'bar'}); Access request cookies, usually L objects. =head2 extract_start_line my $bool = $req->extract_start_line(\$str); Extract request line from string. =head2 fix_headers $req = $req->fix_headers; Make sure request has all required headers. =head2 get_start_line_chunk my $bytes = $req->get_start_line_chunk($offset); Get a chunk of request line data starting from a specific position. =head2 is_secure my $bool = $req->is_secure; Check if connection is secure. =head2 is_xhr my $bool = $req->is_xhr; Check C header for C value. =head2 param my @names = $req->param; my $foo = $req->param('foo'); my @foo = $req->param('foo'); Access GET and POST parameters. Note that this method caches all data, so it should not be called before the entire request body has been received. Parts of the request body need to be loaded into memory to parse POST parameters, so you have to make sure it is not excessively large. =head2 params my $params = $req->params; All GET and POST parameters, usually a L object. Note that this method caches all data, so it should not be called before the entire request body has been received. Parts of the request body need to be loaded into memory to parse POST parameters, so you have to make sure it is not excessively large. # Get parameter value say $req->params->param('foo'); =head2 parse $req = $req->parse('GET /foo/bar HTTP/1.1'); $req = $req->parse(REQUEST_METHOD => 'GET'); $req = $req->parse({REQUEST_METHOD => 'GET'}); Parse HTTP request chunks or environment hash. =head2 proxy my $proxy = $req->proxy; $req = $req->proxy('http://foo:bar@127.0.0.1:3000'); $req = $req->proxy(Mojo::URL->new('http://127.0.0.1:3000')); Proxy URL for request. # Disable proxy $req->proxy(0); =head2 query_params my $params = $req->query_params; All GET parameters, usually a L object. # Turn GET parameters to hash and extract value say $req->query_params->to_hash->{foo}; =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Message/Response.pm0000644000175000017500000001466212254164224024364 0ustar cstamascstamaspackage Mojo::Message::Response; use Mojo::Base 'Mojo::Message'; use Mojo::Cookie::Response; use Mojo::Date; use Mojo::Util 'get_line'; has [qw(code message)]; # Umarked codes are from RFC 2616 my %MESSAGES = ( 100 => 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', # RFC 2518 (WebDAV) 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', # RFC 2518 (WebDAV) 208 => 'Already Reported', # RFC 5842 226 => 'IM Used', # RFC 3229 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect', 308 => 'Permanent Redirect', # Draft 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Request Range Not Satisfiable', 417 => 'Expectation Failed', 418 => "I'm a teapot", # :) 422 => 'Unprocessable Entity', # RFC 2518 (WebDAV) 423 => 'Locked', # RFC 2518 (WebDAV) 424 => 'Failed Dependency', # RFC 2518 (WebDAV) 425 => 'Unordered Colection', # RFC 3648 (WebDAV) 426 => 'Upgrade Required', # RFC 2817 428 => 'Precondition Required', # RFC 6585 429 => 'Too Many Requests', # RFC 6585 431 => 'Request Header Fields Too Large', # RFC 6585 451 => 'Unavailable For Legal Reasons', # Draft 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', # RFC 2295 507 => 'Insufficient Storage', # RFC 2518 (WebDAV) 508 => 'Loop Detected', # RFC 5842 509 => 'Bandwidth Limit Exceeded', # Unofficial 510 => 'Not Extended', # RFC 2774 511 => 'Network Authentication Required' # RFC 6585 ); sub cookies { my $self = shift; # Parse cookies my $headers = $self->headers; return [map { @{Mojo::Cookie::Response->parse($_)} } $headers->set_cookie] unless @_; # Add cookies for my $cookie (@_) { $cookie = Mojo::Cookie::Response->new($cookie) if ref $cookie eq 'HASH'; $headers->add('Set-Cookie' => "$cookie"); } return $self; } sub default_message { $MESSAGES{$_[1] || $_[0]->code || 404} || '' } sub extract_start_line { my ($self, $bufref) = @_; # We have a full response line return undef unless defined(my $line = get_line $bufref); $self->error('Bad response start line') and return undef unless $line =~ m!^\s*HTTP/(\d\.\d)\s+(\d\d\d)\s*(.+)?$!; $self->content->skip_body(1) if $self->code($2)->is_empty; return !!$self->version($1)->message($3)->content->auto_relax(1); } sub fix_headers { my $self = shift; $self->{fix} ? return $self : $self->SUPER::fix_headers(@_); # Date my $headers = $self->headers; $headers->date(Mojo::Date->new->to_string) unless $headers->date; return $self; } sub get_start_line_chunk { my ($self, $offset) = @_; unless (defined $self->{start_buffer}) { my $code = $self->code || 404; my $msg = $self->message || $self->default_message; $self->{start_buffer} = "HTTP/@{[$self->version]} $code $msg\x0d\x0a"; } $self->emit(progress => 'start_line', $offset); return substr $self->{start_buffer}, $offset, 131072; } sub is_empty { my $self = shift; return undef unless my $code = $self->code; return $self->is_status_class(100) || $code eq 204 || $code eq 304; } sub is_status_class { my ($self, $class) = @_; return undef unless my $code = $self->code; return $code >= $class && $code < ($class + 100); } 1; =encoding utf8 =head1 NAME Mojo::Message::Response - HTTP response =head1 SYNOPSIS use Mojo::Message::Response; # Parse my $res = Mojo::Message::Response->new; $res->parse("HTTP/1.0 200 OK\x0d\x0a"); $res->parse("Content-Length: 12\x0d\x0a"); $res->parse("Content-Type: text/plain\x0d\x0a\x0d\x0a"); $res->parse('Hello World!'); say $res->code; say $res->headers->content_type; say $res->body; # Build my $res = Mojo::Message::Response->new; $res->code(200); $res->headers->content_type('text/plain'); $res->body('Hello World!'); say $res->to_string; =head1 DESCRIPTION L is a container for HTTP responses as described in RFC 2616. =head1 EVENTS L inherits all events from L. =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 code my $code = $res->code; $res = $res->code(200); HTTP response code. =head2 message my $msg = $res->message; $res = $res->message('OK'); HTTP response message. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 cookies my $cookies = $res->cookies; $res = $res->cookies(Mojo::Cookie::Response->new); $res = $res->cookies({name => 'foo', value => 'bar'}); Access response cookies, usually L objects. =head2 default_message my $msg = $res->default_message; Generate default response message for code. =head2 extract_start_line my $bool = $res->extract_start_line(\$str); Extract status line from string. =head2 fix_headers $res = $res->fix_headers; Make sure response has all required headers. =head2 get_start_line_chunk my $bytes = $res->get_start_line_chunk($offset); Get a chunk of status line data starting from a specific position. =head2 is_empty my $bool = $res->is_empty; Check if this is a C<1xx>, C<204> or C<304> response. =head2 is_status_class my $bool = $res->is_status_class(200); Check response status class. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Message.pm0000644000175000017500000003632012254163603022561 0ustar cstamascstamaspackage Mojo::Message; use Mojo::Base 'Mojo::EventEmitter'; use Carp 'croak'; use Mojo::Asset::Memory; use Mojo::Content::Single; use Mojo::DOM; use Mojo::JSON; use Mojo::JSON::Pointer; use Mojo::Parameters; use Mojo::Upload; use Mojo::Util 'decode'; has content => sub { Mojo::Content::Single->new }; has default_charset => 'UTF-8'; has max_line_size => sub { $ENV{MOJO_MAX_LINE_SIZE} || 10240 }; has max_message_size => sub { $ENV{MOJO_MAX_MESSAGE_SIZE} // 10485760 }; has version => '1.1'; sub body { my $self = shift; # Downgrade multipart content my $content = $self->content; $content = $self->content(Mojo::Content::Single->new)->content if $content->is_multipart; # Get return $content->asset->slurp unless @_; # Set $content->asset(Mojo::Asset::Memory->new->add_chunk(@_)); return $self; } sub body_params { my $self = shift; return $self->{body_params} if $self->{body_params}; my $params = $self->{body_params} = Mojo::Parameters->new; $params->charset($self->content->charset || $self->default_charset); # "application/x-www-form-urlencoded" my $type = $self->headers->content_type // ''; if ($type =~ m!application/x-www-form-urlencoded!i) { $params->parse($self->content->asset->slurp); } # "multipart/form-data" elsif ($type =~ m!multipart/form-data!i) { $params->append(@$_[0, 1]) for @{$self->_parse_formdata}; } return $params; } sub body_size { shift->content->body_size } sub build_body { shift->_build('get_body_chunk') } sub build_headers { shift->_build('get_header_chunk') } sub build_start_line { shift->_build('get_start_line_chunk') } sub cookie { shift->_cache(cookies => @_) } sub cookies { croak 'Method "cookies" not implemented by subclass' } sub dom { my $self = shift; return undef if $self->content->is_multipart; my $dom = $self->{dom} ||= Mojo::DOM->new($self->text); return @_ ? $dom->find(@_) : $dom; } sub error { my $self = shift; # Set if (@_) { $self->{error} = [@_]; return $self->finish; } # Get return unless my $err = $self->{error}; return wantarray ? @$err : $err->[0]; } sub extract_start_line { croak 'Method "extract_start_line" not implemented by subclass'; } sub finish { my $self = shift; $self->{state} = 'finished'; return $self->{finished}++ ? $self : $self->emit('finish'); } sub fix_headers { my $self = shift; # Content-Length or Connection (unless chunked transfer encoding is used) my $content = $self->content; return $self if $self->{fix}++ || $content->is_chunked; my $headers = $self->headers; $content->is_dynamic ? $headers->connection('close') : $headers->content_length($self->body_size) unless $headers->content_length; return $self; } sub get_body_chunk { my ($self, $offset) = @_; $self->emit('progress', 'body', $offset); my $chunk = $self->content->get_body_chunk($offset); return $chunk if !defined $chunk || length $chunk; $self->finish; return $chunk; } sub get_header_chunk { my ($self, $offset) = @_; $self->emit('progress', 'headers', $offset); return $self->fix_headers->content->get_header_chunk($offset); } sub get_start_line_chunk { croak 'Method "get_start_line_chunk" not implemented by subclass'; } sub header_size { shift->fix_headers->content->header_size } sub headers { shift->content->headers } sub is_finished { (shift->{state} // '') eq 'finished' } sub is_limit_exceeded { !!shift->{limit} } sub json { my ($self, $pointer) = @_; return undef if $self->content->is_multipart; my $data = $self->{json} ||= Mojo::JSON->new->decode($self->body); return $pointer ? Mojo::JSON::Pointer->new->get($data, $pointer) : $data; } sub param { shift->body_params->param(@_) } sub parse { my ($self, $chunk) = @_; # Check message size my $max = $self->max_message_size; return $self->_limit('Maximum message size exceeded', 413) if $max && ($self->{raw_size} += length($chunk //= '')) > $max; $self->{buffer} .= $chunk; # Start line unless ($self->{state}) { # Check line size my $len = index $self->{buffer}, "\x0a"; $len = length $self->{buffer} if $len < 0; return $self->_limit('Maximum line size exceeded', 431) if $len > $self->max_line_size; $self->{state} = 'content' if $self->extract_start_line(\$self->{buffer}); } # Content my $state = $self->{state} // ''; $self->content($self->content->parse(delete $self->{buffer})) if $state eq 'content' || $state eq 'finished'; # Check line size return $self->_limit('Maximum line size exceeded', 431) if $self->headers->is_limit_exceeded; # Check buffer size return $self->error('Maximum buffer size exceeded', 400) if $self->content->is_limit_exceeded; return $self->emit('progress')->content->is_finished ? $self->finish : $self; } sub start_line_size { length shift->build_start_line } sub text { my $self = shift; my $body = $self->body; my $charset = $self->content->charset; return $charset ? decode($charset, $body) // $body : $body; } sub to_string { my $self = shift; return $self->build_start_line . $self->build_headers . $self->build_body; } sub upload { shift->_cache(uploads => @_) } sub uploads { my $self = shift; my @uploads; for my $data (@{$self->_parse_formdata(1)}) { my $upload = Mojo::Upload->new( name => $data->[0], filename => $data->[2], asset => $data->[1]->asset, headers => $data->[1]->headers ); push @uploads, $upload; } return \@uploads; } sub _build { my ($self, $method) = @_; my $buffer = ''; my $offset = 0; while (1) { # No chunk yet, try again next unless defined(my $chunk = $self->$method($offset)); # End of part last unless my $len = length $chunk; $offset += $len; $buffer .= $chunk; } return $buffer; } sub _cache { my ($self, $method, $name) = @_; # Cache objects by name unless ($self->{$method}) { $self->{$method} = {}; push @{$self->{$method}{$_->name}}, $_ for @{$self->$method}; } return unless my $objects = $self->{$method}{$name}; return wantarray ? @$objects : $objects->[0]; } sub _limit { my $self = shift; $self->{limit} = 1; $self->error(@_); } sub _parse_formdata { my ($self, $upload) = @_; my @formdata; my $content = $self->content; return \@formdata unless $content->is_multipart; my $charset = $content->charset || $self->default_charset; # Check all parts recursively my @parts = ($content); while (my $part = shift @parts) { if ($part->is_multipart) { unshift @parts, @{$part->parts}; next; } next unless my $disposition = $part->headers->content_disposition; my ($filename) = $disposition =~ /[; ]filename\s*=\s*"?((?:\\"|[^"])*)"?/i; next if ($upload && !defined $filename) || (!$upload && defined $filename); my ($name) = $disposition =~ /[; ]name\s*=\s*"?((?:\\"|[^";])+)"?/i; if ($charset) { $name = decode($charset, $name) // $name if $name; $filename = decode($charset, $filename) // $filename if $filename; } unless ($upload) { $part = $part->asset->slurp; $part = decode($charset, $part) // $part if $charset; } push @formdata, [$name, $part, $filename]; } return \@formdata; } 1; =encoding utf8 =head1 NAME Mojo::Message - HTTP message base class =head1 SYNOPSIS package Mojo::Message::MyMessage; use Mojo::Base 'Mojo::Message'; sub cookies {...} sub extract_start_line {...} sub get_start_line_chunk {...} =head1 DESCRIPTION L is an abstract base class for HTTP messages as described in RFC 2616 and RFC 2388. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 finish $msg->on(finish => sub { my $msg = shift; ... }); Emitted after message building or parsing is finished. my $before = time; $msg->on(finish => sub { my $msg = shift; $msg->headers->header('X-Parser-Time' => time - $before); }); =head2 progress $msg->on(progress => sub { my $msg = shift; ... }); Emitted when message building or parsing makes progress. # Building $msg->on(progress => sub { my ($msg, $state, $offset) = @_; say qq{Building "$state" at offset $offset}; }); # Parsing $msg->on(progress => sub { my $msg = shift; return unless my $len = $msg->headers->content_length; my $size = $msg->content->progress; say 'Progress: ', $size == $len ? 100 : int($size / ($len / 100)), '%'; }); =head1 ATTRIBUTES L implements the following attributes. =head2 content my $msg = $msg->content; $msg = $msg->content(Mojo::Content::Single->new); Message content, defaults to a L object. =head2 default_charset my $charset = $msg->default_charset; $msg = $msg->default_charset('UTF-8'); Default charset used for form-data parsing, defaults to C. =head2 max_line_size my $size = $msg->max_line_size; $msg = $msg->max_line_size(1024); Maximum start line size in bytes, defaults to the value of the MOJO_MAX_LINE_SIZE environment variable or C<10240>. =head2 max_message_size my $size = $msg->max_message_size; $msg = $msg->max_message_size(1024); Maximum message size in bytes, defaults to the value of the MOJO_MAX_MESSAGE_SIZE environment variable or C<10485760>. Setting the value to C<0> will allow messages of indefinite size. Note that increasing this value can also drastically increase memory usage, should you for example attempt to parse an excessively large message body with the L, L or L methods. =head2 version my $version = $msg->version; $msg = $msg->version('1.1'); HTTP version of message, defaults to C<1.1>. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 body my $bytes = $msg->body; $msg = $msg->body('Hello!'); Slurp or replace L, L will be automatically downgraded to L. =head2 body_params my $params = $msg->body_params; POST parameters extracted from C or C message body, usually a L object. Note that this method caches all data, so it should not be called before the entire message body has been received. Parts of the message body need to be loaded into memory to parse POST parameters, so you have to make sure it is not excessively large. # Get POST parameter value say $msg->body_params->param('foo'); =head2 body_size my $size = $msg->body_size; Content size in bytes. =head2 build_body my $bytes = $msg->build_body; Render whole body. =head2 build_headers my $bytes = $msg->build_headers; Render all headers. =head2 build_start_line my $bytes = $msg->build_start_line; Render start line. =head2 cookie my $cookie = $msg->cookie('foo'); my @cookies = $msg->cookie('foo'); Access message cookies, usually L or L objects. Note that this method caches all data, so it should not be called before all headers have been received. # Get cookie value say $msg->cookie('foo')->value; =head2 cookies my $cookies = $msg->cookies; Access message cookies. Meant to be overloaded in a subclass. =head2 dom my $dom = $msg->dom; my $collection = $msg->dom('a[href]'); Turns message body into a L object and takes an optional selector to perform a C on it right away, which returns a L object. Note that this method caches all data, so it should not be called before the entire message body has been received. The whole message body needs to be loaded into memory to parse it, so you have to make sure it is not excessively large. # Perform "find" right away say $msg->dom('h1, h2, h3')->text; # Use everything else Mojo::DOM has to offer say $msg->dom->at('title')->text; say $msg->dom->html->body->children->type->uniq; =head2 error my $err = $msg->error; my ($err, $code) = $msg->error; $msg = $msg->error('Parser error'); $msg = $msg->error('Parser error', 500); Error and code. =head2 extract_start_line my $bool = $msg->extract_start_line(\$str); Extract start line from string. Meant to be overloaded in a subclass. =head2 finish $msg = $msg->finish; Finish message parser/generator. =head2 fix_headers $msg = $msg->fix_headers; Make sure message has all required headers. =head2 get_body_chunk my $bytes = $msg->get_body_chunk($offset); Get a chunk of body data starting from a specific position. =head2 get_header_chunk my $bytes = $msg->get_header_chunk($offset); Get a chunk of header data, starting from a specific position. =head2 get_start_line_chunk my $bytes = $msg->get_start_line_chunk($offset); Get a chunk of start line data starting from a specific position. Meant to be overloaded in a subclass. =head2 header_size my $size = $msg->header_size; Size of headers in bytes. =head2 headers my $headers = $msg->headers; Message headers, usually a L object. =head2 is_finished my $bool = $msg->is_finished; Check if message parser/generator is finished. =head2 is_limit_exceeded my $bool = $msg->is_limit_exceeded; Check if message has exceeded L or L. =head2 json my $hash = $msg->json; my $array = $msg->json; my $value = $msg->json('/foo/bar'); Decode JSON message body directly using L if possible, returns C otherwise. An optional JSON Pointer can be used to extract a specific value with L. Note that this method caches all data, so it should not be called before the entire message body has been received. The whole message body needs to be loaded into memory to parse it, so you have to make sure it is not excessively large. # Extract JSON values say $msg->json->{foo}{bar}[23]; say $msg->json('/foo/bar/23'); =head2 param my @names = $msg->param; my $foo = $msg->param('foo'); my @foo = $msg->param('foo'); Access POST parameters. Note that this method caches all data, so it should not be called before the entire message body has been received. Parts of the message body need to be loaded into memory to parse POST parameters, so you have to make sure it is not excessively large. =head2 parse $msg = $msg->parse('HTTP/1.1 200 OK...'); Parse message chunk. =head2 start_line_size my $size = $msg->start_line_size; Size of the start line in bytes. =head2 text my $str = $msg->text; Retrieve L and try to decode it if a charset could be extracted with L. =head2 to_string my $str = $msg->to_string; Render whole message. =head2 upload my $upload = $msg->upload('foo'); my @uploads = $msg->upload('foo'); Access C file uploads, usually L objects. Note that this method caches all data, so it should not be called before the entire message body has been received. # Get content of uploaded file say $msg->upload('foo')->asset->slurp; =head2 uploads my $uploads = $msg->uploads; All C file uploads, usually L objects. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Parameters.pm0000644000175000017500000001671312242771675023317 0ustar cstamascstamaspackage Mojo::Parameters; use Mojo::Base -base; use overload '@{}' => sub { shift->params }, bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1; use Mojo::Util qw(decode encode url_escape url_unescape); has charset => 'UTF-8'; sub new { shift->SUPER::new->parse(@_) } sub append { my ($self, @pairs) = @_; my $params = $self->params; for (my $i = 0; $i < @pairs; $i += 2) { my $key = $pairs[$i] // ''; my $value = $pairs[$i + 1] // ''; # Single value if (ref $value ne 'ARRAY') { push @$params, $key => $value } # Multiple values else { push @$params, $key => (defined $_ ? "$_" : '') for @$value } } return $self; } sub clone { my $self = shift; my $clone = $self->new->charset($self->charset); if (defined $self->{string}) { $clone->{string} = $self->{string} } else { $clone->params([@{$self->params}]) } return $clone; } sub merge { my $self = shift; push @{$self->params}, @{$_->params} for @_; return $self; } sub param { my ($self, $name) = (shift, shift); # List names return sort keys %{$self->to_hash} unless $name; # Replace values $self->remove($name) if defined $_[0]; $self->append($name, $_) for @_; # List values my @values; my $params = $self->params; for (my $i = 0; $i < @$params; $i += 2) { push @values, $params->[$i + 1] if $params->[$i] eq $name; } return wantarray ? @values : $values[0]; } sub params { my $self = shift; # Replace parameters if (@_) { $self->{params} = shift; delete $self->{string}; return $self; } # Parse string if (defined(my $str = delete $self->{string})) { my $params = $self->{params} = []; return $params unless length $str; # W3C suggests to also accept ";" as a separator my $charset = $self->charset; for my $pair (split /&|;/, $str) { next unless $pair =~ /^([^=]+)(?:=(.*))?$/; my $name = $1; my $value = $2 // ''; # Replace "+" with whitespace, unescape and decode s/\+/ /g for $name, $value; $name = url_unescape $name; $name = decode($charset, $name) // $name if $charset; $value = url_unescape $value; $value = decode($charset, $value) // $value if $charset; push @$params, $name, $value; } } return $self->{params} ||= []; } sub parse { my $self = shift; # Pairs if (@_ > 1) { $self->append(@_) } # String else { $self->{string} = $_[0] } return $self; } sub remove { my $self = shift; my $name = shift // ''; my $params = $self->params; for (my $i = 0; $i < @$params;) { if ($params->[$i] eq $name) { splice @$params, $i, 2 } else { $i += 2 } } return $self->params($params); } sub to_hash { my $self = shift; my $params = $self->params; my %hash; for (my $i = 0; $i < @$params; $i += 2) { my ($name, $value) = @{$params}[$i, $i + 1]; # Array if (exists $hash{$name}) { $hash{$name} = [$hash{$name}] unless ref $hash{$name} eq 'ARRAY'; push @{$hash{$name}}, $value; } # String else { $hash{$name} = $value } } return \%hash; } sub to_string { my $self = shift; # String my $charset = $self->charset; if (defined(my $str = $self->{string})) { $str = encode $charset, $str if $charset; return url_escape $str, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/?'; } # Build pairs my $params = $self->params; return '' unless @$params; my @pairs; for (my $i = 0; $i < @$params; $i += 2) { my ($name, $value) = @{$params}[$i, $i + 1]; # Escape and replace whitespace with "+" $name = encode $charset, $name if $charset; $name = url_escape $name, '^A-Za-z0-9\-._~!$\'()*,:@/?'; $value = encode $charset, $value if $charset; $value = url_escape $value, '^A-Za-z0-9\-._~!$\'()*,:@/?'; s/\%20/\+/g for $name, $value; push @pairs, "$name=$value"; } return join '&', @pairs; } 1; =encoding utf8 =head1 NAME Mojo::Parameters - Parameters =head1 SYNOPSIS use Mojo::Parameters; # Parse my $params = Mojo::Parameters->new('foo=bar&baz=23'); say $params->param('baz'); # Build my $params = Mojo::Parameters->new(foo => 'bar', baz => 23); push @$params, i => '♥ mojolicious'; say "$params"; =head1 DESCRIPTION L is a container for form parameters used by L. =head1 ATTRIBUTES L implements the following attributes. =head2 charset my $charset = $params->charset; $params = $params->charset('UTF-8'); Charset used for encoding and decoding parameters, defaults to C. # Disable encoding and decoding $params->charset(undef); =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $params = Mojo::Parameters->new; my $params = Mojo::Parameters->new('foo=b%3Bar&baz=23'); my $params = Mojo::Parameters->new(foo => 'b;ar'); my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az']); my $params = Mojo::Parameters->new(foo => ['ba;r', 'b;az'], bar => 23); Construct a new L object and L parameters if necessary. =head2 append $params = $params->append(foo => 'ba;r'); $params = $params->append(foo => ['ba;r', 'b;az']); $params = $params->append(foo => ['ba;r', 'b;az'], bar => 23); Append parameters. Note that this method will normalize the parameters. # "foo=bar&foo=baz" Mojo::Parameters->new('foo=bar')->append(foo => 'baz'); # "foo=bar&foo=baz&foo=yada" Mojo::Parameters->new('foo=bar')->append(foo => ['baz', 'yada']); # "foo=bar&foo=baz&foo=yada&bar=23" Mojo::Parameters->new('foo=bar')->append(foo => ['baz', 'yada'], bar => 23); =head2 clone my $params2 = $params->clone; Clone parameters. =head2 merge $params = $params->merge(Mojo::Parameters->new(foo => 'b;ar', baz => 23)); Merge L objects. Note that this method will normalize the parameters. =head2 param my @names = $params->param; my $foo = $params->param('foo'); my @foo = $params->param('foo'); my $foo = $params->param(foo => 'ba;r'); my @foo = $params->param(foo => qw(ba;r ba;z)); Check and replace parameter value. Be aware that if you request a parameter by name in scalar context, you will receive only the I value for that parameter, if there are multiple values for that name. In list context you will receive I of the values for that name. Note that this method will normalize the parameters. =head2 params my $array = $params->params; $params = $params->params([foo => 'b;ar', baz => 23]); Parsed parameters. Note that this method will normalize the parameters. =head2 parse $params = $params->parse('foo=b%3Bar&baz=23'); Parse parameters. =head2 remove $params = $params->remove('foo'); Remove parameters. Note that this method will normalize the parameters. # "bar=yada" Mojo::Parameters->new('foo=bar&foo=baz&bar=yada')->remove('foo'); =head2 to_hash my $hash = $params->to_hash; Turn parameters into a hash reference. Note that this method will normalize the parameters. # "baz" Mojo::Parameters->new('foo=bar&foo=baz')->to_hash->{foo}[1]; =head2 to_string my $str = $params->to_string; my $str = "$params"; Turn parameters into a string. =head1 PARAMETERS Direct array reference access to the parsed parameters is also possible. Note that this will normalize the parameters. say $params->[0]; say for @$params; =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Path.pm0000644000175000017500000001622512242771673022104 0ustar cstamascstamaspackage Mojo::Path; use Mojo::Base -base; use overload '@{}' => sub { shift->parts }, bool => sub {1}, '""' => sub { shift->to_string }, fallback => 1; use Mojo::Util qw(decode encode url_escape url_unescape); has charset => 'UTF-8'; sub new { shift->SUPER::new->parse(@_) } sub canonicalize { my $self = shift; my @parts; for my $part (@{$self->parts}) { # ".." if ($part eq '..') { (@parts && $parts[-1] ne '..') ? pop @parts : push @parts, '..'; } # Something else than "." elsif ($part ne '.' && $part ne '') { push @parts, $part } } $self->trailing_slash(undef) unless @parts; return $self->parts(\@parts); } sub clone { my $self = shift; my $clone = $self->new->charset($self->charset); if (my $parts = $self->{parts}) { $clone->{$_} = $self->{$_} for qw(leading_slash trailing_slash); $clone->{parts} = [@$parts]; } else { $clone->{path} = $self->{path} } return $clone; } sub contains { my ($self, $path) = @_; return $path eq '/' || $self->to_route =~ m!^\Q$path\E(?:/|$)!; } sub leading_slash { shift->_parse(leading_slash => @_) } sub merge { my ($self, $path) = @_; # Replace return $self->parse($path) if $path =~ m!^/!; # Merge pop @{$self->parts} unless $self->trailing_slash; $path = $self->new($path); push @{$self->parts}, @{$path->parts}; return $self->trailing_slash($path->trailing_slash); } sub parse { my $self = shift; $self->{path} = shift; delete @$self{qw(leading_slash parts trailing_slash)}; return $self; } sub parts { shift->_parse(parts => @_) } sub to_abs_string { my $path = shift->to_string; return $path =~ m!^/! ? $path : "/$path"; } sub to_dir { my $clone = shift->clone; pop @{$clone->parts} unless $clone->trailing_slash; return $clone->trailing_slash(!!@{$clone->parts}); } sub to_route { my $clone = shift->clone; my $route = join '/', @{$clone->parts}; return "/$route" . ($clone->trailing_slash ? '/' : ''); } sub to_string { my $self = shift; # Path my $charset = $self->charset; if (defined(my $path = $self->{path})) { $path = encode $charset, $path if $charset; return url_escape $path, '^A-Za-z0-9\-._~!$&\'()*+,;=%:@/'; } # Build path my @parts = @{$self->parts}; @parts = map { encode $charset, $_ } @parts if $charset; my $path = join '/', map { url_escape $_, '^A-Za-z0-9\-._~!$&\'()*+,;=:@' } @parts; $path = "/$path" if $self->leading_slash; $path = "$path/" if $self->trailing_slash; return $path; } sub trailing_slash { shift->_parse(trailing_slash => @_) } sub _parse { my ($self, $name) = (shift, shift); unless ($self->{parts}) { my $path = url_unescape delete($self->{path}) // ''; my $charset = $self->charset; $path = decode($charset, $path) // $path if $charset; $self->{leading_slash} = $path =~ s!^/!!; $self->{trailing_slash} = $path =~ s!/$!!; $self->{parts} = [split '/', $path, -1]; } return $self->{$name} unless @_; $self->{$name} = shift; return $self; } 1; =encoding utf8 =head1 NAME Mojo::Path - Path =head1 SYNOPSIS use Mojo::Path; # Parse my $path = Mojo::Path->new('/foo%2Fbar%3B/baz.html'); say $path->[0]; # Build my $path = Mojo::Path->new('/i/♥'); push @$path, 'mojolicious'; say "$path"; =head1 DESCRIPTION L is a container for paths used by L. =head1 ATTRIBUTES L implements the following attributes. =head2 charset my $charset = $path->charset; $path = $path->charset('UTF-8'); Charset used for encoding and decoding, defaults to C. # Disable encoding and decoding $path->charset(undef); =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $path = Mojo::Path->new; my $path = Mojo::Path->new('/foo%2Fbar%3B/baz.html'); Construct a new L object and L path if necessary. =head2 canonicalize $path = $path->canonicalize; Canonicalize path. # "/foo/baz" Mojo::Path->new('/foo/./bar/../baz')->canonicalize; # "/../baz" Mojo::Path->new('/foo/../bar/../../baz')->canonicalize; =head2 clone my $clone = $path->clone; Clone path. =head2 contains my $bool = $path->contains('/i/♥/mojolicious'); Check if path contains given prefix. # True Mojo::Path->new('/foo/bar')->contains('/'); Mojo::Path->new('/foo/bar')->contains('/foo'); Mojo::Path->new('/foo/bar')->contains('/foo/bar'); # False Mojo::Path->new('/foo/bar')->contains('/f'); Mojo::Path->new('/foo/bar')->contains('/bar'); Mojo::Path->new('/foo/bar')->contains('/whatever'); =head2 leading_slash my $bool = $path->leading_slash; $path = $path->leading_slash($bool); Path has a leading slash. Note that this method will normalize the path and that C<%2F> will be treated as C for security reasons. =head2 merge $path = $path->merge('/foo/bar'); $path = $path->merge('foo/bar'); $path = $path->merge(Mojo::Path->new('foo/bar')); Merge paths. Note that this method will normalize both paths if necessary and that C<%2F> will be treated as C for security reasons. # "/baz/yada" Mojo::Path->new('/foo/bar')->merge('/baz/yada'); # "/foo/baz/yada" Mojo::Path->new('/foo/bar')->merge('baz/yada'); # "/foo/bar/baz/yada" Mojo::Path->new('/foo/bar/')->merge('baz/yada'); =head2 parse $path = $path->parse('/foo%2Fbar%3B/baz.html'); Parse path. =head2 to_abs_string my $str = $path->to_abs_string; Turn path into an absolute string. # "/i/%E2%99%A5/mojolicious" Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_abs_string; Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_abs_string; =head2 parts my $parts = $path->parts; $path = $path->parts([qw(foo bar baz)]); The path parts. Note that this method will normalize the path and that C<%2F> will be treated as C for security reasons. # Part with slash push @{$path->parts}, 'foo/bar'; =head2 to_dir my $dir = $route->to_dir; Clone path and remove everything after the right-most slash. # "/i/%E2%99%A5/" Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_dir->to_abs_string; # "i/%E2%99%A5/" Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_dir->to_abs_string; =head2 to_route my $route = $path->to_route; Turn path into a route. # "/i/♥/mojolicious" Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_route; Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_route; =head2 to_string my $str = $path->to_string; my $str = "$path"; Turn path into a string. # "/i/%E2%99%A5/mojolicious" Mojo::Path->new('/i/%E2%99%A5/mojolicious')->to_string; # "i/%E2%99%A5/mojolicious" Mojo::Path->new('i/%E2%99%A5/mojolicious')->to_string; =head2 trailing_slash my $bool = $path->trailing_slash; $path = $path->trailing_slash($bool); Path has a trailing slash. Note that this method will normalize the path and that C<%2F> will be treated as C for security reasons. =head1 PATH PARTS Direct array reference access to path parts is also possible. Note that this will normalize the path and that C<%2F> will be treated as C for security reasons. say $path->[0]; say for @$path; =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Reactor/0000755000175000017500000000000012256126533022235 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Reactor/EV.pm0000644000175000017500000000760112246232147023107 0ustar cstamascstamaspackage Mojo::Reactor::EV; use Mojo::Base 'Mojo::Reactor::Poll'; use EV 4.0; use Scalar::Util 'weaken'; my $EV; sub CLONE { die "EV does not work with ithreads.\n" } sub DESTROY { undef $EV } # We have to fall back to Mojo::Reactor::Poll, since EV is unique sub new { $EV++ ? Mojo::Reactor::Poll->new : shift->SUPER::new } sub again { shift->{timers}{shift()}{watcher}->again } sub is_running { !!EV::depth } sub one_tick { EV::run(EV::RUN_ONCE) } sub recurring { shift->_timer(1, @_) } sub start {EV::run} sub stop { EV::break(EV::BREAK_ALL) } sub timer { shift->_timer(0, @_) } sub watch { my ($self, $handle, $read, $write) = @_; my $fd = fileno $handle; my $io = $self->{io}{$fd}; my $mode; if ($read && $write) { $mode = EV::READ | EV::WRITE } elsif ($read) { $mode = EV::READ } elsif ($write) { $mode = EV::WRITE } else { delete $io->{watcher} } if (my $w = $io->{watcher}) { $w->set($fd, $mode) } elsif ($mode) { weaken $self; $io->{watcher} = EV::io($fd, $mode, sub { $self->_io($fd, @_) }); } return $self; } sub _io { my ($self, $fd, $w, $revents) = @_; my $io = $self->{io}{$fd}; $self->_sandbox('Read', $io->{cb}, 0) if EV::READ &$revents; $self->_sandbox('Write', $io->{cb}, 1) if EV::WRITE &$revents && $self->{io}{$fd}; } sub _timer { my ($self, $recurring, $after, $cb) = @_; $after ||= '0.0001'; my $id = $self->SUPER::_timer(0, 0, $cb); weaken $self; $self->{timers}{$id}{watcher} = EV::timer( $after => $after => sub { my $timer = $self->{timers}{$id}; delete delete($self->{timers}{$id})->{watcher} unless $recurring; $self->_sandbox("Timer $id", $timer->{cb}); } ); return $id; } 1; =encoding utf8 =head1 NAME Mojo::Reactor::EV - Low level event reactor with libev support =head1 SYNOPSIS use Mojo::Reactor::EV; # Watch if handle becomes readable or writable my $reactor = Mojo::Reactor::EV->new; $reactor->io($handle => sub { my ($reactor, $writable) = @_; say $writable ? 'Handle is writable' : 'Handle is readable'; }); # Change to watching only if handle becomes writable $reactor->watch($handle, 0, 1); # Add a timer $reactor->timer(15 => sub { my $reactor = shift; $reactor->remove($handle); say 'Timeout!'; }); # Start reactor if necessary $reactor->start unless $reactor->is_running; =head1 DESCRIPTION L is a low level event reactor based on L (4.0+). =head1 EVENTS L inherits all events from L. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $reactor = Mojo::Reactor::EV->new; Construct a new L object. =head2 again $reactor->again($id); Restart active timer. =head2 is_running my $bool = $reactor->is_running; Check if reactor is running. =head2 one_tick $reactor->one_tick; Run reactor until an event occurs or no events are being watched anymore. Note that this method can recurse back into the reactor, so you need to be careful. =head2 recurring my $id = $reactor->recurring(0.25 => sub {...}); Create a new recurring timer, invoking the callback repeatedly after a given amount of time in seconds. =head2 start $reactor->start; Start watching for I/O and timer events, this will block until L is called or no events are being watched anymore. =head2 stop $reactor->stop; Stop watching for I/O and timer events. =head2 timer my $id = $reactor->timer(0.5 => sub {...}); Create a new timer, invoking the callback after a given amount of time in seconds. =head2 watch $reactor = $reactor->watch($handle, $readable, $writable); Change I/O events to watch handle for with true and false values. Note that this method requires an active I/O watcher. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Reactor/Poll.pm0000644000175000017500000001274512242772023023506 0ustar cstamascstamaspackage Mojo::Reactor::Poll; use Mojo::Base 'Mojo::Reactor'; use IO::Poll qw(POLLERR POLLHUP POLLIN POLLOUT); use List::Util 'min'; use Mojo::Util qw(md5_sum steady_time); use Time::HiRes 'usleep'; sub again { my $timer = shift->{timers}{shift()}; $timer->{time} = steady_time + $timer->{after}; } sub io { my ($self, $handle, $cb) = @_; $self->{io}{fileno $handle} = {cb => $cb}; return $self->watch($handle, 1, 1); } sub is_running { !!shift->{running} } sub one_tick { my $self = shift; # Remember state for later my $running = $self->{running}; $self->{running} = 1; # Wait for one event my $i; my $poll = $self->_poll; until ($i) { # Stop automatically if there is nothing to watch return $self->stop unless keys %{$self->{timers}} || keys %{$self->{io}}; # Calculate ideal timeout based on timers my $min = min map { $_->{time} } values %{$self->{timers}}; my $timeout = defined $min ? ($min - steady_time) : 0.5; $timeout = 0 if $timeout < 0; # I/O if (keys %{$self->{io}}) { $poll->poll($timeout); ++$i and $self->_sandbox('Read', $self->{io}{fileno $_}{cb}, 0) for $poll->handles(POLLIN | POLLHUP | POLLERR); ++$i and $self->_sandbox('Write', $self->{io}{fileno $_}{cb}, 1) for $poll->handles(POLLOUT); } # Wait for timeout if poll can't be used elsif ($timeout) { usleep $timeout * 1000000 } # Timers (time should not change in between timers) my $now = steady_time; for my $id (keys %{$self->{timers}}) { next unless my $t = $self->{timers}{$id}; next unless $t->{time} <= $now; # Recurring timer if (exists $t->{recurring}) { $t->{time} = $now + $t->{recurring} } # Normal timer else { $self->remove($id) } ++$i and $self->_sandbox("Timer $id", $t->{cb}) if $t->{cb}; } } # Restore state if necessary $self->{running} = $running if $self->{running}; } sub recurring { shift->_timer(1, @_) } sub remove { my ($self, $remove) = @_; return !!delete $self->{timers}{$remove} unless ref $remove; $self->_poll->remove($remove); return !!delete $self->{io}{fileno $remove}; } sub start { my $self = shift; $self->{running}++; $self->one_tick while $self->{running}; } sub stop { delete shift->{running} } sub timer { shift->_timer(0, @_) } sub watch { my ($self, $handle, $read, $write) = @_; my $poll = $self->_poll; $poll->remove($handle); if ($read && $write) { $poll->mask($handle, POLLIN | POLLOUT) } elsif ($read) { $poll->mask($handle, POLLIN) } elsif ($write) { $poll->mask($handle, POLLOUT) } return $self; } sub _poll { shift->{poll} ||= IO::Poll->new } sub _sandbox { my ($self, $event, $cb) = (shift, shift, shift); eval { $self->$cb(@_); 1 } or $self->emit(error => "$event failed: $@"); } sub _timer { my ($self, $recurring, $after, $cb) = @_; my $timers = $self->{timers} //= {}; my $id; do { $id = md5_sum('t' . steady_time . rand 999) } while $timers->{$id}; my $timer = $timers->{$id} = {cb => $cb, after => $after, time => steady_time + $after}; $timer->{recurring} = $after if $recurring; return $id; } 1; =encoding utf8 =head1 NAME Mojo::Reactor::Poll - Low level event reactor with poll support =head1 SYNOPSIS use Mojo::Reactor::Poll; # Watch if handle becomes readable or writable my $reactor = Mojo::Reactor::Poll->new; $reactor->io($handle => sub { my ($reactor, $writable) = @_; say $writable ? 'Handle is writable' : 'Handle is readable'; }); # Change to watching only if handle becomes writable $reactor->watch($handle, 0, 1); # Add a timer $reactor->timer(15 => sub { my $reactor = shift; $reactor->remove($handle); say 'Timeout!'; }); # Start reactor if necessary $reactor->start unless $reactor->is_running; =head1 DESCRIPTION L is a low level event reactor based on L. =head1 EVENTS L inherits all events from L. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 again $reactor->again($id); Restart active timer. =head2 io $reactor = $reactor->io($handle => sub {...}); Watch handle for I/O events, invoking the callback whenever handle becomes readable or writable. =head2 is_running my $bool = $reactor->is_running; Check if reactor is running. =head2 one_tick $reactor->one_tick; Run reactor until an event occurs or no events are being watched anymore. Note that this method can recurse back into the reactor, so you need to be careful. =head2 recurring my $id = $reactor->recurring(0.25 => sub {...}); Create a new recurring timer, invoking the callback repeatedly after a given amount of time in seconds. =head2 remove my $bool = $reactor->remove($handle); my $bool = $reactor->remove($id); Remove handle or timer. =head2 start $reactor->start; Start watching for I/O and timer events, this will block until L is called or no events are being watched anymore. =head2 stop $reactor->stop; Stop watching for I/O and timer events. =head2 timer my $id = $reactor->timer(0.5 => sub {...}); Create a new timer, invoking the callback after a given amount of time in seconds. =head2 watch $reactor = $reactor->watch($handle, $readable, $writable); Change I/O events to watch handle for with true and false values. Note that this method requires an active I/O watcher. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Reactor.pm0000644000175000017500000001261712242771671022606 0ustar cstamascstamaspackage Mojo::Reactor; use Mojo::Base 'Mojo::EventEmitter'; use Carp 'croak'; use IO::Poll qw(POLLERR POLLHUP POLLIN); use Mojo::Loader; sub again { croak 'Method "again" not implemented by subclass' } sub detect { my $try = $ENV{MOJO_REACTOR} || 'Mojo::Reactor::EV'; return Mojo::Loader->new->load($try) ? 'Mojo::Reactor::Poll' : $try; } sub io { croak 'Method "io" not implemented by subclass' } sub is_readable { my ($self, $handle) = @_; my $test = $self->{test} ||= IO::Poll->new; $test->mask($handle, POLLIN); $test->poll(0); my $result = $test->handles(POLLIN | POLLERR | POLLHUP); $test->remove($handle); return !!$result; } sub is_running { croak 'Method "is_running" not implemented by subclass' } sub one_tick { croak 'Method "one_tick" not implemented by subclass' } sub recurring { croak 'Method "recurring" not implemented by subclass' } sub remove { croak 'Method "remove" not implemented by subclass' } sub start { croak 'Method "start" not implemented by subclass' } sub stop { croak 'Method "stop" not implemented by subclass' } sub timer { croak 'Method "timer" not implemented by subclass' } sub watch { croak 'Method "watch" not implemented by subclass' } 1; =encoding utf8 =head1 NAME Mojo::Reactor - Low level event reactor base class =head1 SYNOPSIS package Mojo::Reactor::MyEventLoop; use Mojo::Base 'Mojo::Reactor'; $ENV{MOJO_REACTOR} ||= 'Mojo::Reactor::MyEventLoop'; sub again {...} sub io {...} sub is_running {...} sub one_tick {...} sub recurring {...} sub remove {...} sub start {...} sub stop {...} sub timer {...} sub watch {...} =head1 DESCRIPTION L is an abstract base class for low level event reactors. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 error $reactor->on(error => sub { my ($reactor, $err) = @_; ... }); Emitted for exceptions caught in callbacks, fatal if unhandled. Note that if this event is unhandled or fails it might kill your program, so you need to be careful. $reactor->on(error => sub { my ($reactor, $err) = @_; say "Something very bad happened: $err"; }); =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 again $reactor->again($id); Restart active timer. Meant to be overloaded in a subclass. =head2 detect my $class = Mojo::Reactor->detect; Detect and load the best reactor implementation available, will try the value of the MOJO_REACTOR environment variable, L or L. # Instantiate best reactor implementation available my $reactor = Mojo::Reactor->detect->new; =head2 io $reactor = $reactor->io($handle => sub {...}); Watch handle for I/O events, invoking the callback whenever handle becomes readable or writable. Meant to be overloaded in a subclass. # Callback will be invoked twice if handle becomes readable and writable $reactor->io($handle => sub { my ($reactor, $writable) = @_; say $writable ? 'Handle is writable' : 'Handle is readable'; }); =head2 is_readable my $bool = $reactor->is_readable($handle); Quick non-blocking check if a handle is readable, useful for identifying tainted sockets. =head2 is_running my $bool = $reactor->is_running; Check if reactor is running. Meant to be overloaded in a subclass. =head2 one_tick $reactor->one_tick; Run reactor until an event occurs. Note that this method can recurse back into the reactor, so you need to be careful. Meant to be overloaded in a subclass. # Don't block longer than 0.5 seconds my $id = $reactor->timer(0.5 => sub {}); $reactor->one_tick; $reactor->remove($id); =head2 recurring my $id = $reactor->recurring(0.25 => sub {...}); Create a new recurring timer, invoking the callback repeatedly after a given amount of time in seconds. Meant to be overloaded in a subclass. # Invoke as soon as possible $reactor->recurring(0 => sub { say 'Reactor tick.' }); =head2 remove my $bool = $reactor->remove($handle); my $bool = $reactor->remove($id); Remove handle or timer. Meant to be overloaded in a subclass. =head2 start $reactor->start; Start watching for I/O and timer events, this will block until L is called. Note that some reactors stop automatically if there are no events being watched anymore. Meant to be overloaded in a subclass. =head2 stop $reactor->stop; Stop watching for I/O and timer events. Meant to be overloaded in a subclass. =head2 timer my $id = $reactor->timer(0.5 => sub {...}); Create a new timer, invoking the callback after a given amount of time in seconds. Meant to be overloaded in a subclass. # Invoke as soon as possible $reactor->timer(0 => sub { say 'Next tick.' }); =head2 watch $reactor = $reactor->watch($handle, $readable, $writable); Change I/O events to watch handle for with true and false values. Meant to be overloaded in a subclass. Note that this method requires an active I/O watcher. # Watch only for readable events $reactor->watch($handle, 1, 0); # Watch only for writable events $reactor->watch($handle, 0, 1); # Watch for readable and writable events $reactor->watch($handle, 1, 1); # Pause watching for events $reactor->watch($handle, 0, 0); =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server/0000755000175000017500000000000012256126533022104 5ustar cstamascstamaslibmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server/CGI.pm0000644000175000017500000000534212242772022023043 0ustar cstamascstamaspackage Mojo::Server::CGI; use Mojo::Base 'Mojo::Server'; has 'nph'; sub run { my $self = shift; my $tx = $self->build_tx; my $req = $tx->req->parse(\%ENV); $tx->local_port($ENV{SERVER_PORT})->remote_address($ENV{REMOTE_ADDR}); # Request body (may block if we try to read too much) binmode STDIN; my $len = $req->headers->content_length; until ($req->is_finished) { my $chunk = ($len && $len < 131072) ? $len : 131072; last unless my $read = STDIN->read(my $buffer, $chunk, 0); $req->parse($buffer); last if ($len -= $read) <= 0; } # Handle request $self->emit(request => $tx); # Response start line STDOUT->autoflush(1); binmode STDOUT; my $res = $tx->res; return undef if $self->nph && !_write($res, 'get_start_line_chunk'); # Response headers $res->fix_headers; my $code = $res->code || 404; my $msg = $res->message || $res->default_message; $res->headers->status("$code $msg") unless $self->nph; return undef unless _write($res, 'get_header_chunk'); # Response body $tx->is_empty or _write($res, 'get_body_chunk') or return undef; # Finish transaction $tx->server_close; return $res->code; } sub _write { my ($res, $method) = @_; my $offset = 0; while (1) { # No chunk yet, try again sleep 1 and next unless defined(my $chunk = $res->$method($offset)); # End of part last unless my $len = length $chunk; # Make sure we can still write $offset += $len; return undef unless STDOUT->opened; print STDOUT $chunk; } return 1; } 1; =encoding utf8 =head1 NAME Mojo::Server::CGI - CGI server =head1 SYNOPSIS use Mojo::Server::CGI; my $cgi = Mojo::Server::CGI->new; $cgi->unsubscribe('request') $cgi->on(request => sub { my ($cgi, $tx) = @_; # Request my $method = $tx->req->method; my $path = $tx->req->url->path; # Response $tx->res->code(200); $tx->res->headers->content_type('text/plain'); $tx->res->body("$method request for $path!"); # Resume transaction $tx->resume; }); $cgi->run; =head1 DESCRIPTION L is a simple and portable implementation of RFC 3875. See L for more. =head1 EVENTS L inherits all events from L. =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 nph my $bool = $cgi->nph; $cgi = $cgi->nph($bool); Activate non-parsed header mode. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 run my $status = $cgi->run; Run CGI. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server/Daemon.pm0000644000175000017500000002701612254164221023645 0ustar cstamascstamaspackage Mojo::Server::Daemon; use Mojo::Base 'Mojo::Server'; use Carp 'croak'; use Mojo::IOLoop; use Mojo::URL; use POSIX; use Scalar::Util 'weaken'; use constant DEBUG => $ENV{MOJO_DAEMON_DEBUG} || 0; has acceptors => sub { [] }; has [qw(backlog group silent user)]; has inactivity_timeout => sub { $ENV{MOJO_INACTIVITY_TIMEOUT} // 15 }; has ioloop => sub { Mojo::IOLoop->singleton }; has listen => sub { [split /,/, $ENV{MOJO_LISTEN} || 'http://*:3000'] }; has max_clients => 1000; has max_requests => 25; sub DESTROY { my $self = shift; return unless my $loop = $self->ioloop; $self->_remove($_) for keys %{$self->{connections} || {}}; $loop->remove($_) for @{$self->acceptors}; } sub run { my $self = shift; local $SIG{INT} = local $SIG{TERM} = sub { $self->ioloop->stop }; $self->start->setuidgid->ioloop->start; } sub setuidgid { my $self = shift; # Group if (my $group = $self->group) { croak qq{Group "$group" does not exist} unless defined(my $gid = getgrnam $group); POSIX::setgid($gid) or croak qq{Can't switch to group "$group": $!}; } # User if (my $user = $self->user) { croak qq{User "$user" does not exist} unless defined(my $uid = getpwnam $user); POSIX::setuid($uid) or croak qq{Can't switch to user "$user": $!}; } return $self; } sub start { my $self = shift; # Resume accepting connections my $loop = $self->ioloop; if (my $servers = $self->{servers}) { push @{$self->acceptors}, $loop->acceptor(delete $servers->{$_}) for keys %$servers; } # Start listening else { $self->_listen($_) for @{$self->listen} } $loop->max_connections($self->max_clients); return $self; } sub stop { my $self = shift; # Suspend accepting connections but keep listen sockets open my $loop = $self->ioloop; while (my $id = shift @{$self->acceptors}) { my $server = $self->{servers}{$id} = $loop->acceptor($id); $loop->remove($id); $server->stop; } return $self; } sub _build_tx { my ($self, $id, $c) = @_; my $tx = $self->build_tx->connection($id); $tx->res->headers->server('Mojolicious (Perl)'); my $handle = $self->ioloop->stream($id)->handle; $tx->local_address($handle->sockhost)->local_port($handle->sockport); $tx->remote_address($handle->peerhost)->remote_port($handle->peerport); $tx->req->url->base->scheme('https') if $c->{tls}; # Handle upgrades and requests weaken $self; $tx->on( upgrade => sub { my ($tx, $ws) = @_; $ws->server_handshake; $self->{connections}{$id}{ws} = $ws; } ); $tx->on( request => sub { my $tx = shift; $self->emit(request => $self->{connections}{$id}{ws} || $tx); $tx->on(resume => sub { $self->_write($id) }); } ); # Kept alive if we have more than one request on the connection return ++$c->{requests} > 1 ? $tx->kept_alive(1) : $tx; } sub _close { my ($self, $id) = @_; # Finish gracefully if (my $tx = $self->{connections}{$id}{tx}) { $tx->server_close } delete $self->{connections}{$id}; } sub _finish { my ($self, $id, $tx) = @_; # Always remove connection for WebSockets return $self->_remove($id) if $tx->is_websocket; # Finish transaction $tx->server_close; # Upgrade connection to WebSocket my $c = $self->{connections}{$id}; if (my $ws = $c->{tx} = delete $c->{ws}) { # Successful upgrade if ($ws->res->code eq '101') { weaken $self; $ws->on(resume => sub { $self->_write($id) }); } # Failed upgrade else { delete $c->{tx}; $ws->server_close; } } # Close connection if necessary my $req = $tx->req; return $self->_remove($id) if $req->error || !$tx->keep_alive; # Build new transaction for leftovers return unless length(my $leftovers = $req->content->leftovers); $tx = $c->{tx} = $self->_build_tx($id, $c); $tx->server_read($leftovers); } sub _listen { my ($self, $listen) = @_; my $url = Mojo::URL->new($listen); my $query = $url->query; my $options = { address => $url->host, backlog => $self->backlog, port => $url->port, reuse => scalar $query->param('reuse'), }; $options->{"tls_$_"} = scalar $query->param($_) for qw(ca cert ciphers key); my $verify = $query->param('verify'); $options->{tls_verify} = hex $verify if defined $verify; delete $options->{address} if $options->{address} eq '*'; my $tls = $options->{tls} = $url->protocol eq 'https'; weaken $self; push @{$self->acceptors}, $self->ioloop->server( $options => sub { my ($loop, $stream, $id) = @_; my $c = $self->{connections}{$id} = {tls => $tls}; warn "-- Accept (@{[$stream->handle->peerhost]})\n" if DEBUG; $stream->timeout($self->inactivity_timeout); $stream->on(close => sub { $self->_close($id) }); $stream->on( error => sub { return unless $self; $self->app->log->error(pop); $self->_close($id); } ); $stream->on(read => sub { $self->_read($id => pop) }); $stream->on(timeout => sub { $self->app->log->debug('Inactivity timeout.') if $c->{tx} }); } ); return if $self->silent; $self->app->log->info(qq{Listening at "$url".}); $query->params([]); $url->host('127.0.0.1') if $url->host eq '*'; say "Server available at $url."; } sub _read { my ($self, $id, $chunk) = @_; # Make sure we have a transaction and parse chunk return unless my $c = $self->{connections}{$id}; my $tx = $c->{tx} ||= $self->_build_tx($id, $c); warn "-- Server <<< Client (@{[$tx->req->url->to_abs]})\n$chunk\n" if DEBUG; $tx->server_read($chunk); # Last keep-alive request or corrupted connection $tx->res->headers->connection('close') if (($c->{requests} || 0) >= $self->max_requests) || $tx->req->error; # Finish or start writing if ($tx->is_finished) { $self->_finish($id, $tx) } elsif ($tx->is_writing) { $self->_write($id) } } sub _remove { my ($self, $id) = @_; $self->ioloop->remove($id); $self->_close($id); } sub _write { my ($self, $id) = @_; # Not writing return unless my $c = $self->{connections}{$id}; return unless my $tx = $c->{tx}; return unless $tx->is_writing; # Get chunk and write return if $c->{writing}++; my $chunk = $tx->server_write; delete $c->{writing}; warn "-- Server >>> Client (@{[$tx->req->url->to_abs]})\n$chunk\n" if DEBUG; my $stream = $self->ioloop->stream($id)->write($chunk); # Finish or continue writing weaken $self; my $cb = sub { $self->_write($id) }; if ($tx->is_finished) { if ($tx->has_subscribers('finish')) { $cb = sub { $self->_finish($id, $tx) } } else { $self->_finish($id, $tx); return unless $c->{tx}; } } $stream->write('' => $cb); } 1; =encoding utf8 =head1 NAME Mojo::Server::Daemon - Non-blocking I/O HTTP and WebSocket server =head1 SYNOPSIS use Mojo::Server::Daemon; my $daemon = Mojo::Server::Daemon->new(listen => ['http://*:8080']); $daemon->unsubscribe('request'); $daemon->on(request => sub { my ($daemon, $tx) = @_; # Request my $method = $tx->req->method; my $path = $tx->req->url->path; # Response $tx->res->code(200); $tx->res->headers->content_type('text/plain'); $tx->res->body("$method request for $path!"); # Resume transaction $tx->resume; }); $daemon->run; =head1 DESCRIPTION L is a full featured, highly portable non-blocking I/O HTTP and WebSocket server, with IPv6, TLS, Comet (long polling), keep-alive, connection pooling, timeout, cookie, multipart and multiple event loop support. For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS support, the optional modules L (4.0+), L (0.16+) and L (1.75+) will be used automatically by L if they are installed. Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables. See L for more. =head1 EVENTS L inherits all events from L. =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 acceptors my $acceptors = $daemon->acceptors; $daemon = $daemon->acceptors([]); Active acceptors. =head2 backlog my $backlog = $daemon->backlog; $daemon = $daemon->backlog(128); Listen backlog size, defaults to C. =head2 group my $group = $daemon->group; $daemon = $daemon->group('users'); Group for server process. =head2 inactivity_timeout my $timeout = $daemon->inactivity_timeout; $daemon = $daemon->inactivity_timeout(5); Maximum amount of time in seconds a connection can be inactive before getting closed, defaults to the value of the MOJO_INACTIVITY_TIMEOUT environment variable or C<15>. Setting the value to C<0> will allow connections to be inactive indefinitely. =head2 ioloop my $loop = $daemon->ioloop; $daemon = $daemon->ioloop(Mojo::IOLoop->new); Event loop object to use for I/O operations, defaults to the global L singleton. =head2 listen my $listen = $daemon->listen; $daemon = $daemon->listen(['https://localhost:3000']); List of one or more locations to listen on, defaults to the value of the MOJO_LISTEN environment variable or C. # Allow multiple servers to use the same port (SO_REUSEPORT) $daemon->listen(['http://*:8080?reuse=1']); # Listen on IPv6 interface $daemon->listen(['http://[::1]:4000']); # Listen on two ports with HTTP and HTTPS at the same time $daemon->listen([qw(http://*:3000 https://*:4000)]); # Use a custom certificate and key $daemon->listen(['https://*:3000?cert=/x/server.crt&key=/y/server.key']); # Or even a custom certificate authority $daemon->listen( ['https://*:3000?cert=/x/server.crt&key=/y/server.key&ca=/z/ca.crt']); These parameters are currently available: =over 2 =item ca ca=/etc/tls/ca.crt Path to TLS certificate authority file. =item cert cert=/etc/tls/server.crt Path to the TLS cert file, defaults to a built-in test certificate. =item ciphers ciphers=AES128-GCM-SHA256:RC4:HIGH:!MD5:!aNULL:!EDH Cipher specification string. =item key key=/etc/tls/server.key Path to the TLS key file, defaults to a built-in test key. =item reuse reuse=1 Allow multiple servers to use the same port with the C socket option. =item verify verify=0x00 TLS verification mode, defaults to C<0x03>. =back =head2 max_clients my $max = $daemon->max_clients; $daemon = $daemon->max_clients(1000); Maximum number of parallel client connections, defaults to C<1000>. =head2 max_requests my $max = $daemon->max_requests; $daemon = $daemon->max_requests(100); Maximum number of keep-alive requests per connection, defaults to C<25>. =head2 silent my $bool = $daemon->silent; $daemon = $daemon->silent($bool); Disable console messages. =head2 user my $user = $daemon->user; $daemon = $daemon->user('web'); User for the server process. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 run $daemon->run; Run server. =head2 setuidgid $daemon = $daemon->setuidgid; Set user and group for process. =head2 start $daemon = $daemon->start; Start accepting connections. =head2 stop $daemon = $daemon->stop; Stop accepting connections. =head1 DEBUGGING You can set the MOJO_DAEMON_DEBUG environment variable to get some advanced diagnostics information printed to C. MOJO_DAEMON_DEBUG=1 =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server/Hypnotoad.pm0000644000175000017500000002451612246232147024415 0ustar cstamascstamaspackage Mojo::Server::Hypnotoad; use Mojo::Base -base; # "Bender: I was God once. # God: Yes, I saw. You were doing well, until everyone died." use Cwd 'abs_path'; use File::Basename 'dirname'; use File::Spec::Functions 'catfile'; use Mojo::Server::Prefork; use Mojo::Util 'steady_time'; use POSIX 'setsid'; use Scalar::Util 'weaken'; sub run { my ($self, $path) = @_; # No Windows support _exit('Hypnotoad not available for Windows.') if $^O eq 'MSWin32'; # Remember application for later $ENV{HYPNOTOAD_APP} ||= abs_path $path; # This is a production server $ENV{MOJO_MODE} ||= 'production'; # Remember executable for later $ENV{HYPNOTOAD_EXE} ||= $0; $0 = $ENV{HYPNOTOAD_APP}; # Clean start die "Can't exec: $!" if !$ENV{HYPNOTOAD_REV}++ && !exec $ENV{HYPNOTOAD_EXE}; # Preload application and configure server my $prefork = $self->{prefork} = Mojo::Server::Prefork->new; my $app = $prefork->load_app($ENV{HYPNOTOAD_APP}); $self->_config($app); weaken $self; $prefork->on(wait => sub { $self->_manage }); $prefork->on(reap => sub { $self->_reap(pop) }); $prefork->on(finish => sub { $self->{finished} = 1 }); # Testing _exit('Everything looks good!') if $ENV{HYPNOTOAD_TEST}; # Stop running server $self->_stop if $ENV{HYPNOTOAD_STOP}; # Initiate hot deployment $self->_hot_deploy unless $ENV{HYPNOTOAD_PID}; # Daemonize as early as possible (but not for restarts) if (!$ENV{HYPNOTOAD_FOREGROUND} && $ENV{HYPNOTOAD_REV} < 3) { # Fork and kill parent die "Can't fork: $!" unless defined(my $pid = fork); exit 0 if $pid; setsid or die "Can't start a new session: $!"; # Close filehandles open STDIN, '/dev/null'; open STDERR, '>&STDOUT'; } # Start accepting connections local $SIG{USR2} = sub { $self->{upgrade} ||= steady_time }; $prefork->run; } sub _config { my ($self, $app) = @_; # Hypnotoad settings my $c = $app->config('hypnotoad') || {}; $self->{upgrade_timeout} = $c->{upgrade_timeout} || 60; # Prefork settings $ENV{MOJO_REVERSE_PROXY} = $c->{proxy} if defined $c->{proxy}; my $prefork = $self->{prefork}->listen($c->{listen} || ['http://*:8080']); my $file = catfile dirname($ENV{HYPNOTOAD_APP}), 'hypnotoad.pid'; $prefork->pid_file($c->{pid_file} || $file); $prefork->max_clients($c->{clients}) if $c->{clients}; $prefork->max_requests($c->{keep_alive_requests}) if $c->{keep_alive_requests}; defined $c->{$_} and $prefork->$_($c->{$_}) for qw(accept_interval accepts backlog graceful_timeout group), qw(heartbeat_interval heartbeat_timeout inactivity_timeout lock_file), qw(lock_timeout multi_accept user workers); } sub _exit { say shift and exit 0 } sub _hot_deploy { my $self = shift; # Make sure server is running return unless my $pid = $self->{prefork}->check_pid; # Start hot deployment kill 'USR2', $pid; _exit("Starting hot deployment for Hypnotoad server $pid."); } sub _manage { my $self = shift; # Upgraded my $log = $self->{prefork}->app->log; if ($ENV{HYPNOTOAD_PID} && $ENV{HYPNOTOAD_PID} ne $$) { $log->info("Upgrade successful, stopping $ENV{HYPNOTOAD_PID}."); kill 'QUIT', $ENV{HYPNOTOAD_PID}; } $ENV{HYPNOTOAD_PID} = $$ unless ($ENV{HYPNOTOAD_PID} // '') eq $$; # Upgrade if ($self->{upgrade} && !$self->{finished}) { # Fresh start unless ($self->{new}) { $log->info('Starting zero downtime software upgrade.'); die "Can't fork: $!" unless defined(my $pid = $self->{new} = fork); exec($ENV{HYPNOTOAD_EXE}) or die("Can't exec: $!") unless $pid; } # Timeout kill 'KILL', $self->{new} if $self->{upgrade} + $self->{upgrade_timeout} <= steady_time; } } sub _reap { my ($self, $pid) = @_; # Clean up failed upgrade return unless ($self->{new} || '') eq $pid; $self->{prefork}->app->log->info('Zero downtime software upgrade failed.'); delete @$self{qw(new upgrade)}; } sub _stop { _exit('Hypnotoad server not running.') unless my $pid = shift->{prefork}->check_pid; kill 'QUIT', $pid; _exit("Stopping Hypnotoad server $pid gracefully."); } 1; =encoding utf8 =head1 NAME Mojo::Server::Hypnotoad - ALL GLORY TO THE HYPNOTOAD! =head1 SYNOPSIS use Mojo::Server::Hypnotoad; my $toad = Mojo::Server::Hypnotoad->new; $toad->run('/home/sri/myapp.pl'); =head1 DESCRIPTION L is a full featured, UNIX optimized, preforking non-blocking I/O HTTP and WebSocket server, built around the very well tested and reliable L, with IPv6, TLS, Comet (long polling), keep-alive, connection pooling, timeout, cookie, multipart, multiple event loop and hot deployment support that just works. Note that the server uses signals for process management, so you should avoid modifying signal handlers in your applications. To start applications with it you can use the L script, for L and L applications it will default to C mode. $ hypnotoad myapp.pl Server available at http://127.0.0.1:8080. You can run the same command again for automatic hot deployment. $ hypnotoad myapp.pl Starting hot deployment for Hypnotoad server 31841. This second invocation will load the application again, detect the process id file with it, and send a L signal to the already running server. For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS support, the optional modules L (4.0+), L (0.16+) and L (1.75+) will be used automatically by L if they are installed. Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables. See L for more. =head1 MANAGER SIGNALS The L manager process can be controlled at runtime with the following signals. =head2 INT, TERM Shutdown server immediately. =head2 QUIT Shutdown server gracefully. =head2 TTIN Increase worker pool by one. =head2 TTOU Decrease worker pool by one. =head2 USR2 Attempt zero downtime software upgrade (hot deployment) without losing any incoming connections. Manager (old) |- Worker [1] |- Worker [2] |- Worker [3] |- Worker [4] +- Manager (new) |- Worker [1] |- Worker [2] |- Worker [3] +- Worker [4] The new manager will automatically send a L signal to the old manager and take over serving requests after starting up successfully. =head1 WORKER SIGNALS L worker processes can be controlled at runtime with the following signals. =head2 INT, TERM Stop worker immediately. =head2 QUIT Stop worker gracefully. =head1 SETTINGS L can be configured with the following settings, see L for examples. =head2 accept_interval accept_interval => 0.5 Interval in seconds for trying to reacquire the accept mutex, defaults to C<0.025>. Note that changing this value can affect performance and idle CPU usage. =head2 accepts accepts => 100 Maximum number of connections a worker is allowed to accept before stopping gracefully, defaults to C<1000>. Setting the value to C<0> will allow workers to accept new connections indefinitely. Note that up to half of this value can be subtracted randomly to improve load balancing, and that worker processes will stop sending heartbeat messages once the limit has been reached. =head2 backlog backlog => 128 Listen backlog size, defaults to C. =head2 clients clients => 100 Maximum number of parallel client connections per worker process, defaults to C<1000>. Note that depending on how much your application may block, you might want to decrease this value and increase L instead for better performance. =head2 graceful_timeout graceful_timeout => 15 Maximum amount of time in seconds stopping a worker gracefully may take before being forced, defaults to C<20>. =head2 group group => 'staff' Group name for worker processes. =head2 heartbeat_interval heartbeat_interval => 3 Heartbeat interval in seconds, defaults to C<5>. =head2 heartbeat_timeout heartbeat_timeout => 2 Maximum amount of time in seconds before a worker without a heartbeat will be stopped gracefully, defaults to C<20>. =head2 inactivity_timeout inactivity_timeout => 10 Maximum amount of time in seconds a connection can be inactive before getting closed, defaults to C<15>. Setting the value to C<0> will allow connections to be inactive indefinitely. =head2 keep_alive_requests keep_alive_requests => 50 Number of keep-alive requests per connection, defaults to C<25>. =head2 listen listen => ['http://*:80'] List of one or more locations to listen on, defaults to C. See also L for more examples. =head2 lock_file lock_file => '/tmp/hypnotoad.lock' Full path of accept mutex lock file prefix, to which the process id will be appended, defaults to a random temporary path. =head2 lock_timeout lock_timeout => 0.5 Maximum amount of time in seconds a worker may block when waiting for the accept mutex, defaults to C<1>. Note that changing this value can affect performance and idle CPU usage. =head2 multi_accept multi_accept => 100 Number of connections to accept at once, defaults to C<50>. =head2 pid_file pid_file => '/var/run/hypnotoad.pid' Full path to process id file, defaults to C in the same directory as the application. Note that this value can only be changed after the server has been stopped. =head2 proxy proxy => 1 Activate reverse proxy support, which allows for the C and C headers to be picked up automatically, defaults to the value of the MOJO_REVERSE_PROXY environment variable. =head2 upgrade_timeout upgrade_timeout => 45 Maximum amount of time in seconds a zero downtime software upgrade may take before getting canceled, defaults to C<60>. =head2 user user => 'sri' Username for worker processes. =head2 workers workers => 10 Number of worker processes, defaults to C<4>. A good rule of thumb is two worker processes per CPU core. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 run $toad->run('script/myapp'); Run server for application. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server/Morbo.pm0000644000175000017500000001074212242772014023520 0ustar cstamascstamaspackage Mojo::Server::Morbo; use Mojo::Base -base; # "Linda: With Haley's Comet out of ice, Earth is experiencing the devastating # effects of sudden, intense global warming. # Morbo: Morbo is pleased but sticky." use Mojo::Home; use Mojo::Server::Daemon; use POSIX 'WNOHANG'; has watch => sub { [qw(lib templates)] }; sub check_file { my ($self, $file) = @_; # Check if modify time and/or size have changed my ($size, $mtime) = (stat $file)[7, 9]; return undef unless defined $mtime; my $cache = $self->{cache} ||= {}; my $stats = $cache->{$file} ||= [$^T, $size]; return undef if $mtime <= $stats->[0] && $size == $stats->[1]; return !!($cache->{$file} = [$mtime, $size]); } sub run { my ($self, $app) = @_; # Clean manager environment local $SIG{CHLD} = sub { $self->_reap }; local $SIG{INT} = local $SIG{TERM} = local $SIG{QUIT} = sub { $self->{finished} = 1; kill 'TERM', $self->{running} if $self->{running}; }; unshift @{$self->watch}, $app; $self->{modified} = 1; # Prepare and cache listen sockets for smooth restarting my $daemon = Mojo::Server::Daemon->new(silent => 1)->start->stop; $self->_manage while !$self->{finished} || $self->{running}; exit 0; } sub _manage { my $self = shift; # Discover files my @files; for my $watch (@{$self->watch}) { if (-d $watch) { my $home = Mojo::Home->new->parse($watch); push @files, $home->rel_file($_) for @{$home->list_files}; } elsif (-r $watch) { push @files, $watch } } # Check files for my $file (@files) { next unless $self->check_file($file); say qq{File "$file" changed, restarting.} if $ENV{MORBO_VERBOSE}; kill 'TERM', $self->{running} if $self->{running}; $self->{modified} = 1; } $self->_reap; delete $self->{running} if $self->{running} && !kill 0, $self->{running}; $self->_spawn if !$self->{running} && delete $self->{modified}; sleep 1; } sub _reap { my $self = shift; while ((my $pid = waitpid -1, WNOHANG) > 0) { delete $self->{running} } } sub _spawn { my $self = shift; # Fork my $manager = $$; $ENV{MORBO_REV}++; die "Can't fork: $!" unless defined(my $pid = fork); # Manager return $self->{running} = $pid if $pid; # Worker $SIG{CHLD} = 'DEFAULT'; $SIG{INT} = $SIG{TERM} = $SIG{QUIT} = sub { $self->{finished} = 1 }; my $daemon = Mojo::Server::Daemon->new; $daemon->load_app($self->watch->[0]); $daemon->silent(1) if $ENV{MORBO_REV} > 1; $daemon->start; my $loop = $daemon->ioloop; $loop->recurring( 1 => sub { shift->stop if !kill(0, $manager) || $self->{finished} }); $loop->start; exit 0; } 1; =encoding utf8 =head1 NAME Mojo::Server::Morbo - DOOOOOOOOOOOOOOOOOOM! =head1 SYNOPSIS use Mojo::Server::Morbo; my $morbo = Mojo::Server::Morbo->new; $morbo->run('/home/sri/myapp.pl'); =head1 DESCRIPTION L is a full featured, self-restart capable non-blocking I/O HTTP and WebSocket server, built around the very well tested and reliable L, with IPv6, TLS, Comet (long polling), keep-alive, connection pooling, timeout, cookie, multipart and multiple event loop support. Note that the server uses signals for process management, so you should avoid modifying signal handlers in your applications. To start applications with it you can use the L script. $ morbo myapp.pl Server available at http://127.0.0.1:3000. For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS support, the optional modules L (4.0+), L (0.16+) and L (1.75+) will be used automatically by L if they are installed. Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables. See L for more. =head1 ATTRIBUTES L implements the following attributes. =head2 watch my $watch = $morbo->watch; $morbo = $morbo->watch(['/home/sri/myapp']); Files and directories to watch for changes, defaults to the application script as well as the C and C directories in the current working directory. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 check_file my $bool = $morbo->check_file('/home/sri/lib/MyApp.pm'); Check if file has been modified since last check. =head2 run $morbo->run('script/myapp'); Run server for application. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server/Prefork.pm0000644000175000017500000003023012246232147024046 0ustar cstamascstamaspackage Mojo::Server::Prefork; use Mojo::Base 'Mojo::Server::Daemon'; use Fcntl ':flock'; use File::Spec::Functions qw(catfile tmpdir); use IO::Poll 'POLLIN'; use List::Util 'shuffle'; use Mojo::Util 'steady_time'; use POSIX 'WNOHANG'; use Scalar::Util 'weaken'; use Time::HiRes (); has accepts => 1000; has accept_interval => 0.025; has [qw(graceful_timeout heartbeat_timeout)] => 20; has heartbeat_interval => 5; has lock_file => sub { catfile tmpdir, 'prefork.lock' }; has lock_timeout => 1; has multi_accept => 50; has pid_file => sub { catfile tmpdir, 'prefork.pid' }; has workers => 4; sub DESTROY { my $self = shift; # Worker return unless $self->{finished}; # Manager if (my $file = $self->{lock_file}) { unlink $file if -w $file } if (my $file = $self->pid_file) { unlink $file if -w $file } } sub check_pid { my $file = shift->pid_file; return undef unless open my $handle, '<', $file; my $pid = <$handle>; chomp $pid; # Running return $pid if $pid && kill 0, $pid; # Not running unlink $file if -w $file; return undef; } sub run { my $self = shift; # No Windows support say 'Preforking not available for Windows.' and exit 0 if $^O eq 'MSWin32'; # Prepare lock file and event loop $self->{lock_file} = $self->lock_file . ".$$"; my $loop = $self->ioloop->max_accepts($self->accepts); $loop->$_($self->$_) for qw(accept_interval multi_accept); # Pipe for worker communication pipe($self->{reader}, $self->{writer}) or die "Can't create pipe: $!"; $self->{poll} = IO::Poll->new; $self->{poll}->mask($self->{reader}, POLLIN); # Clean manager environment local $SIG{INT} = local $SIG{TERM} = sub { $self->_term }; local $SIG{CHLD} = sub { while ((my $pid = waitpid -1, WNOHANG) > 0) { $self->app->log->debug("Worker $pid stopped.") if delete $self->emit(reap => $pid)->{pool}{$pid}; } }; local $SIG{QUIT} = sub { $self->_term(1) }; local $SIG{TTIN} = sub { $self->workers($self->workers + 1) }; local $SIG{TTOU} = sub { $self->workers($self->workers - 1) if $self->workers > 0; return unless $self->workers; $self->{pool}{shuffle keys %{$self->{pool}}}{graceful} ||= steady_time; }; # Preload application before starting workers $self->start->app->log->info("Manager $$ started."); $self->{running} = 1; $self->_manage while $self->{running}; } sub _heartbeat { my $self = shift; # Poll for heartbeats my $poll = $self->{poll}; $poll->poll(1); return unless $poll->handles(POLLIN); return unless $self->{reader}->sysread(my $chunk, 4194304); # Update heartbeats my $time = steady_time; $self->{pool}{$1} and $self->emit(heartbeat => $1)->{pool}{$1}{time} = $time while $chunk =~ /(\d+)\n/g; } sub _manage { my $self = shift; # Spawn more workers and check PID file if (!$self->{finished}) { $self->_spawn while keys %{$self->{pool}} < $self->workers; $self->_pid_file; } # Shutdown elsif (!keys %{$self->{pool}}) { return delete $self->{running} } # Manage workers $self->emit('wait')->_heartbeat; my $log = $self->app->log; for my $pid (keys %{$self->{pool}}) { next unless my $w = $self->{pool}{$pid}; # No heartbeat (graceful stop) my $interval = $self->heartbeat_interval; my $timeout = $self->heartbeat_timeout; my $time = steady_time; if (!$w->{graceful} && ($w->{time} + $interval + $timeout <= $time)) { $log->info("Worker $pid has no heartbeat, restarting."); $w->{graceful} = $time; } # Graceful stop with timeout $w->{graceful} ||= $time if $self->{graceful}; if ($w->{graceful}) { $log->debug("Trying to stop worker $pid gracefully."); kill 'QUIT', $pid; $w->{force} = 1 if $w->{graceful} + $self->graceful_timeout <= $time; } # Normal stop if (($self->{finished} && !$self->{graceful}) || $w->{force}) { $log->debug("Stopping worker $pid."); kill 'KILL', $pid; } } } sub _pid_file { my $self = shift; # Check if PID file already exists return if -e (my $file = $self->pid_file); # Create PID file $self->app->log->info(qq{Creating process id file "$file".}); die qq{Can't create process id file "$file": $!} unless open my $handle, '>', $file; chmod 0644, $handle; print $handle $$; } sub _spawn { my $self = shift; # Manager die "Can't fork: $!" unless defined(my $pid = fork); return $self->emit(spawn => $pid)->{pool}{$pid} = {time => steady_time} if $pid; # Prepare lock file my $file = $self->{lock_file}; die qq{Can't open lock file "$file": $!} unless open my $handle, '>', $file; # Change user/group my $loop = $self->setuidgid->ioloop; # Accept mutex $loop->lock( sub { # Blocking ("ualarm" can't be imported on Windows) my $lock; if ($_[1]) { eval { local $SIG{ALRM} = sub { die "alarm\n" }; my $old = Time::HiRes::ualarm $self->lock_timeout * 1000000; $lock = flock $handle, LOCK_EX; Time::HiRes::ualarm $old; 1; } or $lock = $@ eq "alarm\n" ? 0 : die $@; } # Non blocking else { $lock = flock $handle, LOCK_EX | LOCK_NB } return $lock; } ); $loop->unlock(sub { flock $handle, LOCK_UN }); # Heartbeat messages (stop sending during graceful stop) weaken $self; $loop->recurring( $self->heartbeat_interval => sub { return unless shift->max_connections; $self->{writer}->syswrite("$$\n") or exit 0; } ); # Clean worker environment $SIG{$_} = 'DEFAULT' for qw(INT TERM CHLD TTIN TTOU); $SIG{QUIT} = sub { $loop->max_connections(0) }; delete @$self{qw(poll reader)}; $self->app->log->debug("Worker $$ started."); $loop->start; exit 0; } sub _term { my ($self, $graceful) = @_; $self->emit(finish => $graceful)->{finished} = 1; $self->{graceful} = 1 if $graceful; } 1; =encoding utf8 =head1 NAME Mojo::Server::Prefork - Preforking non-blocking I/O HTTP and WebSocket server =head1 SYNOPSIS use Mojo::Server::Prefork; my $prefork = Mojo::Server::Prefork->new(listen => ['http://*:8080']); $prefork->unsubscribe('request'); $prefork->on(request => sub { my ($prefork, $tx) = @_; # Request my $method = $tx->req->method; my $path = $tx->req->url->path; # Response $tx->res->code(200); $tx->res->headers->content_type('text/plain'); $tx->res->body("$method request for $path!"); # Resume transaction $tx->resume; }); $prefork->run; =head1 DESCRIPTION L is a full featured, UNIX optimized, preforking non-blocking I/O HTTP and WebSocket server, built around the very well tested and reliable L, with IPv6, TLS, Comet (long polling), keep-alive, connection pooling, timeout, cookie, multipart and multiple event loop support. Note that the server uses signals for process management, so you should avoid modifying signal handlers in your applications. For better scalability (epoll, kqueue) and to provide IPv6 as well as TLS support, the optional modules L (4.0+), L (0.16+) and L (1.75+) will be used automatically by L if they are installed. Individual features can also be disabled with the MOJO_NO_IPV6 and MOJO_NO_TLS environment variables. See L for more. =head1 MANAGER SIGNALS The L manager process can be controlled at runtime with the following signals. =head2 INT, TERM Shutdown server immediately. =head2 QUIT Shutdown server gracefully. =head2 TTIN Increase worker pool by one. =head2 TTOU Decrease worker pool by one. =head1 WORKER SIGNALS L worker processes can be controlled at runtime with the following signals. =head2 INT, TERM Stop worker immediately. =head2 QUIT Stop worker gracefully. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 finish $prefork->on(finish => sub { my ($prefork, $graceful) = @_; ... }); Emitted when the server shuts down. $prefork->on(finish => sub { my ($prefork, $graceful) = @_; say $graceful ? 'Graceful server shutdown' : 'Server shutdown'; }); =head2 heartbeat $prefork->on(heartbeat => sub { my ($prefork, $pid) = @_; ... }); Emitted when a heartbeat message has been received from a worker. $prefork->on(heartbeat => sub { my ($prefork, $pid) = @_; say "Worker $pid has a heartbeat"; }); =head2 reap $prefork->on(reap => sub { my ($prefork, $pid) = @_; ... }); Emitted when a child process dies. $prefork->on(reap => sub { my ($prefork, $pid) = @_; say "Worker $pid stopped"; }); =head2 spawn $prefork->on(spawn => sub { my ($prefork, $pid) = @_; ... }); Emitted when a worker process is spawned. $prefork->on(spawn => sub { my ($prefork, $pid) = @_; say "Worker $pid started"; }); =head2 wait $prefork->on(wait => sub { my $prefork = shift; ... }); Emitted when the manager starts waiting for new heartbeat messages. $prefork->on(wait => sub { my $prefork = shift; my $workers = $prefork->workers; say "Waiting for heartbeat messages from $workers workers"; }); =head1 ATTRIBUTES L inherits all attributes from L and implements the following new ones. =head2 accept_interval my $interval = $prefork->accept_interval; $prefork = $prefork->accept_interval(0.5); Interval in seconds for trying to reacquire the accept mutex, defaults to C<0.025>. Note that changing this value can affect performance and idle CPU usage. =head2 accepts my $accepts = $prefork->accepts; $prefork = $prefork->accepts(100); Maximum number of connections a worker is allowed to accept before stopping gracefully, defaults to C<1000>. Setting the value to C<0> will allow workers to accept new connections indefinitely. Note that up to half of this value can be subtracted randomly to improve load balancing, and that worker processes will stop sending heartbeat messages once the limit has been reached. =head2 graceful_timeout my $timeout = $prefork->graceful_timeout; $prefork = $prefork->graceful_timeout(15); Maximum amount of time in seconds stopping a worker gracefully may take before being forced, defaults to C<20>. =head2 heartbeat_interval my $interval = $prefork->heartbeat_intrval; $prefork = $prefork->heartbeat_interval(3); Heartbeat interval in seconds, defaults to C<5>. =head2 heartbeat_timeout my $timeout = $prefork->heartbeat_timeout; $prefork = $prefork->heartbeat_timeout(2); Maximum amount of time in seconds before a worker without a heartbeat will be stopped gracefully, defaults to C<20>. =head2 lock_file my $file = $prefork->lock_file; $prefork = $prefork->lock_file('/tmp/prefork.lock'); Full path of accept mutex lock file prefix, to which the process id will be appended, defaults to a random temporary path. =head2 lock_timeout my $timeout = $prefork->lock_timeout; $prefork = $prefork->lock_timeout(0.5); Maximum amount of time in seconds a worker may block when waiting for the accept mutex, defaults to C<1>. Note that changing this value can affect performance and idle CPU usage. =head2 multi_accept my $multi = $prefork->multi_accept; $prefork = $prefork->multi_accept(100); Number of connections to accept at once, defaults to C<50>. =head2 pid_file my $file = $prefork->pid_file; $prefork = $prefork->pid_file('/tmp/prefork.pid'); Full path of process id file, defaults to a random temporary path. =head2 workers my $workers = $prefork->workers; $prefork = $prefork->workers(10); Number of worker processes, defaults to C<4>. A good rule of thumb is two worker processes per CPU core. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 check_pid my $pid = $prefork->check_pid; Get process id for running server from L or delete it if server is not running. say 'Server is not running' unless $prefork->check_pid; =head2 run $prefork->run; Run server. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server/PSGI.pm0000644000175000017500000000523412242772011023201 0ustar cstamascstamaspackage Mojo::Server::PSGI; use Mojo::Base 'Mojo::Server'; sub run { my ($self, $env) = @_; my $tx = $self->build_tx; my $req = $tx->req->parse($env); $tx->local_port($env->{SERVER_PORT})->remote_address($env->{REMOTE_ADDR}); # Request body (may block if we try to read too much) my $len = $env->{CONTENT_LENGTH}; until ($req->is_finished) { my $chunk = ($len && $len < 131072) ? $len : 131072; last unless my $read = $env->{'psgi.input'}->read(my $buffer, $chunk, 0); $req->parse($buffer); last if ($len -= $read) <= 0; } # Handle request $self->emit(request => $tx); # Response headers my $res = $tx->res->fix_headers; my $headers = $res->content->headers; my @headers; for my $name (@{$headers->names}) { push @headers, $name => $_ for map {@$_} $headers->header($name); } # PSGI response my $io = Mojo::Server::PSGI::_IO->new(tx => $tx, empty => $tx->is_empty); return [$res->code || 404, \@headers, $io]; } sub to_psgi_app { my $self = shift; # Preload application and wrap it $self->app; return sub { $self->run(@_) } } package Mojo::Server::PSGI::_IO; use Mojo::Base -base; # Finish transaction sub close { shift->{tx}->server_close } sub getline { my $self = shift; # Empty return undef if $self->{empty}; # No content yet, try again later my $chunk = $self->{tx}->res->get_body_chunk($self->{offset} //= 0); return '' unless defined $chunk; # End of content return undef unless length $chunk; $self->{offset} += length $chunk; return $chunk; } 1; =encoding utf8 =head1 NAME Mojo::Server::PSGI - PSGI server =head1 SYNOPSIS use Mojo::Server::PSGI; my $psgi = Mojo::Server::PSGI->new; $psgi->unsubscribe('request'); $psgi->on(request => sub { my ($psgi, $tx) = @_; # Request my $method = $tx->req->method; my $path = $tx->req->url->path; # Response $tx->res->code(200); $tx->res->headers->content_type('text/plain'); $tx->res->body("$method request for $path!"); # Resume transaction $tx->resume; }); my $app = $psgi->to_psgi_app; =head1 DESCRIPTION L allows L applications to run on all PSGI compatible servers. See L for more. =head1 EVENTS L inherits all events from L. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 run my $res = $psgi->run($env); Run L. =head2 to_psgi_app my $app = $psgi->to_psgi_app; Turn L application into L application. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Server.pm0000644000175000017500000000625112254163600022440 0ustar cstamascstamaspackage Mojo::Server; use Mojo::Base 'Mojo::EventEmitter'; use Carp 'croak'; use Mojo::Loader; use Mojo::Util 'md5_sum'; use Scalar::Util 'blessed'; has app => sub { shift->build_app('Mojo::HelloWorld') }; sub new { my $self = shift->SUPER::new(@_); $self->on(request => sub { shift->app->handler(shift) }); return $self; } sub build_app { my ($self, $app) = @_; local $ENV{MOJO_EXE}; return $app->new unless my $e = Mojo::Loader->new->load($app); die ref $e ? $e : qq{Couldn't find application class "$app".\n}; } sub build_tx { shift->app->build_tx } sub load_app { my ($self, $path) = @_; # Clean environment (reset FindBin defensively) { local $0 = $path; require FindBin; FindBin->again; local $ENV{MOJO_APP_LOADER} = 1; local $ENV{MOJO_EXE}; # Try to load application from script into sandbox my $app = eval sprintf <<'EOF', md5_sum($path . $$); package Mojo::Server::SandBox::%s; my $app = do $path; if (!$app && (my $e = $@ || $!)) { die $e } $app; EOF die qq{Couldn't load application from file "$path": $@} if !$app && $@; die qq{File "$path" did not return an application object.\n} unless blessed $app && $app->isa('Mojo'); $self->app($app); }; FindBin->again; return $self->app; } sub run { croak 'Method "run" not implemented by subclass' } 1; =encoding utf8 =head1 NAME Mojo::Server - HTTP server base class =head1 SYNOPSIS package Mojo::Server::MyServer; use Mojo::Base 'Mojo::Server'; sub run { my $self = shift; # Get a transaction my $tx = $self->build_tx; # Emit "request" event $self->emit(request => $tx); } =head1 DESCRIPTION L is an abstract HTTP server base class. =head1 EVENTS L inherits all events from L and can emit the following new ones. =head2 request $server->on(request => sub { my ($server, $tx) = @_; ... }); Emitted when a request is ready and needs to be handled. $server->unsubscribe('request'); $server->on(request => sub { my ($server, $tx) = @_; $tx->res->code(200); $tx->res->headers->content_type('text/plain'); $tx->res->body('Hello World!'); $tx->resume; }); =head1 ATTRIBUTES L implements the following attributes. =head2 app my $app = $server->app; $server = $server->app(MojoSubclass->new); Application this server handles, defaults to a L object. =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 new my $server = Mojo::Server->new; Construct a new L object and subscribe to L event with default request handling. =head2 build_app my $app = $server->build_app('Mojo::HelloWorld'); Build application from class. =head2 build_tx my $tx = $server->build_tx; Let application build a transaction. =head2 load_app my $app = $server->load_app('/home/sri/myapp.pl'); Load application from script. say Mojo::Server->new->load_app('./myapp.pl')->home; =head2 run $server->run; Run server. Meant to be overloaded in a subclass. =head1 SEE ALSO L, L, L. =cut libmojolicious-perl-4.63+dfsg.orig/lib/Mojo/Template.pm0000644000175000017500000004064212254131067022751 0ustar cstamascstamaspackage Mojo::Template; use Mojo::Base -base; use Carp 'croak'; use Mojo::ByteStream; use Mojo::Exception; use Mojo::Util qw(decode encode monkey_patch slurp); use constant DEBUG => $ENV{MOJO_TEMPLATE_DEBUG} || 0; has [qw(auto_escape compiled)]; has [qw(append code prepend template)] => ''; has capture_end => 'end'; has capture_start => 'begin'; has comment_mark => '#'; has encoding => 'UTF-8'; has escape => sub { \&Mojo::Util::xml_escape }; has [qw(escape_mark expression_mark trim_mark)] => '='; has [qw(line_start replace_mark)] => '%'; has name => 'template'; has namespace => 'Mojo::Template::SandBox'; has tag_start => '<%'; has tag_end => '%>'; has tree => sub { [] }; sub build { my $self = shift; my (@lines, $cpst, $multi); my $escape = $self->auto_escape; for my $line (@{$self->tree}) { push @lines, ''; for (my $j = 0; $j < @{$line}; $j += 2) { my $type = $line->[$j]; my $value = $line->[$j + 1] || ''; my $newline = chomp $value; # Capture end if ($type eq 'cpen') { # End block $lines[-1] .= 'return Mojo::ByteStream->new($_M) }'; # No following code my $next = $line->[$j + 3]; $lines[-1] .= ';' if !defined $next || $next =~ /^\s*$/; } # Text if ($type eq 'text') { # Quote and fix line ending $value = quotemeta $value; $value .= '\n' if $newline; $lines[-1] .= "\$_M .= \"" . $value . "\";" if length $value; } # Code or multiline expression if ($type eq 'code' || $multi) { $lines[-1] .= "$value" } # Expression if ($type eq 'expr' || $type eq 'escp') { # Start unless ($multi) { # Escaped if (($type eq 'escp' && !$escape) || ($type eq 'expr' && $escape)) { $lines[-1] .= "\$_M .= _escape"; $lines[-1] .= " scalar $value" if length $value; } # Raw else { $lines[-1] .= "\$_M .= scalar $value" } } # Multiline $multi = !(($line->[$j + 2] // '') eq 'text' && ($line->[$j + 3] // '') eq ''); # Append semicolon $lines[-1] .= ';' if !$multi && !$cpst; } # Capture start if ($cpst) { $lines[-1] .= $cpst; $cpst = undef; } $cpst = " sub { my \$_M = ''; " if $type eq 'cpst'; } } return $self->code($self->_wrap(\@lines))->tree([]); } sub compile { my $self = shift; # Compile with line directive return undef unless my $code = $self->code; my $name = $self->name; $name =~ s/"//g; my $compiled = eval qq{#line 1 "$name"\n$code}; $self->compiled($compiled) and return undef unless $@; # Use local stacktrace for compile exceptions return Mojo::Exception->new($@, [$self->template, $code])->trace->verbose(1); } sub interpret { my $self = shift; # Stacktrace local $SIG{__DIE__} = sub { CORE::die($_[0]) if ref $_[0]; Mojo::Exception->throw(shift, [$self->template, $self->code]); }; return undef unless my $compiled = $self->compiled; my $output; return $output if eval { $output = $compiled->(@_); 1 }; # Exception with template context return Mojo::Exception->new($@, [$self->template])->verbose(1); } sub parse { my ($self, $template) = @_; # Clean start my $tree = $self->template($template)->tree([])->tree; my $tag = $self->tag_start; my $replace = $self->replace_mark; my $expr = $self->expression_mark; my $escp = $self->escape_mark; my $cpen = $self->capture_end; my $cmnt = $self->comment_mark; my $cpst = $self->capture_start; my $trim = $self->trim_mark; my $end = $self->tag_end; my $start = $self->line_start; my $token_re = qr/ ( \Q$tag$replace\E # Replace | \Q$tag$expr$escp\E\s*\Q$cpen\E(?!\w) # Escaped expression (end) | \Q$tag$expr$escp\E # Escaped expression | \Q$tag$expr\E\s*\Q$cpen\E(?!\w) # Expression (end) | \Q$tag$expr\E # Expression | \Q$tag$cmnt\E # Comment | \Q$tag\E\s*\Q$cpen\E(?!\w) # Code (end) | \Q$tag\E # Code | (?_trim(\@token); } # Hint at end push @token, 'text', ''; } # Code elsif ($token =~ /^\Q$tag\E$/) { $state = 'code' } # Expression elsif ($token =~ /^\Q$tag$expr\E$/) { $state = 'expr' } # Expression that needs to be escaped elsif ($token =~ /^\Q$tag$expr$escp\E$/) { $state = 'escp' } # Comment elsif ($token =~ /^\Q$tag$cmnt\E$/) { $state = 'cmnt' } # Text else { # Replace $token = $tag if $token eq "$tag$replace"; # Convert whitespace text to line noise if ($trimming && $token =~ s/^(\s+)//) { push @token, 'code', $1; $trimming = 0; } # Comments are ignored next if $state eq 'cmnt'; push @token, @capture_token, $state, $token; @capture_token = (); } } push @$tree, \@token; } return $self; } sub render { my $self = shift; return $self->parse(shift)->build->compile || $self->interpret(@_); } sub render_file { my ($self, $path) = (shift, shift); $self->name($path) unless defined $self->{name}; my $template = slurp $path; my $encoding = $self->encoding; croak qq{Template "$path" has invalid encoding.} if $encoding && !defined($template = decode $encoding, $template); return $self->render($template, @_); } sub _trim { my ($self, $line) = @_; # Walk line backwards for (my $j = @$line - 4; $j >= 0; $j -= 2) { # Skip captures next if $line->[$j] eq 'cpst' || $line->[$j] eq 'cpen'; # Only trim text return unless $line->[$j] eq 'text'; # Convert whitespace text to line noise my $value = $line->[$j + 1]; if ($line->[$j + 1] =~ s/(\s+)$//) { $value = $line->[$j + 1]; splice @$line, $j, 0, 'code', $1; } # Text left return if length $value; } } sub _wrap { my ($self, $lines) = @_; # Escape function my $escape = $self->escape; monkey_patch $self->namespace, _escape => sub { no warnings 'uninitialized'; ref $_[0] eq 'Mojo::ByteStream' ? $_[0] : $escape->("$_[0]"); }; # Wrap lines my $first = $lines->[0] ||= ''; $lines->[0] = "package @{[$self->namespace]}; use Mojo::Base -strict;"; $lines->[0] .= "sub { my \$_M = ''; @{[$self->prepend]}; do { $first"; $lines->[-1] .= "@{[$self->append]}; \$_M } };"; my $code = join "\n", @$lines; warn "-- Code for @{[$self->name]}\n@{[encode 'UTF-8', $code]}\n\n" if DEBUG; return $code; } 1; =encoding utf8 =head1 NAME Mojo::Template - Perl-ish templates! =head1 SYNOPSIS use Mojo::Template; # Simple my $mt = Mojo::Template->new; my $output = $mt->render(<<'EOF'); % use Time::Piece; Simple % my $now = localtime; Time: <%= $now->hms %> EOF say $output; # More advanced my $output = $mt->render(<<'EOF', 23, 'foo bar'); % my ($num, $text) = @_; %= 5 * 5 More advanced test 123 foo <% my $i = $num + 2; %> % for (1 .. 23) { * some text <%= $i++ %> % } EOF say $output; =head1 DESCRIPTION L is a minimalistic and very Perl-ish template engine, designed specifically for all those small tasks that come up during big projects. Like preprocessing a configuration file, generating text from heredocs and stuff like that. See L for information on how to generate content with the L renderer. =head1 SYNTAX For all templates L, L, L and Perl 5.10 features are automatically enabled. <% Perl code %> <%= Perl expression, replaced with result %> <%== Perl expression, replaced with XML escaped result %> <%# Comment, useful for debugging %> <%% Replaced with "<%", useful for generating templates %> % Perl code line, treated as "<% line =%>" %= Perl expression line, treated as "<%= line %>" %== Perl expression line, treated as "<%== line %>" %# Comment line, useful for debugging %% Replaced with "%", useful for generating templates Escaping behavior can be reversed with the L attribute, this is the default in L C<.ep> templates for example. <%= Perl expression, replaced with XML escaped result %> <%== Perl expression, replaced with result %> L objects are always excluded from automatic escaping. % use Mojo::ByteStream 'b'; <%= b('
excluded!
') %> Newline characters can be escaped with a backslash. This is <%= 1 + 1 %> a\ single line And a backslash in front of a newline character can be escaped with another backslash. This will <%= 1 + 1 %> result\\ in multiple\\ lines Whitespace characters around tags can be trimmed with a special tag ending. <%= All whitespace characters around this expression will be trimmed =%> You can capture whole template blocks for reuse later with the C and C keywords. <% my $block = begin %> <% my $name = shift; =%> Hello <%= $name %>. <% end %> <%= $block->('Baerbel') %> <%= $block->('Wolfgang') %> Perl lines can also be indented freely. % my $block = begin % my $name = shift; Hello <%= $name %>. % end %= $block->('Baerbel') %= $block->('Wolfgang') L templates get compiled to a Perl subroutine, that means you can access arguments simply via C<@_>. % my ($foo, $bar) = @_; % my $x = shift; test 123 <%= $foo %> The compilation of templates to Perl code can make debugging a bit tricky, but L will return L objects that stringify to error messages with context. Bareword "xx" not allowed while "strict subs" in use at template line 4. 2: 3: 4: % my $i = 2; xx 5: %= $i * 2 6: =head1 ATTRIBUTES L implements the following attributes. =head2 auto_escape my $bool = $mt->auto_escape; $mt = $mt->auto_escape($bool); Activate automatic escaping. =head2 append my $code = $mt->append; $mt = $mt->append('warn "Processed template"'); Append Perl code to compiled template. Note that this code should not contain newline characters, or line numbers in error messages might end up being wrong. =head2 capture_end my $end = $mt->capture_end; $mt = $mt->capture_end('end'); Keyword indicating the end of a capture block, defaults to C. <% my $block = begin %> Some data! <% end %> =head2 capture_start my $start = $mt->capture_start; $mt = $mt->capture_start('begin'); Keyword indicating the start of a capture block, defaults to C. <% my $block = begin %> Some data! <% end %> =head2 code my $code = $mt->code; $mt = $mt->code($code); Perl code for template. =head2 comment_mark my $mark = $mt->comment_mark; $mt = $mt->comment_mark('#'); Character indicating the start of a comment, defaults to C<#>. <%# This is a comment %> =head2 compiled my $compiled = $mt->compiled; $mt = $mt->compiled($compiled); Compiled template code. =head2 encoding my $encoding = $mt->encoding; $mt = $mt->encoding('UTF-8'); Encoding used for template files. =head2 escape my $cb = $mt->escape; $mt = $mt->escape(sub { reverse $_[0] }); A callback used to escape the results of escaped expressions, defaults to L. =head2 escape_mark my $mark = $mt->escape_mark; $mt = $mt->escape_mark('='); Character indicating the start of an escaped expression, defaults to C<=>. <%== $foo %> =head2 expression_mark my $mark = $mt->expression_mark; $mt = $mt->expression_mark('='); Character indicating the start of an expression, defaults to C<=>. <%= $foo %> =head2 line_start my $start = $mt->line_start; $mt = $mt->line_start('%'); Character indicating the start of a code line, defaults to C<%>. % $foo = 23; =head2 name my $name = $mt->name; $mt = $mt->name('foo.mt'); Name of template currently being processed, defaults to C