OWIN — Open Web Server Interface for .NET, v1.0 Draft 5

Contents

Overview

This document defines OWIN, a standard interface between .NET web servers and web applications. The goal of OWIN is to decouple server and application and, by being an open standard, stimulate the open source ecosystem of .NET web development tools.

OWIN is defined in terms of a delegate structure. There is no assembly called OWIN.dll or similar. Implementing either the host or application side the OWIN spec does not introduce a dependency to a project.

In this document, the C# Action/Func syntax is used to notate the delegate structure. However, the delegate structure could be equivalently represented with F# native functions, CLR interfaces, or named delegates. This is by design; when implementing OWIN, choose a delegate representation that works for you and your stack.

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.

Normative sections are highlighted with a red outline, important notes are highlighted with yellow.

Definition

In this document, an OWIN-compatible web server is referred to as a "host", and an instance of an application delegate (described below) is referred to as an "application". Broadly speaking, a host invokes an application (providing as arguments an environment dictionary, and response and error callbacks); an application either provides a response to the host by invoking the response callback with response information, or indicates an error by invoking the error callback with an exception.

How an application is provided to a host is outside the scope of this specification and must be documented by the host implementor.

Application Delegate

The primary interface in OWIN is called the application delegate. An application delegate takes three parameters: an environment dictionary, a response callback, and an error callback.

Action<
    // an environment dictionary containing host and request data
    IDictionary<string, object>, 
    
    // response callback
    Action<
		string, // response status, e.g., "200 OK"
		IDictionary<string, string>, // response headers
		[a body delegate] // response body, as represented by a body delegate (described below)
	>, 
    
    // error callback
    Action<Exception>
>

Environment Dictionary

When a host invokes an application delegate, it provides the application with an environment dictionary. The environment dictionary represents the request the application is to process.

An environment dictionary must be mutable and must contain the keys in the table below. The values of the keys must be non-null, unless otherwise specified.


"owin.RequestMethod" A string containing the HTTP request method of the request (e.g., "GET", "POST").
"owin.RequestPath" A string containing the request path. The path must be relative to the "root" of the application delegate; see Paths.
"owin.RequestPathBase" A string containing the portion of the request path corresponding to the "root" of the application delegate; see Paths. The value may be an empty string.
"owin.RequestQueryString" A string containing the query string component of the HTTP request URI (e.g., "foo=bar&baz=quux"). The value may be an empty string.
"owin.RequestHeaders" An instance of IDictionary<string, string> which represents the HTTP headers present in the request (the request header dictionary); see Headers.
"owin.RequestBody" An instance of the body delegate representing the body of the request. May be null.
"owin.RequestScheme" A string containing the URI scheme used for the request (e.g., "http", "https"); see URI Scheme.
"owin.Version" The string "1.0" indicating OWIN version 1.0.

In addition to these keys, the host, application, or user may add arbitrary data associated with the request to the environment dictionary.

Response Callback

The response callback of the application delegate takes three arguments. The first is a string object representing the response status; the second is an instance of IDictionary<string, string> representing the response headers; the third is a body delegate representing the response body. These arguments together represent an HTTP response generated by an application.

Headers

The headers of HTTP messages are represented by objects of type IDictionary<string, string>. Request headers are contained within the environment dictionary, and response headers are provided to the response callback.

Common header dictionary requirements

The requirements below are predicated on RFC 2616 section 4.2.

Request header dictionary requirements

Response header dictionary requirements

Body Delegate

The body delegate is the mechanism which transfers entity data between host and application. It is used for both request and response entities in OWIN. Code sending data using the delegate is called the "producer", and code receiving data using the delegate is called the "consumer". In the context of a request, the host plays the role of producer; in the context of a response, the application plays the role of producer.

An instance of the delegate is implemented by a producer; a consumer invokes the delegate and provides it on-next, on-error, and on-complete callbacks. The return value of the body delegate is a cancellation delegate, which allows the consumer to instruct the producer not to produce any further values.

The body delegate is equivalent to IObserver/IObservable, except for a modified on-next callback signature. In addition to taking a data value parameter, the on-next callback takes a continuation parameter, and returns a boolean value indicating whether or not it will invoke the continuation.

Func<
	
	// on next
	Func<
		ArraySegment<byte>, // data
		Action, // continuation
		bool // will invoke continuation
	>,
 	
	// on error
	Action<Exception>,
	
	// on complete
	Action,
	
	// cancel 
	Action 
>

The signature of the on-next callback allows the consumer to instruct the producer to "back off" and not produce values for a time (specifically, until the consumer invokes the continuation). Without this backpressure mechanism, a producer could potentially produce values faster than a consumer could process them without buffering, and the buffer could grow unbounded.

In general, a consumer should not invoke a body delegate more than once. While a "repeatable" producer is possible, consumers should not assume that a producer is repeatable and producers may not support repeatability.

Instances of ArraySegment<byte> provided to consumers should be considered internal to the producer implementation and are guaranteed to be valid only for the duration of the on-next callback. Once the on-next callback returns, the ArraySegment<byte> may be invalid. If a consumer wishes to retain the data it should copy it out of the buffer before the on-next callback returns.

URI Reconstruction

Applications often require the ability to reconstruct the complete URI of a request. This process cannot be perfect since HTTP clients do not usually transmit the complete URI which they are requesting, but OWIN makes provisions for the purpose of reconstructing the URI of a request.

URI Scheme

This information is usually not transmitted by an HTTP client and, depending on network configuration, it may not be possible for an OWIN host to determine a correct value. In these cases, the user may have to manually configure or compute a value.

Hosts must provide a best-guess value for "owin.RequestScheme".

Hostname

In the context of an HTTP/1.1 request, the name of the host to which the client is making a request is usually indicated in the Host header field-value of the request, although it might be specified using an absolute Request-URI (see RFC 2616, sections 5.1.2, 19.6.1.1).

A host must provide a value for the "Host" key in the request header dictionary. The format of the value must be "<hostname>[:<port>]". The value must be deduced by the host using the following steps:

  1. If the Request-URI of the incoming request is an absolute URI, the value of the "Host" key must be taken from the host part of the absolute URI.
  2. If the Request-URI of the incoming request is not an absolute URI, the value of the "Host" key must be taken from the Host header field-value of the incoming request.
  3. If the Host header is not present in the incoming request (as in an HTTP/1.0 request), or if its value consists entirely of linear whitespace, the server must provide a sensible best-guess value for the "Host" key.

Paths

Hosts may have the ability to map application delegates to some base path. For example, a host might have an application delegate configured to respond to requests beginning with "/my-app", in which case it should set the value of "owin.RequestPathBase" in the environment dictionary to "/my-app". If this host receives a request for "/my-app/foo", the owin.RequestPath value of the environment dictionary provided to the application configured to respond at "/my-app" should be "/foo".

URI Reconstruction Algorithm

The following algorithm can be used to reconstruct the complete URI of the current request:

var uri =
  (string)env["owin.RequestScheme"] + 
  "://" +
  ((IDictionary<string, string>)env["owin.RequestHeaders"])["Host"] +
  (string)env["owin.RequestPathBase"] +
  (string)env["owin.RequestPath"];
	
if (env["owin.QueryString"] != "")
  uri += "?" + (string)env["owin.QueryString"];

The result of this algorithm may not be identical to the URI the client used to make the request; for example, the host may have done some rewriting to canonicalize the request. Further, it is subject to the caveats described in the URI Scheme and Hostname sections above.

Error Handling

Application Errors

An application may generate an exception in the following places:

An application should attempt to trap its own internal errors and generate an appropriate (possibly 500-level) response rather than propagating an exception up to the host.

After an application provides a response, if the response body delegate is non-null, the host should wait to receive least one on-next callback from the the response body delegate before writing the response headers to the underlying transport. In this way, if instead of an on-next callback the host gets an on-error callback, the host will be able to generate a 500-level response. If the host gets an on-next callback first, it can safely assume that the application has caught as many of its internal errors as possible; the host can begin the response without further buffering. If an on-error callback is subsequently received, the host may write a textual description of the error to the underlying transport, and/or close the connection.

Host Errors

A host may generate exceptions in the following places:

An exception generated in either of these places may indicate that the client has closed or dropped the connection, or another transport-layer error has occurred.

If an application receives an error from a host, it must propagate it back to the host through one of the sites described in Application Errors.

There are several other points where an application might call into the host but cannot meaningfully handle an exception from thrown from the call.

A host should not generate exceptions in the following places: