Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

updated spec

  • Loading branch information...
commit 0fea45e32a8c8733d209094fb4421155b380aac7 1 parent b771017
Benjamin van der Veen authored
Showing with 89 additions and 17 deletions.
  1. +89 −17 index.html
View
106 index.html
@@ -13,20 +13,41 @@
<h1>OWIN &mdash; Open Web Interface for .NET, v1.0 Draft</h1>
<ul>
<li>Author: <a href="http://bvanderveen.com">Benjamin van der Veen</a></li>
- <li>Last updated: 9 December 2010</li>
+ <li>Last updated: 11 December 2010</li>
<li>Discussion: <a href="http://groups.google.com/group/net-http-abstractions">.NET HTTP Abstractions</a></li>
</ul>
+<h2>Contents</h2>
+<ul>
+ <li><a href="#Overview">Overview</a></li>
+ <li><a href="#Definition">Definition</a>
+ <ul>
+ <li><a href="#IApplication"><code>IApplication</code></a></li>
+ <li><a href="#IRequest"><code>IRequest</code></a></li>
+ <li><a href="#IResponse"><code>IResponse</code></a></li>
+ </ul>
+ </li>
+ <li><a href="#Paths">Paths</a></li>
+ <li><a href="#ErrorHandling">Error Handling</a>
+ <ul>
+ <li><a href="#ApplicationErrors">Application Errors</a></li>
+ <li><a href="#HostErrors">Host Errors</a></li>
+ </ul>
+ </li>
+ <li><a href="#Acknowledgements">Acknowledgements</a></li>
+</ul>
+<a name="Overview"></a>
<h2>Overview</h2>
-<p>This document defines a standard interface between .NET web servers and web applications. The goal of the OWIN interface is to decouple server and application, encourage the development of simple modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.</p>
+<p>This document defines a standard interface between .NET web servers and web applications. The goal of the OWIN interface is to decouple server and application, encourage the development of simple "middleware" modules for .NET web development, and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.</p>
-<p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119. For readability, these words do not appear in all uppercase letters in this specification.</p>
+<p>The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.</p>
+<a name="Definition"></a>
<h2>Definition</h2>
-<p>OWIN comprises three core interfaces: <code>IApplication</code>, <code>IRequest</code>, and <code>IResponse</code>. Broadly speaking, hosts provide application objects with request objects, and application objects provide response objects back to the server. In this document, an OWIN-compatible web server is referred to as a "host", and an object implementing <code>IApplication</code> is referred to as an "application". How an application is provided to a host is outside the scope of this specification.</p>
+<p>OWIN comprises three core interfaces: <code>IApplication</code>, <code>IRequest</code>, and <code>IResponse</code>. In this document, an OWIN-compatible web server is referred to as a "host", and an object implementing <code>IApplication</code> is referred to as an "application". Broadly speaking, hosts provide application objects with request objects, and application objects provide response objects back to the host. How an application is provided to a host is outside the scope of this specification and must be documented by the host implementor.</p>
<a name="IApplication"></a>
<h3>IApplication</h3>
@@ -38,7 +59,9 @@
}
</code></pre>
-<p>Applications generate responses to requests received by a host by implementing the <code>IApplication</code> interface, which defines single asynchronous operation returning IResponse. The asynchronous operation uses the IAsyncResult pattern (see: <a href="http://msdn.microsoft.com/en-us/library/ms228963.aspx">MSDN Asynchronous Programming Overview</a>). Applications must invoke the <code>AsyncCallback</code> and return a non-null response object or throw an exception from <code>EndInvoke</code>, or throw an exception from <code>BeginInvoke</code>. </p>
+<p>An application generates a response to a request received by a host by implementing the <code>IApplication</code> interface. This interface defines a single asynchronous operation returning IResponse. The asynchronous operation uses the IAsyncResult pattern (see: <a href="http://msdn.microsoft.com/en-us/library/ms228963.aspx">MSDN Asynchronous Programming Overview</a>).</p>
+
+<p>The hosts must call the <code>BeginInvoke</code> method with a non-null <code>IResponse</code> object and a non-null <code>AsyncCallback</code>. The application must either throw an exception from <code>BeginInvoke</code>, or invoke the <code>AsyncCallback</code> in response to the call to <code>BeginInvoke</code>. The host must call <code>EndInvoke</code> in response to the <code>AsyncCallback</code>. The <code>EndInvoke</code> method must return a non-null response object or throw an exception.</p>
<a name="IRequest"></a>
<h3>IRequest</h3>
@@ -62,13 +85,13 @@
<p>The <code>Headers</code> property is a dictionary whose items correspond to HTTP headers in the request. Keys must be header names without <code>':'</code> or whitespace, and the keys must be case-insensitive. Values are <code>IEnumerable&lt;string&gt;</code> sequences containing the corresponding header value strings, without newlines. If a header appears in a request multiple times, the sequence value for that key must contain a number of elements corresponding to the number of times the header appears in the request, with each element being a value of a single header.</p>
-<p>The methods <code>BeginReadBody</code> and <code>EndReadBody</code> define an asynchronous operation which reads body data of the request into a destination buffer. Hosts must return from the <code>EndReadBody</code> method the number of bytes copied into the destination as a result of the read operation. Hosts must signal the end of the request body by returning 0 from <code>EndReadBody</code>.</p>
+<p>The <code>BeginReadBody</code> and <code>EndReadBody</code> methods define an asynchronous operation which reads body data of the request into a destination buffer. Applications must provide a valid destination buffer and a non-null <code>AsyncCallback</code> to the <code>BeginReadBody</code> method. Hosts must either throw an exception from <code>BeginReadBody</code>, or invoke the <code>AsyncCallback</code> in response to the call to <code>BeginReadBody</code>. The application must call <code>EndReadBody</code> in response to the <code>AsyncCallback</code>. The <code>EndReadBody</code> method must return the number of bytes copied into the destination buffer as a result of the read operation, or return 0 to signal the end of the request body, or throw an exception. If either <code>BeginReadBody</code> or <code>EndReadBody</code> throw an exception, the application must propagate the error back to the host. See <a href="#ErrorHandling">Error Handling</a>.</p>
<p>The <code>Items</code> property is a bag in which the host, application, or user can store arbitrary data associated with the request. Hosts should provide the following keys in <code>Items</code>:</p>
<ul>
<li><code>owin.BaseUri</code> &mdash; The portion of the request URI's path corresponding to the "root" of the application object. See <a href="#Paths">Paths</a>.</li>
-<li><code>owin.ServerName</code>, <code>owin.ServerPort</code> &mdash; Hosts should provide values can be used to reconstruct the full URL of the request in absence of the HTTP <code>Host</code> header of the request.</li>
+<li><code>owin.ServerName</code>, <code>owin.ServerPort</code> &mdash; Hosts should provide values which can be used to reconstruct the full URL of the request in absence of the HTTP <code>Host</code> header of the request.</li>
<li><code>owin.UriScheme</code> &mdash; <code>"http"</code> or <code>"https"</code></li>
<li><code>owin.RemoteEndPoint</code> &mdash; A <code>System.Net.IPEndPoint</code> representing the connected client.</li>
</ul>
@@ -88,7 +111,7 @@
<p>The <code>Headers</code> property is a dictionary representing the headers to be sent with the request. Keys must be header names without <code>':'</code> or whitespace. Values must be <code>IEnumerable&lt;string&gt;</code> sequences containing the corresponding header value strings, without newlines. If the sequence value for a header name contains multiple elements, the host must write a header name-value line with that name once for each value in the sequence. All characters in header name and value strings should be within the ASCII codepage.</p>
-<p>The <code>GetBody</code> method may an enumerable which represents the body data or null. Each element in the enumerable must be of one of the following types:</p>
+<p>The <code>GetBody</code> method may an enumerable which represents the body data, or null. Each element in the enumerable must be of one of the following types:</p>
<ul>
<li><code>byte[]</code></li>
@@ -97,7 +120,7 @@
<li><code>Task&lt;T&gt;</code>, where <code>T</code> is one of the above types.</li>
</ul>
-<p>Hosts must write both <code>byte[]</code> and <code>ArraySegment&lt;byte&gt;</code> as raw data. <code>FileInfo</code> must cause the host to write the named file to the underlying transport. How relative file paths are resolved is outside the scope of this specification. After all of the items have been enumerated or if an error occurs during enumeration, the host must call the <code>Dispose</code> of the enumerator.</p>
+<p>Hosts must write both <code>byte[]</code> and <code>ArraySegment&lt;byte&gt;</code> to the underlying transport as raw data. <code>FileInfo</code> must cause the host to write the named file to the underlying transport. How relative file paths are resolved is outside the scope of this specification and must be documented by the host implementor. After all of the items have been enumerated or if an error occurs during enumeration, the host must call the <code>Dispose</code> of the enumerator.</p>
<p>[TODO] Discuss <code>Task&lt;T&gt;</code>.</p>
@@ -112,11 +135,12 @@
<a name="ApplicationErrors"></a>
<h3>Application Errors</h3>
-<p>Applications may throw exceptions in the following places:</p>
+<p>An application might throw an exception in the following places:</p>
<ul>
<li>The <code>IApplication.BeginInvoke</code> method</li>
<li>The <code>IApplication.EndInvoke</code> method</li>
+<li>The <code>AsyncCallback</code> provided to <code>BeginReadBody</code>
<li>The <code>IResponse.GetBody</code> method</li>
<li>The <code>GetEnumerator</code> method of the <code>IEnumerable&lt;object&gt;</code> returned by <code>IResponse.GetBody</code></li>
<li>The <code>MoveNext</code> method of the enumerator returned by the <code>GetEnumerator</code> method of the <code>IEnumerable&lt;object&gt;</code> returned by <code>IResponse.GetBody</code></li>
@@ -124,10 +148,9 @@
<li>[TODO] Discuss Task&lt;T&gt; exceptions</li>
</ul>
-<p>Host implementations should strive to write response data to the network as "late" as possible, so as to be able to handle as many errors from the application as possible and cleanly send the client a 500-level response. Generally, this means invoking the application and enumerating the first object from its response body, if any, before writing any header or body data to the network. If an exception is thrown from the application before data is written to the network, the server should provide a 500-level response. If an exception is thrown while enumerating subsequent items from the response body enumerable, the host may append a textual description of the error to the response data which it has already sent and close the connection.</p>
-
-<p>If an uncaught error occurs during the <code>Invoke</code> operation of an application, the application must invoke the <code>AsyncCallback</code> provided by the host and throw an exception from <code>EndInvoke</code>, effectively propagating the exception back to the host.</p>
-
+<p>An application should make every attempt to trap its own internal errors and generate an appropriate (possibly 500-level) response rather than throwing an exception up to the host. Before writing the response headers to the underlying transport, the host must call <code>GetBody</code> and if the return value is a non-null enumerable containing at least one item, the host must enumerate at least one item from the enumerable. This allows the application to guarantee that it has caught as many of its internal errors as possible; that the host can begin the response without further buffering. If an exception is thrown by the application while enumerating subsequent items from the response body enumerable, the host may write a textual description of the error to the underlying transport, and/or close the connection.</p>
+
+
<a name="HostErrors"></a>
<h3>Host Errors</h3>
@@ -138,11 +161,60 @@
<li>The <code>IRequest.EndReadBody</code> method</li>
</ul>
-<p>An exception from either of these methods may indicates that the client has closed or dropped the connection, or another transport-layer error has occurred. The application should perform any post-mortem logic it needs to, and must propagate the exception back to the host through one of the calls described in <a href="#ApplicationErrors">Application Errors</a>.</p>
+<p>Hosts must not throw exceptions from the <code>AsyncCallback</code> provided to the application through the <code>BeginInvoke</code> method.</p>
-<h2>Acknowledgments</h2>
+<p>An exception from either of these methods may indicate that the client has closed or dropped the connection, or another transport-layer error has occurred. The application should perform any post-mortem logic it needs to, and must propagate the exception back to the host through one of the calls described in <a href="#ApplicationErrors">Application Errors</a>.</p>
+
+<a name="Examples"></a>
+<h2>Examples</h2>
+
+<pre><code>public class HelloApp : IApplication
+{
+ public IAsyncResult BeginInvoke(IRequest request, AsyncCallback callback, object state)
+ {
+ callback(null);
+ return null;
+ }
+
+ IResponse EndInvoke(IAsyncResult result)
+ {
+ return new HelloResponse();
+ }
+}
-<p>This specification draws heavily on the wonderful <a href="http://www.python.org/dev/peps/pep-0333/">PEP 333 (WSGI)</a>. Many thanks to everyone participating in the discussion at <a href="http://groups.google.com/group/net-http-abstractions">.NET HTTP Abstractions</a>, and in particular <a href="http://twitter.com/panesofglass">Ryan Riley</a> and <a href="http://twitter.com/serialseb">Sebastien Lambla</a>.</p>
+class HelloResponse : IResponse
+{
+ public string Status
+ {
+ get { return "200 OK"; }
+ }
+
+ public IDictionary&lt;string, IEnumerable&lt;string&gt;&gt; Headers
+ {
+ get
+ {
+ return new Dictionary&lt;string, IEnumerable&lt;string&gt;&gt;() {
+ { "Content-Type", new string[] { "text/html" } },
+ { "Content-Length", new string[] { "13" } }
+ };
+ }
+ }
+
+ public IEnumerable&lt;object&gt; GetBody()
+ {
+ yield return Encoding.UTF8.GetBytes("Hello, world!");
+ }
+}
+</code></pre>
+
+<a name="Acknowledgements"></a>
+<h2>Acknowledgments</h2>
+<p>This specification draws heavily on the wonderful <a href="http://www.python.org/dev/peps/pep-0333/">PEP 333 (WSGI)</a>. Many thanks to everyone participating in the discussion at <a href="http://groups.google.com/group/net-http-abstractions">.NET HTTP Abstractions</a>, and in particular:
+ <ul>
+ <li><a href="http://twitter.com/panesofglass">Ryan Riley</a></li>
+ <li><a href="http://twitter.com/serialseb">Sebastien Lambla</a></li>
+ <li><a href="http://jdhardy.blogspot.com/">Jeff Hardy</a></li>
+ </ul>
</body>
</html>
Please sign in to comment.
Something went wrong with that request. Please try again.