Routing in Private Spaces
Last updated May 07, 2024
Table of Contents
- Heroku error codes
- Large cookie & header support
- Response body size logging
- Dyno connection reuse
- Response body buffering
- Maintenance mode & custom error pages
- Content-Length & Content-Type headers
- Query string logging
- SNI servername & host header matching
- SSL security
- HTTP 1.0
- Status Line
- Supported HTTP Methods
- Custom DNS Resolvers
The routers in Private Spaces have a slightly different behavior to the routers found in the Common Runtime. This article explains the differences. Please refer to HTTP Routing for an understanding of the shared routing behavior between Common Runtime and Private Spaces.
Heroku error codes
Among the Heroku error codes for the Common Runtime, Private Space routers support the following errors:
- H10 - App crashed
- H11 - Backlog too deep
- H12 - Request timeout
- H13 - Connection closed without response
- H15 - Idle connection
- H17 - Poorly formatted HTTP response
- H18 - Server Request Interrupted
- H19 - Backend connection timeout
- H21 - Backend connection refused
- H25 - HTTP Restriction: Oversized cookies
- H25 - HTTP Restriction: Oversized header
- H25 - HTTP Restriction: Oversized status line
- H26 - Request Error: Unsupported expect header value
- H26 - Request Error: Bad header
- H27 - Client Request Interrupted
- H28 - Client Connection Idle
- H99 - Platform error
Large cookie & header support
Private Space routers support individual HTTP headers up to 512 KB in size.
Response body size logging
Private Space routers count only the size of the response body in the bytes
field of app logs. The Heroku router for Common Runtime counts the status line, headers, and body size.
Dyno connection reuse
For applications that support persistent HTTP connections, Private Space routers might reuse connections to the dyno for multiple requests. These reused connections are independent of the connections between the client software and the Heroku platform.
Response body buffering
Private Space routers might buffer response bodies internally to avoid sending many small body fragments to the client. This improves performance for most applications, but it can have a detrimental effect on applications that require low-latency streaming. Small body fragments are buffered for a maximum of 10ms, but the client might observe larger buffering times due to networking characteristics.
Maintenance mode & custom error pages
Both Maintenance Mode and Custom Error Pages are supported in Private Spaces. Unlike the Common Runtime, however, at least one web dyno must be running for the Private Space routers to serve maintenance and custom error pages.
Content-Length & Content-Type headers
Unlike Common Runtime routing, which allows multiple Content-Length
headers in a request as long as they contain the same value, Private Space routers serve a 400 Bad Response
whenever multiple Content-Length
headers are present.
Private Space routers also attempt to set a Content-Type
header on requests when missing from the dyno’s response based on the MIME Sniffing Standard.
Query string logging
Log messages generated by the Private Spaces router contain query string parameters (also known as URL or Get parameters) in the path
field. Some applications pass sensitive data using the query string. For example, OAuth applications typically use a query string parameter for passing temporary tokens between services. For applications that cannot log query string parameters due to compliance or security concerns, this behavior can be disabled by enabling the spaces-no-log-query
feature via the Heroku CLI:
$ heroku features:enable spaces-no-log-query --app desolate-dawn-42
SNI servername & host header matching
Some clients and CDNs set a different value for the SNI servername than the request’s host header when connecting to a Heroku application. Heroku recommends Private Space applications set up a CNAME record for an application’s public DNS entry that points to the internal space name. This is typically a record for your www.example-app.com
custom domain that points to a desolate-dawn-42.fathomless-ravine-43.herokuspace.com
style record.
Mismatched servername and host header values are allowed, as long as both names are configured as domains for the same application. The desolate-dawn-42.fathomless-ravine-43.herokuspace.com
style domains are configured and managed by Heroku.
Client support for SNI is required by default in Private Spaces. Please contact Heroku Support if your application needs to serve legacy clients that do not support SNI.
SSL security
Apps in Private Spaces have a choice of cipher suites used to negotiate TLS connections with clients.
Default
The default suite supports TLSv1.1 and TLSv1.2 (but not TLSv1.0). It provides good security and is compatible with a large range of browsers and clients.
To get the default TLS behavior, disable all TLS-related features:
$ heroku features:disable spaces-tls-modern --app desolate-dawn-42
$ heroku features:disable spaces-tls-legacy --app desolate-dawn-42
$ heroku features:disable spaces-strict-tls --app desolate-dawn-42
Cipher Suites
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
Modern
The modern suite supports only TLSv1.2. It provides excellent security and works with relatively new browsers and mobile/IoT clients.
heroku features:disable spaces-strict-tls --app your-app
heroku features:enable spaces-tls-modern --app your-app
Cipher Suites
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Legacy
The legacy suite supports TLSv1, TLSv1.1 and TLSv1.2.It should only be used if backwards compatibility with old clients is required.
heroku features:disable spaces-strict-tls --app your-app
heroku features:enable spaces-tls-legacy --app your-app
Cipher Suites
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_AES_128_GCM_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA256
TLS_RSA_WITH_AES_128_CBC_SHA
TLS_RSA_WITH_AES_256_GCM_SHA384
TLS_RSA_WITH_AES_256_CBC_SHA
TLS_RSA_WITH_3DES_EDE_CBC_SHA
[Deprecated] Strict
With the spaces-strict-tls
feature flag enabled, the Private Spaces routers supports TLS versions 1.1 and 1.2. This flag is deprecated and should only be used for backwards compatibility with previous Heroku TLS termination behavior.
heroku features:enable spaces-strict-tls --app your-app
Cipher Suites
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
HTTP 1.0
Private Space routers convert HTTP 1.0 into HTTP 1.1 requests that are forwarded to dynos. HTTP 1.1 responses from dynos are sent to the client as HTTP 1.0 responses if the original request used HTTP 1.0.
Common Runtime routers convert HTTP 1.0 requests to HTTP 1.1 requests, but do not convert HTTP 1.1 responses back to HTTP 1.0 responses.
Status Line
Private Space routers treat the entire first line of the request (up to the first \n
character) as the status line, regardless of the line ending in a CRLF
(\r\n
) as specified in the HTTP 1.1 RFC. It is typical for HTTP servers like Nginx to allow bare newlines in the end of the status line.
Supported HTTP Methods
Private Space routers supports any HTTP method (sometimes called a “verb”), even those not defined in an RFC.
Custom DNS Resolvers
Private Space apps support injecting a single DNS Resolver as the Dynos first DNS server target, followed by the standard Private Space DNS target. To use this feature you need to enable the spaces-extra-resolver
flag on the desired apps and then configure the HEROKU_EXTRA_RESOLVER
config var.
Example:
heroku labs:enable spaces-extra-resolver -a "$APP_NAME"
heroku config:set -a "$APP_NAME" HEROKU_EXTRA_RESOLVER=DNS-Server-IP