HTTP Server
Enabling the HTTPServer facility makes your web service endpoints accessible to callers via HTTP. The HTTP server that is created is a wrapper over Go’s built-in HTTP serving functionality.
It is agnostic of the content types being accepted or served by your handlers - that is controlled by enabling either the JSONWS or XMLWs facility and/or defining custom content type handling in your endpoints.
This page covers the following:
- Enabling and configuring the HTTP server
- Extending functionality by providing components that implement particular interfaces
- How the HTTP server is affected by application lifecycle events
- Enabling and configuring access logging
Enabling
The HTTPServer facility is disabled by default. To enable it, you must set the following in your configuration
{
"Facilities": {
"HTTPServer": true
}
}
Configuration
The default configuration for this facility can be found in the Granitic source under facility/config/httpserver.json
and is:
{
"HTTPServer":{
"Port": 8080,
"Address": "",
"AllowEarlyInstrumentation": false,
"DisableInstrumentationAutoWire": false,
"MaxConcurrent": 0,
"TooBusyStatus": 503,
"AutoFindHandlers": true,
"RequestID": {
"Enabled": false,
"Format": "UUIDV4",
"UUID":{
"Encoding": "RFC4122"
}
},
"AccessLogging": false,
"AccessLog": {
"LogPath": "./access.log",
"LogLinePreset": "framework",
"UtcTimes": true,
"LineBufferSize": 10,
"Entry": "TEXT",
"JSON": {
"Prefix": "",
"Fields": [
["Remote", "REMOTE"],
["ForwardedFor", "REQ_HEADER", "X-Forwarded-For"],
["Received", "RECEIVED", "02/Jan/2006:15:04:05 Z0700"],
["Method", "HTTP_METHOD"],
["Path", "PATH"],
["Query", "QUERY"],
["Status", "STATUS"],
["BytesReturned", "BYTES_OUT"],
["ProcessTimeMicro", "PROCESS_TIME", "MICRO"]
],
"Suffix": "\n"
}
}
}
}
Listening
By default the HTTP server listens on port 8080
on all available IP addresses (including localhost), on IPV4 and IPV6. Setting
HTTPServer.Port
in your configuration changes the TCP/IP that clients can connect to.
To listen on a specific IP address, you should set HTTPServer.Address
to an IP address associated with
one of the network interfaces available to your server.
This example:
{
"HTTPServer": {
"Port": 80,
"Address": "192.168.0.142"
}
}
Will start an HTTP server that only listens on 192.168.0.142:80
HTTPS
The Granitic HTTP server does not support HTTPS at this time. Your application should be deployed behind a web server or load-balancer with HTTPS support if this is required.
Load management
By default the HTTP server will accept an unlimited number of concurrent requests. This behaviour can be changed
by setting HTTPServer.MaxConcurrent
to an integer greater than zero.
Any client attempting to connect to the server while it is already handling the maximum concurrent requests will
receive an error response with the HTTP Status code defined in TooBusyStatus
(deafult 503
).
Finding endpoints
By default any component you have created that implements the httpendpoint.Provider interface will automatically found and added to the list of endpoints that can be matched against incoming HTTP requests.
See the web services documentation for more details on creating handler components.
This behaviour can disabled by setting HTTPServer.AutoFindHandlers
to false. This is advanced behaviour only
generally required when you are running multiple custom instances of the Granitic HTTP server in the same application.
Extending functionality
Handling abnormal statuses
Granitic’s web service processing pipeline delegates the responsibility for writing HTTP responses to the web service handlers, or more specifically the ws.ResponseWriter attached to the handler.
There many circumstances under which the HTTP server will reject an inbound request before it reaches a handler, most
commonly when the request cannot be matched to a handler (a 404
). In these circumstances, the HTTP server still needs
to be able to construct an HTTP response body that is consistent with ‘normal’ responses.
If you are using the JSONWS or XMLWs facility, this is handled automatically. If you not using either of those facilities (or want different behaviour) you must provide the HTTP server with an abnormal status writer by creating a component that implements ws.AbnormalStatusWriter and instructing the HTTP server to use it by providing a framework modifier like:
{
"frameworkModifiers": {
"grncHTTPServer": {
"AbnormalStatusWriter": "myStatusWriter"
}
}
}
where myStatusWriter
is the name of your component that implements ws.AbnormalStatusWriter.
Request identification
If you have created a component that implements httpserver.IdentifiedRequestContextBuilder that component will be automatically be used to create, derive or inherit a ID for the current request using information included in the HTTP request.
See request identification for more information.
You may instruct Granitic to assign a UUID V4 ID to each request by setting HTTPServer.RequestID.Enabled
to
true
. By default these IDs will be standard RFC4122 formatted UUIDs, but you
can choose to alter the formatting by setting HTTPServer.RequestID.UUID.Encoding
to Base32
or Base64
“RFC4122”:
Instrumentation
The HTTP server supports and coordinates the instrumentation of web service requests automatically finding a component you have registered that implements instrument.RequestInstrumentationManager.
There are two configuration settings that affect this behaviour.
Auto-wiring
Setting HTTPServer.DisableInstrumentationAutoWire
to true
means that the HTTP server will not automatically look for a component that implements instrument.RequestInstrumentationManager.
Instead you will need to explicit provide an instrumentation manager via a framework modifier like:
{
"frameworkModifiers": {
"grncHTTPServer": {
"InstrumentationManager": "myInstrumentationManager"
}
}
}
Early instrumentation
By default Granitic does not start instrumentation until after a request has been accepted (e.g. after checks have taken place to make sure the server is not too busy or suspended). This is to provide some protection against deliberate or accidental denial-of-service attacks putting load on your instrumentation implementation at the cost of losing some fine-grained timing information around the very early stages of request processing and losing all visibility of requests that were rejected because the server was busy.
If you want to be able to instrument these types of request, set HTTPServer.AllowEarlyInstrumentation
to true
.
Access logging
Granitic can be configured to write a summary of each request received to a log file, similar to most web and application
servers. This feature is disabled by default and can be enabled by setting HTTPServer.AccessLogging
to true in your
configuration.
This will create (or append) a UTF-8 encoded file called access.log
in the same directory that you started your application (e.g. your
application’s working directory). You can change this specifying a full or relative path to a file with
HTTPServer.AccessLog.LogPath
. Your application must have filesystem permission to create and edit the file at that path.
The format and information recorded for each request is highly customisable and is described in detail below.
STDOUT logging
If you need your application to write access logs to STDOUT
, the preferred option is to set
HTTPServer.AccessLog.LogPath
to whatever file path represents STDOUT
on your OS (e.g. /dev/stdout
).
If your OS does not support this concept, you can set HTTPServer.AccessLog.LogPath
to STDOUT
and Granitic will
use Go’s os.Stdout file to write access log entries.
Timestamps
You may choose to have the timestamps associated with each request as UTC (recommended and the default), or in the local
time of your server. To use local time, set HTTPServer.AccessLog.UtcTimes
to false
.
Non-blocking writing
Lines are written to the access log asynchronously. You web service calls will not block for log writing as long as there
is space in the log line buffer. The size of this buffer is defined at HTTPServer.AccessLog.LineBufferSize
with a default
value of 10
. If your application is writing logs to a slow storage system or handles large numbers of simultaneous
requests, you might want to adjust this value.
If you want to force blocking writing (useful for tests), set HTTPServer.AccessLog.LineBufferSize
to zero or less.
Text access log line format
The information you want to include in each line of the access log is controlled by a format string comprised of ‘verbs’ and fixed characters similar to fmt.Printf or HTTPD. You may choose from a preset format or define your own.
Preset formats
Granitic currently specifies threee preset formats. You can set HTTPServer.AccessLog.LogLinePreset
to framework
, common
or combined
. The default is framework
. The common
and combined
formats are intended to be similar to the
Apache HTTPD log formats of the same name.
Name | Format | Example |
---|---|---|
framework | %h XFF[%{X-Forwarded-For}i] %l %u [%{02/Jan/2006:15:04:05 Z0700}t] “%m %U%q” %s %bB %{us}Tμs | [::1]:49574 XFF[-] - - [09/Oct/2019:14:59:55 Z] “POST /test” 200 -B 252μs |
common | %h %l %u %t “%r” %s %b | [::1]:49580 - - [09/Oct/2019:15:01:35 +0000] “POST /test HTTP/1.1” 200 - |
combined | %h %l %u %t “%r” %s %b “%{Referer}i” “%{User-agent}i” | [::1]:49584 - - [09/Oct/2019:15:02:37 +0000] “POST /test HTTP/1.1” 200 - “-” “-” |
Available verbs
Formatting Verb | Meaning and usage |
---|---|
%% | The percent symbol |
%b | The number of bytes (excluding headers) sent to client or the - symbol if zero |
%B | The number of bytes (excluding headers) sent to client or the 0 symbol if zero |
%D | The wall-clock time the service spent processing the request in microseconds |
%h | The host (as IPV4 or IPV6 address) from which the client is connecting |
%{?}i | The string value of a header included in the HTTP request where ? is the case insensitive name of the header |
%l | Prints the - symbol. For compatibility with common log formats always. |
%m | The HTTP method (GET, POST etc) of the request |
%q | The query string of the request, including a leading ? character |
%r | The HTTP request line (method, path and HTTP version) |
%s | The HTTP status code (200, 404 etc) sent to the client with the response |
%{?}t | The point in time at which the request was received where ? is a standard Go date/time format string (e.g. 02/Jan/2006:15:04:05 Z0700 ). In UTC or local time according to access log configuration |
%{?}T | The wall-clock time the service spent processing the request in a unit specified by ? where s gives seconds, ms gives milliseconds and us gives microseconds |
%u | A string representation of the ID of the user on whose behalf the request is being made. Only available if IAM is configured, otherwise the - symbol is printed |
%U | The path portion of the HTTP request line |
%{?}X | A value from a context.Context that has been made available to the access logger via a component you have written implementing logging.ContextFilter where ? is the key to the value |
JSON access log line format
As an alternative to the semi-structured lines of plain text described above, Granitic can be configured to write each access log entry as a single line JSON document. This feature can be enabled by setting:
HTTPServer.AccessLog.Entry
to "JSON"
in your configuration. This will cause your application to log access
lines like:
{"BytesReturned":"60","ForwardedFor":"","Method":"GET","Path":"/test","ProcessTimeMicro":"33","Query":"","Received":"28/Apr/2020:13:31:05 +0100","Remote":"[::1]:53003","Status":"200"}
The name of each generated JSON field and the associated value can be changed in configuration. The default can be seen
in the configuration sample at the top of this page at HTTPServer.AccessLog.JSON.Fields
Each entry in the Fields
array is a string array with two or three elements.
* The name of the field as it will be written in JSON.
* The type of data (content type) that should be used to set a value for the field
* An optional argument if required by the content type
Content Type | Meaning and usage | Argument |
---|---|---|
CONTEXT_VALUE | A value from a context.Context that has been exposed by a logging.ContextFilter component |
The string key of the exposed value |
REMOTE | The equivalent to %h in text log lines |
N/A |
REQ_HEADER | The equivalent to %{?}i in text log lines |
The name of the header |
RECEIVED | The equivalent to %{?}t in text log lines |
A standard Go datetime format string |
HTTP_METHOD | The equivalent to %m in text log lines |
N/A |
REQ_PATH | The equivalent to %U in text log lines |
N/A |
STATUS | The equivalent to %s in text log lines |
N/A |
BYTES_OUT | The equivalent to %B in text log lines |
N/A |
PROCESS_TIME | The equivalent to %{?}T in text log lines |
SECONDS , MILLI or MICRO |
REQUEST_LINE | The equivalent to %r in text log lines |
N/A |
INSTANCE_ID | The ID assigned to the current instance of your application | N/A |
TEXT | The static text specified in the argument | The text to use as a value |
Line prefix and suffix
Each line of JSON formatted log entry can be prefixed or suffixed with a static string by setting HTTPServer.AccessLog.JSON.Prefix
(default empty string) or HTTPServer.AccessLog.JSON.Prefix
(default \n
)
Lifecycle
The IOC component that represents the HTTP server is integrated with Granitic’s component lifecycle model and has different behaviour depending on which lifecycle state or transition the component is in.
The server can be suspended and resumed using runtime control
Start
- Finds any other components required to run (handlers, instrumentation, abnormal status writer, request identifier)
- DOES NOT open or listening on the configured address and port
Allow Access
- Confirms that it is possible to listen on the configured address and port
- Starts listening for HTTP requests on the configured address and port
Suspend
- Keeps listening for requests but sends a ‘too busy’ response (default 503)
Resume
- Allows requests to be processed again
Prepare to stop
- Keeps processing existing requests but sends a ‘too busy’ response (default 503) for any new requests
Ready to stop check
- Returns true if no requests are currently being processed
Stop
- Shuts down the underlying HTTP server, terminating any requests that are still running
Component reference
The following components are created when this facility is enabled:
Name | Type |
---|---|
grncHTTPServer | httpserver.HTTPServer |
grncAccessLogWriter | httpserver.AccessLogWriter |
Next: Logger facility
Prev: Facilities index