Abstract

This specification defines a mechanism for an HTML document to discover and subsequently communicate with HTTP-based services advertised via common discovery protocols within the current network.

Status of This Document

This section describes the status of this document at the time of its publication. Other documents may supersede this document. A list of current W3C publications and the latest revision of this technical report can be found in the W3C technical reports index at http://www.w3.org/TR/.

This version of the specification is an update to the previously published 24 September 2013 Working Draft version of the same document.

A full change log is available for this specification and a full HTML diff is also available. Significant changes from the previously published working draft include updates to the privacy and security considerations of this API, adding CORS support and the preliminary CORS check procedure, improvements to garbage collection and other minor technical clarifications.

This document was published by the Device APIs Working Group as a Working Draft. This document is intended to become a W3C Recommendation. If you wish to make comments regarding this document, please send them to public-device-apis@w3.org (subscribe, archives). All comments are welcome.

Publication as a Working Draft does not imply endorsement by the W3C Membership. This is a draft document and may be updated, replaced or obsoleted by other documents at any time. It is inappropriate to cite this document as other than work in progress.

This document was produced by a group operating under the 5 February 2004 W3C Patent Policy. W3C maintains a public list of any patent disclosures made in connection with the deliverables of the group; that page also includes instructions for disclosing a patent. An individual who has actual knowledge of a patent which the individual believes contains Essential Claim(s) must disclose the information in accordance with section 6 of the W3C Patent Policy.

Table of Contents

1. Introduction

This section is non-normative.

This specification defines the NavigatorNetworkService interface to enable Web pages to connect and communicate with Local-networked Services provided over HTTP. This enables access to services and content provided by home network devices, including the discovery and playback of content available to those devices, both from services such as traditional broadcast media and internet based services as well as local services. Initial design goals and requirements provided by the W3C Web & TV interest group are documented in [hnreq].

Using this API consists of requesting a well-known service type, known by developers and advertised by Local-networked Devices. User authorization, where the user connects the web page to discovered services, is expected before the web page is able to interact with any Local-networked Services.

A web page creates a request to obtain connectivity to services running in the network by specifying a well-known discovery service type that it wishes to interact with.

The user agent, having captured all advertised services on the network from the service discovery mechanisms included in this recommendation, attempts to match the requested service type to a discovered service according to the processing described herein. Only Local-networked Services that pass a preliminary CORS check should be made available to web pages by a user agent. A user agent may provide a way for users to white-list non-CORS enabled Local-networked Services but implementation of such a feature is left to the discretion of the implementer.

If a service connectivity request is successful then the Web page is provided with a promise-based success callback with the all necessary information to communicate with the authorized Local-networked Service. If the request fails then the Web page will receive a promise-based error callback containing an error string describing the cause of Local-networked Service connectivity failure.

Once connected to a Local-networked Service the Web page can send requests and receive responses to the Local-networked Service via the messaging format and appropriate channel inferred from the service type authorized via the provided API. The Web page, once connected, can also receive service-pushed events, in the messaging format supported by the Local-networked Device, if such event subscription functionality is provided by the connected Local-networked Service.

Services available within the local network can connect and disconnect at different times during the execution of a web page. The user agent can inform a web page when the state of networked services matching any of the requested valid service types change. Web pages can use this information to enable in-page experiences for communicating the state of networked services with the ability to change the particular service or set of services the page is connected to (by re-invoking the getNetworkServices() method defined herein).

Example of requesting a DNS-SD advertised service:


function showServices( services ) {
  // Show a list of all the services provided to the web page
  for(var i = 0, l = services.length; i < l; i++) console.log( services[i].name );
}

navigator.getNetworkServices('zeroconf:_boxee-jsonrpc._tcp').then(showServices);

Example of requesting a UPnP advertised service, also handling error conditions:


function showServices( services ) {
  // Show a list of all the services provided to the web page
  for(var i = 0, l = services.length; i < l; i++) console.log( services[i].name );
}

function error( e ) {
  console.log( "Error occurred: " + e.name );
}

navigator.getNetworkServices('upnp:urn:schemas-upnp-org:service:ContentDirectory:1').then(showServices, error);

Example of requesting either a DNS-SD or UPnP advertised service:


function showServices( services ) {
  // Show a list of all the services provided to the web page (+ service type)
  for(var i = 0, l = services.length; i < l; i++)
     console.log( services[i].name + '(' + services[i].type + ')' );
}

navigator.getNetworkServices([
  'zeroconf:_boxee-jsonrpc._tcp',
  'upnp:urn:schemas-upnp-org:service:ContentDirectory:1'
]).then(showServices);

For more detailed examples, including examples of communicating with obtained networked services, see the Examples section.

2. Conformance

As well as sections marked as non-normative, all authoring guidelines, diagrams, examples, and notes in this specification are non-normative. Everything else in this specification is normative.

The key words MUST, MUST NOT, REQUIRED, SHOULD, SHOULD NOT, RECOMMENDED, MAY, and OPTIONAL in this specification are to be interpreted as described in [RFC2119].

Requirements phrased in the imperative as part of algorithms (such as "strip any leading space characters" or "return false and abort these steps") are to be interpreted with the meaning of the key word ("must", "should", "may", etc) used in introducing the algorithm.

Some conformance requirements are phrased as requirements on attributes, methods or objects. Such requirements are to be interpreted as requirements on user agents.

Conformance requirements phrased as algorithms or specific steps MAY be implemented in any manner, so long as the end result is equivalent. (In particular, the algorithms defined in this specification are intended to be easy to follow, and not intended to be performant.)

The only conformance class defined by this specification is a user agent.

User agents MAY impose implementation-specific limits on otherwise unconstrained inputs, e.g. to prevent denial of service attacks, to guard against running out of memory, or to work around platform-specific limitations.

When support for a feature is disabled (e.g. as an emergency measure to mitigate a security problem, or to aid in development, or for performance reasons), user agents MUST act as if they had no support for the feature whatsoever, and as if the feature was not mentioned in this specification. For example, if a particular feature is accessed via an attribute in a Web IDL interface, the attribute itself would be omitted from the objects that implement that interface - leaving the attribute on the object but making it return null or throw an exception is insufficient.

2.1 Dependencies

This specification relies on several other underlying specifications.
HTML
Many fundamental concepts from HTML are used by this specification. [HTML5]
WebIDL
The IDL blocks in this specification use the semantics of the WebIDL specification. [WEBIDL]

3. Terminology

The construction "a Foo object", where Foo is actually an interface, is sometimes used instead of the more accurate "an object implementing the interface Foo".

The term DOM is used to refer to the API set made available to scripts in Web applications, and does not necessarily imply the existence of an actual Document object or of any other Node objects as defined in the DOM Core specifications. [DOM4]

An IDL attribute is said to be getting when its value is being retrieved (e.g. by author script), and is said to be setting when a new value is assigned to it.

A valid service type is any of the following:

A valid service type provided in the type attribute of the getNetworkServices() method will be matched against the services currently contained in the list of available service records according to the algorithms defined in this specification.

A user-agent generated callback url is a Local-network accessible URL endpoint that a user agent generates and maintains for receiving HTTP NOTIFY requests from UPnP Event sources. It is only required when the user agent implements UPnP Service Discovery as defined in this specification.

In this specification we use the following terms to describe the processes required for Local-networked Services management:

A network services whitelist is a list of zero or more valid service type tokens that, when matched to a service type discovered in the local network, enables that service to be shared with a web page even if that Local-networked Service does not itself allow Cross-Origin Resource Sharing [CORS]. A user agent MUST simulate CORS support for all service interaction in this case. Implementation of this feature is at implementer's discretion. When a user agent does not implement a network services whitelist then it is to treat this as always being an empty list.

4. Security and privacy considerations

The API defined in this specification can be used to find and connect to devices and services within a user's current network. This discloses information related to a user's network: devices available on their network and the publicly-accessible services ("networked services") currently running and available on those devices. The distribution of this information could potentially compromise the user's privacy. A conforming implementation of this specification MUST provide a mechanism that protects the user's privacy. This mechanism MUST ensure that no networked service information is retrievable without the user's express permission.

4.1 Security considerations for API implementations

A user agent SHOULD only allow web pages to connect with Local-networked Services that have passed a preliminary CORS check indicating they support Cross-Origin Resource Sharing [CORS]. In this way, a user agent SHOULD NOT allow web pages to access other arbitrary networked services on the current local network.

A user agent MAY provide a way for users to enable access to non-CORS enabled Local-networked Services from web pages (i.e. operate a network services whitelist). Implementation of such a network services whitelist, if any, is left to an implementer's discretion. Such a whitelist may be configurable by each user at runtime or may be managed by the implementation itself on behalf of its users. In the case that a user agent provides a network services whitelist, it MUST act as if all URLs for the Local-networked Service corresponding to any previously whitelisted service type had Cross-Origin Resource Sharing [CORS] enabled indefinitely.

4.2 Privacy considerations for API implementations

A user agent MUST NOT provide networked service information to web sites without the express permission of the user. A user agent MUST acquire permission through a user interface, unless they have prearranged trust relationships with users, as described below. The user interface MUST include the document base URL. Those permissions that are acquired through the user interface and that are preserved beyond the current browsing session (i.e. beyond the time when the browsing context is navigated to another URL) MUST be revocable and a user agent MUST respect revoked permissions.

Obtaining the user's express permission to access one API method does not imply the user has granted permission for the same web site to access any other methods that may be provided by this API, or to access the same method with a different set of arguments, as part of the same permission context. If a user has expressed permission for an implementation to, e.g. find a set of existing networked services, the implementation MUST seek the user's express permission if and when any subsequent functions are called on this API.

A user agent MAY have prearranged trust relationships that do not require such user interfaces. For example, while a web browser will present a user interface when a web site performs a networked service lookup, a different runtime may have a prearranged, delegated security relationship with the user and, as such, a suitable alternative security and privacy mechanism with which to authorise the retrieval of networked service information.

4.3 Additional API implementation considerations

This section is non-normative.

Further to the requirements listed in the previous section, implementers of the Network Service Discovery API are also advised to consider the following aspects that can negatively affect the privacy of their users: in certain cases, users can inadvertently grant permission to the user agent to disclose networked services to Web sites. In other cases, the content hosted at a certain URL changes in such a way that previously granted networked service permissions no longer apply as far as the user is concerned. Or the users might simply change their minds.

Predicting or preventing these situations is inherently difficult. Mitigation and in-depth defensive measures are an implementation responsibility and not prescribed by this specification. However, in designing these measures, implementers are advised to enable user awareness of networked service sharing, and to provide easy access to interfaces that enable revocation of permissions that web applications have for accessing networked services via this API.

5. Requesting networked services

This section includes references and terminology related to Promise objects that at the time of publication were still under development. Promise-related concepts included in this section are temporarily drafted elsewhere and can be found here.

[Supplemental, NoInterfaceObject]
interface NavigatorNetworkService {
Promise getNetworkServices( in any type );
};

Navigator implements NavigatorNetworkService;

5.1 Methods

promise = window . navigator . getNetworkServices ( type )

Immediately returns a new Promise object and then the user is prompted to select discovered network services that have advertised support for the requested service type(s).

The type argument contains one or more valid service type tokens that the web page would like to interact with.

If the user accepts, the promise object is resolved, with a NetworkServices object as its argument.

If the user declines, or an error occurs, the promise object is rejected.

When the getNetworkServices(type) method is called, the user agent MUST run the following steps:

  1. Let Network Service Promise be a new Promise object.
  2. Let Network Service Promise's Resolver be the default resolver of Network Service Promise.
  3. Return Network Service Promise, and run the remaining steps asynchronously.
  4. Let requested control types be initially set to an empty array.
  5. If type is an array consisting of one or more valid service type tokens, then let requested control types be the value of type, removing any non-valid service type tokens from the resulting array.
  6. If type is a string consisting of one valid service type token, then let requested control types be an array containing one item with a value of type.
  7. If requested control types is an array that contains at least one or more valid service type tokens then continue to the step labeled process below. Otherwise, reject Network Service Promise by running the resolver reject algorithm against the Network Service Promise's Resolver, passing in a newly constructed DOMError object whose name attribute has the string value "UnknownTypePrefixError" (UNKNOWN_TYPE_PREFIX_ERR) and whose message attribute has a helpful implementation-dependent message that explains this error, abort any remaining steps and return.
  8. Process: Let services found be an empty array.
  9. For each available service in the list of available service records run the following steps:
    1. For each requested control type in requested control types: If available service's type attribute equals the requested control type then let matched service equal the value of available service. Otherwise, abort the remaining sub-steps and continue above at the next available service.
    2. If matched service is not empty then run the following steps:
      1. Let CORS check result be the result of running the preliminary CORS check algorithm, passing in matched services's url attribute as the control endpoint URL argument and the entry script's origin as the request origin argument.
      2. If CORS check result is not pass and matched service's type attribute is also not present in the network services whitelist then abort the remaining sub-steps and continue above at the next available service.
      3. Let new service object be a new NetworkService object, mapping the parameters of matched service to this new object where possible.
      4. Append new service object to the services found array.
  10. Optionally, e.g. based on a previously-established user preference, for security reasons, or due to platform limitations, the user agent MAY reject Network Service Promise by running the resolver reject algorithm against the Network Service Promise's Resolver, passing in a newly constructed DOMError object whose name attribute has the string value "PermissionDeniedError" (PERMISSION_DENIED_ERR) and whose message attribute has a helpful implementation-dependent message that explains this error, abort any remaining steps and return.
  11. The user agent MUST NOT provide the entry script's origin with a NetworkServices object without prior permission given by the user.

    If services found is not an empty array then the user agent MAY choose to prompt the user in a user-agent-specific manner for permission to provide the entry script's origin with a NetworkServices object representing the user-authorized subset of services found.

    Alternatively, the user agent MAY wish to skip this user opt-in step and choose to fulfill Network Service Promise immediately based on a previously-established user preference, for security reasons, or due to platform limitations. In such an implementation, if Network Service Promise is to be fulfilled as a result of a previously-established user preference then the user agent MUST continue at the next step of this algorithm.

    If permission has been granted by the user to access one or more networked services then the user agent SHOULD include an "ongoing local-network communication" indicator.

    If permission has been denied by the user, user agent or platform, then the user agent MUST reject Network Service Promise by running the resolver reject algorithm against the Network Service Promise's Resolver, passing in a newly constructed DOMError object whose name attribute has the string value "PermissionDeniedError" (PERMISSION_DENIED_ERR) and whose message attribute has a helpful implementation-dependent message that explains this error, abort any remaining steps and return.

    If the user never responds or no previously-established user preference has been met, this algorithm stalls on this step.

  12. Let services be an empty array.
  13. If services found is not an empty array then set services to be an array of one or more NetworkService objects for which the user granted permission above - known as the current objects user-authorized services.
  14. For each Object service in services, if any, run the following sub-steps:
    1. If service's type parameter begins with the DOMString "upnp:" and the service's eventsUrl parameter is not empty then setup a UPnP Events Subscription for service.
  15. Let services manager be a new NetworkServices object.
  16. Store requested control types against services manager as an internal variable.
  17. Set services manager's servicesAvailable attribute to the number of items currently found in the list of available service records whose type property matches any of the tokens requested in requested control types.
  18. Add services, if any, to the services manager object as its collection of indexed properties. If services is an empty array then the services manager does not have any indexed properties.
  19. Set services manager's length attribute to the number of items in services.
  20. Add services manager to the list of active service managers.
  21. The user agent MUST fulfill Network Service Promise by running the resolver fulfill algorithm against the Network Service Promise's Resolver, passing in services manager as its argument.

The task source for these tasks is the user interaction task source.

The preliminary CORS check algorithm determines whether a Local-networked Service supports Cross-Origin Resource Sharing [CORS] as part of a call to the getNetworkServices() method, prior to that service being proposed for sharing to users and prior to active sharing with web pages. This algorithm takes two arguments, control endpoint URL and request origin, and consists of running the following steps:

  1. Let CORS available check be the result of applying the make a request steps [CORS], setting the request method to OPTIONS, the request URL to control endpoint URL, the source origin to request origin, setting the omit credentials flag to true and including an Access-Control-Request-Method header with a value of GET.
  2. If CORS available check is cancelled by the user, or it results in a network error, or its response does not have an HTTP status code of 200 then abort any remaining steps and return fail.
  3. Return the result of running the resource sharing check [CORS] against the successful HTTP response of the CORS available check.
    Note

    This returned result will always be either pass or fail.

There is no implied persistence to networked service sharing provided to a web page. It MUST NOT be possible to access a networked service previously granted to a web page without user authorization in all of the following cases:

  • If the current script is reloaded at any point in the same or different window.
  • if the current script reinvokes the getNetworkServices() method at any point in its execution.
  • If the user navigates forward or back in their history to reload the current page.
  • If a script is running in a different origin.

5.2 Error Handling

error . name

Returns the current error's error name. At the current time, this will be "PermissionDeniedError" or "UnknownTypePrefixError", for which the corresponding error constants PERMISSION_DENIED_ERR and UNKNOWN_TYPE_PREFIX_ERR are defined.

The name attribute of a DOMError object returned from this API MUST return the name for the error, which will be one of the following:

PERMISSION_DENIED_ERR (DOMString value "PermissionDeniedError")
The user or user agent denied the page permission to access any services.
UNKNOWN_TYPE_PREFIX_ERR (DOMString value "UnknownTypePrefixError")
No valid service type tokens were provided in the method invocation.

6. Obtaining networked services

The NetworkServices interface represents a collection of zero or more indexed properties that are each a user-authorized NetworkService object.

A NetworkServices object is the promise result from a call to getNetworkServices().

[NoInterfaceObject]
interface NetworkServices {
  readonly attribute unsigned long    length;
  getter NetworkService (unsigned long index);
  NetworkService? getServiceById(DOMString id);

  readonly attribute unsigned long    servicesAvailable;

  // event handler attributes
           attribute EventHandler     onservicefound;
           attribute EventHandler     onservicelost;

};

NetworkServices implements EventTarget;

6.1 Attributes

length

Returns the current number of indexed properties in the current object's collection.

servicesAvailable

Returns the current number of items matching one of the app-requested valid service type tokens in the list of available service records.

The length attribute MUST return the number of NetworkService objects represented by the collection.

The servicesAvailable attribute MUST return the number of services in the list of available service records whose type attribute matches any of the valid service type tokens that were initially used to create the current NetworkServices object.

6.2 Methods

services [ index ]

Returns the specified NetworkService object.

services . getServiceById ( id )

Returns the NetworkService object with the given identifier, or null if no service has that identifier.

A NetworkServices object represents the current collection of zero or more NetworkService objects - its indexed properties. The indexed properties of a NetworkServices object are immutable meaning that indexed properties cannot be added and indexed properties cannot be removed for the lifetime of a NetworkServices object.

The supported property indices of NetworkServices objects at any instant are the numbers from zero to the number of the NetworkService objects in the collection minus one.

Note

Each service in a NetworkServices object thus has an index; the first has the index 0, and each subsequent service is numbered one higher than the previous one.

To determine the value of an indexed property for a given index index in a NetworkServices object the user agent MUST return the NetworkService object that represents the indexth item in the collection.

The getServiceById(id) method MUST return the first NetworkService object in the collection whose id attribute is equal to the value of the id argument provided. When no NetworkService objects match the given argument, the method MUST return null.

6.3 Events

The following are the event handlers (and their corresponding event handler event types) that MUST be supported, as IDL attributes, by all objects implementing the NetworkServices interface:

Event handler Event handler event type
onservicefound servicefound
onservicelost servicelost

7. Communicating with a networked service

The NetworkService interface is used to provide a set of connection information for an HTTP service endpoint and if available, service events, running on a networked device.

[NoInterfaceObject]
interface NetworkService {
  readonly attribute DOMString        id;
  readonly attribute DOMString        name;
  readonly attribute DOMString        type;
  readonly attribute DOMString        url;
  readonly attribute DOMString        config;

  readonly attribute boolean          online;

  // event handler attributes
           attribute EventHandler     onavailable;
           attribute EventHandler     onunavailable;

           attribute EventHandler     onnotify;
};

NetworkService implements EventTarget;

7.1 Attributes

service . id

A unique identifier for the given user-selected service instance.

service . name

The name of the user-selected service.

service . type

The valid service type token value of the user-selected service.

service . url

The control URL endpoint (including any required port information) of the user-selected control service.

service . config

The configuration information associated with the service depending on the requested service type.

The id attribute is a unique identifier for the service. The same service provided at different times or on different objects MUST have the same id value.

The name attribute represents a human-readable title for the service.

The type attribute reflects the value of the valid service type of the service.

The url attribute is an absolute URL pointing to the root HTTP endpoint for the service. Web pages can subsequently use this value for implicit cross-document messaging via various existing mechanisms (e.g. Web Sockets, Server-Sent Events, Web Messaging, XMLHttpRequest).

The config attribute provides the raw configuration information extracted from the given network service.

7.2 States

service . online

Returns true if the service is reporting that it is accessible on the local network or false if the service is no longer accessible (temporarily or permanently) on the local network.

The online attribute indicates whether the service is either online, and therefore accessible on the local network, in which case this attribute will return true or, offline, and therefore not accessible on the local network, either temporarily or permanently, in which case this attribute will return false. This attribute MUST default to true.

7.3 Events

The following are the event handlers (and their corresponding event handler event types) that MUST be supported, as IDL attributes, by all objects implementing the NetworkService interface:

Event handler Event handler event type
onnotify notify
onavailable available
onunavailable unavailable

8. Service Discovery

A user agent conforming to this specification MAY implement SSDP [UPNP-DEVICEARCH11], Zeroconf [DNS-SD] + [MDNS] and/or DIAL [DIAL] service discovery mechanisms - the requirements detailed in this section of the specification - to enable Web pages to request and connect with HTTP services running on networked devices, discovered via any of these mechanisms, through this API. When a user agent implements any of these service discovery mechanisms, then it MUST conform to the corresponding algorithms provided in this section of the specification.

This section presents how the results of these service discovery mechanisms will be matched to requested service types, how the user agent stores available and active services and how their properties are applied to any resulting NetworkService objects.

It is expected that user agents will perform these service discovery mechanisms asynchronously and periodically update the list of available service records as required. The timing of any service discovery mechanisms is an implementation detail left to the discretion of the implementer (e.g. by continuously monitoring the network as a background process or on invocation of this API from a Web page).

The list of available service records is a single dynamic internal lookup table within user agents that is used to track all the services that have been discovered and are available in the current network at the current time. At any point during the running of any of the service discovery mechanisms then existing entries within this table can be updated, entries can be added and entries can be removed as the status of networked services changes according to the rules defined in this specification.

The list of active service managers is an internal list within user agents that is used to track all NetworkServices objects currently being shared with any web pages at the current time within the user agent. Each NetworkServices object in the list of active service managers represents a collection of zero or more NetworkService objects - known as its indexed properties. NetworkService objects are attached as the indexed properties of a NetworkServices object as part of the getNetworkServices() algorithm.

The rule for adding an available service is the process of adding a new service or updating an existing service that is generally available on the user's current network in the list of available service records. This rule takes one argument, network service record, and consists of running the following steps:

  1. For each existing service record in the current list of available service records, run the following sub-steps:
    1. If the existing service record's id property does not equal network service record's id property then abort any remaining sub-steps and continue at the next available existing service record.
    2. Replace the value of existing service record in the current list of available service records with the value of network service record, aborting any remaining steps in this algorithm and return.
  2. Add network service record to the list of available service records as a new item.
  3. For each service manager in the list of active service managers run the following steps:
    1. For each active service in service manager run the following steps:
      1. If the network service record's id property equals the active service's id attribute and active service's online attribute is currently set to false then set active service's online attribute to true and then queue a task to dispatch a newly created event with the name available that uses the Event interface, which does not bubble, is not cancellable, and has no default action, at the current active service object.
    2. Let 'service type in current service manager' flag be false.
    3. For each requested control type of the requested control types in service manager run the following steps:
      1. If network service record's type property does not equal requested control type then abort any remaining sub-steps and continue at the next available requested control type.
      2. Set the 'service type in current service manager' flag to true, abort any remaining sub-steps and continue.
    4. If the 'service type in current service manager' flag is set to true then increment service manager's servicesAvailable attribute by 1 and then queue a task to dispatch a newly created event with the name servicefound that uses the Event interface, which does not bubble, is not cancellable, and has no default action, at the current service manager object.

The rule for removing an available service is the general process of removing an existing service from the list of available service records that has left the user's current network or has otherwise expired. This rule takes one argument, service identifier, and consists of running the following steps:

  1. For each existing service record in the current list of available service records, run the following sub-steps:
    1. If the existing service record's id property does not match service identifier then skip any remaining sub-steps for the current existing service record and continue at the next available existing service record.
    2. Let 'service type in use' flag be false.
    3. For each service manager in the list of active service managers run the following steps:
      1. Let 'service type in current service manager' flag be false.
      2. For each active service in service manager run the following steps:
        1. If existing service record's id property equals the active service's id attribute and active service's online attribute is currently set to true then set active service's online attribute to false and then queue a task to dispatch a newly created event with the name unavailable that uses the Event interface, which does not bubble, is not cancellable, and has no default action, at the current active service.
      3. For each requested control type of the requested control types in service manager run the following steps:
        1. If existing service record's type property does not equal requested control type then abort any remaining sub-steps and continue at the next available requested control type.
        2. Set the 'service type in current service manager' flag to true and the 'service type in use' flag to true, abort any remaining sub-steps and continue.
      4. If the 'service type in current service manager' flag is set to true then decrement service manager's servicesAvailable attribute by 1 and then queue a task to dispatch a newly created event with the name servicelost that uses the Event interface, which does not bubble, is not cancellable, and has no default action, at the current service manager object.
    4. If the 'service type in use' flag is false and the existing service record's type property begins with the DOMString "upnp:" and existing service record's eventsURL property is set then run the rule to terminate an existing UPnP Events Subscription, if one is currently active (as a result of having previously called setup a UPnP Events Subscription against the current existing service record).
    5. Remove existing service record from the current list of available service records.

User agents SHOULD expire a service record from the list of available service records when its expiryTimestamp attribute exceeds the current UTC timestamp. When this condition is met the user agent SHOULD run the rule for removing an available service, passing in the expired service record's id attribute as the only argument.

8.1 Zeroconf (mDNS + DNS-SD)

For each DNS response received from a user-agent-initiated Multicast DNS Browse for PTR records with the name _services._dns-sd._udp on the resolved recommended automatic browsing domain [MDNS], the user agent MUST run the following steps:

  1. Let service mDNS responses be an array of PTR records received by issuing a Multicast DNS Browse for PTR records with the name of the current discovered service type.
  2. For each Object service mDNS response in service mDNS responses, run the following steps:
    1. Let network service record be an Object consisting of the following empty properties: id, name, type, url, config, expiryTimestamp.
    2. Set network service record's id property to the value of the full PTR Service Instance Name [MDNS].
    3. Set network service record's name property to the value of the PTR Service Instance Name's Instance component [MDNS].
    4. Set network service record's type property to the concatenation of the string zeroconf: followed be the value of the PTR Service Instance Name's Service component [MDNS].
    5. Set network service record's url property to the resolvable Service URL obtained from performing an DNS-SD Lookup [DNS-SD] of the current service from the PTR record provided [MDNS].
    6. Set network service record's config property to the string value of the contents of the first DNS-SD TXT record associated with the service mDNS response as defined in [DNS-SD].
    7. Set network service record's expiryTimestamp property to the value of the current date, in UTC timestamp format, plus a value of 120 seconds.
    8. Run the general rule for adding an available service, passing in the current network service record as the only argument.

8.2 Simple Service Discovery Protocol (SSDP)

A user agent that implements UPnP service discovery MUST issue a search request for UPnP root devices against the user's current local network according to the full normative text and timing provided in 'Section 1.3.2: Search request with M-SEARCH' detailed in [UPNP-DEVICEARCH11].

The user agent MUST issue all search requests for UPnP root devices with a HTTP request line equal to M-SEARCH * HTTP/1.1, with a HOST header equal to the reserved multicast address and port of 239.255.255.250:1900 and a MAN header equal to ssdp:discover. The user agent must also send an ST header with this HTTP request equal to the String value of ssdp:all or upnp:rootdevice or a single valid service type token beginning with the String value upnp:. If a single valid service type token beginning with the String value upnp: is to be used, the user agent MUST strip the leading String upnp: before using this value in this HTTP request. The user-agent MUST also send an MX header equal to a maximum UPnP advertisement response wait time value between 1 and 5 seconds with this HTTP request.

The user agent MUST listen for any incoming responses to any search request for UPnP root devices.

For each HTTP Response following an initial search request for UPnP root devices sent on a standard UPnP address and port the user agent MUST run the following steps:

  1. If the HTTP Response is not a HTTP 200 OK response then this response is invalid and the user agent MUST discard this response, abort any remaining steps and return. The user agent MAY issue a new search request for UPnP root devices as a result of this error occurring.
  2. If the maximum UPnP advertisement response wait time has been exceeded since the initial search request for UPnP root devices was sent then the HTTP Response is invalid and the user agent MUST discard this response, abort any remaining steps and return. The user agent MAY stop listening for responses from the current search request for UPnP root devices as a result of this error occurring. Equally, the user agent MAY issue a new search request for UPnP root devices as a result of this error occurring.
  3. Let ssdp device be an Object with a property for each HTTP header received in the HTTP Response, with each key being the name of a HTTP response header and each value being that HTTP response header's value.
  4. If ssdp device does not contain at least one CACHE-CONTROL entry, at least one USN entry, at least one ST entry and at least one LOCATION entry then the HTTP Response is invalid and the user agent MUST discard this response, abort any remaining steps and return.
  5. The user agent MUST run the rule for obtaining a UPnP Device Description File passing in the first occurrence of LOCATION from ssdp device as the device descriptor URL argument and the first occurrence of USN from ssdp device as the device identifier argument and the first occurrence of CACHE-CONTROL from ssdp device (minus the leading string of max-age=) as the device expiry argument.

The user agent MUST listen for incoming requests on the standard UPnP address and port on all current local network interface addresses with the port 1900.

For each HTTP Request received on a standard UPnP address and port the user agent MUST run the following steps:

  1. If the HTTP Request is not a HTTP NOTIFY request then it is not a valid UPnP Request and the user agent MUST discard this request, abort any remaining steps and return.
  2. Let ssdp device be an Object with a property for each HTTP header received in the HTTP Request, with each key being the name of a HTTP header and each value being that HTTP header's value.
  3. If ssdp device's NTS entry is equal to ssdp:alive and the HTTP Request does not contain at least one CACHE-CONTROL entry, at least one USN entry, at least one NT entry, at least one NTS entry and at least one LOCATION entry, then the user agent MUST discard this request, abort any remaining steps and return.
  4. If ssdp device's NTS entry is equal to ssdp:alive then the user agent MUST run the rule for obtaining a UPnP Device Description File passing in the first occurrence of LOCATION from ssdp device as the device descriptor URL argument and the first occurrence of USN from ssdp device as the device identifier argument and the first occurrence of CACHE-CONTROL from ssdp device (minus the leading string of max-age=) as the device expiry.

    Otherwise, if ssdp device's NTS entry is equal to ssdp:byebye then the user agent MUST run the rule for removing all services from a registered UPnP Device passing in the first occurrence of USN from ssdp device as the device identifier argument.

The rule for obtaining a UPnP Device Description File is the process of obtaining the contents of a standard UPnP Device Description [UPNP-DEVICEARCH11] from a URL-based resource. This rule takes three arguments - device descriptor URL, device identifier and device expiry - and when called the user agent MUST run the following steps:

  1. Let device descriptor file contain the contents of the file located at the URL provided in device descriptor URL obtained according to the rules defined in 'Section 2.11: Retrieving a description using HTTP' in [UPNP-DEVICEARCH11].
  2. If the value provided in device descriptor URL cannot be resolved as a reachable URL on the current network or the device descriptor file remains empty then it is invalid and the user agent MUST abort any remaining steps and return.
  3. Run the rule for processing a UPnP Device Description File, passing in the current device descriptor file, device identifier and device expiry arguments.

The rule for processing a UPnP Device Description File is the process of parsing the contents of a standard UPnP Device Description [UPNP-DEVICEARCH11] and registering the UPnP services contained therein within the list of available service records.

The rule for processing a UPnP Device Description File takes three arguments - device descriptor file, device identifier and device expiry - and when called the user agent MUST run the following steps:

  1. Let advertised services be a list of all advertised services obtained from the device descriptor file containing the value of the first occurrence of the <serviceList> element as it is defined in 'Section 2.3: Device Description' in [UPNP-DEVICEARCH11].
  2. For each <service> element - known as an advertised service - in advertised services run the following steps:
    1. Let network service record be a new Object consisting of the following empty properties: id, deviceId, name, type, url, eventsUrl, config, expiryTimestamp.
    2. Set network service record's id property to the concatenated string value of the first occurrence of the <UDN> element in the device descriptor file with the advertised service's <serviceId> sub-element.
    3. Set network service record's deviceId property to the value of device identifier.
    4. Set network service record's name property to the string value of the first occurrence of the advertised service's <serviceId> sub-element.
    5. Set network service record's type property to the concatenation of the string upnp: followed by the string value of the first occurrence of the advertised service's <serviceType> sub-element.
    6. Set network service record's url property to the string value of the first occurrence of the advertised service's <controlURL> sub-element.
    7. Set network service record's config property to the string value of the contents of the first occurrence of the <device> element in the device descriptor file.
    8. If advertised service's <eventSubURL> sub-element is not empty, then set network service record's eventsUrl property to the string value of the first occurrence of the advertised service's <eventSubURL> sub-element. Otherwise, do not set network service record's eventsUrl property.
    9. Set network service record's expiryTimestamp property to the value of the current date, in UTC timestamp format, plus the value of device expiry.
    10. Run the general rule for adding an available service, passing in the current network service record as the only argument.
  3. If device descriptor file contains a <deviceList> element then for each <device> element within <deviceList> - herein known as an embedded device descriptor file - the user agent MUST run the rule for processing a UPnP Device Description File, passing in the current embedded device descriptor file as the device descriptor file argument, along with the current device identifier and device expiry arguments.

The rule for removing all services from a registered UPnP Device is the process of removing all services associated with a device from the list of available service records that has left the user's current network or has otherwise timed out or expired. This rule takes one argument, device identifier, and consists of running the following steps:

  1. For each existing service record in the current list of available service records, run the following sub-steps:
    1. If the existing service record's deviceId property does not match device identifier then skip any remaining sub-steps for the current existing service record and continue at the next available existing service record.
    2. Run the general rule for removing an available service passing in existing service record's id property as the only argument.

When the user agent is to setup a UPnP Events Subscription, it is to run the following steps with the current network service record object as defined in 'Section 4.1.2: SUBSCRIBE with NT and CALLBACK' in [UPNP-DEVICEARCH11]:

  1. If network service record's eventsUrl property is empty then the user agent MUST abort these steps.
  2. Let callback URL be the value of creating a new user-agent generated callback url.
  3. Send a HTTP SUBSCRIBE request with a NT header with a string value of upnp:event, a TIMEOUT header with a user-agent defined timeout value (in the form Second-XX where XX is the user-agent defined timeout value in seconds) and a CALLBACK header with a string value of callback URL towards the network service record's eventsUrl property.
  4. If a non-200 OK response is received from the HTTP SUBSCRIBE request then the user agent MUST abort these steps.
  5. On receiving a valid 200 OK response, run the following steps:
    1. Let callback ID equal the string value of the first included SID header, if it exists.
    2. Let timeout date equal the sum of the current UTC date value plus the integer value of the first included TIMEOUT header (minus the leading string of Second-), if it exists.
    3. Run the following steps asynchronously and continue to the step labeled listen below.
    4. Refresh Subscription: Run the following steps at a set interval (X) within the user agent:
      1. Let current date equal the current UTC date.
      2. If current date is less than the timeout date then continue to the step labeled refresh subscription above.
      3. Send a HTTP SUBSCRIBE request with a SID header with the string value of callback ID and a user-agent defined TIMEOUT header (in the form Second-XX where XX is the user-agent defined timeout value in seconds) towards the network service record's eventsUrl property.
      4. On receiving a valid 200 OK, update callback ID with the string value of the first included SID header and set timeout date to the sum of the current UTC date value plus the integer value of the first included TIMEOUT header (minus the leading string of Second-), if it exists. If the current date is greater than or equal to timeout date then the user agent SHOULD continue from the step labeled refresh subscription above. For all non 200 OK responses the user agent SHOULD continue from the step labeled refresh subscription above.
    5. Listen: For each HTTP NOTIFY request received at the callback URL the user agent is to run the following steps:
      1. Let content clone be the result of obtaining the message body of the HTTP NOTIFY request. If content clone is empty, then the user agent MUST abort these steps.
      2. Let notification event be a new simple event that uses the Event interface with the name notify, which does not bubble, is not cancellable, and has no default action.
      3. Let the data attribute of notification event have the DOMString value of content clone.
      4. Queue a task to dispatch notification event at the current NetworkService object.
      5. Return a HTTP 200 OK response to the sender of the HTTP NOTIFY request.

A user agent can terminate an existing UPnP Events Subscription at any time for a network service record by sending an HTTP UNSUBSCRIBE request - as defined in 'Section 4.1.4: Cancelling a subscription with UNSUBSCRIBE' in [UPNP-DEVICEARCH11] - with a HOST header set to that active service's eventsUrl property and a SID header set to the callback ID obtained when the initial setup a UPnP Events Subscription action occurred.

8.3 Discovery and Launch Protocol (DIAL)

A user agent that implements DIAL service discovery MUST issue a search request for DIAL-enabled devices against the user's current local network according to the full normative text and timing provided in 'Section 1.3.2: Search request with M-SEARCH' detailed in [UPNP-DEVICEARCH11].

Let dial version be the version number specified in the valid service type token. Let dial search target be the concatentation of the urn:dial-multiscreen-org:service:dial: string constant with the dial version (currently, dial version can only be 1)

The user agent MUST issue all search requests for DIAL-enabled devices with a HTTP request line equal to M-SEARCH * HTTP/1.1, with a HOST header equal to the reserved multicast address and port of 239.255.255.250:1900, a MAN header equal to ssdp:discover, an ST header equal to dial search target and a user-agent defined MX header equal to a maximum DIAL advertisement response wait time value between 1 and 5 seconds.

The user agent MUST listen for any incoming responses to a search request for DIAL-enabled devices.

For each HTTP Response following an initial search request for DIAL-enabled devices sent on a standard UPnP address and port the user agent MUST run the following steps:

  1. If the HTTP Response is not a HTTP 200 OK response then this response is invalid and the user agent MUST discard this response, abort any remaining steps and return. The user agent MAY issue a new search request for DIAL-enabled devices as a result of this error occurring.
  2. If the maximum DIAL advertisement response wait time has been exceeded since the initial search request for DIAL-enabled devices was sent then the HTTP Response is invalid and the user agent MUST discard this response, abort any remaining steps and return. The user agent MAY stop listening for responses from the current search request for DIAL-enabled devices as a result of this error occurring. Equally, the user agent MAY issue a new search request for DIAL-enabled devices as a result of this error occurring.
  3. Let dial device be an Object with a property for each HTTP header received in the HTTP Response, with each key being the name of a HTTP response header and each value being that HTTP response header's value.
  4. If dial device does not contain at least one CACHE-CONTROL entry, at least one USN entry, at least one ST entry and at least one LOCATION entry or the value of its ST entry is not dial search target, then the HTTP Response is invalid and the user agent MUST discard this response, abort any remaining steps and return.
  5. The user agent MUST run the rule for obtaining a UPnP Device Description File passing in the first occurrence of LOCATION from dial device as the device descriptor URL argument and the first occurrence of USN from dial device as the device identifier argument and the first occurrence of CACHE-CONTROL from dial device (minus the leading string of max-age=) as the device expiry argument.

The rule for obtaining a DIAL Device Description File is the process of obtaining the contents of a standard UPnP Device Description [UPNP-DEVICEARCH11] from a URL-based resource. This rule takes three arguments - device descriptor URL, device identifier and device expiry - and when called the user agent MUST run the following steps:

  1. Let device descriptor file contain the contents of the file located at the URL provided in device descriptor URL obtained according to the rules defined in 'Section 2.11: Retrieving a description using HTTP' in [UPNP-DEVICEARCH11].
  2. Let application url be the value of the first occurrence of the Application-URL response header field obtained according to the rules defined in 'Section 5.4: Device Description Response' in [DIAL]
  3. If the value provided in device descriptor URL cannot be resolved as a reachable URL on the current network or the device descriptor file remains empty or application url is undefined then it is invalid and the user agent MUST abort any remaining steps and return.
  4. Run the following steps to add the newly discovered DIAL service:
    1. Let network service record be a new Object consisting of the following empty properties: id, deviceId, name, type, url, expiryTimestamp.
    2. Set network service record's id property to the first occurrence of the <UDN> element in the descriptor file prefixed with the dial: string constant
    3. Set network service record's deviceId property to the value of device identifier.
    4. Set network service record's name property to the string value of the first occurrence of the <friendlyName> element in the descriptor file.
    5. Set network service record's type property to dial search target.
    6. Set network service record's url property to the string value of the application url.
    7. Set network service record's expiryTimestamp property to the value of the current date, in UTC timestamp format, plus the value of device expiry.
    8. Run the general rule for adding an available service, passing in the current network service record as the only argument.

8.4 Network Topology Monitoring

When the user agent detects that the user has dropped from a connected network then, for each existing service record in the list of available service records discovered via that network connection, the user agent MUST run the general rule for removing an available service passing in each existing service record's id property as the only argument for each call.

When the user agent detects that the user has connected to a new network or reconnected to an existing network, then it SHOULD restart its discovery mechanisms as defined in the Service Discovery section of this specification, maintaining the existing list of active service managers currently in use.

9. Events Summary

The following events are dispatched on the NetworkServices and/or NetworkService objects:

Event name Interface Dispatched when...
servicefound Event When a new service that matches one of the requested type tokens is found in the current network.
servicelost Event When an existing service that matches one of the requested type tokens gracefully leaves or expires from the current network.
available Event When a current service renews its service registration within the current network.
unavailable Event When a current service gracefully leaves or otherwise expires from the current network.
notify Event When a valid UPnP Events Subscription Message is received on a user-agent generated callback url for a current service. This event never fires for Zeroconf-based services.

10. Garbage collection

There is an implied strong reference from any IDL attribute in this API that returns a pre-existing object to that object.

Note

For example, if a NetworkServices object has one or more indexed properties attached to it then there is a strong reference from that NetworkServices object toward each of its indexed properties.

If a user agent is to make disappear a NetworkServices object (this happens when a Document object goes away), the user agent MUST remove this object from the list of active service managers.

11. Use Cases and Requirements

This section covers what the requirements are for this API, as well as illustrates some use cases.

A. Examples

This section is non-normative.

This sample code exposes a button. When clicked, this button is disabled and the user is prompted to offer a network service. The user may also select multiple network services. When the user has authorized a network service to be connected to the web page then the web page issues a simple command to get a list of all the albums stored on the connected media player service.

The button is re-enabled only when the connected network service disconnects for whatever reason (the service becomes unavailable on the network, the user disconnects from their current network or the user revokes access to the service from the current web page). At this point the user can re-click the button to select a new network service to connect to the web page and the above steps are repeated.

The provided service type identifier and service interaction used in this example is based on the well-defined service type and messaging format supported by the XBMC Media Server.


<input type="button" value="Start" onclick="start()" id="startBtn"/>
<div id="debugconsole"></div>

<script>
 var startBtn = document.getElementById('startBtn'),
     debug = document.getElementById('debugconsole');

 function start() {
   if(navigator.getNetworkServices) {
      navigator.getNetworkServices('zeroconf:_xbmc-jsonrpc._tcp').then(gotXBMCService).catch(error);
      startBtn.disabled = true;
   } else {
      debug.innerHTML += "<br>Service Discovery not supported!";
   }
 }

 function gotXBMCService(services) {

// Listen for service disconnect messages

   services[0].addEventListener('unavailable', function ( e ) {
       debug.innerHTML += "<br>" + services[0].name + " disconnected.";
       startBtn.disabled = false;
   }, false);

// Send a service message to get albums list (and process the service response)

   var svcXhr = new XMLHttpRequest();
   svcXhr.open("POST", services[0].url + "/getAlbums"); // services[0].url and its sub-resources are
                                                        // available for cross-site XHR use.

   svcXhr.setRequestHeader('Content-Type', 'application/json-rpc');

   svcXhr.addEventListener('readystatechange', function ( response ) {
     if( response.readyState != 4 || response.status != 200 )
        return;
     debug.innerHTML += "<br>" + services[0].name + " response received: ";
     debug.textContent += JSON.parse(response.responseText);
   }, false);

   var svcMsg = [
     { "jsonrpc": "2.0", "method": "AudioLibrary.GetAlbums", "params": { "genreid": -1,
         "artistid": -1, "start": -1, "end": -1 }, "id": "1" }
   ];

   svcXhr.send(JSON.stringify(svcMsg));
   debug.innerHTML += "<br>" + services[0].name + " request sent: ";
   debug.textContent += JSON.stringify(svcMsg);

 }

 function error( err ) {
   debug.innerHTML += "<br>An error occurred obtaining a local network service.";
   startBtn.disabled = false;
 }
</script>

This sample exposes a drop-down list containing a number of common Home-based audio devices. When the user selects an audio device from the list provided, they are prompted to authorize a network service based on the service type requested. The user may also select multiple network services matching the selected service type. In this example, the user selects their make as being Sony and their model as being Bravia S1000 from which the Web page can derive a service type (urn:schemas-upnp-org:service:RenderingControl:1).

Once the user has authorized the device, the web page sends a simple mute command according to the messaging format supported by the device.


<select name="make" id="make">
  <option selected="selected" disabled="disabled">Select make</option>
  <option>Sony</option>
  <option>Philips</option>
  <option>Alba</option>
</select>
<select name="model" id="model"></select>
<div id="debugconsole"></div>

<script>
  var debug = document.getElementById('debugconsole');

  var models = {
    "Sony": [
      {"name": "Bravia TV S1000", "type": "upnp", "service": "urn:schemas-upnp-org:service:RenderingControl:1" },
      {"name": "Bravia TV S2000", "type": "zeroconf", "service": "_mediarenderer._http._tcp" },
      {"name": "HiFi WD10", "type": "upnp", "service": "urn:schemas-upnp-org:service:RenderingControl:1" }
    ],
    "Philips": [ /* ... */ ],
    "Alba": [ /* ... */ ]
  };

  var makeEl = document.getElementById("make"),
      modelEl = document.getElementById("model");

  makeEl.addEventListener('change', function() {
    modelEl.innerHTML = ""; // reset
    var defaultOption = document.createElement("option");
    defaultOption.textContent = "Select model";
    defaultOption.setAttribute("disabled", "disabled");
    defaultOption.setAttribute("selected", "selected");
    modelEl.appendChild(defaultOption);
    for(var i = 0, l = models[makeEl.value].length; i < l; i++) {
      var option = document.createElement("option");
      option.textContent = models[makeEl.value][i]["name"];
      option.setAttribute("value", models[makeEl.value][i]["type"] + ":" + models[makeEl.value][i]["service"]);
      modelEl.appendChild(option);
    }
  }, false);

  modelEl.addEventListener('change', function() {
    if(navigator.getNetworkServices &&
         modelEl.value == "upnp:urn:schemas-upnp-org:service:RenderingControl:1") {
      var servicesPromise = navigator.getNetworkServices(modelEl.value).then(successCallback, errorCallback);
    } else if (modelEl.value == "zeroconf:_mediarenderer._http._tcp") {
      debug.innerHTML += "<br>Service type is not implemented by this application.";
    } else {
      debug.innerHTML += "<br>Service Discovery is not supported!";
    }
  }, false);
</script>

<script>
  function successCallback( services ) {

  // Listen for service push notification messages

    services[0].addEventListener('notify', function ( msg ) {
         debug.innerHTML += "<br>" + services[0].name + " event received: ";
         debug.textContent += msg.data;
    }, false);

 // Send a control signal to mute the service audio

    var svcXhr = new XMLHttpRequest();
    svcXhr.open("POST", services[0].url); // services[0].url and its sub-resources are
                                          // available for cross-site XHR use.

    svcXhr.setRequestHeader('SOAPAction', 'urn:schemas-upnp-org:service:RenderingControl:1#SetMute');
    svcXhr.setRequestHeader('Content-Type', 'text/xml; charset="utf-8";');

    svcXhr.onreadystatechange = function ( response ) {
      if( response.readyState != 4 || response.status != 200 )
        return;
      debug.innerHTML += "<br>" + services[0].name + " response received: ";
      debug.textContent += response.responseXML;
    }

    // Service messaging to mute the provided service
    var svcMsg = '<?xml version="1.0" encoding="utf-8"?>' +
                 '<s:Envelope s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" ' +
                   'xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">' +
                   '<s:Body>' +
                     '<u:SetMute xmlns:u="urn:schemas-upnp-org:service:RenderingControl:1">' +
                       '<InstanceID>0</InstanceID>' +
                       '<Channel>Master</Channel>' +
                       '<DesiredMute>true</DesiredMute>' +
                     '</u:SetMute>' +
                   '</s:Body>' +
                 '</s:Envelope>';

    svcXhr.send(svcMsg);
    debug.innerHTML += "<br>" + services[0].name + " request sent: ";
    debug.textContent += svcMsg;
  }

  function errorCallback( error ) {
    debug.innerHTML += "<br>An error occurred: " + error.name;
  }
</script>

B. Acknowledgements

Thanks are expressed by the editor to the following individuals for their feedback on this specification to date (in alphabetical order):

Adam Barth, Gar Bergstedt, Robin Berjon, Lars-Erik Bolstad, Marcos Caceres, Cathy Chan, Daniel Danciu, Jean-Claude Dufourd, Youenn Fablot, Mark Foltz, Dominique Hazael-Massieux, Frederick Hirsch, Tatsuya Igarashi, Hari G Kumar, Bob Lund, Giuseppe Pascale, Marcin Simonides, Clarke Stevens, Christian Söderström, Mark Vickers.

Thanks are also expressed by the editor to the following organizations and groups for their support in producing this specification to date (in alphabetical order):

CableLabs, Google Inc., Opera Software ASA, Nokia Corp., Télécom ParisTech, W3C Device APIs Working Group, W3C Web and TV Interest Group.

C. Change Log

This section will be removed before final publication. The last edit is displayed first.

Rich Tibbett Update working version to latest respec build
Rich Tibbett Fix minor respec link bugs and other minor editorials
Rich Tibbett [discovery-api] Re-write CORS-related parts of the spec following subsequent feedback on http://lists.w3.org/Archives/Public/public-device-apis/2013Oct/0049.html
Rich Tibbett Add CORS as the primary network service opt-in mechanism for the NSD API specification
Rich Tibbett Fix [DAP-ISSUE-147]: Reference 'Requirements for Home Networking Scenarios' in Introduction
Rich Tibbett Fix [DAP-ISSUE-134]: Rename NetworkServices and NetworkService events
Rich Tibbett Replace numeric error codes with string-based error types and fold the NavigatorNetworkServiceError interface in to DOMError (therefore, removing NavigatorNetworkServiceError from spec)
Rich Tibbett Fix [DAP-ISSUE-136]: Issues related to garbage collection
Rich Tibbett Fix [DAP-ISSUE-135]: Add security and privacy considerations section [Network Service Discovery]
Rich Tibbett Fix minor typo in NSD API spec examples
Rich Tibbett Change getNetworkServices API + associated algorithms to use DOM Promises
Rich Tibbett Add WD (29th March 2013) for Network Service Discovery API
Rich Tibbett Fix CSS rendering in NSD spec
Rich Tibbett Minor editorial changes to NSD spec
Rich Tibbett Move informative text introducing NSD events to Introduction section
Rich Tibbett Only set online to true if it was previously false in Step 3.1.1 of the rule for 'adding an available service'.
Rich Tibbett Clarify in Section 7.2 that only a UPnP service type token can be used and the user agent must strip the preceeding string 'upnp:' from that UPnP service type token before initiating a network search.
Rich Tibbett Update spec to clarify that devices don't (necessarily) report themselves as offline
Rich Tibbett Update immutability defintion to clarify that only indexed properties of a NetworkServices object are immutable.
Rich Tibbett Clarify the terms 'new service', 'existing service' and 'current service'
Rich Tibbett Only remove UPnP Events subscription once it is no longer in use by any active services
Rich Tibbett Add removal of entry script origin's URL whitelist urls during the getNetworkServices() algorithm.
Rich Tibbett Update 'Network Topology Monitoring' to clarify that only services discovered via a particular network interface that has now been dropped should be removed.
Rich Tibbett Increment/decrement servicesAvailable in rules for 'adding an available service' and 'removing an available service' based on the original requested control types provided in the original getNetworkServices() call (from: http://lists.w3.org/Archives/Public/public-device-apis/2012Oct/0020.html)
Rich Tibbett HTTP Request processing - ssdp:alive validation changes
Rich Tibbett Clarify rules for 'adding an available service' and 'removing an available service' from http://lists.w3.org/Archives/Public/public-device-apis/2012Oct/0020.html
Rich Tibbett Allow SSDP service discovery request to issue an ST header equal to 'ssdp:all', 'upnp:rootdevice' or urn:schemas-upnp-org:service:serviceType:ver
Rich Tibbett Rewrite Step 9 of getNetworkService algorithm following feedback @ http://lists.w3.org/Archives/Public/public-device-apis/2012Sep/0141.html
Rich Tibbett Minor editorial changes to DIAL protocol support section
Rich Tibbett Apply DIAL protocol support patch
Daniel Danciu Added DIAL support
Frederick Hirsch update publication date
Rich Tibbett Editorial updates to NSD spec
Rich Tibbett Updates to Service Discovery & Messaging according to feedback @ http://lists.w3.org/Archives/Public/public-device-apis/2012Oct/0005.html
Rich Tibbett Apply pub rules to proposed Working Draft update
Rich Tibbett Prepare Working Draft for NSD
Rich Tibbett Minor editorial updates
Rich Tibbett HTML5 Tidy on Network Service Discovery spec markup
Rich Tibbett Editorial changes to Service Discovery spec
Rich Tibbett Add embedded device processing to SSDP algorithms + minor editorial updates
Rich Tibbett Updates to Service Discovery & Messaging according to feedback @ http://lists.w3.org/Archives/Public/public-device-apis/2012Aug/0095.html
Rich Tibbett Re-write of Section 7: Service Discovery according to feedback @ http://lists.w3.org/Archives/Public/public-device-apis/2012Aug/0017.html
Anssi Kostiainen merge heads
Rich Tibbett Revert the majority of commit 9e85394e6ede due to the deletion of files. Please always do 'hg pull' followed by 'hg update' before committing your own changes to this repo.
Anssi Kostiainen merge heads, back to one head
Anssi Kostiainen merge heads
Rich Tibbett Change 'two services must have the same id' to 'A service...'
Rich Tibbett Clean up the UPnP Update Service Monitor
Rich Tibbett Minor editorial to Networked Service Discovery
Rich Tibbett Discovery API updates following feedback from http://lists.w3.org/Archives/Public/public-device-apis/2012Aug/0016.html
Rich Tibbett Discovery API updates following feedback from http://lists.w3.org/Archives/Public/public-device-apis/2012Aug/0016.html
Robin Berjon validity errors
Robin Berjon shortname
Robin Berjon FPWD
Robin Berjon config tweaks
Rich Tibbett First draft of Networked Service Discovery and Messaging

D. References

D.1 Normative references

[CORS]
Anne van Kesteren. Cross-Origin Resource Sharing. 16 January 2014. W3C Recommendation. URL: http://www.w3.org/TR/cors/
[DNS-SD]
S. Cheshire; M. Krochmal. DNS-Based Service Discovery. February 2013. RFC. URL: http://www.ietf.org/rfc/rfc6763.txt
[DOM4]
Anne van Kesteren; Aryeh Gregor; Ms2ger; Alex Russell; Robin Berjon. W3C DOM4. 4 February 2014. W3C Last Call Working Draft. URL: http://www.w3.org/TR/dom/
[HTML5]
Robin Berjon; Steve Faulkner; Travis Leithead; Erika Doyle Navara; Edward O'Connor; Silvia Pfeiffer. HTML5. 4 February 2014. W3C Candidate Recommendation. URL: http://www.w3.org/TR/html5/
[MDNS]
S. Cheshire; M. Krochmal. Multicast DNS. February 2013. RFC. URL: http://www.ietf.org/rfc/rfc6763.txt
[RFC2119]
S. Bradner. Key words for use in RFCs to Indicate Requirement Levels. March 1997. Internet RFC 2119. URL: http://www.ietf.org/rfc/rfc2119.txt
[UPNP-DEVICEARCH11]
UPnP Device Architecture 1.1. 15 October 2008. UPnP Forum. PDF document. URL: http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.1.pdf
[WEBIDL]
Cameron McCormack. Web IDL. 19 April 2012. W3C Candidate Recommendation. URL: http://www.w3.org/TR/WebIDL/

D.2 Informative references

[hnreq]
Giuseppe Pascale. Requirements for Home Networking Scenarios. 1 December 2011. W3C Note. URL: http://www.w3.org/TR/hnreq/