├── .gitignore ├── LICENSE ├── META6.json ├── Makefile ├── README.md ├── RakuWAPI.pod ├── eg ├── 100-continue.wapi ├── README.md ├── block-ext.wapi ├── done-ext.wapi ├── dump-env.wapi ├── factorial-stream.wapi ├── factorial.wapi ├── hello.wapi ├── psgi-delayed.wapi ├── psgi-middleware.wapi ├── psgi-streaming.wapi ├── ready-check.wapi ├── simple.wapi ├── te-chunked-mw.wapi ├── te-chunked.wapi ├── time.wapi ├── upgrade-ext-h2c.wapi ├── upgrade-ext-ws.wapi └── upgrade-h2c.wapi └── fixup-markdown /.gitignore: -------------------------------------------------------------------------------- 1 | README.md.tmp 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The Artistic License 2.0 2 | 3 | Copyright (c) 2000-2015, Andrew Sterling Hanenkamp. 4 | 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | This license establishes the terms under which a given free software 11 | Package may be copied, modified, distributed, and/or redistributed. 12 | The intent is that the Copyright Holder maintains some artistic 13 | control over the development of that Package while still keeping the 14 | Package available as open source and free software. 15 | 16 | You are always permitted to make arrangements wholly outside of this 17 | license directly with the Copyright Holder of a given Package. If the 18 | terms of this license do not permit the full use that you propose to 19 | make of the Package, you should contact the Copyright Holder and seek 20 | a different licensing arrangement. 21 | 22 | Definitions 23 | 24 | "Copyright Holder" means the individual(s) or organization(s) 25 | named in the copyright notice for the entire Package. 26 | 27 | "Contributor" means any party that has contributed code or other 28 | material to the Package, in accordance with the Copyright Holder's 29 | procedures. 30 | 31 | "You" and "your" means any person who would like to copy, 32 | distribute, or modify the Package. 33 | 34 | "Package" means the collection of files distributed by the 35 | Copyright Holder, and derivatives of that collection and/or of 36 | those files. A given Package may consist of either the Standard 37 | Version, or a Modified Version. 38 | 39 | "Distribute" means providing a copy of the Package or making it 40 | accessible to anyone else, or in the case of a company or 41 | organization, to others outside of your company or organization. 42 | 43 | "Distributor Fee" means any fee that you charge for Distributing 44 | this Package or providing support for this Package to another 45 | party. It does not mean licensing fees. 46 | 47 | "Standard Version" refers to the Package if it has not been 48 | modified, or has been modified only in ways explicitly requested 49 | by the Copyright Holder. 50 | 51 | "Modified Version" means the Package, if it has been changed, and 52 | such changes were not explicitly requested by the Copyright 53 | Holder. 54 | 55 | "Original License" means this Artistic License as Distributed with 56 | the Standard Version of the Package, in its current version or as 57 | it may be modified by Andrew Sterling Hanenkamp in the future. 58 | 59 | "Source" form means the source code, documentation source, and 60 | configuration files for the Package. 61 | 62 | "Compiled" form means the compiled bytecode, object code, binary, 63 | or any other form resulting from mechanical transformation or 64 | translation of the Source form. 65 | 66 | 67 | Permission for Use and Modification Without Distribution 68 | 69 | (1) You are permitted to use the Standard Version and create and use 70 | Modified Versions for any purpose without restriction, provided that 71 | you do not Distribute the Modified Version. 72 | 73 | 74 | Permissions for Redistribution of the Standard Version 75 | 76 | (2) You may Distribute verbatim copies of the Source form of the 77 | Standard Version of this Package in any medium without restriction, 78 | either gratis or for a Distributor Fee, provided that you duplicate 79 | all of the original copyright notices and associated disclaimers. At 80 | your discretion, such verbatim copies may or may not include a 81 | Compiled form of the Package. 82 | 83 | (3) You may apply any bug fixes, portability changes, and other 84 | modifications made available from the Copyright Holder. The resulting 85 | Package will still be considered the Standard Version, and as such 86 | will be subject to the Original License. 87 | 88 | 89 | Distribution of Modified Versions of the Package as Source 90 | 91 | (4) You may Distribute your Modified Version as Source (either gratis 92 | or for a Distributor Fee, and with or without a Compiled form of the 93 | Modified Version) provided that you clearly document how it differs 94 | from the Standard Version, including, but not limited to, documenting 95 | any non-standard features, executables, or modules, and provided that 96 | you do at least ONE of the following: 97 | 98 | (a) make the Modified Version available to the Copyright Holder 99 | of the Standard Version, under the Original License, so that the 100 | Copyright Holder may include your modifications in the Standard 101 | Version. 102 | 103 | (b) ensure that installation of your Modified Version does not 104 | prevent the user installing or running the Standard Version. In 105 | addition, the Modified Version must bear a name that is different 106 | from the name of the Standard Version. 107 | 108 | (c) allow anyone who receives a copy of the Modified Version to 109 | make the Source form of the Modified Version available to others 110 | under 111 | 112 | (i) the Original License or 113 | 114 | (ii) a license that permits the licensee to freely copy, 115 | modify and redistribute the Modified Version using the same 116 | licensing terms that apply to the copy that the licensee 117 | received, and requires that the Source form of the Modified 118 | Version, and of any works derived from it, be made freely 119 | available in that license fees are prohibited but Distributor 120 | Fees are allowed. 121 | 122 | 123 | Distribution of Compiled Forms of the Standard Version 124 | or Modified Versions without the Source 125 | 126 | (5) You may Distribute Compiled forms of the Standard Version without 127 | the Source, provided that you include complete instructions on how to 128 | get the Source of the Standard Version. Such instructions must be 129 | valid at the time of your distribution. If these instructions, at any 130 | time while you are carrying out such distribution, become invalid, you 131 | must provide new instructions on demand or cease further distribution. 132 | If you provide valid instructions or cease distribution within thirty 133 | days after you become aware that the instructions are invalid, then 134 | you do not forfeit any of your rights under this license. 135 | 136 | (6) You may Distribute a Modified Version in Compiled form without 137 | the Source, provided that you comply with Section 4 with respect to 138 | the Source of the Modified Version. 139 | 140 | 141 | Aggregating or Linking the Package 142 | 143 | (7) You may aggregate the Package (either the Standard Version or 144 | Modified Version) with other packages and Distribute the resulting 145 | aggregation provided that you do not charge a licensing fee for the 146 | Package. Distributor Fees are permitted, and licensing fees for other 147 | components in the aggregation are permitted. The terms of this license 148 | apply to the use and Distribution of the Standard or Modified Versions 149 | as included in the aggregation. 150 | 151 | (8) You are permitted to link Modified and Standard Versions with 152 | other works, to embed the Package in a larger work of your own, or to 153 | build stand-alone binary or bytecode versions of applications that 154 | include the Package, and Distribute the result without restriction, 155 | provided the result does not expose a direct interface to the Package. 156 | 157 | 158 | Items That are Not Considered Part of a Modified Version 159 | 160 | (9) Works (including, but not limited to, modules and scripts) that 161 | merely extend or make use of the Package, do not, by themselves, cause 162 | the Package to be a Modified Version. In addition, such works are not 163 | considered parts of the Package itself, and are not subject to the 164 | terms of this license. 165 | 166 | 167 | General Provisions 168 | 169 | (10) Any use, modification, and distribution of the Standard or 170 | Modified Versions is governed by this Artistic License. By using, 171 | modifying or distributing the Package, you accept this license. Do not 172 | use, modify, or distribute the Package, if you do not accept this 173 | license. 174 | 175 | (11) If your Modified Version has been derived from a Modified 176 | Version made by someone other than you, you are nevertheless required 177 | to ensure that your Modified Version complies with the requirements of 178 | this license. 179 | 180 | (12) This license does not grant you the right to use any trademark, 181 | service mark, tradename, or logo of the Copyright Holder. 182 | 183 | (13) This license includes the non-exclusive, worldwide, 184 | free-of-charge patent license to make, have made, use, offer to sell, 185 | sell, import and otherwise transfer the Package with respect to any 186 | patent claims licensable by the Copyright Holder that are necessarily 187 | infringed by the Package. If you institute patent litigation 188 | (including a cross-claim or counterclaim) against any party alleging 189 | that the Package constitutes direct or contributory patent 190 | infringement, then this Artistic License to you shall terminate on the 191 | date that such litigation is filed. 192 | 193 | (14) Disclaimer of Warranty: 194 | THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS 195 | IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED 196 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR 197 | NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL 198 | LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL 199 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL 200 | DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF 201 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 202 | -------------------------------------------------------------------------------- /META6.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "P6W", 3 | "license" : "Artistic-2.0", 4 | "version" : "0.7.Draft", 5 | "description" : "Web API for Perl 6", 6 | "authors" : [ 7 | "Sterling Hanenkamp " 8 | ], 9 | "perl" : "6.c", 10 | "provides" : { 11 | "P6W": "RakuWAPI.pod" 12 | }, 13 | "depends" : [ ], 14 | "source-url" : "git://github.com/zostay/RakuWAPI.git" 15 | } 16 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | README.md: fixup-markdown RakuWAPI.pod 2 | perl6 --doc=Markdown RakuWAPI.pod | perl6 fixup-markdown > README.md 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NAME 2 | ==== 3 | 4 | Web API for Raku (RakuWAPI) 5 | 6 | STATUS 7 | ====== 8 | 9 | This is a Proposed Draft. 10 | 11 | Version 0.9.Draft 12 | 13 | 0 INTRODUCTION 14 | ============== 15 | 16 | This document standardizes an API for web application and server framework developers in Raku. It provides a standard protocol by which web applications and application servers may communicate with each other. 17 | 18 | This standard has the following goals: 19 | 20 | * Standardize the interface between server and application so that web developers may focus on application development rather than the nuances of supporting different server platforms. 21 | 22 | * Keep the interface simple so that a web application or middleware requires no additional tools or libraries other than what exists in a standard Raku environment, and no module installations are required. 23 | 24 | * Keep the interface simple so that servers and middleware are simple to implement. 25 | 26 | * Allow the interface to be flexible enough to accommodate a variety of common use-cases and simple optimzations as well as supporting unanticipated use-cases and future extensions. 27 | 28 | Aside from that is the underlying assumption that this is a simple interface and ought to at least somewhat resemble work in the standards it is derived from, including [Rack](http://www.rubydoc.info/github/rack/rack/master/file/SPEC), [WSGI](https://www.python.org/dev/peps/pep-0333/), [PSGI](https://metacpan.com/pod/PSGI), [CGI](http://www.w3.org/CGI/), and others. 29 | 30 | 1 TERMINOLOGY 31 | ============= 32 | 33 | 1.0 Glossary 34 | ------------ 35 | 36 | A RakuWAPI application is a Raku routine that expects to receive an environment from an *application server* and returns a response each time it is called by the server. 37 | 38 | A Web Server is an application that processes requests and responses according to a web-related protocol, such as HTTP or WebSockets or similar protocol. 39 | 40 | The origin is the external entity that makes a given request and/or expects a response from the application server. This can be thought of generically as a web browser, bot, or other user agent. 41 | 42 | An application server is a program that is able to provide an environment to a *RakuWAPI application* and process the value returned from such an application. 43 | 44 | The *application server* might be associated with a *web server*, might itself be a *web server*, might process a protocol used to communicate with a *web server* (such as CGI or FastCGI), or may be something else entirely not related to a *web server* (such as a tool for testing *RakuWAPI applications*). 45 | 46 | Middleware is a *RakuWAPI application* that wraps another *RakuWAPI application* for the purpose of performing some auxiliary task such as preprocessing request environments, logging, postprocessing responses, etc. 47 | 48 | A framework developer is a developer who writes an *application server*. 49 | 50 | An application developer is a developer who writes a *RakuWAPI application*. 51 | 52 | A sane Supply is a Supply object that follows the emit*-done/quit protocol, i.e., it will emit 0 or more objects followed by a call to the done or quit handler. See [Supply](http://doc.perl6.org/type/Supply) for details. 53 | 54 | 1.1 Type Constraints 55 | -------------------- 56 | 57 | The following type constraints are defined for use with this document. 58 | 59 | ```perl6 60 | subset NonEmptyStr of Str where { !.defined || .chars > 0 }; 61 | subset PathStr of Str where { !.defined || $_ ~~ any('', m{ ^ "/" }) }; 62 | subset PositiveInt of Int where { !.defined || $_ > 0 }; 63 | subset Supplierish of Any where { !.defined || ?.can('emit').grep(*.arity == 2) }; 64 | ``` 65 | 66 | Any place a type is used in this document, the implementation is free to use any subtype (either subset or sub-class) of that type in place of the named type so long as the type constraint is guaranteed to hold for the subtype. For example, if an `Int` is required, it would be permissible to use an `IntStr` instead. 67 | 68 | 2 SPECIFICATION 69 | =============== 70 | 71 | This specification is divided into three layers: 72 | 73 | * Layer 0: Server 74 | 75 | * Layer 1: Middleware 76 | 77 | * Layer 2: Application 78 | 79 | Each layer has a specific role related to the other layers. The server layer is responsible for managing the application lifecycle and performing communication with the origin. The application layer is responsible for receiving metadata and content from the server and delivering metadata and content back to the server. The middleware layer is responsible for enhancing the application or server by providing additional services and utilities. 80 | 81 | This specification goes through each layer in order. In the process, each section only specifies the requirements and recommendations for the layer that section describes. When other layers a mentioned outside of its section, the specification is deliberately vague to keep all specifics in the appropriate section. 82 | 83 | To aid in reading this specification, the numbering subsections of 2.0, 2.1, and 2.2 are matched so that you can navigate between them to compare the requirements of each layer. For example, 2.0.1 describes the environment the server provides, 2.1.1 describes how the application interacts with that environment, and 2.1.1 describes how middleware may manipulate that environment. 84 | 85 | 2.0 Layer 0: Server 86 | ------------------- 87 | 88 | A RakuWAPI application server is a program capable of running RakuWAPI applications as defined by this specification. 89 | 90 | A RakuWAPI application server implements some kind of web service. For example, this may mean implementing an HTTP or WebSocket service or a related protocol such as CGI, FastCGI, SCGI, etc. An application server also manages the application lifecycle and executes the application, providing it with a complete environment, and processing the response from the application to determine how to respond to the origin. 91 | 92 | One important aspect of this specification that is not defined is the meaning of a server error. At times it is suggested that certain states be treated as a server error, but what that actually means to a given implementation is deliberatly undefined. That is a complex topic which varies by implementation and by the state the server is in when such a state is discovered. The server SHOULD log such events and SHOULD use the appropriate means of communication provided to notify the application that a server error has occurred while responding. 93 | 94 | ### 2.0.0 Application Definition 95 | 96 | A RakuWAPI application is defined as a class or object, which must be implemented according to a particular interface. The application server MUST provide a means by which an application is loaded. The application server SHOULD be able to load them by executing a RakuWAPI script file. 97 | 98 | For example, here is a simple application: 99 | 100 | ```perl6 101 | use v6; 102 | sub app(%env) { 103 | start { 104 | 200, [ Content-Type => 'text/plain' ], [ 'Hello World!' ] 105 | } 106 | } 107 | ``` 108 | 109 | For full details on how an application is defined, see Section 2.2.0. For details on how a server interacts with the application, see Section 2.0.4. 110 | 111 | ### 2.0.1 The Environment 112 | 113 | The environment is delivered to the application via hashes, they MUST be [Associative](http://doc.perl6.org/type/Associative). The application server makes the environment available to the application at runtime. The environment is used to: 114 | 115 | * Communicate server capabilities to the application, 116 | 117 | * Allow the application to communicate with the server, and 118 | 119 | * Allow the application to respond to calls to the application. 120 | 121 | Each variable or key in the environment is described as belonging to one of two roles: 122 | 123 | * A configuration environment variable describes global capabilities and configuration information to application. 124 | 125 | * A runtime environment variable describes per-call information related to the particular request. 126 | 127 | Calls to the runtime routine MUST be provided with all required environment variables belonging to either of these roles in the passed environment hash. However, calls to the configuration routine (see 2.0.4) MUST include the configuration envrionment and SHOULD NOT include runtime environment in the passed environment hash. 128 | 129 | The server MAY provide variables in the environment in either role in addition to the ones defined here, but they MUST contain a period and SHOULD be given a unique prefix to avoid name clashes. 130 | 131 | The following prefixes are reserved and SHOULD NOT be used unless defined by this specification and only according to the definition given here. 132 | 133 | * `wapi.` is for RakuWAPI core standard environment. 134 | 135 | * `wapix.` is for RakuWAPI standard extensions to the environment. 136 | 137 | In the tables below, a type constraint is given for each variable. The application server MUST provide each key as the named type. All variables given in the tables with 2.0.1.0 and 2.0.1.1 MUST be provided. 138 | 139 | #### 2.0.1.0 Configuration Environment 140 | 141 | The configuration environment MUST be made available to the application during every call made to the application, both to the configuration routine and the runtime routine. 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 |
Variable Constraint Description
wapi.version Version:D This is the version of this specification, v0.9.Draft.
wapi.errors Supplierish:D The error stream for logging.
wapi.multithread Bool:D True if the app may be simultaneously invoked in another thread in the same process.
wapi.multiprocess Bool:D True if the app may be simultaneously invoked in another process.
wapi.run-once Bool:D True if the server expects the app to be invoked only once during the life of the process. This is not a guarantee.
wapi.protocol.support Set:D This is a Set of strings naming the protocols supported by the application server.
wapi.protocol.enabled SetHash:D This is the set of enabled protocols. The application may modify this set with those found in wapi.protocol.support to enable/disable protocols the server is permitted to use.
151 | 152 | #### 2.0.1.1 Runtime Environment 153 | 154 | Many of the runtime environment variables are derived from the old Common Gateway Interface (CGI). This environment MUST be given when the application is being called, i.e., whenever the runtime routine is called. 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 |
Variable Constraint Description
REQUEST_METHOD NonEmptyStr:D The HTTP request method, such as "GET" or "POST".
SCRIPT_NAME PathStr:D This is the initial portion of the URI path that refers to the application.
PATH_INFO PathStr:D This is the remainder of the request URI path within the application. This value SHOULD be URI decoded by the application server according to RFC 3875
REQUEST_URI Str:D This is the exact URI sent by the client in the request line of the HTTP request. The application server SHOULD NOT perform any decoding on it.
QUERY_STRING Str:D This is the portion of the requested URL following the ?, if any.
SERVER_NAME NonEmptyStr:D This is the name of the web server.
SERVER_PORT PositiveInt:D This is the port number of the web server.
SERVER_PROTOCOL NonEmptyStr:D This is the server protocol sent by the client, e.g. "HTTP/1.0" or "HTTP/1.1".
CONTENT_LENGTH Int:_ This corresponds to the Content-Length header sent by the client. If no such header was sent the application server MUST set this key to the Int type value.
CONTENT_TYPE Str:_ This corresponds to the Content-Type header sent by the client. If no such header was sent the application server MUST set this key to the Str type value.
HTTP_* Str:_ The remaining request headers are placed here. The names are prefixed with HTTP_, in ALL CAPS with the hyphens ("-") turned to underscores ("_"). Multiple incoming headers with the same name MUST have their values joined with a comma (", ") as described in RFC 2616. The HTTP_CONTENT_LENGTH and HTTP_CONTENT_TYPE headers MUST NOT be set.
Other CGI Keys Str:_ The server MUST attempt to provide as many other CGI variables as possible, but no others are required or formally specified.
wapi.url-scheme Str:D Either "http" or "https".
wapi.input Supply:D The input stream for reading the body of the request, if any.
wapi.ready Promise:D This is a vowed Promise that MUST be kept by the server as soon as the server has tapped the application's output Supply and is ready to receive emitted messages. The value of the kept Promise is irrelevent. The server SHOULD NOT break this Promise.
wapi.body.encoding Str:D Name of the encoding the server will use for any strings it is sent.
wapi.protocol Str:D This is a string naming the response protocols the server is expecting from the application for call.
164 | 165 | In the environment, either `SCRIPT_NAME` or `PATH_INFO` must be set to a non-empty string. When `REQUEST_URI` is "/", the `PATH_INFO` SHOULD be "/" and `SCRIPT_NAME` SHOULD be the empty string. `SCRIPT_NAME` MUST NOT be set to "/". 166 | 167 | ### 2.0.2 The Input Stream 168 | 169 | The input stream is set in the `wapi.input` key of the runtime environment. This represents the request payload sent from the origin. Unless otherwise indicated as part of the protocol definition, the server MUST provide a *sane* [Supply](http://doc.perl6.org/type/Supply) that emits [Blob](http://doc.perl6.org/type/Blob) objects containing the content of the request payload. It MAY emit nothing and just signal `done` if the request payload is empty. 170 | 171 | ### 2.0.3 The Error Stream 172 | 173 | The error stream MUST be given in the configuration environment via `wapi.errors`. This MUST be a [Supplierish](http://doc.perl6.org/type/Supplierish) (see Section 1.1) object the server provides for emitting errors. This is a defined object that has an `emit` method that has the same signature as `Supplier.emit`. 174 | 175 | The application MAY call `emit` on this object zero or more times, passing any object that may be stringified. The server SHOULD write these log entries to a suitable log file or to `$*ERR` or wherever appropriate. If written to a typical file handle, it should automatically append a newline to each emitted message. 176 | 177 | ### 2.0.4 Application Lifecycle 178 | 179 | After the application has been defined, it will be called each time the application server needs to respond to the origin. What that means will vary depending on which protocol is needed to appropriately respond to the origin. 180 | 181 | These requirements, however, are in held in common regardless of protocol, the application server requirements are as follows: 182 | 183 | * The application server MUST check the type of the return value of the application routine. If the application return value is [Callable](http://doc.perl6.org/type/Callable), the application has returned a configuration routine. Otherwise, the application has returned a runtime routine. 184 | 185 | * If the application returned a configuration routine, as detected by the previous requirement, the application server MUST call this routine and pass the configuration environment in a hash as the first argument to the routine. The return value of this routine is the runtime routine for the application. 186 | 187 | * Prior to each call to runtime routine, the application server MUST set the `wapi.protocol` variable to the name of the protocol the server will use to communicate with the application. 188 | 189 | * The server MUST receive the return value of runtime routine and process it according to the application protocol in use for this call, the protocol matching the one set in the previous requirement. 190 | 191 | * The server MUST pass a [Hash](http://doc.perl6.org/type/Hash) containing all variables of both the configuration environment and runtime environments as the first argument to the runtime routine. 192 | 193 | The server MUST NOT call the application with `wapi.protocol` set to a protocol that has been previously disabled by the application via the `wapi.protocol.enabled` setting. 194 | 195 | For details on how each protocol handles the application call, see section 4. 196 | 197 | 2.1 Layer 1: Middleware 198 | ----------------------- 199 | 200 | RakuWAPI middleware is simply an application that wraps another application. Middleware is used to perform any kind of pre-processing, post-processing, or side-effects that might be added onto an application. Possible uses include logging, encoding, validation, security, debugging, routing, interface adaptation, and header manipulation. 201 | 202 | For example, in the following snippet, `mw` is a middleware application that adds a custom header: 203 | 204 | ```perl6 205 | sub app(%env) { start { 200, [ Content-Type => 'text/plain' ], [ 'Hello World' ] } } 206 | sub mw(&wrappee is copy, %config) returns Callable { 207 | &wrappee = wrappee(%config) if &wrappee.returns ~~ Callable; 208 | sub (%env) { 209 | wrappee(%env).then( 210 | -> $p { 211 | my @r = $p.result; 212 | @r[1].push: 'WAPI-Used' => 'True'; 213 | @r 214 | } 215 | ); 216 | } 217 | } 218 | my &mw-app = &mw.assuming(&app); 219 | ``` 220 | 221 | ### 2.1.0 Middleware Definition 222 | 223 | The way in which middleware is defined and applied is left up to the middleware author. The example in the previous section uses a combination of priming and defining a closure. This is, by no means, the only way to define RakuWAPI middleware in Raku. 224 | 225 | What is important in middleware definition is the following: 226 | 227 | * A middleware application MUST be a RakuWAPI application, viz., it MUST be a configuration routine or runtime routine as defined in section 2.2.0. 228 | 229 | * Middleware SHOULD check to see if the application being wrapped returns a configuration routine or a runtime routine by testing whether the return value of the routine is [Callable](http://doc.perl6.org/type/Callable). 230 | 231 | * A middleware configuration routine SHOULD run the wrapped configuration application at configuration time with the configuration environment. 232 | 233 | * A middleware runtime routine SHOULD fail if the wrapped configuration application is a configuration routine. 234 | 235 | Any general purpose middleware should be defined as a configuration routine. 236 | 237 | Otherwise, There Is More Than One Way To Do It. 238 | 239 | ### 2.1.1 The Environment 240 | 241 | Middleware applications MAY set or modify the environment (both configuration and runtime environment) as needed. Middleware applications MUST maintain the typing required for the server in Sections 2.0.1.0 and 2.0.1.1 above, as modified by extensions and the application protocol in use. 242 | 243 | Whenever setting new variables in the environment, the variables MUST contain a period and SHOULD use a unique prefix to avoid name clashes with servers, other middleware, and applications. 244 | 245 | ### 2.1.2 The Input Stream 246 | 247 | An application server is required to provide the input stream as a [Supply](http://doc.perl6.org/type/Supply) emitting [Blob](http://doc.perl6.org/type/Blob)s. Middleware MUST provide the same. 248 | 249 | However, it is possible that the middleware will consume the data in `wapi.input` for the purpose of parsing or providing the data contained in another form. In such a case, the middleware SHOULD provide an empty, already closed, [Supply](http://doc.perl6.org/type/Supply). The middleware should provide the data in another environment variable. 250 | 251 | ### 2.1.3 The Error Stream 252 | 253 | See sections 2.0.3 and 2.2.3. 254 | 255 | ### 2.1.4 Application Lifecycle 256 | 257 | Middleware MUST return a valid response to the server according to the value set in `wapi.protocol` by the server (or whatever middleware came before it). 258 | 259 | See sections 2.0.4 and 2.2.4. Middleware MUST adhere to all requirements of the application as respects the server (2.2.4) and all requirements of the server as respects the application (2.0.4). 260 | 261 | See section 4 for details on protocol handling. 262 | 263 | 2.2 Layer 2: Application 264 | ------------------------ 265 | 266 | A RakuWAPI application is a Raku routine. The application MUST be [Callable](http://doc.perl6.org/type/Callable). An application may be defined as either a runtime routine or a configuration routine. A configuration routine receives a RakuWAPI configuration environment and returns a runtime routine. A runtime routine receives a RakuWAPI runtime environment and responds to it by returning a response. 267 | 268 | As an example, a simple Hello World RakuWAPI application defined with a runtime routine could be implemented as follows: 269 | 270 | ```perl6 271 | sub app(%env) { 272 | start { 273 | 200, [ Content-Type => 'text/plain' ], [ 'Hello World' ] 274 | } 275 | } 276 | ``` 277 | 278 | Or, a slightly more complex Hello World application could be implemented using a configuration routine instead like so: 279 | 280 | ```perl6 281 | sub app-config(%config) returns Callable { 282 | %config ∩= set('request-response'); 283 | sub app(%env) { 284 | start { 285 | 200, [ Content-Type => 'text/plain' ], [ 'Hello World' ] 286 | } 287 | } 288 | } 289 | ``` 290 | 291 | This second application makes sure that only the request-response protocol is enabled before returning an application only capable of responding that way (see Section 4). 292 | 293 | ### 2.2.0 Defining an Application 294 | 295 | An application is defined in one of two mechanisms, as mentioned in the previous section: 296 | 297 | * A runtime routine defines just the part of the application that reacts to incoming calls from the application server. (See Section 2.2.0.0.) 298 | 299 | * A configuration routine defines a special routine that is called prior to handling any incoming calls from the application server to give the application a chance to communicate with the server. (See Section 2.2.0.1.) 300 | 301 | During application defintion, the application MAY also instantiate and apply middleware to be used by the application. 302 | 303 | ### 2.2.0.0 Runtime Routine 304 | 305 | To define an application as a runtime routine, the application is defined as a [Callable](http://doc.perl6.org/type/Callable) (typically a [Routine](http://doc.perl6.org/type/Routine)). This application MUST accept a single parameter as its argument. When the application server handles a request, the server will set this parameter to the runtime environment for the request. The application MUST NOT have a return type set to a [Callable](http://doc.perl6.org/type/Callable). 306 | 307 | The application SHOULD respond to the caller, i.e., the application server or outer middleware, according to the `wapi.protocol` string set in the passed environment. 308 | 309 | Here, for example, is a RakuWAPI application that calculates and prints the Nth Lucas number depending on the value passed in the query string. This assumes a `request-response` protocol (see Section 4.0). 310 | 311 | ```perl6 312 | sub lucas-runtime(%env) { 313 | start { 314 | my $n = %env.Int; 315 | my $lucas-number := 2, 1, * + * ... *; 316 | 200, [ Content-Type => 'text/plain' ], [ $lucas-number[$n] ]; 317 | } 318 | } 319 | ``` 320 | 321 | This application is vulnerable, however, to problems if the server might call the application with a different protocol. 322 | 323 | ### 2.2.0.1 Configuration Routine 324 | 325 | An application SHOULD return a configuration routine, which is defined just like the runtime routine, but it must constrain its return type to something [Callable](http://doc.perl6.org/type/Callable). This application MUST accept a single parameter as its argument, just like the runtime routine. This single parameter will be set to the configuration environment when called by the application server. This routine will also be called prior to any request or other contact from an origin has occurred, which gives the application the opportunity to communicate with the server early. 326 | 327 | The application SHOULD modify the configuration environment to suit the needs of the application. The application SHOULD end the routine by returning a runtime routine (see the previous section). 328 | 329 | Here is the example from the previous section, but using a configuration routine to guarantee that the only protocol the application can use to contact it is the request-response protocol (see Section 4.0). It ends by returning the `&lucas-app` subroutine defined in the previous section: 330 | 331 | ```perl6 332 | sub lucas-config(%config) returns Callable { 333 | # Only permit the request-response protocol 334 | %config ∩= set('request-response'); 335 | 336 | &lucas-runtime; 337 | } 338 | ``` 339 | 340 | ### 2.2.1 The Environment 341 | 342 | Calls to the configuration routine of the application (if defined) will receive the configuration environment as defined in Section 2.0.1.0. Calls to the runtime routine of the application will receive the combination of the runtime environment and configuration environment as defined in Sections 2.0.1.0 and 2.0.1.1. Additional variables may be provided by your application server and middleware in either environment hash. 343 | 344 | The application itself MAY store additional values in the environment as it sees fit. This allows the application to communicate with a server or middleware or even with itself. When the application modifies the environment, the variables set MUST contain a period and SHOULD start with a unique name that is not `wapi.` or `wapix.` as these are reserved. 345 | 346 | ### 2.2.2 The Input Stream 347 | 348 | Some calls to your application may be accompanied by a request payload. For example, a POST or PUT request sent by an origin using HTTP will typically include such a payload. The application MAY choose to read the payload using the sane [Supply](http://doc.perl6.org/type/Supply) provided in the `wapi.input` variable of the runtime environment. This will provide a stream lf [Blob](http://doc.perl6.org/type/Blob)s. 349 | 350 | ### 2.2.3 The Error Stream 351 | 352 | The application server is required to provide a `wapi.errors` variable in the environment with a [Supplierish](http://doc.perl6.org/type/Supplierish) object (see Section 1.1). The application MAY emit any errors or messages here using any object that stringifies. The application SHOULD NOT terminate such messages with a newline as the server will do so if necessary. 353 | 354 | ### 2.2.4 Application Call 355 | 356 | To handle requests from the origin, the application server will make calls to the application routine. The application SHOULD return a valid response to the server. The response required will depend on what string is set in `wapi.protocol` within the runtime environment, so the application SHOULD check that on every call if it may vary. 357 | 358 | The application SHOULD attempt to return a value as quickly as possible via the runtime routine. For protocols that require the application to return a [Promise](http://doc.perl6.org/type/Promise), the application SHOULD wrap the entire body of the call in a `start` block to minimize the time the server will be waiting on the application. 359 | 360 | See section 4 on how different application protocols are handled. 361 | 362 | 3 Extensions 363 | ============ 364 | 365 | In addition to the standard specification, there are a number of extensions that servers or middleware MAY choose to implement. They are completely optional and applications and middleware SHOULD check for their presence before using them. Such checks SHOULD be performed as early as possible. 366 | 367 | Unless stated otherwise, all environment variables described here are set in the runtime environment, which is passed as the single argument with each call to the runtime routine. 368 | 369 | 3.0 Header Done 370 | --------------- 371 | 372 | The `wapix.header.done` environment variable, if provided, MUST be a vowed [Promise](http://doc.perl6.org/type/Promise). This Promise MUST be kept when the server is done sending or processing the response header. The Promise MUST be broken if the server is unable or unwilling to send the application provided headers. 373 | 374 | This is not an exhaustive list, but here are a few possible reasons why this Promise MAY be broken: 375 | 376 | * The headers are invalid and the application server will not send them. 377 | 378 | * An internal error occurred in the application server. 379 | 380 | * The client hungup the connection before the headers could be sent. 381 | 382 | When broken, this Promise SHOULD be broken with a helpful diagnostic exception. 383 | 384 | 3.1 Body Done 385 | ------------- 386 | 387 | The `wapix.body.done` environment variable, if provided, MUST be a vowed [Promise](http://doc.perl6.org/type/Promise). This Promise MUST be kept when the server is done sending or processing the response body. The Promise MUST be broken if the server is unable or unwilling to send the complete application body. 388 | 389 | This is not an exhaustive list, but here are a few possible reasons why this Promise MAY be broken: 390 | 391 | * The application server has already transmitted `Content-Length`, but the application continued to send bytes after that point. 392 | 393 | * The client hungup the connection before it finished sending the response. 394 | 395 | * An application initiated an HTTP/2 push-promise, which the server had begun to fulfill when it received a cancel message from the client. 396 | 397 | In particular, `wapix.body.done` MUST be broken if `wapix.header.done` is broken (assuming both extensions are implemented). 398 | 399 | When broken, the Promise SHOULD be broken with a helpful diagnostic exception. 400 | 401 | 3.2 Raw Socket 402 | -------------- 403 | 404 | The `wapix.io` environment variable, if provided, SHOULD be the socket object used to communicate to the client. This is the interface of last resort as it sidesteps the entire RakuWAPI interface. It may be useful in cases where an application wishes to control details of the socket itself. 405 | 406 | If your application requires the use of this socket, please file an issue describing the nature of your application in detail. You may have a use-case that a future revision to RakuWAPI can improve. 407 | 408 | This variable MAY be made available as part of the configuration environment. 409 | 410 | 3.3 Logger 411 | ---------- 412 | 413 | The `wapix.logger` environment variable, if provided, MUST be a [Routine](http://doc.perl6.org/type/Routine) defined with a signature as follows: 414 | 415 | ```perl6 416 | sub (Str:D $message, Str:D :$level = 'info'); 417 | ``` 418 | 419 | When called application MUST provide a `$level` that is one of: `"debug"`, `"info"`, `"warn"`, `"error"`, `"fatal"`. 420 | 421 | Te `wapix.logger` environment variable SHOULD be provided in the configuration environment. 422 | 423 | 3.4 Sessions 424 | ------------ 425 | 426 | This extension implements basic session handling that allows certain data to persist across requests. Session data SHOULD be associated with a particular origin. 427 | 428 | The `wapix.session` environment variable, if provided, MUST be an [Associative](http://doc.perl6.org/type/Associative). This hash maps arbitrary keys and values that may be read and written to by an application. The application SHOULD only use [Str](http://doc.perl6.org/type/Str) keys and values. The details of persisting this data is up to the application server or middleware implementing the session extension. 429 | 430 | The `wapix.session.options` environment variable, if provided, MUST be an [Associative](http://doc.perl6.org/type/Associative). This variable uses implementation-specific keys and values to communicate between the application and the extension implementation. This allows the application a channel by which to instruct the session handler how to operate. 431 | 432 | 3.5 Harakiri Mode 433 | ----------------- 434 | 435 | The `wapix.harakiri` environment variable, if provided, MUST be a [Bool](http://doc.perl6.org/type/Bool). If set to `True` it signals to the application that the server supports harakiri mode, which allows the application to ask the server to terminate the current work when the request is complete. This variable SHOULD be set in the configuration environment. 436 | 437 | The `wapix.harakiri.commit` environment variable MAY be set to a `True` value by the application to signal to the server that the current worker should be killed after the current request has been processed. 438 | 439 | 3.6 Cleanup Handlers 440 | -------------------- 441 | 442 | The `wapix.cleanup` environment variable, if provided, MUST be a [Bool](http://doc.perl6.org/type/Bool). If set to `True` it tells the application that the server supports running cleanup handlers after the request is complete. This variable SHOULD be set in the configuration environment. 443 | 444 | The `wapix.cleanup.handlers` environment variable MUST be provided if the `wapix.cleanup` flag is set. This MUST an [Array](http://doc.perl6.org/type/Array). The application adds cleanup handlers to the array by putting [Callable](http://doc.perl6.org/type/Callable)s into the Array (usually by `push`ing). Each handler will be given a copy of the `%env` as the first argument. The server MUST run these handlers, but only after the application has completely finished returning the response and any response payload. 445 | 446 | If the server supports the harakiri extension, it SHOULD allow the cleanup handlers to invoke harakiri mode by setting `wapix.harakiri.commit` (see 3.5). 447 | 448 | 3.7 Output Block Detection 449 | -------------------------- 450 | 451 | The `wapix.body.backpressure` environment variable, if provided, MUST be a [Bool](http://doc.perl6.org/type/Bool) flag. It is set to `True` to indicate that the RakuWAPI server provide response backpressure detection by polling for non-blocking I/O problems. In this case, the server MUST provide the other two environment variables. If `False` or not defined, the server does not provide these two environment variables. This variable SHOULD be defined in the configuration environment. 452 | 453 | The `wapix.body.backpressure.supply` environment variable MUST be provided if `wapix.body.backpressure` is `True`. When provided, it MUST be a live [Supply](http://doc.perl6.org/type/Supply) that periodically emits `True` and `False` values. `True` is emitted when the server polls for backpressure and detects a blocked output socket. `False` is emitted when the server polls for backpressure and detects the previously blocked socket is no longer blocked. 454 | 455 | The `wapix.body.backpressure.test` environment variable MUST be provided if `wapix.body.backpressure` is `True`. When provided, it MUST be a [Bool](http://doc.perl6.org/type/Bool) that is `True` while output has last been detected as blocked and `False` otherwise. This can be useful for detecting the initial state before the backpressure supply has emitted any value or just as a way to poll the last known status of the socket. 456 | 457 | 3.8 Protocol Upgrade 458 | -------------------- 459 | 460 | The `wapix.net-protocol.upgrade` environment variable MUST be provided in the configuration environment, if the server implements the protocol upgrade extension. It MUST be the [Set](http://doc.perl6.org/type/Set) of names of protocols the server supports for upgrade. 461 | 462 | When the client makes a protocol upgrade request using an `Upgrade` header, the application MAY request that the server negotiate the upgrade to one of these supported protocols by sending a `WAPIx-Upgrade` header back to the server with the named protocol. The application MAY send any other headers related to the Upgrade and MAY send a message payload if the upgrade allows it. These SHOULD override any server supplied values or headers. 463 | 464 | The server MUST negotiate the new protocol and enable any environment variables required for interacting through that protocol. After the handshake or upgrade negoatiation is complete, the server MUST make a new call to the application with a new environment to process the remainder of the network request with the origin. 465 | 466 | ### 3.8.0 HTTP/2 Protocol Upgrade 467 | 468 | The workings of HTTP/2 are similar enough to HTTP/1.0 and HTTP/1.1 that use of a protocol upgrade may not be necessary in most or all use-cases. However, servers MAY choose to delegate this to the application using the protocol upgrade extension. 469 | 470 | Servers that support this protocol upgrade MUST place the name "h2c" and/or "h2" into the `wapix.net-protocol.upgrade` set, for support of HTTP/2 over cleartext connections and HTTP/2 over TLS, respectively. 471 | 472 | The application MUST NOT request an upgrade using the `WAPIx-Upgrade` header for "h2c" unless the `wapi.url-scheme` is "http". Similarly, the application MUST NOT request an upgrade for "h2" unless the `wapi.url-scheme` is "https". The application server SHOULD enforce this requirement for security reasons. 473 | 474 | The application MUST NOT tap the `wapi.input` stream when performing this upgrade. The application SHOULD NOT return a message payload aside from an empty [Supply](http://doc.perl6.org/type/Supply). 475 | 476 | ### 3.8.1 WebSocket Protocol Upgrade 477 | 478 | Servers that support the WebSocket protocol upgrade MUST place the name "ws" into the `wapix.net-protocol.upgrade` set. 479 | 480 | The application MUST NOT tap the `wapi.input` stream when performing this upgrade. The application SHOULD NOT return a message payload aside from an empty [Supply](http://doc.perl6.org/type/Supply). 481 | 482 | 3.9 Transfer Encoding 483 | --------------------- 484 | 485 | This extension is only for HTTP/1.1 protocol connections. When the server supports this extension, it MUST provide a `wapix.http11.transfer-encoding` variable containing a `Set` naming the transfer encodings the server supports as strings. This SHOULD be set in the configuration environment. 486 | 487 | When the application returns a header named `WAPIx-Transfer-Encoding` with the name of one of the supported transfer encoding strings, the server MUST apply that transfer encoding to the message payload. If the connection is not HTTP/1.1, the server SHOULD ignore this header. 488 | 489 | ### 3.9.0 Chunked Encoding 490 | 491 | When the server supports and the application requests "chunked" encoding. The application server SHOULD treat each emitted [Str](http://doc.perl6.org/type/Str) or [Blob](http://doc.perl6.org/type/Blob) as a chunk to be encoded according to [RFC7230](https://tools.ietf.org/html/draft-ietf-httpbis-p1-messaging). It MUST adhere to requirements of RFC7230 when sending the response payload to the origin. 492 | 493 | ### 3.9.1 Other Encodings 494 | 495 | All other encodings should be handled as required by the relevant rules for HTTP/1.1. 496 | 497 | ### 3.10 HTTP/2 Push Promises 498 | 499 | When the `SERVER_PROTOCOL` is "HTTP/2", servers SHOULD support the HTTP/2 push promises extension. However, applications SHOULD check to make sure that the `wapix.h2.push-promise` variable is set to a defined value before using this extension. 500 | 501 | This extension is implemented by providing a variable named `wapix.h2.push-promise`. When provided, this MUST be a [Supplier](http://doc.perl6.org/type/Supplier). 502 | 503 | When the application wishes to invoke a server push, it MUST emit a message describing the request the server is pushing. The application server will receive this request and make a new, separate call to the application to fulfill that request. 504 | 505 | Push-promise messages are sent as an [Array](http://doc.perl6.org/type/Array) of [Pair](http://doc.perl6.org/type/Pair)s. This is a set of headers to send with the PUSH_PROMISE frame, including HTTP/2 pseudo-headers like ":path" and ":authority". 506 | 507 | Upon receiving a message to `wapix.h2.push-promise`, the server SHOULD schedule a followup call to the application to fulfill the push-promise as if the push-promise were an incoming request from the client. (The push-promise could be canceled by the client, so the call to the application might not actually happen.) 508 | 509 | 4 Application Protocol Implementation 510 | ===================================== 511 | 512 | One goal of RakuWAPI application servers is to allow the application to focus on building web applications without having to implement the mundane details of web protocols. In times past, this was simply a matter of implementing HTTP/1.x or some kind of front-end to HTTP/1.x (such as CGI or FastCGI). While HTTP/1.x is still relevant to the web today, new protocols have also become important to modern web applications, such as HTTP/2 and WebSocket. 513 | 514 | These protocols may have different interfaces that do not lend themselves to the request-response pattern specifed by PSGI. Therefore, we provide a means by which servers and applications may implement these alternate protocols, which each may have different requirements. These protocols are called application protocols to differentiate them from network protocols. For example, rather than providing a protocol for HTTP, we provide the "request-response" protocol. The underlying network protocol may be HTTP/1.0, HTTP/1.1, HTTP/2 or it may be something else that operates according to a similar pattern. 515 | 516 | The application and application server MUST communicate according to the application protocol used for the current application call. For many applications, just implementing the basic request-response protocol is enough. However, to allow for more complete applications, RakuWAPI provides additional tools to help application and application server to communicate through a variety of situations. This is handled primarily via the `wapi.protocol`, `wapi.protocol.support`, and `wapi.protocol.enabled` values in the environment. 517 | 518 | The application SHOULD check the value in `wapi.protocol`. If the application needs to make a decision based upon the network protocol, the application SHOULD check the `SERVER_PROTOCOL`. 519 | 520 | The application SHOULD check `wapi.protocol.support` to discover which protocols are supported by the application server. An application that is not able to support all supported protocols SHOULD modify `wapi.protocol.enabled` to only include protocols supported by the application as early as possible. 521 | 522 | The application server MUST provide the `wapi.protocol.support` and `wapi.protocol.enabled` values as part of the configuration environment. The application server MUST NOT use any protocol that is not a member of the `wapi.protocol.enabled` set. 523 | 524 | This specification defines the following protocols: 525 | 526 | * **request-response** for request-response protocols, including HTTP 527 | 528 | * **framed-socket** for framed-socket protocols, such as WebSocket 529 | 530 | * **psgi** for legacy PSGI applications 531 | 532 | * **socket** for raw, plain socket protocols, which send and receive data with no expectation of special server handling 533 | 534 | It is recommended that an application server that implements all of these protocols only enable the request-response protocol within `wapi.protocol.enabled` by default. This allows simple RakuWAPI applications to safely operate without having to perform any special configuration. 535 | 536 | 4.0 Request-Response Protocol 537 | ----------------------------- 538 | 539 | The "request-response" protocol SHOULD be used for any HTTP-style client-server web protocol, this include HTTP/1.x and HTTP/2 connections over plain text and TLS or SSL. 540 | 541 | ### 4.0.0 Response 542 | 543 | Here is an example application that implements the "request-response" protocol: 544 | 545 | ```perl6 546 | sub app(%env) { 547 | start { 548 | 200, 549 | [ Content-Type => 'text/plain' ], 550 | supply { 551 | emit "Hello World" 552 | }, 553 | } 554 | } 555 | ``` 556 | 557 | The runtime routine for the application MUST return a [Promise](http://doc.perl6.org/type/Promise). This Promise MUST be kept with a [Capture](http://doc.perl6.org/type/Capture) (or something that becomes one on return) and MAY be broken. The Capture MUST contain 3 positional elements, which are the status code, the list of headers, and the response payload. 558 | 559 | * The status code MUST be an [Int](http://doc.perl6.org/type/Int) or an object that coerces to an Int. It MUST be a valid status code for the [SERVER_PROTOCOL](http://doc.perl6.org/type/SERVER_PROTOCOL). 560 | 561 | * The headers MUST be a [List](http://doc.perl6.org/type/List) of [Pair](http://doc.perl6.org/type/Pair)s or an object that when coerced into a List becomes a List of Pairs. These pairs name the headers to return with the response. Header names MAY be repeated. 562 | 563 | * The message payload MUST be a *sane* [Supply](http://doc.perl6.org/type/Supply) or an object that coerces into a *sane* Supply, such as a [List](http://doc.perl6.org/type/List). 564 | 565 | Here is a more interesting example application of this interface: 566 | 567 | ```perl6 568 | sub app(%env) { 569 | start { 570 | my $n = %env.Int; 571 | 200, 572 | [ Content-Type => 'text/plain' ], 573 | supply { 574 | my $acc = 1.FatRat; 575 | for 1..$n -> $v { 576 | emit $acc *= $v; 577 | emit "\n"; 578 | } 579 | }, 580 | } 581 | } 582 | ``` 583 | 584 | The example application above will print out all the values of factorial from 1 to N where N is given in the query string. The header may be returned immediately and the lines of the body may be returned as the values of factorial are calculated by the application server. 585 | 586 | And here is an example demonstrating a couple ways in which coercion can be used by an application to simplify the result: 587 | 588 | ```perl6 589 | sub app(%env) { 590 | my enum HttpStatus (OK => 200, NotFound => 404, ServerError => 500); 591 | start { 592 | OK, [ Content-Type => 'text/plain' ], [ 'Hello World' ] 593 | } 594 | } 595 | ``` 596 | 597 | In this example, the status is returned using an enumeration which coerces to an appropriate integer value. The payload is returned as a list, which is automatically coerced into a Supply. 598 | 599 | Applications SHOULD return a Promise as soon as possible. It is recommended that applications wrap all operations within a `start` block to make this automatic. 600 | 601 | Application servers SHOULD NOT assume that the returned [Promise](http://doc.perl6.org/type/Promise) will be kept. It SHOULD assume that the Promise has been vowed and MUST NOT try to keep or break the Promise from the application. 602 | 603 | ### 4.0.1 Response Payload 604 | 605 | The response payload, in the result of the application's promise, must be a *sane* [Supply](http://doc.perl6.org/type/Supply). This supply MUST emit nothing for requests whose response must be empty. 606 | 607 | For any other request, the application MAY emit zero or more messages in the returned payload Supply. The messages SHOULD be handled as follows: 608 | 609 | * [Blob](http://doc.perl6.org/type/Blob). Any Blob emitted by the application SHOULD be treated as binary data to be passed through to the origin as-is. 610 | 611 | * [List](http://doc.perl6.org/type/List) of [Pair](http://doc.perl6.org/type/Pair)s. Some response payloads may contain trailing headers. Any List of Pairs emitted should be treated as trailing headers. 612 | 613 | * [Associative](http://doc.perl6.org/type/Associative). Any Associative object emitted should be treated as a message to communicate between layers of the application, middleware, and server. These should be ignored and passed on by middleware to the next layer unless consumed by the current middleware. Any message that reaches the application server but is not consumed by the application server MAY result in a warning being reported, but SHOULD otherwise be ignored. These objects MUST NOT be transmitted to the origin. 614 | 615 | * [Mu](http://doc.perl6.org/type/Mu). Any other Mu SHOULD be stringified with the `Str` method and encoded by the application server. If an object given cannot be stringified, the server SHOULD report a warning. 616 | 617 | ### 4.0.2 Encoding 618 | 619 | The application server SHOULD handle encoding of strings or stringified objects emitted to it. When performing encoding, the application server SHOULD honor the `charset` set within the `Content-Type` header, if given. If it does not honor the `charset` or no `charset` is set by the application, it MUST encode any strings in the response payload according to the encoding named in `wapi.body.encoding`. 620 | 621 | ### 4.0.3 Request-Response Lifecycle 622 | 623 | The application server performs the following during a single request-response interaction: 624 | 625 | * Receive a request from an origin and begin parsing the request according to the network protocol. 626 | 627 | * Construct a runtime environment and combine it with the configuration environment. The `wapi.input` part of the environment should continue reading data from the origin as it arrives until the request has been completely read. 628 | 629 | * Call the application runtime routine with the constructed environment and await a value from the returned [Promise](http://doc.perl6.org/type/Promise). 630 | 631 | * Return the start of the response using the HTTP status code and headers provided, formatted according to the protocol requirements. 632 | 633 | * Tap the supply part of the response and return data to the origin, formatted in ways appropriate for the environment settings and the network protocol in place. 634 | 635 | The server processes requests from an origin, passes the processed request information to the application by calling the application, waits for the application's response, and then returns the response to the origin. In the simplest example this means handling an HTTP roundtrip. Yet, it may also mean implementing a related protocol like CGI or FastCGI or SCGI or something else entirely. 636 | 637 | In the modern web, an application may want to implement a variety of complex HTTP interactions. These use-cases are not described by the typical HTTP request-response roundtrip with which most web developers are familiar. For example, an interactive Accept-Continue response or a data stream to or from the origin or an upgrade request to switch protocols. As such, application servers SHOULD make a best effort to be implemented in such a way as to make this variety applications possible. 638 | 639 | The application server SHOULD pass control to the application as soon as the headers have been received and the environment can be constructed. The application server MAY continue processing the request payload while the application server begins its work. The server SHOULD NOT emit the request payload to `wapi.input` yet. 640 | 641 | Once the application has returned the its [Promise](http://doc.perl6.org/type/Promise) to respond, the server SHOULD wait until the promise is kept. Once kept, the server SHOULD tap the response payload as soon as possible. After tapping the Supply, the application server SHOULD keep the [Promise](http://doc.perl6.org/type/Promise) in `wapi.ready` (the application server SHOULD NOT break this Promise). Once that promise has been kept, only then SHOULD the server start emitting the contents of the request payload, if any, to `wapi.input`. 642 | 643 | The server SHOULD return the application response headers back to the origin as soon as they are received. After which, the server SHOULD return each chunk emitted by the response body from the application as soon as possible. 644 | 645 | This particular order of operations during the application call will ensure that the application has the greatest opportunity to perform well and be able to execute a variety of novel HTTP interactions. 646 | 647 | ### 4.0.4 HTTP/1.1 Keep Alive 648 | 649 | When an application server supports HTTP/1.1 with keep-alive, each request sent on the connection MUST be handled as a separate call to the application. 650 | 651 | ### 4.0.4 HTTP/2 Handling 652 | 653 | When a server supports HTTP/2 it SHOULD implement the HTTP/2 Push Promise Extension defined in section 3.10. An application server MAY want to consider implementing HTTP/2 protocol upgrades using the extension described in section 3.8 or MAY perform such upgrades automatically instead. 654 | 655 | The application MUST be called once for each request or push-promise made on an HTTP/2 stream. 656 | 657 | 4.1 Framed-Socket Protocol 658 | -------------------------- 659 | 660 | The "framed-socket" protocol is appropriate for WebSocket-style peer-to-peer TCP connections. The following sections assume a WebSocket connection, but might be adaptable for use with other framed message exchanges, such as message queues or chat servers. 661 | 662 | ### 4.1.0 Response 663 | 664 | Any application server implementing WebSocket MUST adhere to all the requirements described above with the following modifications when calling the application for a WebSocket: 665 | 666 | * The `REQUEST_METHOD` MUST be set to the HTTP method used when the WebSocket connection was negotiated, i.e., usually "GET". Similarly, `SCRIPT_NAME`, `PATH_INFO`, `REQUEST_URI`, `QUERY_STRING`, `SERVER_NAME`, `SERVER_PORT`, `CONTENT_TYPE`, and `HTTP_*` variables in the environment MUST be set to the values from the original upgrade request sent from the origin. 667 | 668 | * The `SERVER_PROTOCOL` MUST be set to "WebSocket/13" or a similar string representing the revision of the WebSocket network protocol which in use. 669 | 670 | * The `CONTENT_LENGTH` SHOULD be set to an undefined [Int](http://doc.perl6.org/type/Int). 671 | 672 | * The `wapi.url-scheme` MUST be set to "ws" for plain text WebSocket connections or "wss" for encrypted WebSocket connections. 673 | 674 | * The `wapi.protocol` MUST be set to "framed-socket". 675 | 676 | * The server MUST decode frames received from the client and emit each of them to `wapi.input`. The frames MUST NOT be buffered or concatenated. 677 | 678 | * The server's supplied `wapi.input` [Supply](http://doc.perl6.org/type/Supply) must be *sane*. The server SHOULD signal `done` through the Supply when either the client or server closes the WebSocket connection normally and `quit` on abnormal termination of the connection. 679 | 680 | * The server MUST encode frames emitted by the application in the message payload as data frames sent to the client. The frames MUST be separated out as emitted by the application without any buffering or concatenation. 681 | 682 | The application MUST return a [Promise](http://doc.perl6.org/type/Promise) that is kept with just a [Supply](http://doc.perl6.org/type/Supply) (i.e., not a 3-element Capture as is used with the request-response protocol). The application MAY break this Promise. The application will emit frames to send back to the origin using the promised Supply. 683 | 684 | ### 4.1.1 Response Payload 685 | 686 | Applications MUST return a *sane* [Supply](http://doc.perl6.org/type/Supply) that emits an object for every frame it wishes to return to the origin. The application MAY emit zero or more messages to this supply. The application MAY emit `done` to signal that the connection is to be terminated with the client. 687 | 688 | The messages MUST be framed and returned to the origin by the application server as follows, based on message type: 689 | 690 | * [Blob](http://doc.perl6.org/type/Blob). Any Blob emitted by the application SHOULD be treated as binary data, framed exactly as is, and returned to the client. 691 | 692 | * [Associative](http://doc.perl6.org/type/Associative). Any Associative object emitted should be treated as a message to communicate between layers of the application, middleware, and server. These should be ignored and passed on by middleware to the next layer unless consumed by the current middleware. Any message that reaches the application server but is not consumed by the application server MAY result in a warning being reported, but SHOULD otherwise be ignored. These objects MUST NOT be transmitted to the origin. 693 | 694 | * [Mu](http://doc.perl6.org/type/Mu). Any other Mu SHOULD be stringified, if possible, and encoded by the application server. If an object given cannot be stringified, the server SHOULD report a warning. 695 | 696 | ### 4.1.2 Encoding 697 | 698 | The application server SHOULD handle encoding of strings or stringified objects emitted to it. The server MUST encode any strings in the message payload according to the encoding named in `wapi.body.encoding`. 699 | 700 | 4.2 PSGI Protocol 701 | ----------------- 702 | 703 | To handle legacy applications, this specification defines the "psgi" protocol. If `wapi.protocol.enabled` has both "psgi" and "request-response" enabled, the "request-response" protocol SHOULD be preferred. 704 | 705 | ### 4.2.0 Response 706 | 707 | The application SHOULD return a 3-element [Capture](http://doc.perl6.org/type/Capture) directly. The first element being the numeric status code, the second being an array of pairs naming the headers to return in the response, and finally an array of values representing the response payload. 708 | 709 | ### 4.2.1 Payload 710 | 711 | The payload SHOULD be delivered as an array of strings, never as a supply. 712 | 713 | ### 4.2.2 Encoding 714 | 715 | String encoding is not defined by this document. 716 | 717 | 4.3 Socket Protocol 718 | ------------------- 719 | 720 | The "socket" protocol can be provided by an application server wishing to allow the application to basically take over the socket connection with the origin. This allows the application to implement an arbitrary protocol. It does so, however, in a way that is aimed toward providing better portability than using the socket extension. 721 | 722 | The socket provided sends and receives data directly to and from the application without any framing, buffering, or modification. 723 | 724 | The "socket" protocol SHOULD only be used when it is enabled in `wapi.protocol.enabled` and no other protocol enabled there can fulfill the current application call. 725 | 726 | 4.3.0 Response 727 | -------------- 728 | 729 | Here's an example application that implements the "socket" protocol to create a naïve HTTP server: 730 | 731 | ```perl6 732 | sub app(%env) { 733 | start { 734 | supply { 735 | whenever %env -> $msg { 736 | my $req = parse-http-request($msg); 737 | 738 | if $req.method eq 'GET' { 739 | emit "200 OK HTTP/1.0\r\n"; 740 | emit "\r\n"; 741 | emit "Custom HTTP Server"; 742 | } 743 | } 744 | } 745 | } 746 | } 747 | ``` 748 | 749 | The socket protocol behaves very much like "framed-socket", but with fewer specified details in the environment. Some of the mandatory environment are not mandatory for the socket protocol. 750 | 751 | The following parts of the environment SHOULD be provided as undefined values: 752 | 753 | * REQUEST_METHOD 754 | 755 | * SCRIPT_NAME 756 | 757 | * PATH_INFO 758 | 759 | * REQUEST_URI 760 | 761 | * QUERY_STRING 762 | 763 | * SERVER_NAME 764 | 765 | * SERVER_PORT 766 | 767 | * CONTENT_TYPE 768 | 769 | * HTTP_* 770 | 771 | * wapi.url-scheme 772 | 773 | * wapi.ready 774 | 775 | * wapi.body.encoding 776 | 777 | * SERVER_PROTOCOL 778 | 779 | The `wapi.protocol` must be set to "socket". 780 | 781 | The application server SHOULD provide data sent by the origin to the application through the `wapi.input` supply as it arrives. It MUST still be a *sane* supply. 782 | 783 | The application server MAY tunnel the connection through another socket, stream, file handle, or what-not. That is, the application MAY NOT assume the communication is being performed over any particular medium. The application server SHOULD transmit the data to the origin as faithfully as possible, keeping the intent of the application as much as possible. 784 | 785 | The application server SHOULD forward on data emitted by the application in the returned payload supply as it arrives. The application server SHOULD send no other data to the origin over that socket once the application is handed control, unless related to how the data is being tunneled or handled by the server. The application server SHOULD close the connection with the origin when the application server sends the "done" message to the supply. Similarly, the application server SHOULD send "done" the `wapi.input` supply when the connection is closed by the client or server. 786 | 787 | ### 4.3.1 Response Payload 788 | 789 | Applications MUST return a *sane* [Supply](http://doc.perl6.org/type/Supply) which emits a string of bytes for every message to be sent. The messages returned on this stream MUST be [Blob](http://doc.perl6.org/type/Blob) objects. 790 | 791 | ### 4.3.2 Encoding 792 | 793 | The application server SHOULD reject any object other than a [Blob](http://doc.perl6.org/type/Blob) sent as part of the message payload. The application server is not expected to perform any encoding or stringification of messages. 794 | 795 | Changes 796 | ======= 797 | 798 | 0.9.Draft 799 | --------- 800 | 801 | * The error stream is now defined to be a `Supplierish` object, defined in Section 1.1. 802 | 803 | * Section 2.2.0.0 has been changed to forbid runtime routines from having a `Callable` return type. 804 | 805 | * Section 2.1.2 was rewritten to disallow what was previously allowed: the modification of the input stream. 806 | 807 | * Eliminated ambiguity regarding typing of environment in the middleware section. 808 | 809 | * Added a section for type constraints and made better use of subset types to streamline and simplify some of the documentation. 810 | 811 | * Cleaned up some old language left over from previous versions of the specification. 812 | 813 | * Eliminated some ambiguities in the type required for undefined environment values. The undefined environment values MUST match the given type constraint and be set to type objects of that type if they are not defined. 814 | 815 | * Changed the abbreviation from P6WAPI to RakuWAPI. 816 | 817 | * Changed all `p6w.*` environment prefixes to `wapi.*` 818 | 819 | * Changed all `p6wx.*` environment prefixes to `wapix.*` 820 | 821 | * Changed all `P6Wx-*` header names to `WAPIx-*` header names 822 | 823 | * Renamed all example `*.p6w` files to `*.wapi` 824 | 825 | 0.8.Draft 826 | --------- 827 | 828 | * Changed the abbreviation from P6W to P6WAPI. 829 | 830 | 0.7.Draft 831 | --------- 832 | 833 | * Renamed the standard from Perl 6 Standard Gateway Interface (P6SGI) to the Web API for Perl 6 (P6W). 834 | 835 | * Some grammar fixes, typo fixes, and general verbiage cleanup and simplification. 836 | 837 | * Renaming `p6sgi.*` to `p6w.*` and `p6sgix.*` to `p6wx.*`. 838 | 839 | * The errors stream is now a `Supplier` rather than a `Supply` because of recent changes to the Supply interface in Perl 6. Made other supply-related syntax changes because of design changes to S17. 840 | 841 | * Eliminating the requirement that things emitted in the response payload be [Cool](http://doc.perl6.org/type/Cool) if they are to be stringified and encoded. Any stringifiable [Mu](http://doc.perl6.org/type/Mu) is permitted. 842 | 843 | * Adding `p6w.protocol`, `p6w.protocol.support`, and `p6w.protocol.enabled` to handle server-to-application notification of the required response protocol. 844 | 845 | * Breaking sections 2.0.4, 2.1.4, and 2.2.4 up to discuss the difference between the HTTP and WebSocket protocol response requirements. 846 | 847 | * Moving 2.0.5, 2.1.5, and 2.2.5 under 2.*.4 because of the protocol changes made in 2.*.4. 848 | 849 | * Changed `p6wx.protocol.upgrade` from an [Array](http://doc.perl6.org/type/Array) to a [Set](http://doc.perl6.org/type/Set) of supported protocol names. 850 | 851 | * Split the environment and the application into two parts: configuration and runtime. 852 | 853 | * Added Section 4 to describe protocol-specific features of the specification. Section 4.0 is for HTTP, 4.1 is for WebSocket, 4.2 is for PSGI, and 4.3 is for Socket. 854 | 855 | 0.6.Draft 856 | --------- 857 | 858 | * Added Protocol-specific details and modifications to the standard HTTP/1.x environment. 859 | 860 | * Adding the Protocol Upgrade extension and started details for HTTP/2 and WebSocket upgrade handling. 861 | 862 | * Adding the Transfer Encoding extension because leaving this to the application or unspecified can lead to tricky scenarios. 863 | 864 | 0.5.Draft 865 | --------- 866 | 867 | * Adding `p6sgi.ready` and added the Application Lifecycle section to describe the ideal lifecycle of an application. 868 | 869 | * Changed `p6sgi.input` and `p6sgi.errors` to Supply objects. 870 | 871 | * Porting extensions from PSGI and moving the existing extensions into the extension section. 872 | 873 | * Adding some notes about middleware encoding. 874 | 875 | * Renamed `p6sgi.encoding` to `p6sgi.body.encoding`. 876 | 877 | * Renamed `p6sgix.response.sent` to `p6sgix.body.done`. 878 | 879 | * Added `p6sgix.header.done` as a new P6SGI extension. 880 | 881 | 0.4.Draft 882 | --------- 883 | 884 | * Cutting back on some more verbose or unnecessary statements in the standard, trying to stick with just what is important and nothing more. 885 | 886 | * The application response has been completely restructured in a form that is both easy on applications and easy on middleware, mainly taking advantage of the fact that a List easily coerces into a Supply. 887 | 888 | * Eliminating the P6SGI compilation unit again as it is no longer necessary. 889 | 890 | * Change the Supply to emit Cool and Blob rather than just Str and Blob. 891 | 892 | 0.3.Draft 893 | --------- 894 | 895 | * Splitting the standard formally into layers: Application, Server, and Middleware. 896 | 897 | * Bringing back the legacy standards and bringing back the variety of standard response forms. 898 | 899 | * Middleware is given a higher priority in this revision and more explanation. 900 | 901 | * Adding the P6SGI compilation unit to provide basic tools that allow middleware and possibly servers to easily process all standard response forms. 902 | 903 | * Section numbering has been added. 904 | 905 | * Added the Changes section. 906 | 907 | * Use `p6sgi.` prefixes in the environment rather than `psgi.` 908 | 909 | 0.2.Draft 910 | --------- 911 | 912 | This second revision eliminates the legacy standard and requires that all P6SGI responses be returned as a [Promise](http://doc.perl6.org/type/Promise). The goal is to try and gain some uniformity in the responses the server must deal with. 913 | 914 | 0.1.Draft 915 | --------- 916 | 917 | This is the first published version. It was heavily influenced by PSGI and included interfaces based on the standard, deferred, and streaming responses of PSGI. Instead of callbacks, however, it used [Promise](http://doc.perl6.org/type/Promise) to handle deferred responses and [Channel](http://doc.perl6.org/type/Channel) to handle streaming. It mentioned middleware in passing. 918 | 919 | -------------------------------------------------------------------------------- /RakuWAPI.pod: -------------------------------------------------------------------------------- 1 | =NAME Web API for Raku (RakuWAPI) 2 | 3 | =begin pod 4 | 5 | =head1 STATUS 6 | 7 | This is a Proposed Draft. 8 | 9 | Version 0.9.Draft 10 | 11 | =head1 0 INTRODUCTION 12 | 13 | This document standardizes an API for web application and server framework developers in Raku. It provides a standard protocol by which web applications and application servers may communicate with each other. 14 | 15 | This standard has the following goals: 16 | 17 | =item Standardize the interface between server and application so that web developers may focus on application development rather than the nuances of supporting different server platforms. 18 | 19 | =item Keep the interface simple so that a web application or middleware requires no additional tools or libraries other than what exists in a standard Raku environment, and no module installations are required. 20 | 21 | =item Keep the interface simple so that servers and middleware are simple to implement. 22 | 23 | =item Allow the interface to be flexible enough to accommodate a variety of common use-cases and simple optimzations as well as supporting unanticipated use-cases and future extensions. 24 | 25 | Aside from that is the underlying assumption that this is a simple interface and ought to at least somewhat resemble work in the standards it is derived from, including [Rack](http://www.rubydoc.info/github/rack/rack/master/file/SPEC), [WSGI](https://www.python.org/dev/peps/pep-0333/), [PSGI](https://metacpan.com/pod/PSGI), [CGI](http://www.w3.org/CGI/), and others. 26 | 27 | =head1 1 TERMINOLOGY 28 | 29 | =head2 1.0 Glossary 30 | 31 | A D is a Raku routine that expects to receive an environment from an I and returns a response each time it is called by the server. 32 | 33 | A D is an application that processes requests and responses according to a web-related protocol, such as HTTP or WebSockets or similar protocol. 34 | 35 | The D is the external entity that makes a given request and/or expects a response from the application server. This can be thought of generically as a web browser, bot, or other user agent. 36 | 37 | An D is a program that is able to provide an environment to a I and process the value returned from such an application. 38 | 39 | The I might be associated with a I, might itself be a I, might process a protocol used to communicate with a I (such as CGI or FastCGI), or may be something else entirely not related to a I (such as a tool for testing I). 40 | 41 | D is a I that wraps another I for the purpose of performing some auxiliary task such as preprocessing request environments, logging, postprocessing responses, etc. 42 | 43 | A D is a developer who writes an I. 44 | 45 | An D is a developer who writes a I. 46 | 47 | A D is a Supply object that follows the emit*-done/quit protocol, i.e., it will emit 0 or more objects followed by a call to the done or quit handler. See L for details. 48 | 49 | =head2 1.1 Type Constraints 50 | 51 | The following type constraints are defined for use with this document. 52 | 53 | subset NonEmptyStr of Str where { !.defined || .chars > 0 }; 54 | subset PathStr of Str where { !.defined || $_ ~~ any('', m{ ^ "/" }) }; 55 | subset PositiveInt of Int where { !.defined || $_ > 0 }; 56 | subset Supplierish of Any where { !.defined || ?.can('emit').grep(*.arity == 2) }; 57 | 58 | Any place a type is used in this document, the implementation is free to use any subtype (either subset or sub-class) of that type in place of the named type so long as the type constraint is guaranteed to hold for the subtype. For example, if an C is required, it would be permissible to use an C instead. 59 | 60 | =head1 2 SPECIFICATION 61 | 62 | This specification is divided into three layers: 63 | 64 | =item Layer 0: Server 65 | 66 | =item Layer 1: Middleware 67 | 68 | =item Layer 2: Application 69 | 70 | Each layer has a specific role related to the other layers. The server layer is responsible for managing the application lifecycle and performing communication with the origin. The application layer is responsible for receiving metadata and content from the server and delivering metadata and content back to the server. The middleware layer is responsible for enhancing the application or server by providing additional services and utilities. 71 | 72 | This specification goes through each layer in order. In the process, each section only specifies the requirements and recommendations for the layer that section describes. When other layers a mentioned outside of its section, the specification is deliberately vague to keep all specifics in the appropriate section. 73 | 74 | To aid in reading this specification, the numbering subsections of 2.0, 2.1, and 2.2 are matched so that you can navigate between them to compare the requirements of each layer. For example, 2.0.1 describes the environment the server provides, 2.1.1 describes how the application interacts with that environment, and 2.1.1 describes how middleware may manipulate that environment. 75 | 76 | =head2 2.0 Layer 0: Server 77 | 78 | A RakuWAPI application server is a program capable of running RakuWAPI applications as defined by this specification. 79 | 80 | A RakuWAPI application server implements some kind of web service. For example, this may mean implementing an HTTP or WebSocket service or a related protocol such as CGI, FastCGI, SCGI, etc. An application server also manages the application lifecycle and executes the application, providing it with a complete environment, and processing the response from the application to determine how to respond to the origin. 81 | 82 | One important aspect of this specification that is not defined is the meaning of a server error. At times it is suggested that certain states be treated as a server error, but what that actually means to a given implementation is deliberatly undefined. That is a complex topic which varies by implementation and by the state the server is in when such a state is discovered. The server SHOULD log such events and SHOULD use the appropriate means of communication provided to notify the application that a server error has occurred while responding. 83 | 84 | =head3 2.0.0 Application Definition 85 | 86 | A RakuWAPI application is defined as a class or object, which must be implemented according to a particular interface. The application server MUST provide a means by which an application is loaded. The application server SHOULD be able to load them by executing a RakuWAPI script file. 87 | 88 | For example, here is a simple application: 89 | 90 | use v6; 91 | sub app(%env) { 92 | start { 93 | 200, [ Content-Type => 'text/plain' ], [ 'Hello World!' ] 94 | } 95 | } 96 | 97 | For full details on how an application is defined, see Section 2.2.0. For details on how a server interacts with the application, see Section 2.0.4. 98 | 99 | =head3 2.0.1 The Environment 100 | 101 | The environment is delivered to the application via hashes, they MUST be L. The application server makes the environment available to the application at runtime. The environment is used to: 102 | 103 | =item Communicate server capabilities to the application, 104 | =item Allow the application to communicate with the server, and 105 | =item Allow the application to respond to calls to the application. 106 | 107 | Each variable or key in the environment is described as belonging to one of two roles: 108 | 109 | =item A D describes global capabilities and configuration information to application. 110 | 111 | =item A D describes per-call information related to the particular request. 112 | 113 | Calls to the runtime routine MUST be provided with all required environment variables belonging to either of these roles in the passed environment hash. However, calls to the configuration routine (see 2.0.4) MUST include the configuration envrionment and SHOULD NOT include runtime environment in the passed environment hash. 114 | 115 | The server MAY provide variables in the environment in either role in addition to the ones defined here, but they MUST contain a period and SHOULD be given a unique prefix to avoid name clashes. 116 | 117 | The following prefixes are reserved and SHOULD NOT be used unless defined by this specification and only according to the definition given here. 118 | 119 | =item C is for RakuWAPI core standard environment. 120 | 121 | =item C is for RakuWAPI standard extensions to the environment. 122 | 123 | In the tables below, a type constraint is given for each variable. The application server MUST provide each key as the named type. All variables given in the tables with 2.0.1.0 and 2.0.1.1 MUST be provided. 124 | 125 | =head4 2.0.1.0 Configuration Environment 126 | 127 | The configuration environment MUST be made available to the application during every call made to the application, both to the configuration routine and the runtime routine. 128 | 129 | =begin table :allow 130 | 131 | Variable | Constraint | Description 132 | =========================|======================|====================================== 133 | C | C<< Version:D >> | This is the version of this 134 | | | specification, C. 135 | 136 | C | C<< Supplierish:D >> | The error stream for logging. 137 | 138 | C | C<< Bool:D >> | True if the app may be 139 | | | simultaneously invoked in another 140 | | | thread in the same 141 | | | process. 142 | 143 | C | C<< Bool:D >> | True if the app may be simultaneously 144 | | | invoked in another process. 145 | 146 | C | C<< Bool:D >> | True if the server expects the app 147 | | | to be invoked only once during the 148 | | | life of the process. This is not a 149 | | | guarantee. 150 | 151 | C | C<< Set:D >> | This is a L of strings naming the 152 | | | protocols supported by the application 153 | | | server. 154 | 155 | C | C<< SetHash:D >> | This is the set of enabled protocols. 156 | | | The application may modify this set 157 | | | with those found in 158 | | | C to 159 | | | enable/disable protocols the server 160 | | | is permitted to use. 161 | 162 | =end table 163 | 164 | =head4 2.0.1.1 Runtime Environment 165 | 166 | Many of the runtime environment variables are derived from the old Common Gateway Interface (CGI). This environment MUST be given when the application is being called, i.e., whenever the runtime routine is called. 167 | 168 | =begin table :allow 169 | 170 | Variable | Constraint | Description 171 | =========================|======================|====================================== 172 | C | C<< NonEmptyStr:D >> | The HTTP request method, such as 173 | | | "GET" or "POST". 174 | 175 | C | C<< PathStr:D >> | This is the initial portion of the 176 | | | URI path that refers to the 177 | | | application. 178 | 179 | C | C<< PathStr:D >> | This is the remainder of the request 180 | | | URI path within the application. 181 | | | This value SHOULD be URI decoded by 182 | | | the application server according to 183 | | | L 184 | 185 | C | C<< Str:D >> | This is the exact URI sent by the 186 | | | client in the request line of the 187 | | | HTTP request. The application server 188 | | | SHOULD NOT perform any decoding on 189 | | | it. 190 | 191 | C | C<< Str:D >> | This is the portion of the requested 192 | | | URL following the C, if any. 193 | 194 | C | C<< NonEmptyStr:D >> | This is the name of the web server. 195 | 196 | C | C<< PositiveInt:D >> | This is the port number of the web 197 | | | server. 198 | 199 | C | C<< NonEmptyStr:D >> | This is the server protocol sent by 200 | | | the client, e.g. "HTTP/1.0" 201 | | | or "HTTP/1.1". 202 | 203 | C | C<< Int:_ >> | This corresponds to the 204 | | | Content-Length header sent by the 205 | | | client. If no such header was sent 206 | | | the application server MUST set 207 | | | this key to the L type value. 208 | 209 | C | C<< Str:_ >> | This corresponds to the Content-Type 210 | | | header sent by the client. If no 211 | | | such header was sent the application 212 | | | server MUST set this key to the 213 | | | L type value. 214 | 215 | C | C<< Str:_ >> | The remaining request headers are 216 | | | placed here. The names are prefixed 217 | | | with C, in ALL CAPS with the 218 | | | hyphens ("-") turned to underscores 219 | | | ("_"). Multiple incoming headers 220 | | | with the same name MUST have their 221 | | | values joined with a comma (", ") as 222 | | | described in 223 | | | L. 224 | | | The C and 225 | | | C headers MUST 226 | | | NOT be set. 227 | 228 | Other CGI Keys | C<< Str:_ >> | The server MUST attempt to provide 229 | | | as many other CGI variables as 230 | | | possible, but no others are required 231 | | | or formally specified. 232 | 233 | C | C<< Str:D >> | Either "http" or "https". 234 | 235 | C | C<< Supply:D >> | The input stream for reading the 236 | | | body of the request, if any. 237 | 238 | C | C<< Promise:D >> | This is a vowed Promise that MUST be 239 | | | kept by the server as soon as the 240 | | | server has tapped the application's 241 | | | output Supply and is ready to 242 | | | receive emitted messages. The value 243 | | | of the kept Promise is irrelevent. 244 | | | The server SHOULD NOT break this 245 | | | Promise. 246 | 247 | C | C<< Str:D >> | Name of the encoding the server will 248 | | | use for any strings it is sent. 249 | 250 | C | C<< Str:D >> | This is a string naming the 251 | | | response protocols the server is 252 | | | expecting from the application for 253 | | | call. 254 | 255 | =end table 256 | 257 | In the environment, either C or C must be set to a non-empty string. When C is "/", the C SHOULD be "/" and C SHOULD be the empty string. C MUST NOT be set to "/". 258 | 259 | =head3 2.0.2 The Input Stream 260 | 261 | The input stream is set in the C key of the runtime environment. This represents the request payload sent from the origin. Unless otherwise indicated as part of the protocol definition, the server MUST provide a I L that emits L objects containing the content of the request payload. It MAY emit nothing and just signal C if the request payload is empty. 262 | 263 | =head3 2.0.3 The Error Stream 264 | 265 | The error stream MUST be given in the configuration environment via C. This MUST be a L (see Section 1.1) object the server provides for emitting errors. This is a defined object that has an C method that has the same signature as C. 266 | 267 | The application MAY call C on this object zero or more times, passing any object that may be stringified. The server SHOULD write these log entries to a suitable log file or to C<$*ERR> or wherever appropriate. If written to a typical file handle, it should automatically append a newline to each emitted message. 268 | 269 | =head3 2.0.4 Application Lifecycle 270 | 271 | After the application has been defined, it will be called each time the application server needs to respond to the origin. What that means will vary depending on which protocol is needed to appropriately respond to the origin. 272 | 273 | These requirements, however, are in held in common regardless of protocol, the application server requirements are as follows: 274 | 275 | =item The application server MUST check the type of the return value of the application routine. If the application return value is L, the application has returned a configuration routine. Otherwise, the application has returned a runtime routine. 276 | 277 | =item If the application returned a configuration routine, as detected by the previous requirement, the application server MUST call this routine and pass the configuration environment in a hash as the first argument to the routine. The return value of this routine is the runtime routine for the application. 278 | 279 | =item Prior to each call to runtime routine, the application server MUST set the C variable to the name of the protocol the server will use to communicate with the application. 280 | 281 | =item The server MUST receive the return value of runtime routine and process it according to the application protocol in use for this call, the protocol matching the one set in the previous requirement. 282 | 283 | =item The server MUST pass a L containing all variables of both the configuration environment and runtime environments as the first argument to the runtime routine. 284 | 285 | The server MUST NOT call the application with C set to a protocol that has been previously disabled by the application via the C setting. 286 | 287 | For details on how each protocol handles the application call, see section 4. 288 | 289 | =head2 2.1 Layer 1: Middleware 290 | 291 | RakuWAPI middleware is simply an application that wraps another application. Middleware is used to perform any kind of pre-processing, post-processing, or side-effects that might be added onto an application. Possible uses include logging, encoding, validation, security, debugging, routing, interface adaptation, and header manipulation. 292 | 293 | For example, in the following snippet, C is a middleware application that adds a custom header: 294 | 295 | sub app(%env) { start { 200, [ Content-Type => 'text/plain' ], [ 'Hello World' ] } } 296 | sub mw(&wrappee is copy, %config) returns Callable { 297 | &wrappee = wrappee(%config) if &wrappee.returns ~~ Callable; 298 | sub (%env) { 299 | wrappee(%env).then( 300 | -> $p { 301 | my @r = $p.result; 302 | @r[1].push: 'WAPI-Used' => 'True'; 303 | @r 304 | } 305 | ); 306 | } 307 | } 308 | my &mw-app = &mw.assuming(&app); 309 | 310 | =head3 2.1.0 Middleware Definition 311 | 312 | The way in which middleware is defined and applied is left up to the middleware author. The example in the previous section uses a combination of priming and defining a closure. This is, by no means, the only way to define RakuWAPI middleware in Raku. 313 | 314 | What is important in middleware definition is the following: 315 | 316 | =item A middleware application MUST be a RakuWAPI application, viz., it MUST be a configuration routine or runtime routine as defined in section 2.2.0. 317 | 318 | =item Middleware SHOULD check to see if the application being wrapped returns a configuration routine or a runtime routine by testing whether the return value of the routine is L. 319 | 320 | =item A middleware configuration routine SHOULD run the wrapped configuration application at configuration time with the configuration environment. 321 | 322 | =item A middleware runtime routine SHOULD fail if the wrapped configuration application is a configuration routine. 323 | 324 | Any general purpose middleware should be defined as a configuration routine. 325 | 326 | Otherwise, There Is More Than One Way To Do It. 327 | 328 | =head3 2.1.1 The Environment 329 | 330 | Middleware applications MAY set or modify the environment (both configuration and runtime environment) as needed. Middleware applications MUST maintain the typing required for the server in Sections 2.0.1.0 and 2.0.1.1 above, as modified by extensions and the application protocol in use. 331 | 332 | Whenever setting new variables in the environment, the variables MUST contain a period and SHOULD use a unique prefix to avoid name clashes with servers, other middleware, and applications. 333 | 334 | =head3 2.1.2 The Input Stream 335 | 336 | An application server is required to provide the input stream as a L emitting Ls. Middleware MUST provide the same. 337 | 338 | However, it is possible that the middleware will consume the data in C for the purpose of parsing or providing the data contained in another form. In such a case, the middleware SHOULD provide an empty, already closed, L. The middleware should provide the data in another environment variable. 339 | 340 | =head3 2.1.3 The Error Stream 341 | 342 | See sections 2.0.3 and 2.2.3. 343 | 344 | =head3 2.1.4 Application Lifecycle 345 | 346 | Middleware MUST return a valid response to the server according to the value set in C by the server (or whatever middleware came before it). 347 | 348 | See sections 2.0.4 and 2.2.4. Middleware MUST adhere to all requirements of the application as respects the server (2.2.4) and all requirements of the server as respects the application (2.0.4). 349 | 350 | See section 4 for details on protocol handling. 351 | 352 | =head2 2.2 Layer 2: Application 353 | 354 | A RakuWAPI application is a Raku routine. The application MUST be L. An application may be defined as either a runtime routine or a configuration routine. A configuration routine receives a RakuWAPI configuration environment and returns a runtime routine. A runtime routine receives a RakuWAPI runtime environment and responds to it by returning a response. 355 | 356 | As an example, a simple Hello World RakuWAPI application defined with a runtime routine could be implemented as follows: 357 | 358 | sub app(%env) { 359 | start { 360 | 200, [ Content-Type => 'text/plain' ], [ 'Hello World' ] 361 | } 362 | } 363 | 364 | Or, a slightly more complex Hello World application could be implemented using a configuration routine instead like so: 365 | 366 | sub app-config(%config) returns Callable { 367 | %config ∩= set('request-response'); 368 | sub app(%env) { 369 | start { 370 | 200, [ Content-Type => 'text/plain' ], [ 'Hello World' ] 371 | } 372 | } 373 | } 374 | 375 | This second application makes sure that only the request-response protocol is enabled before returning an application only capable of responding that way (see Section 4). 376 | 377 | =head3 2.2.0 Defining an Application 378 | 379 | An application is defined in one of two mechanisms, as mentioned in the previous section: 380 | 381 | =item A D defines just the part of the application that reacts to incoming calls from the application server. (See Section 2.2.0.0.) 382 | 383 | =item A D defines a special routine that is called prior to handling any incoming calls from the application server to give the application a chance to communicate with the server. (See Section 2.2.0.1.) 384 | 385 | During application defintion, the application MAY also instantiate and apply middleware to be used by the application. 386 | 387 | =head3 2.2.0.0 Runtime Routine 388 | 389 | To define an application as a runtime routine, the application is defined as a L (typically a L). This application MUST accept a single parameter as its argument. When the application server handles a request, the server will set this parameter to the runtime environment for the request. The application MUST NOT have a return type set to a L. 390 | 391 | The application SHOULD respond to the caller, i.e., the application server or outer middleware, according to the C string set in the passed environment. 392 | 393 | Here, for example, is a RakuWAPI application that calculates and prints the Nth Lucas number depending on the value passed in the query string. This assumes a C protocol (see Section 4.0). 394 | 395 | sub lucas-runtime(%env) { 396 | start { 397 | my $n = %env.Int; 398 | my $lucas-number := 2, 1, * + * ... *; 399 | 200, [ Content-Type => 'text/plain' ], [ $lucas-number[$n] ]; 400 | } 401 | } 402 | 403 | This application is vulnerable, however, to problems if the server might call the application with a different protocol. 404 | 405 | =head3 2.2.0.1 Configuration Routine 406 | 407 | An application SHOULD return a configuration routine, which is defined just like the runtime routine, but it must constrain its return type to something L. This application MUST accept a single parameter as its argument, just like the runtime routine. This single parameter will be set to the configuration environment when called by the application server. This routine will also be called prior to any request or other contact from an origin has occurred, which gives the application the opportunity to communicate with the server early. 408 | 409 | The application SHOULD modify the configuration environment to suit the needs of the application. The application SHOULD end the routine by returning a runtime routine (see the previous section). 410 | 411 | Here is the example from the previous section, but using a configuration routine to guarantee that the only protocol the application can use to contact it is the request-response protocol (see Section 4.0). It ends by returning the C<&lucas-app> subroutine defined in the previous section: 412 | 413 | sub lucas-config(%config) returns Callable { 414 | # Only permit the request-response protocol 415 | %config ∩= set('request-response'); 416 | 417 | &lucas-runtime; 418 | } 419 | 420 | =head3 2.2.1 The Environment 421 | 422 | Calls to the configuration routine of the application (if defined) will receive the configuration environment as defined in Section 2.0.1.0. Calls to the runtime routine of the application will receive the combination of the runtime environment and configuration environment as defined in Sections 2.0.1.0 and 2.0.1.1. Additional variables may be provided by your application server and middleware in either environment hash. 423 | 424 | The application itself MAY store additional values in the environment as it sees fit. This allows the application to communicate with a server or middleware or even with itself. When the application modifies the environment, the variables set MUST contain a period and SHOULD start with a unique name that is not C or C as these are reserved. 425 | 426 | =head3 2.2.2 The Input Stream 427 | 428 | Some calls to your application may be accompanied by a request payload. For example, a POST or PUT request sent by an origin using HTTP will typically include such a payload. The application MAY choose to read the payload using the sane L provided in the C variable of the runtime environment. This will provide a stream lf Ls. 429 | 430 | =head3 2.2.3 The Error Stream 431 | 432 | The application server is required to provide a C variable in the environment with a L object (see Section 1.1). The application MAY emit any errors or messages here using any object that stringifies. The application SHOULD NOT terminate such messages with a newline as the server will do so if necessary. 433 | 434 | =head3 2.2.4 Application Call 435 | 436 | To handle requests from the origin, the application server will make calls to the application routine. The application SHOULD return a valid response to the server. The response required will depend on what string is set in C within the runtime environment, so the application SHOULD check that on every call if it may vary. 437 | 438 | The application SHOULD attempt to return a value as quickly as possible via the runtime routine. For protocols that require the application to return a L, the application SHOULD wrap the entire body of the call in a C block to minimize the time the server will be waiting on the application. 439 | 440 | See section 4 on how different application protocols are handled. 441 | 442 | =head1 3 Extensions 443 | 444 | In addition to the standard specification, there are a number of extensions that servers or middleware MAY choose to implement. They are completely optional and applications and middleware SHOULD check for their presence before using them. Such checks SHOULD be performed as early as possible. 445 | 446 | Unless stated otherwise, all environment variables described here are set in the runtime environment, which is passed as the single argument with each call to the runtime routine. 447 | 448 | =head2 3.0 Header Done 449 | 450 | The C environment variable, if provided, MUST be a vowed L. This Promise MUST be kept when the server is done sending or processing the response header. The Promise MUST be broken if the server is unable or unwilling to send the application provided headers. 451 | 452 | This is not an exhaustive list, but here are a few possible reasons why this Promise MAY be broken: 453 | 454 | =item The headers are invalid and the application server will not send them. 455 | 456 | =item An internal error occurred in the application server. 457 | 458 | =item The client hungup the connection before the headers could be sent. 459 | 460 | When broken, this Promise SHOULD be broken with a helpful diagnostic exception. 461 | 462 | =head2 3.1 Body Done 463 | 464 | The C environment variable, if provided, MUST be a vowed L. This Promise MUST be kept when the server is done sending or processing the response body. The Promise MUST be broken if the server is unable or unwilling to send the complete application body. 465 | 466 | This is not an exhaustive list, but here are a few possible reasons why this Promise MAY be broken: 467 | 468 | =item The application server has already transmitted C, but the application continued to send bytes after that point. 469 | 470 | =item The client hungup the connection before it finished sending the response. 471 | 472 | =item An application initiated an HTTP/2 push-promise, which the server had begun to fulfill when it received a cancel message from the client. 473 | 474 | In particular, C MUST be broken if C is broken (assuming both extensions are implemented). 475 | 476 | When broken, the Promise SHOULD be broken with a helpful diagnostic exception. 477 | 478 | =head2 3.2 Raw Socket 479 | 480 | The C environment variable, if provided, SHOULD be the socket object used to communicate to the client. This is the interface of last resort as it sidesteps the entire RakuWAPI interface. It may be useful in cases where an application wishes to control details of the socket itself. 481 | 482 | If your application requires the use of this socket, please file an issue describing the nature of your application in detail. You may have a use-case that a future revision to RakuWAPI can improve. 483 | 484 | This variable MAY be made available as part of the configuration environment. 485 | 486 | =head2 3.3 Logger 487 | 488 | The C environment variable, if provided, MUST be a L defined with a signature as follows: 489 | 490 | sub (Str:D $message, Str:D :$level = 'info'); 491 | 492 | When called application MUST provide a C<$level> that is one of: C<"debug">, C<"info">, C<"warn">, C<"error">, C<"fatal">. 493 | 494 | Te C environment variable SHOULD be provided in the configuration environment. 495 | 496 | =head2 3.4 Sessions 497 | 498 | This extension implements basic session handling that allows certain data to persist across requests. Session data SHOULD be associated with a particular origin. 499 | 500 | The C environment variable, if provided, MUST be an L. This hash maps arbitrary keys and values that may be read and written to by an application. The application SHOULD only use L keys and values. The details of persisting this data is up to the application server or middleware implementing the session extension. 501 | 502 | The C environment variable, if provided, MUST be an L. This variable uses implementation-specific keys and values to communicate between the application and the extension implementation. This allows the application a channel by which to instruct the session handler how to operate. 503 | 504 | =head2 3.5 Harakiri Mode 505 | 506 | The C environment variable, if provided, MUST be a L. If set to C it signals to the application that the server supports harakiri mode, which allows the application to ask the server to terminate the current work when the request is complete. This variable SHOULD be set in the configuration environment. 507 | 508 | The C environment variable MAY be set to a C value by the application to signal to the server that the current worker should be killed after the current request has been processed. 509 | 510 | =head2 3.6 Cleanup Handlers 511 | 512 | The C environment variable, if provided, MUST be a L. If set to C it tells the application that the server supports running cleanup handlers after the request is complete. This variable SHOULD be set in the configuration environment. 513 | 514 | The C environment variable MUST be provided if the C flag is set. This MUST an L. The application adds cleanup handlers to the array by putting Ls into the Array (usually by Cing). Each handler will be given a copy of the C<%env> as the first argument. The server MUST run these handlers, but only after the application has completely finished returning the response and any response payload. 515 | 516 | If the server supports the harakiri extension, it SHOULD allow the cleanup handlers to invoke harakiri mode by setting C (see 3.5). 517 | 518 | =head2 3.7 Output Block Detection 519 | 520 | The C environment variable, if provided, MUST be a L flag. It is set to C to indicate that the RakuWAPI server provide response backpressure detection by polling for non-blocking I/O problems. In this case, the server MUST provide the other two environment variables. If C or not defined, the server does not provide these two environment variables. This variable SHOULD be defined in the configuration environment. 521 | 522 | The C environment variable MUST be provided if C is C. When provided, it MUST be a live L that periodically emits C and C values. C is emitted when the server polls for backpressure and detects a blocked output socket. C is emitted when the server polls for backpressure and detects the previously blocked socket is no longer blocked. 523 | 524 | The C environment variable MUST be provided if C is C. When provided, it MUST be a L that is C while output has last been detected as blocked and C otherwise. This can be useful for detecting the initial state before the backpressure supply has emitted any value or just as a way to poll the last known status of the socket. 525 | 526 | =head2 3.8 Protocol Upgrade 527 | 528 | The C environment variable MUST be provided in the configuration environment, if the server implements the protocol upgrade extension. It MUST be the L of names of protocols the server supports for upgrade. 529 | 530 | When the client makes a protocol upgrade request using an C header, the application MAY request that the server negotiate the upgrade to one of these supported protocols by sending a C header back to the server with the named protocol. The application MAY send any other headers related to the Upgrade and MAY send a message payload if the upgrade allows it. These SHOULD override any server supplied values or headers. 531 | 532 | The server MUST negotiate the new protocol and enable any environment variables required for interacting through that protocol. After the handshake or upgrade negoatiation is complete, the server MUST make a new call to the application with a new environment to process the remainder of the network request with the origin. 533 | 534 | =head3 3.8.0 HTTP/2 Protocol Upgrade 535 | 536 | The workings of HTTP/2 are similar enough to HTTP/1.0 and HTTP/1.1 that use of a protocol upgrade may not be necessary in most or all use-cases. However, servers MAY choose to delegate this to the application using the protocol upgrade extension. 537 | 538 | Servers that support this protocol upgrade MUST place the name "h2c" and/or "h2" into the C set, for support of HTTP/2 over cleartext connections and HTTP/2 over TLS, respectively. 539 | 540 | The application MUST NOT request an upgrade using the C header for "h2c" unless the C is "http". Similarly, the application MUST NOT request an upgrade for "h2" unless the C is "https". The application server SHOULD enforce this requirement for security reasons. 541 | 542 | The application MUST NOT tap the C stream when performing this upgrade. The application SHOULD NOT return a message payload aside from an empty L. 543 | 544 | =head3 3.8.1 WebSocket Protocol Upgrade 545 | 546 | Servers that support the WebSocket protocol upgrade MUST place the name "ws" into the C set. 547 | 548 | The application MUST NOT tap the C stream when performing this upgrade. The application SHOULD NOT return a message payload aside from an empty L. 549 | 550 | =head2 3.9 Transfer Encoding 551 | 552 | This extension is only for HTTP/1.1 protocol connections. When the server supports this extension, it MUST provide a C variable containing a C naming the transfer encodings the server supports as strings. This SHOULD be set in the configuration environment. 553 | 554 | When the application returns a header named C with the name of one of the supported transfer encoding strings, the server MUST apply that transfer encoding to the message payload. If the connection is not HTTP/1.1, the server SHOULD ignore this header. 555 | 556 | =head3 3.9.0 Chunked Encoding 557 | 558 | When the server supports and the application requests "chunked" encoding. The application server SHOULD treat each emitted L or L as a chunk to be encoded according to L. It MUST adhere to requirements of RFC7230 when sending the response payload to the origin. 559 | 560 | =head3 3.9.1 Other Encodings 561 | 562 | All other encodings should be handled as required by the relevant rules for HTTP/1.1. 563 | 564 | =head3 3.10 HTTP/2 Push Promises 565 | 566 | When the C is "HTTP/2", servers SHOULD support the HTTP/2 push promises extension. However, applications SHOULD check to make sure that the C variable is set to a defined value before using this extension. 567 | 568 | This extension is implemented by providing a variable named C. When provided, this MUST be a L. 569 | 570 | When the application wishes to invoke a server push, it MUST emit a message describing the request the server is pushing. The application server will receive this request and make a new, separate call to the application to fulfill that request. 571 | 572 | Push-promise messages are sent as an L of Ls. This is a set of headers to send with the PUSH_PROMISE frame, including HTTP/2 pseudo-headers like ":path" and ":authority". 573 | 574 | Upon receiving a message to C, the server SHOULD schedule a followup call to the application to fulfill the push-promise as if the push-promise were an incoming request from the client. (The push-promise could be canceled by the client, so the call to the application might not actually happen.) 575 | 576 | =head1 4 Application Protocol Implementation 577 | 578 | One goal of RakuWAPI application servers is to allow the application to focus on building web applications without having to implement the mundane details of web protocols. In times past, this was simply a matter of implementing HTTP/1.x or some kind of front-end to HTTP/1.x (such as CGI or FastCGI). While HTTP/1.x is still relevant to the web today, new protocols have also become important to modern web applications, such as HTTP/2 and WebSocket. 579 | 580 | These protocols may have different interfaces that do not lend themselves to the request-response pattern specifed by PSGI. Therefore, we provide a means by which servers and applications may implement these alternate protocols, which each may have different requirements. These protocols are called D to differentiate them from network protocols. For example, rather than providing a protocol for HTTP, we provide the "request-response" protocol. The underlying network protocol may be HTTP/1.0, HTTP/1.1, HTTP/2 or it may be something else that operates according to a similar pattern. 581 | 582 | The application and application server SHOULD communicate according to the application protocol used for the current application call. Otherwise, they will be unable to communicate. For many applications, just implementing the basic protocol request-response protocol is enough. However, to allow for more complete applications, RakuWAPI provides additional tools to help application and application server to communicate through a variety of situations. This is handled primarily via the C, C, and C values in the environment. 583 | 584 | The application SHOULD check the value in C. The application SHOULD NOT make assumptions about the network protocol based upon the C value for the current request. If the application needs to make a decision based upon the network protocol, the application SHOULD check the C. 585 | 586 | The application SHOULD check C to discover which protocols are supported by the application server. An application that is not able to support all supported protocols SHOULD modify C to only include protocols supported by the application as early as possible. 587 | 588 | The application server MUST provide the C and C values as part of the configuration environment. The application server MUST NOT use any protocol that is not a member of the C set. If a protocol becomes disabled in the middle of a request, the request MUST continue, but subsequent requests MUST NOT use that protocol unless it is later enabled. 589 | 590 | This specification defines the following protocols: 591 | 592 | =item B for request-response protocols, including HTTP 593 | 594 | =item B for framed-socket protocols, such as WebSocket 595 | 596 | =item B for legacy PSGI applications 597 | 598 | =item B for raw, plain socket protocols, which send and receive data with no expectation of special server handling 599 | 600 | It is recommended that an application server that implements all of these protocols only enable the request-response protocol within C by default. This allows simple RakuWAPI applications to safely operate without having to perform any special configuration. 601 | 602 | =head2 4.0 Request-Response Protocol 603 | 604 | The "request-response" protocol SHOULD be used for any HTTP-style client-server web protocol, this include HTTP/1.x and HTTP/2 connections over plain text and TLS or SSL. 605 | 606 | =head3 4.0.0 Response 607 | 608 | Here is an example application that implements the "request-response" protocol: 609 | 610 | sub app(%env) { 611 | start { 612 | 200, 613 | [ Content-Type => 'text/plain' ], 614 | supply { 615 | emit "Hello World" 616 | }, 617 | } 618 | } 619 | 620 | An application MUST return a L. This Promise MUST be kept with a L (or something that becomes one on return) or MAY be broken. The Capture MUST contain 3 positional elements, which are the status code, the list of headers, and the response payload. 621 | 622 | =item The status code MUST be an L or object that coerces to an Int. It MUST be a valid status code for the L. 623 | 624 | =item The headers MUST be a L of Ls or an object that when coerced into a List becomes a List of Pairs. These pairs name the headers to return with the response. Header names MAY be repeated. 625 | 626 | =item The message payload MUST be a I L or an object that coerces into a I Supply, such as a L. 627 | 628 | Here is a more interesting example application demonstrating some of the power of this interface: 629 | 630 | sub app(%env) { 631 | start { 632 | my $n = %env.Int; 633 | 200, 634 | [ Content-Type => 'text/plain' ], 635 | supply { 636 | my $acc = 1.FatRat; 637 | for 1..$n -> $v { 638 | emit $acc *= $v; 639 | emit "\n"; 640 | } 641 | }, 642 | } 643 | } 644 | 645 | The example application above will print out all the values of factorial from 1 to N where N is given in the query string. The header is returned immediately, but the lines of the body are returned as the values of factorial are calculated. The asynchronous interface is concise and efficient. 646 | 647 | And here is an example demonstrating a couple ways in which coercion can be used by an application to improve readability: 648 | 649 | sub app(%env) { 650 | my enum HttpStatus (OK => 200, NotFound => 404, ServerError => 500); 651 | start { 652 | OK, [ Content-Type => 'text/plain' ], [ 'Hello World' ] 653 | } 654 | } 655 | 656 | In this example, the status is returned using an enumeration which coerces to an appropriate integer value. The payload is returned as a list, which is automatically coerced into a Supply. 657 | 658 | Applications SHOULD return a Promise as soon as possible. It is recommended that applications wrap all operations within a C block to make this automatic. 659 | 660 | Application servers SHOULD NOT assume that the returned L will be kept. It SHOULD assume that the Promise has been vowed and MUST NOT try to keep or break the Promise from the application. 661 | 662 | =head3 4.0.1 Response Payload 663 | 664 | The response payload, in the result of the application's promise, must be a I L. This supply MUST emit nothing for requests whose response must be empty. 665 | 666 | For any other request, the application MAY emit zero or more messages in the returned payload Supply. The messages SHOULD be handled as follows: 667 | 668 | =item L. Any Blob emitted by the application SHOULD be treated as binary data to be passed through to the origin as-is. 669 | 670 | =item L of Ls. Some response payloads may contain trailing headers. Any List of Pairs emitted should be treated as trailing headers. 671 | 672 | =item L. Any Associative object emitted should be treated as a message to communicate between layers of the application, middleware, and server. These should be ignored and passed on by middleware to the next layer unless consumed by the current middleware. Any message that reaches the application server but is not consumed by the application server MAY result in a warning being reported, but SHOULD otherwise be ignored. These objects MUST NOT be transmitted to the origin. 673 | 674 | =item L. Any other Mu SHOULD be stringified, if possible, and encoded by the application server. If an object given cannot be stringified, the server SHOULD report a warning. 675 | 676 | =head3 4.0.2 Encoding 677 | 678 | The application server SHOULD handle encoding of strings or stringified objects emitted to it. When performing encoding, the application server SHOULD honor the C set within the C header, if given. If it does not honor the C, it MUST encode any strings in the response payload according to the encoding named in C. 679 | 680 | =head3 4.0.3 Request-Response Lifecycle 681 | 682 | The server processes requests from an origin, passes the partially processed request information to the application by calling the application, waits for the application's response, and then returns the response to the origin. In the simplest example this means handling an HTTP roundtrip. Yet, it may also mean implementing a related protocol like CGI or FastCGI or SCGI or something else entirely. 683 | 684 | In the modern web, an application may want to implement a variety of complex HTTP interactions. These use-cases are not described by the typical HTTP request-response roundtrip with which most web developers are familiar. For example, an interactive Accept-Continue response or a data stream to or from the origin or an upgrade request to switch protocols. As such, application servers SHOULD make a best effort to be implemented in such a way as to make this variety applications possible. 685 | 686 | The application server SHOULD pass control to the application as soon as the headers have been received and the environment can be constructed. The application server MAY continue processing the request payload while the application server begins its work. The server SHOULD NOT emit the request payload to C yet. 687 | 688 | Once the application has returned the its L to respond, the server SHOULD wait until the promise is kept. Once kept, the server SHOULD tap the response payload as soon as possible. After tapping the Supply, the application server SHOULD keep the L in C (the application server SHOULD NOT break this Promise). Once that promise has been kept, only then SHOULD the server start emitting the contents of the request payload, if any, to C. 689 | 690 | The server SHOULD return the application response headers back to the origin as soon as they are received. After which, the server SHOULD return each chunk emitted by the response body from the application as soon as possible. 691 | 692 | This particular order of operations during the application call will ensure that the application has the greatest opportunity to perform well and be able to execute a variety of novel HTTP interactions. 693 | 694 | =head3 4.0.4 HTTP/1.1 Keep Alive 695 | 696 | When an application server supports HTTP/1.1 with keep-alive, each request sent on the connection MUST be handled as a separate call to the application. 697 | 698 | =head3 4.0.4 HTTP/2 Handling 699 | 700 | When a server supports HTTP/2 it SHOULD implement the HTTP/2 Push Promise Extension defined in section 3.10. An application server MAY want to consider implementing HTTP/2 protocol upgrades using the extension described in section 3.8 or MAY perform such upgrades automatically instead. 701 | 702 | The application MUST be called once for each request or push-promise made on an HTTP/2 stream. 703 | 704 | =head2 4.1 Framed-Socket Protocol 705 | 706 | The "framed-socket" protocol is appropriate for WebSocket-style peer-to-peer TCP connections. The following sections assume a WebSocket connection, but might be adaptable for use with other framed message exchanges, such as message queues or chat servers. 707 | 708 | =head3 4.1.0 Response 709 | 710 | Any application server implementing WebSocket MUST adhere to all the requirements described above with the following modifications when calling the application for a WebSocket: 711 | 712 | =item The C MUST be set to the HTTP method used when the WebSocket connection was negotiated, i.e., usually "GET". Similarly, C, C, C, C, C, C, C, and C variables in the environment MUST be set to the values from the original upgrade request sent from the origin. 713 | 714 | =item The C MUST be set to "WebSocket/13" or a similar string representing the revision of the WebSocket network protocol which in use. 715 | 716 | =item The C SHOULD be set to an undefined L. 717 | 718 | =item The C MUST be set to "ws" for plain text WebSocket connections or "wss" for encrypted WebSocket connections. 719 | 720 | =item The C MUST be set to "framed-socket". 721 | 722 | =item The server MUST decode frames received from the client and emit each of them to C. The frames MUST NOT be buffered or concatenated. 723 | 724 | =item The server's supplied C L must be I. The server SHOULD signal C through the Supply when either the client or server closes the WebSocket connection normally and C on abnormal termination of the connection. 725 | 726 | =item The server MUST encode frames emitted by the application in the message payload as data frames sent to the client. The frames MUST be separated out as emitted by the application without any buffering or concatenation. 727 | 728 | The application MUST return a L that is kept with just a L (i.e., not a 3-element Capture as is used with the request-response protocol). The application MAY break this Promise. The application will emit frames to send back to the origin using the promised Supply. 729 | 730 | =head3 4.1.1 Response Payload 731 | 732 | Applications MUST return a I L that emits an object for every frame it wishes to return to the origin. The application MAY emit zero or more messages to this supply. The application MAY emit C to signal that the connection is to be terminated with the client. 733 | 734 | The messages MUST be framed and returned to the origin by the application server as follows, based on message type: 735 | 736 | =item L. Any Blob emitted by the application SHOULD be treated as binary data, framed exactly as is, and returned to the client. 737 | 738 | =item L. Any Associative object emitted should be treated as a message to communicate between layers of the application, middleware, and server. These should be ignored and passed on by middleware to the next layer unless consumed by the current middleware. Any message that reaches the application server but is not consumed by the application server MAY result in a warning being reported, but SHOULD otherwise be ignored. These objects MUST NOT be transmitted to the origin. 739 | 740 | =item L. Any other Mu SHOULD be stringified, if possible, and encoded by the application server. If an object given cannot be stringified, the server SHOULD report a warning. 741 | 742 | =head3 4.1.2 Encoding 743 | 744 | The application server SHOULD handle encoding of strings or stringified objects emitted to it. The server MUST encode any strings in the message payload according to the encoding named in C. 745 | 746 | =head2 4.2 PSGI Protocol 747 | 748 | To handle legacy applications, this specification defines the "psgi" protocol. If C has both "psgi" and "request-response" enabled, the "request-response" protocol SHOULD be preferred. 749 | 750 | =head3 4.2.0 Response 751 | 752 | The application SHOULD return a 3-element L directly. The first element being the numeric status code, the second being an array of pairs naming the headers to return in the response, and finally an array of values representing the response payload. 753 | 754 | =head3 4.2.1 Payload 755 | 756 | The payload SHOULD be delivered as an array of strings, never as a supply. 757 | 758 | =head3 4.2.2 Encoding 759 | 760 | String encoding is not defined by this document. 761 | 762 | =head2 4.3 Socket Protocol 763 | 764 | The "socket" protocol can be provided by an application server wishing to allow the application to basically take over the socket connection with the origin. This allows the application to implement an arbitrary protocol. It does so, however, in a way that is aimed toward providing better portability than using the socket extension. 765 | 766 | The socket provided sends and receives data directly to and from the application without any framing, buffering, or modification. 767 | 768 | The "socket" protocol SHOULD only be used when it is enabled in C and no other protocol enabled there can fulfill the current application call. 769 | 770 | =head2 4.3.0 Response 771 | 772 | Here's an example application that implements the "socket" protocol to create a naïve HTTP server: 773 | 774 | sub app(%env) { 775 | start { 776 | supply { 777 | whenever %env -> $msg { 778 | my $req = parse-http-request($msg); 779 | 780 | if $req.method eq 'GET' { 781 | emit "200 OK HTTP/1.0\r\n"; 782 | emit "\r\n"; 783 | emit "Custom HTTP Server"; 784 | } 785 | } 786 | } 787 | } 788 | } 789 | 790 | The socket protocol behaves very much like "framed-socket", but with fewer specified details in the environment. Some of the mandatory environment are not mandatory for the socket protocol. 791 | 792 | The following parts of the environment SHOULD be provided as undefined values: 793 | 794 | =item REQUEST_METHOD 795 | 796 | =item SCRIPT_NAME 797 | 798 | =item PATH_INFO 799 | 800 | =item REQUEST_URI 801 | 802 | =item QUERY_STRING 803 | 804 | =item SERVER_NAME 805 | 806 | =item SERVER_PORT 807 | 808 | =item CONTENT_TYPE 809 | 810 | =item HTTP_* 811 | 812 | =item wapi.url-scheme 813 | 814 | =item wapi.ready 815 | 816 | =item wapi.body.encoding 817 | 818 | =item SERVER_PROTOCOL 819 | 820 | The C must be set to "socket". 821 | 822 | The application server SHOULD provide data sent by the origin to the application through the C supply as it arrives. It MUST still be a I supply. 823 | 824 | The application server MAY tunnel the connection through another socket, stream, file handle, or what-not. That is, the application MAY NOT assume the communication is being performed over any particular medium. The application server SHOULD transmit the data to the origin as faithfully as possible, keeping the intent of the application as much as possible. 825 | 826 | The application server SHOULD forward on data emitted by the application in the returned payload supply as it arrives. The application server SHOULD send no other data to the origin over that socket once the application is handed control, unless related to how the data is being tunneled or handled by the server. The application server SHOULD close the connection with the origin when the application server sends the "done" message to the supply. Similarly, the application server SHOULD send "done" the C supply when the connection is closed by the client or server. 827 | 828 | =head3 4.3.1 Response Payload 829 | 830 | Applications MUST return a I L which emits a string of bytes for every message to be sent. The messages returned on this stream MUST be L objects. 831 | 832 | =head3 4.3.2 Encoding 833 | 834 | The application server SHOULD reject any object other than a L sent as part of the message payload. The application server is not expected to perform any encoding or stringification of messages. 835 | 836 | =head1 Changes 837 | 838 | =head2 0.9.Draft 839 | 840 | =item The error stream is now defined to be a C object, defined in Section 1.1. 841 | 842 | =item Section 2.2.0.0 has been changed to forbid runtime routines from having a C return type. 843 | 844 | =item Section 2.1.2 was rewritten to disallow what was previously allowed: the modification of the input stream. 845 | 846 | =item Eliminated ambiguity regarding typing of environment in the middleware section. 847 | 848 | =item Added a section for type constraints and made better use of subset types to streamline and simplify some of the documentation. 849 | 850 | =item Cleaned up some old language left over from previous versions of the specification. 851 | 852 | =item Eliminated some ambiguities in the type required for undefined environment values. The undefined environment values MUST match the given type constraint and be set to type objects of that type if they are not defined. 853 | 854 | =item Changed the abbreviation from P6WAPI to RakuWAPI. 855 | 856 | =item Changed all C environment prefixes to C 857 | 858 | =item Changed all C environment prefixes to C 859 | 860 | =item Changed all C header names to C header names 861 | 862 | =item Renamed all example C<*.p6w> files to C<*.wapi> 863 | 864 | =head2 0.8.Draft 865 | 866 | =item Changed the abbreviation from P6W to P6WAPI. 867 | 868 | =head2 0.7.Draft 869 | 870 | =item Renamed the standard from Perl 6 Standard Gateway Interface (P6SGI) to the Web API for Perl 6 (P6W). 871 | 872 | =item Some grammar fixes, typo fixes, and general verbiage cleanup and simplification. 873 | 874 | =item Renaming C to C and C to C. 875 | 876 | =item The errors stream is now a C rather than a C because of recent changes to the Supply interface in Perl 6. Made other supply-related syntax changes because of design changes to S17. 877 | 878 | =item Eliminating the requirement that things emitted in the response payload be L if they are to be stringified and encoded. Any stringifiable L is permitted. 879 | 880 | =item Adding C, C, and C to handle server-to-application notification of the required response protocol. 881 | 882 | =item Breaking sections 2.0.4, 2.1.4, and 2.2.4 up to discuss the difference between the HTTP and WebSocket protocol response requirements. 883 | 884 | =item Moving 2.0.5, 2.1.5, and 2.2.5 under 2.*.4 because of the protocol changes made in 2.*.4. 885 | 886 | =item Changed C from an L to a L of supported protocol names. 887 | 888 | =item Split the environment and the application into two parts: configuration and runtime. 889 | 890 | =item Added Section 4 to describe protocol-specific features of the specification. Section 4.0 is for HTTP, 4.1 is for WebSocket, 4.2 is for PSGI, and 4.3 is for Socket. 891 | 892 | =head2 0.6.Draft 893 | 894 | =item Added Protocol-specific details and modifications to the standard HTTP/1.x environment. 895 | 896 | =item Adding the Protocol Upgrade extension and started details for HTTP/2 and WebSocket upgrade handling. 897 | 898 | =item Adding the Transfer Encoding extension because leaving this to the application or unspecified can lead to tricky scenarios. 899 | 900 | =head2 0.5.Draft 901 | 902 | =item Adding C and added the Application Lifecycle section to describe the ideal lifecycle of an application. 903 | 904 | =item Changed C and C to Supply objects. 905 | 906 | =item Porting extensions from PSGI and moving the existing extensions into the extension section. 907 | 908 | =item Adding some notes about middleware encoding. 909 | 910 | =item Renamed C to C. 911 | 912 | =item Renamed C to C. 913 | 914 | =item Added C as a new P6SGI extension. 915 | 916 | =head2 0.4.Draft 917 | 918 | =item Cutting back on some more verbose or unnecessary statements in the standard, trying to stick with just what is important and nothing more. 919 | 920 | =item The application response has been completely restructured in a form that is both easy on applications and easy on middleware, mainly taking advantage of the fact that a List easily coerces into a Supply. 921 | 922 | =item Eliminating the P6SGI compilation unit again as it is no longer necessary. 923 | 924 | =item Change the Supply to emit Cool and Blob rather than just Str and Blob. 925 | 926 | =head2 0.3.Draft 927 | 928 | =item Splitting the standard formally into layers: Application, Server, and Middleware. 929 | 930 | =item Bringing back the legacy standards and bringing back the variety of standard response forms. 931 | 932 | =item Middleware is given a higher priority in this revision and more explanation. 933 | 934 | =item Adding the P6SGI compilation unit to provide basic tools that allow middleware and possibly servers to easily process all standard response forms. 935 | 936 | =item Section numbering has been added. 937 | 938 | =item Added the Changes section. 939 | 940 | =item Use C prefixes in the environment rather than C 941 | 942 | =head2 0.2.Draft 943 | 944 | This second revision eliminates the legacy standard and requires that all P6SGI responses be returned as a L. The goal is to try and gain some uniformity in the responses the server must deal with. 945 | 946 | =head2 0.1.Draft 947 | 948 | This is the first published version. It was heavily influenced by PSGI and included interfaces based on the standard, deferred, and streaming responses of PSGI. Instead of callbacks, however, it used L to handle deferred responses and L to handle streaming. It mentioned middleware in passing. 949 | 950 | =end pod 951 | -------------------------------------------------------------------------------- /eg/100-continue.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | my $ok = %env eq 'text/csv' 7 | && %env 8 | && %env <= 1024 ** 2; 9 | 10 | my $expect-continue = %env ~~ 'HTTP/1.1'|'HTTP/2' 11 | && %env eq '100-continue'; 12 | 13 | if $expect-continue && !$ok { 14 | return 15 | 417, 16 | [ 17 | Content-Type => 'text/plain', 18 | Content-Length => 18, 19 | ], 20 | [ 'Expectation Failed' ] 21 | } 22 | 23 | my sub process-input { 24 | # process input here... 25 | 26 | 200, 27 | [ Content-Type => 'text/plain', Content-Length => 2 ], 28 | [ 'OK' ] 29 | } 30 | 31 | if $expect-continue { 32 | 100, 33 | [ ], 34 | on -> $out { 35 | my ($s, @h, Supply() $b) = process-input(); 36 | @h.push: ':status' => $s; 37 | $out.emit(@h); 38 | $b.do: -> $v { $out.emit($v) {; 39 | }; 40 | } 41 | else { 42 | process-input(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /eg/README.md: -------------------------------------------------------------------------------- 1 | # Examples README 2 | 3 | These examples were presented to Pittsburgh Perl Workshop 2015 as an [P6SGI 4 | RFC](https://speakerdeck.com/zostay/perl-6-standard-gateway-interface-ppw-2015). 5 | 6 | These examples are non-normative and (as of this writing) not tested to see if 7 | they compile or work at all. Hopefully, these will be updated with the state of 8 | the art at some point and/or moved somewhere else more appropriate. 9 | 10 | -------------------------------------------------------------------------------- /eg/block-ext.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | my $fh = "really-big-file.txt".IO.open(:r); 7 | 8 | 200, [ Content-Type => 'text/plain' ], 9 | on { 10 | %env => -> $yes { 11 | sleep 10 if $yes; 12 | }, 13 | $fh => -> $chars { 14 | # throws an exception when this promise is broken 15 | %env.result 16 | if %env.status ~~ Broken; 17 | 18 | .emit($chars); 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /eg/done-ext.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | 200, [ Content-Type => 'text/plain' ], 7 | on { 8 | await %env; 9 | .emit("HEADER WRITTEN OUT YAY!"); 10 | .done; 11 | await %env; 12 | 13 | %env.emit("BODY WRITTEN OUT YAY!"); 14 | 15 | # TODO Lame. Come up with something better. 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /eg/dump-env.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | 200, 7 | [ Content-Type => 'text/plain' ], 8 | [ %env.perl ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /eg/factorial-stream.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | 200, 7 | [ Content-Type => 'text/plain' ], 8 | Supply.on-demand(-> $content { 9 | my $acc = 1.FatRat; 10 | for 1..* -> $v { 11 | $content.emit($acc *= $v); 12 | $content.emit("\n"); 13 | } 14 | $content.done; 15 | }); 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /eg/factorial.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | my $n = %env.Int; 7 | 200, 8 | [ Content-Type => 'text/plain' ], 9 | on -> $content { 10 | my $acc = 1.FatRat; 11 | for 1..$n -> $v { 12 | $content.emit($acc *= $v); 13 | $content.emit("\n"); 14 | } 15 | $content.done; 16 | 17 | () 18 | }; 19 | }; 20 | } 21 | -------------------------------------------------------------------------------- /eg/hello.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | 200, 7 | [ Content-Type => 'text/plain' ], 8 | [ 'Hello World' ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /eg/psgi-delayed.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | my &app = sub (%env) { 5 | # Delays response until it fetches content from the network 6 | start { 7 | my $content = fetch-content-from-server(); 8 | 200, $headers, [ $content ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /eg/psgi-middleware.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | # &xheader is a piece of middleware that wraps some &app 5 | my &xheader = sub (%env) { 6 | nextsame.then(-> $r { 7 | my ($s, @h, $p) = $r.result; 8 | @h.push: 'P6SGI-Used' => 1; 9 | $s, @h, $p 10 | }); 11 | }; 12 | 13 | # &app is a simple PSGI application 14 | my &app = sub (%env) { 15 |     200, 16 |     [ Content-Type => 'text/plain' ], 17 |     [ "Hello World" ] 18 | }; 19 |   20 | &app.wrap(&xheader); 21 | -------------------------------------------------------------------------------- /eg/psgi-streaming.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | my &app = sub (%env) { 5 |     # immediately starts the response and stream the content 6 | start { 7 | my $events = wait-for-events(); 8 | 9 |         200, [ 'Content-Type' => 'application/json' ], 10 | $events.map({ .as-json ~ "\n" }); 11 |     } 12 | } 13 | -------------------------------------------------------------------------------- /eg/ready-check.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | 200, [ Content-Type => 'text/plain' ], 7 | on { 8 | await %env; 9 | for 0 .. * -> $n { .emit($n ~ "\n") } 10 | }; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /eg/simple.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | 200, 7 | [ Content-Type => 'text/plain' ], 8 | [ 42 ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /eg/te-chunked-mw.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | constant CHUNK-SIZE = 16384; 5 | constant CRLF = "\x0a\x0d"; 6 | 7 | sub app(%env) { 8 | start { 9 | my $file = "really-big-file.txt".IO; 10 | 200, [ 11 | Content-Type => 'text/plain', 12 | ], 13 | on -> $out { 14 | my $fh = $file.open(:r); 15 | while my $data = $fh.read(CHUNK-SIZE) { 16 | $out.emit($data); 17 | } 18 | $out.done; 19 | 20 | () 21 | }; 22 | } 23 | } 24 | 25 | sub mw(%env) { 26 | nextsame.then(-> $p { 27 | if %env eq 'HTTP/1.1' 28 | && %env ~~ /\<'chunked'\>/ { 29 | 30 | my ($s, List() $h, Supply() $payload) = $p.result; 31 | 32 | return $s, $h, $payload 33 | if $h.first(*.key eq 'Transfer-Encoding'); 34 | 35 | $h.append: Transfer-Encoding => 'chunked'; 36 | 37 | $s, $h, on -> $out { 38 | $payload => -> $data { 39 | $out.emit(CRLF ~ $data.bytes.base(16) ~ CRLF); 40 | $out.emit($data); 41 | }, 42 | }; 43 | } 44 | else { 45 | $p.result 46 | } 47 | }); 48 | } 49 | 50 | &app.wrap(&mw); 51 | &app; 52 | -------------------------------------------------------------------------------- /eg/te-chunked.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | constant CHUNK-SIZE = 16384; 5 | constant CRLF = "\x0a\x0d"; 6 | 7 | sub app(%env) { 8 | start { 9 | my $file = "really-big-file.txt".IO; 10 | if %env eq 'HTTP/1.1' 11 | && %env ~~ /\<'chunked'\>/ { 12 | 13 | 200, [ 14 | Content-Type => 'text/plain', 15 | Transfer-Encoding => 'chunked', 16 | ], 17 | on -> $out { 18 | my $fh = $file.open(:r); 19 | while my $data = $fh.read(CHUNK-SIZE) { 20 | $out.emit(CRLF ~ $data.bytes.base(16) ~ CRLF); 21 | $out.emit($data); 22 | } 23 | $out.done; 24 | 25 | () 26 | }; 27 | } 28 | else { 29 | 200, [ Content-Type => 'text/plain' ], $file.slurp; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /eg/time.wapi: -------------------------------------------------------------------------------- 1 | #!smack 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | 200, 7 | [ Content-Type => 'text/plain' ], 8 | [ time ] 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /eg/upgrade-ext-h2c.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | if %env eq 'HTTP/1.1' 7 | && %env ~~ /\/ 8 | && %env eq 'h2c' 9 | && any(|%env) ~~ 'h2c' { 10 | 11 | 101, [ P6SGIx-Upgrade => 'h2c' ], [] 12 | } 13 | 14 | if %env eq 'HTTP/2' { 15 | %env.emit([ 16 | ':method' => 'GET', 17 | ':scheme' => 'http', 18 | ':path' => 'foo.png', 19 | ]); 20 | } 21 | 22 | if %env eq '/index.html' { 23 | 200, [ 'Content-Type' => 'text/html' ], ... 24 | } 25 | elsif %env eq '/foo.png' { 26 | 200, [ 'Content-Type' => 'image/png' ], ... 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /eg/upgrade-ext-ws.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | if %env eq 'HTTP/1.1' 7 | && %env ~~ /\/ 8 | && %env eq 'websocket' 9 | && any(|%env) ~~ 'websocket' { 10 | 11 | 101, [ P6SGIx-Upgrade => 'websocket' ], [] 12 | } 13 | 14 | # echo service 15 | elsif %env eq 'websocket' { 16 | on -> $out { 17 | %env => -> $v { 18 | $out.emit($v); 19 | }; 20 | }; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /eg/upgrade-h2c.wapi: -------------------------------------------------------------------------------- 1 | #!smackup 2 | use v6; 3 | 4 | sub app(%env) { 5 | start { 6 | if %env ~~ /\/ && %env eq 'h2c' { 7 | 101, 8 | [ 9 | Connection => 'Upgrade', 10 | Upgrade => 'h2c' 11 | ], 12 | on -> $out { 13 | # beginning reading HTTP/2 frames and output HTTP/2 frames 14 | }; 15 | } 16 | else { 17 | ... 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /fixup-markdown: -------------------------------------------------------------------------------- 1 | #!perl6 2 | 3 | use v6; 4 | 5 | # Pod::To::Markdown still has some weaknesses. This script fixes various 6 | # problems with the generated markdown for the README.md generated by this 7 | # standard: 8 | # 9 | # * Fixes unprocessed C<< >> and C< > code highlights in tables 10 | # * Directs class doc links to doc.perl6.org 11 | # * Makes the code blocks into github ```perl6``` style code blocks 12 | 13 | my Bool $in-html = False; 14 | my Bool $in-code = False; 15 | my Int $indent = 0; 16 | my Str $on-hold = ''; 17 | for $*ARGFILES.lines -> $_ is copy { 18 | 19 | $in-html = True if $_ eq ''; 20 | $in-html = False if $_ eq '
'; 21 | 22 | if /^(\s+) "*"/ { 23 | $indent = $0.chars - 1; 24 | } 25 | 26 | if /^\S/ { 27 | $indent = 0; 28 | } 29 | 30 | if $in-code && !m/^\s ** {$indent + 4}/ && m/^\s*\S/ { 31 | $in-code = False; 32 | $on-hold.=subst(/\s+$/, ''); 33 | say $on-hold; 34 | $on-hold = ''; 35 | say ' ' x $indent + 4*?$indent, "```\n"; 36 | } 37 | 38 | if !$in-html && !$in-code && /^\s ** {$indent + 4}/ { 39 | $in-code = True; 40 | say ' ' x $indent + 4*?$indent, "```perl6"; 41 | } 42 | 43 | if $in-code { 44 | $on-hold ~= $_ ~ "\n"; 45 | next; 46 | } 47 | 48 | # Fixup unprocessed C<<>> and C<> tags 49 | .=subst(/ 50 | "C<<" ( [ <-[ & ]> | "&" ]+ ) ">>" 51 | | "C<" ( [ <-[ & ]> | "&" ]+ ) ">" 52 | /, { "{($0 // $1).trim}" }, :g); 53 | 54 | # Fixup unprocessed links 55 | .=subst(/ 56 | 'L<' ( <[ \w \s ]>+ ) '|' ( [ <-[ & ]> | "&" ]+ ) '>' 57 | /, { qq|{$0}| }, :g); 58 | 59 | # Pod::To::Markdown does not handle links well at all 60 | sub url($n) { 61 | given $n { 62 | when 'CGI' { 'http://www.w3.org/CGI/' } 63 | when 'Rack' { 'http://www.rubydoc.info/github/rack/rack/master/file/SPEC' } 64 | when 'WSGI' { 'https://www.python.org/dev/peps/pep-0333/' } 65 | when 'PSGI' { 'https://metacpan.com/pod/PSGI' } 66 | default { "http://doc.perl6.org/type/$n" } 67 | } 68 | } 69 | 70 | .=subst(/ 71 | 'L<' ( <[ \w : ]>+ ) '>' 72 | /, { qq|{$0}| }, :g); 73 | 74 | # Find links [word](word) and make them [word](http://doc.perl6.org/type/word) 75 | .=subst(/ 76 | '[' ( \w+ ) '](' $0 ')' 77 | /, { "[$0]({url($0)})" }, :g); 78 | 79 | .say; 80 | } 81 | --------------------------------------------------------------------------------