About the HTTP server transport
The HTTP server is a transport for use in connectivity plug-ins which external services can connect to over HTTP/REST. It can handle both an HTTP submission-only API which delivers events to the correlator and a REST request/response API where the responses are controlled from EPL. In addition to this, it can serve static files. It also allows support for TLS alongside HTTP basic authentication.
The HTTP server transport can decode HTTP requests and encode EPL responses or static files with gzip or deflate compression format. It also supports HTML form decoding and can decode multipart/form-data
or application/x-www-form-urlencoded
media types to a dictionary payload.
This transport provides a dynamic chain manager (the chain manager for each host/port is configured by an entry under dynamicChainManagers
in the YAML configuration file) which creates chains automatically whenever an HTTP client connects to that host/port. There must be at least one chain definition provided in the dynamicChains
section of the YAML configuration file. If providing more than one definition, the matchPathPrefix
configuration option must be used to distinguish them. For more details, see Handling requests to different paths with different chains. The EPL channel that incoming requests are sent to is specified in the configuration of the dynamicChains
, by rules in the mapperCodec
section that set the metadata.sag.channel
.
HTTP requests are received by the transport and sent to the chain where they are mapped to EPL events as described in Mapping events between EPL and HTTP server requests. Whether the response to the HTTP request is generated automatically or by the EPL application is controlled as described in Handling responses in EPL.
For more information on YAML configuration files, see Using connectivity plug-ins and especially Configuration file for connectivity plug-ins.
Persistent connections to the server are supported for multiple requests. Details of the individual requests are configured through the events sent to the chain. The HTTP server supports HTTP version 1.1 and TLS version 1.2 and above.
The HTTP server is designed to listen for REST services and supports all GET
, POST
, PUT
and DELETE
operations which have been specified in the configuration file. Other than GET
requests served by static files, all requests are treated identically.
The samples/connectivity_plugin/application/httpserver
directory of your Apama installation includes a sample which demonstrate how to use the HTTP server connectivity plug-in to send and receive HTTP requests containing events into the correlator through various configurations. See the README.txt
file included with the sample for complete instructions on how to run the sample application.
OpenAPI definitions
OpenAPI is an open description format for REST APIs. The OpenAPI Specification (OAS), and the related tools available from Swagger (https://swagger.io), can be used to design, document, deploy and test the REST API for an application. The specification allows for API definitions to be written in either YAML or JSON.
Apama API definitions are supplied in JSON format to the OpenAPI/Swagger 3.0 specification.
HTTP response codes
The transport returns a response to the client. If responses are automatically generated, we return a “202 Accepted” response after HTTP parsing, but before processing by the correlator, to indicate that a failure may still occur later in processing the event. If the response is handled by EPL, the response code is defined by the EPL application and configuration. If there is a failure in parsing the HTTP part of the request, an error code is returned instead.
The various response codes that we currently support are described below.
Code | Reason |
---|---|
202 Accepted | Success response code for automatic responses. On a successful submission, this indicates that while we have accepted it, processing will occur later and we cannot guarantee completion. |
400 Bad Request | Any other error we can conclusively say is due to a malformed request. |
401 Unauthorized | We have enabled HTTP basic authentication and the user either does not supply an Authorization header or it is incorrect. |
405 Method Not Allowed | The request has a method we do not support (depending on what is configured in the configuration file). |
413 Request Entity Too Large | The uncompressed payload is larger than defined with the maxRequestBytes configuration option. See Configuring the HTTP server transport for more information on this configuration option. |
415 Unsupported Media Type | The client has sent an unsupported Content-Encoding header. |
429 Too Many Requests | If too many authentication failures occur (maxAttempts ), then requests are throttled for the defined cool-down period (coolDownSecs ) to protect the running correlator. See Configuring the HTTP server transport for more information on the configuration options maxAttempts and coolDownSecs . |
500 Internal Server Error | Any other error which occurs before we send the event into the correlator. |
503 Host Not Ready | The HTTP server received a request before the application called onApplicationInitialized() in the correlator. See Sending and receiving events with connectivity plug-ins for more information on this method. |
504 Gateway Timeout | The EPL application did not respond within the configured timeout. |
Other HTTP response codes | As defined by the EPL application and configuration. |
Loading the HTTP server transport
Loading the HTTP server transport
You can load the HTTP server transport by adding the HTTP Server connectivity bundle to your project in Apama Plugin for Eclipse (see Adding the HTTP server connectivity plug-in to a project) or using the apama_project
tool (see Creating and managing an Apama project from the command line). Alternatively, you can load the transport with the following connectivityPlugins
stanza in your YAML configuration file:
connectivityPlugins:
HTTPServerTransport:
libraryName: connectivity-http-server
class: HTTPServer
Configuring the HTTP server transport
The HTTP server has a manager that deals with connections and one or more chains that deal with mapping events into the correlator. All chains defined are used by all managers. If you require multiple ports (that is, with different options), then you need multiple managers. The HTTP server should be added to a manager and chain containing the appropriate mapping rules (see Mapping events between EPL and HTTP server requests for detailed information).
Manager
Example:
dynamicChainManagers:
HTTPServerManager:
transport: HTTPServerTransport
managerConfig:
port: 15910
bindAddress: 10.13.23.125
tls: false
tlsKeyFile: ${PARENT_DIR}/servername.key.pem
tlsCertificateFile: ${PARENT_DIR}/servername.cert.pem
connectionTimeoutSecs: 60
maxConnections: 16
keepAliveTimeSecs: 120
concurrentChains: true
staticFiles:
/swagger.json:
file: ${PARENT_DIR}/swaggerDefault.json
contentType: application/json
charset: utf-8
The following configuration options are available for the manager on the HTTP server:
Configuration option |
Description |
---|---|
|
Required. The user-defined port on which the server is accessible. Type: |
|
Optional. Binds to specific interfaces, potentially on multiple ports. Each entry is either a host, or a host:port combination. If a port is provided, it is used. Otherwise, the Default: blank. |
|
Optional. Set this to Default: |
|
The private key for the certificate in PEM format. Required if TLS is enabled. Type: |
|
The server certificate file in PEM format. Required if TLS is enabled. Type: |
|
Maximum time to handle a single request before returning a timeout (in seconds). Type: Default: 60. |
|
Maximum number of simultaneous connections which can be handled. Type: Default: 16. |
|
Optional. Set this to the maximum idle time in seconds between requests on a persistent connection before it is closed. If not set, the default value is used. Type: Default: 15. |
|
Optional. Set this to Type: Default: |
|
Optional. Map of static files. Elements are of the form: ``` /url: file: ${PARENT_DIR}/source_file.txt contentType: text/plain charset: utf-8
Type: Default: undefined. |
Chain
Example:
dynamicChains:
HTTPServerChain:
- apama.eventMap
*mapping rules...*
- HTTPServerTransport:
authentication:
authenticationType: none
allowedUsersFile: ${PARENT_DIR}/userfile.txt
maxAttempts: 5
coolDownSecs: 30
automaticResponses: false
responseCompression: "ifRequested"
responseTimeoutMs: 5000
matchPathPrefixes: [""]
allowedMethods: [PUT]
The following configuration options are available for the chain on the HTTP server:
Configuration option |
Description |
---|---|
|
Set this to Default: |
|
Path to the password file (see Authentication). Required if the authentication type is |
|
Maximum number of failed login attempts before throttling the requests for that user. See Authentication for more information. Type: Default: 3. |
|
The number of seconds after the maximum number of failed login attempts before the HTTP server attempts authentication of the user again. See Authentication for more information. Type: Default: 20. |
|
Set this to |
|
The Default: |
|
The number of milliseconds we wait for a response from the EPL application before returning to the client. Type: Default: 5000 (5s). |
|
If providing multiple chains in the |
|
Required. List of permitted HTTP verbs (for example, |
|
Maximum permitted HTTP payload size in bytes. Type: Default: 1048576 (1MB). |
Handling requests to different paths with different chains
You can provide the HTTP server with multiple chain configurations specifying different mapping rules for different requests. These rules are differentiated based on the path of the HTTP request. To do this, provide more than one entry in the dynamicChains
section of your YAML configuration file, each finishing with an instance of the HTTP server transport. To use this feature, you must provide a distinct matchPathPrefixes
configuration option on each of the transports. This is a list of string prefixes which are handled by the given chain. Typically, one of the chains has a default entry of ""
(the empty string) which handles all requests not handled by any other chain.
For example:
dynamicChains:
DefaultHTTPServerChain:
- apama.eventMap
mapping rules...
- HTTPServerTransport:
allowedMethods: [GET]
automaticResponses: false
matchPathPrefixes: ""
RESTHTTPServerChain:
- apama.eventMap
mapping rules...
- HTTPServerTransport:
allowedMethods: [GET]
automaticResponses: false
matchPathPrefixes: ["/rest", "/api"]
CRUDHTTPServerChain:
- apama.eventMap
mapping rules...
- HTTPServerTransport:
allowedMethods: [GET,PUT,DELETE,POST]
automaticResponses: false
matchPathPrefixes: ["/rest/objects"]
In the above example, requests to /rest/objects
are handled by the CRUD chain. Requests to other places under /rest
or /api
are handled by the REST chain. Anything else is handled by the default chain. Each chain can provide different mapping rules for different formats of request, mapping to different EPL events and delivering to different channels.
The HTTP server lazily instantiates chains of each type for each incoming thread (if using the concurrentChains
option), so they are not created until a matching request comes in on a given thread.
If there are two chains with overlapping prefixes, the prefix with the longest match is chosen. For example, if the first chain specifies /data
and the second chain specifies /data/instances
, then a request to /data/global
uses the first chain, but a request to /data/instances/12345
uses the second chain.
Queueing behavior
You can configure each chain to deliver to separate channels. This potentially allows that if requests to one of the channels are backed up or blocked, requests to independent paths can still be processed. It also means that ordering is not guaranteed across different chains. Each chain has its own response channel, which is mapped into the chain using the @{httpServer.responseChannel}
variable when it is created.
If you want to ensure that requests using one chain do not block requests using another chain, then you must do the following:
- Ensure requests on each chain are delivered to a different channel, possibly by setting a different
defaultChannel
configuration property on each host plug-in. - Subscribe different contexts to each channel.
Logging and metrics
In order to distinguish the different chains in log message and Prometheus metrics, a label of {template=nameOfDynamicChain}
is added to the name of the chain and any metrics in that chain.
Handling responses in EPL
In order to have the response to an HTTP request handled by your EPL application, you need to configure the HTTP server chain correctly and then respond to the event delivered to your application. The transport must have automaticResponses
set to false
in the configuration (see also Configuring the HTTP server transport), and it must map the following variables into the message to be able to send responses.
-
metadata.requestId
This variable is set by the transport for every message. Responses must also have the same
metadata.requestId
set. This is normally done by mapping it to a payload field in your request for the message sent to the host and then back into the metadata for the response. -
@{httpServer.responseChannel}
This variable is set when creating the chain. This should be set in your request messages. It tells the EPL application to which channel responses should be sent back. Responding messages should also set
metadata.http.statusCode
correctly.InfoYou must send the response to the channel specified in the corresponding request event. The channel name is not guaranteed to be constant even within a single manager.
For example:
dynamicChains:
HTTPServerChain:
- apama.eventMap:
defaultEventType: RequestEvent
defaultChannel: requests
- mapperCodec:
"*":
towardsHost:
mapFrom:
- payload.requestId: metadata.requestId
defaultValue:
- payload.responseChannel: "@{httpServer.responseChannel}"
towardsTransport:
mapFrom:
- metadata.requestId: payload.requestId
defaultValue:
- metadata.http.statusCode: 200
- jsonCodec
- stringCodec
- HTTPServerTransport:
automaticResponses: false
allowedMethods: [ PUT ]
Your EPL application must then respond to messages, preserving the requestId
and responding on the correct channel. For example:
on all RequestEvent() as re {
any data := // do something to get the response data
send ResponseEvent(re.requestId, data) to re.responseChannel;
}
If a response is not received by the transport within the configured timeout, then the transport returns a “504 Gateway Timeout” response. This timeout can be configured with the responseTimeoutMs
configuration option (see also Configuring the HTTP server transport).
The response messages must be converted and mapped using the chain configuration to meet the following requirements:
- The response payload is a binary message. This will probably be created using the String codec from the event.
- The
metadata.http.statusCode
variable is set. This will usually be set to 200 by the Mapper codec. - The
metadata.contentType
andmetadata.charset
variables are set. These will usually be set by the JSON codec and String codecs when in use, but can also be set by the Mapper codec.
In addition, you can set other HTTP headers. For more details, see Mapping events between EPL and HTTP server requests.
Serving static files
The HTTP server allows you to serve static files from disk. You can list the static file URI which will be available using a GET
request, and it will be served by that file. GET
requests that match a static file do not get passed into the correlator.
Static file requests do not go through the checks that all other requests go through, which are:
- Transport status (host ready)
- HTTP basic authentication
- Allowed methods
- Maximum request size
You must list static files individually in the configuration file, and you must provide the MIME type of the file being served. Optionally, you can also provide the charset
type.
staticFiles:
/swagger.json:
file: ${PARENT_DIR}/swagger.json
contentType: application/json
charset: utf-8
Mapping events between EPL and HTTP server requests
The HTTP server can either be used as a general event submission API or as a general request/response API. A request to the HTTP server contains either a binary payload or a dictionary payload if the request had either an application/x-www-form-urlencoded
or multipart/form-data
content type. In the latter case, there will also be additional metadata fields. For the requests to be useful to EPL, they must be converted into the format expected by Apama. This is done using the Classifier codec, Mapper codec and other codecs (see Codec connectivity plug-ins). For request/response APIs, the same process is used in reverse to turn EPL events into the responses.
The event types used in EPL should be specific to your application and then mapped in the chain from the fields produced by the HTTP server. The following fields are created in each event by the HTTP server. Field names containing periods (.) indicate nested map structures within the metadata. This nesting is automatically handled by the Mapper codec, and fields can be referred to there just using these names (see also The Mapper codec connectivity plug-in).
The fields for requests from the transport to EPL are:
Field | Description |
---|---|
payload |
The binary payload of the request. |
metadata.requestId |
A unique integer identifier which must be preserved in the response when using EPL-supplied responses. |
metadata.contentType |
The MIME type of the payload (string ), taken from the first parameter of the HTTP Content-Type header, converted to lower case and with spaces trimmed off. See also Handling HTTP headers. |
metadata.charset |
The charset parameter of the Content-Type header (string ), converted to lower case, with spaces trimmed off. See also Handling HTTP headers. |
metadata.http.path |
The path component (string ) of the URI. |
metadata.http.method |
The HTTP method of the request: PUT , POST , GET , or DELETE . |
metadata.http.user |
When HTTP basic authentication is enabled, the authenticated user name (string ). |
metadata.http.cookies |
A key-value map of cookies from the request (map ). See also Dealing with cookies. |
metadata.http.queryString |
A key-value map of the options in the query-string component of the request URI (map ). This field is only set in the request when the query string is not empty. See also Providing HTTP query parameters. |
metadata.http.headers |
A key-value map of the HTTP headers sent by the request (map ). Key names are converted to lower case regardless of original capitalization. See also Handling HTTP headers. |
metadata.http.source |
The address and port of the client connection which generated this request. |
The fields for EPL-supplied responses are:
Field | Description |
---|---|
payload |
The binary or dictionary payload of the response. |
metadata.requestId |
The requestId of the corresponding request. Must be correctly set in responses. |
metadata.contentType |
The MIME type of the payload (string ). This is used to construct the HTTP Content-Type header. See also Handling HTTP headers. |
metadata.charset |
The charset of the payload, for text-format payloads. This is used to construct the HTTP Content-Type header. See also Handling HTTP headers. |
metadata.http.statusCode |
The HTTP status code (integer ). Must be set in responses. |
metadata.http.cookies |
A key-value map of cookies to set on the client. See also Dealing with cookies. |
metadata.http.headers |
A key-value map of additional HTTP headers to send in the response. See also Handling HTTP headers. |
metadata.http.form.name.contentType |
The media type of the form data. See also Handling HTTP form decoding. |
metadata.http.form.name.charset |
The encoding of the form data. See also Handling HTTP form decoding. |
metadata.http.form.name.filename |
The filename of the form data. See also Handling HTTP form decoding. |
Distinguishing request types
A single chain will often deal with multiple event types received within requests. For messages towards the host, the event type will not yet have been set. The Mapper and Classifier codecs can use fields in the message (payload or metadata) to set the event type.
You can write the configuration to behave in whatever way you like. There are several ways of determining to which event type the request corresponds. In the default configuration that we supply, the event type is provided as part of the request, but it is also possible to infer the event type from the content of the request.
Below are some examples of what is possible.
You can use the Mapper codec to set the type
and channel
from the payload as shown below. The type is part of the request. The Mapper code assigns it to metadata.sag.type
.
- mapperCodec:
"*":
towardsHost:
mapFrom:
- metadata.sag.type: payload.type
- metadata.sag.channel: payload.channel
- payload: payload.data
You can use the Classifier codec to determine the event type based on incidental fields in the event, such as the method
and path
:
- classifierCodec:
rules:
- KickEvent:
- metadata.http.method: GET
- metadata.http.path: /kick
- DocumentSubmissionEvent:
- metadata.http.method: PUT
- metadata.http.path: /submit
- DocumentUpdateEvent:
- metadata.http.method: PUT
- metadata.http.path: /update
The default event type is generally used if all events received in requests are the same:
- apama.eventMap:
defaultEventType: TestEvent
You can use regular expressions with the Classifier codec to match more than one REST URL to a single event type. The following example shows a rule that matches two different REST URLs such as /database/emptable/78451339
and /database/managertable/50044897
:
- classifierCodec:
rules:
- com.apama.swagger.ISSPositionResponse:
- regex:metadata.http.path: /database/[a-zA-Z0-9]*/[0-9]*
For detailed information on these codecs, see The Mapper codec connectivity plug-in and The Classifier codec connectivity plug-in.
Handling HTTP headers
The HTTP server reads any number of headers from the received request and puts them into metadata.http.headers
. Similarly, when using EPL-supplied responses, headers are read from metadata.http.headers
and written into the response as individual HTTP header lines. Some special handling is applied as described below.
All HTTP headers are converted from ISO-8859-1 (the character set for HTTP headers as defined in the RFC publications) to UTF-8 in the metadata and vice-versa.
All HTTP header keys are converted to lowercase (since HTTP header keys are defined to be case-insensitive). You should use lowercase in all of your mapping and classification rules.
Any HTTP headers for which multiple values have been provided for a single key (after normalization of case) are dropped.
The content type and charset
in requests, which are parsed from the Content-Type
header, are provided in metadata.contentType
and metadata.charset
respectively. For responses, the two metadata fields are combined into the Content-Type
header.
If HTTP basic authentication is enabled, then the authorization
header is removed from metadata.http.headers
, but in this case the user name is still available in metadata.http.user
. If authorization
is none
, then the authorization type is passed through verbatim.
All cookies in requests are put into the metadata.http.cookies
field and that field is used to generate Set-Cookie
headers in responses. See also Dealing with cookies.
To protect the security of personal data, see Protecting personal data in Apama applications.
Handling HTTP form decoding
The HTTP server transport decodes multipart/form-data
or application/x-www-form-urlencoded
media types to a dictionary payload.
If the Content-Type
header field contains the application/x-www-form-urlencoded
media type, the request payload is decoded to a dictionary payload with string keys and string values.
If the Content-type
header field contains the multipart/form-data
media type, the request payload is decoded to a dictionary payload with string keys and either string or binary values.
For the parts that have binary data, additional metadata is created. This metadata contains the contentType
, charset
and filename
information for each binary part.
You can get the metadata as follows:
metadata.http.form.name.contentType
metadata.http.form.name.charset
metadata.http.form.name.filename
where name
corresponds to the data in payload.name
.
Simple example
In this example, a client sends HTTP POST
requests to the HTTP server transport and the Content-Type
header is set to multipart/form-data
. The request payload contains two form fields, one field has both a string key and string value, and the other field has a string key and binary value.
Simple raw HTTP POST
request:
POST http://localhost:80/
Content-Length: 737
Content-Type: multipart/form-data; boundary=--123456789
--123456789
Content-Disposition: form-data; name="foo"
bar
--123456789
Content-Disposition: form-data; name="file"; filename="file.txt"
Content-Type: text/plain; charset=utf-8
File data
--123456789--
For the above request, the HTTP server transport sends a dictionary payload({"foo":"bar", "file":File data})
to EPL.
Metadata created for the file
parts have text/plain
as the content type, utf-8
as the character set, and file.txt
as the filename. You can map the metadata using the Mapper codec:
- mapperCodec:
"*":
towardsHost:
mapFrom:
- payload.contentType: metadata.http.form.file.contentType
- payload.charset: metadata.http.form.file.charset
- payload.filename: metadata.http.form.file.filename
Parts metadata is only created for binary or file-upload form-data.
Mapping the body
The HTTP server accepts the payload as a binary object. What the payload consists of depends on the service you wish to provide. Many services use string-based protocols (such as JSON). For these types of payload, you can use the String codec (see The String codec connectivity plug-in). For messages towards the host, the String codec takes a byte array and decodes it to a string using the UTF-8 encoding. If you are using the String codec, you should put it as the last codec before the HTTP server.
The resulting string can then be mapped directly into a field in an EPL event, or it can be further processed by other codecs (such as the JSON codec, as used in our default configuration) before the resulting fields are mapped into the Apama event.
If you need to vary your processing depending on the type of the data received, you may need to write a custom codec in order to handle this. To help with distinguishing different payload types, the HTTP server sets top-level fields to indicate the type of the payload. The HTTP header indicates the MIME type populated into metadata.http.contentType
. If present, then the character set from the same HTTP header is copied into metadata.http.charset
.
When using EPL-supplied responses, the mapping rules must be bidirectional to map both the request and the response.
Dealing with cookies
The HTTP server stores cookies in metadata.http.cookies.keyname
entries.
In requests, the HTTP server takes any number of HTTP Cookie
headers and turns them into corresponding metadata.http.cookies
entries. You can either map the entire set of cookies to a dictionary field in an event, or you can map a specific cookie key to a field in an event.
In responses, the HTTP server adds Set-Cookie
headers for each entry in metadata.http.cookies
. You must use the Mapper codec to map things from your response events into the metadata entries.
Providing HTTP query parameters
HTTP requests can be set to contain request parameters, which are encoded at the end of the URL in the following form:
/path?key=value&key=value
The request parameters are decoded and added to the metadata.http.queryString
map as key-value pairs. The parameters can either be mapped to a dictionary field in an event, or a specific named parameter can be mapped to a single field. For example:
- mapperCodec:
Request:
towardsHost:
mapFrom:
# set one query parameter individually
- payload.paramValue: metadata.http.queryString.param
# alternatively set all query parameters in an EPL dictionary
- payload.parameters: metadata.http.queryString
The metadata.http.queryString
field is only set in the request when the query string is not empty. If you wish to map the query string to an event field and there is a chance it could be empty, add a defaultValue
for it in your mapperCodec
rules. See also The Mapper codec connectivity plug-in.
Examples
Generic engine_send
HTTP service
This example is the same as the default configuration supplied with Apama.
YAML dynamic chain:
dynamicChains:
HTTPServerChain:
- apama.eventMap
- mapperCodec:
"*":
towardsHost:
mapFrom:
- metadata.sag.type: payload.type
- metadata.sag.channel: payload.channel
- payload: payload.data
- jsonCodec
- stringCodec
- HTTPServerTransport:
authentication:
authenticationType: none
allowedUsersFile: ${PARENT_DIR}/userfile.txt
automaticResponses: true
allowedMethods: [PUT]
EPL:
event Temperature
{
integer sensorId;
string sensorName;
float temperature;
dictionary<string,any> extra;
}
monitor.subscribe("myChannel");
on all Temperature() as e {
//...
}
Curl example:
curl -X PUT http://localhost:8080/ -d '{"type":"Temperature",
"channel":"myChannel", data:{"sensorId":666, "sensorName":"FooBar",
"temperature":3.14",{"A":"alpha"}} }' -H "Content-Type:application/json"
Event type and channel information is specified in headers
YAML dynamic chain:
dynamicChains:
HTTPServerChain:
- apama.eventMap
- mapperCodec:
"*":
towardsHost:
mapFrom:
- metadata.sag.type : metadata.http.headers.x-apamaeventtype
- metadata.sag.channel : metadata.http.headers.x-apamachannel
- jsonCodec
- stringCodec
- HTTPServerTransport:
authenticationType: none
allowedUsersFile: ${PARENT_DIR}/userfile.txt
automaticResponses: true
allowedMethods: [PUT]
EPL:
event Temperature
{
integer sensorId;
string sensorName;
float temperature;
dictionary<string,any> extra;
}
monitor.subscribe("myChannel");
on all Temperature() as e {
//...
}
Curl example:
curl -X PUT -H "X-ApamaEventType:Temperature" -H "X-ApamaChannel:myChannel"
http://localhost:8080/ -d '{"sensorId":666, "sensorName":"FooBar",
"temperature":3.14",{"A":"alpha"} }' -H "Content-Type:application/json"
Event type and channel information is specified in the query string
YAML dynamic chain:
dynamicChains:
HTTPServerChain:
- apama.eventMap
- mapperCodec:
"*":
towardsHost:
mapFrom:
- metadata.sag.type : metadata.http.queryString.eventType
- metadata.sag.channel : metadata.http.queryString.channel
- jsonCodec
- stringCodec
- HTTPServerTransport:
authenticationType: none
allowedUsersFile: ${PARENT_DIR}/userfile.txt
automaticResponses: true
allowedMethods: [PUT]
EPL events:
event Temperature
{
integer sensorId;
string sensorName;
float temperature;
dictionary<string,any> extra;
}
monitor.subscribe("myChannel");
on all Temperature() as e {
//...
}
Curl example:
curl -X PUT 'http://host:port/submit?eventType=Temperature&channel=myChannel'
-d '{"sensorId":666, "sensorName":"FooBar", "temperature":3.14",{"A":"alpha"} }'
Event types are tied to the method and path and the channel is defaulted
YAML dynamic chain:
dynamicChains:
HTTPServerChain:
- apama.eventMap
- mapperCodec:
KickEvent:
towardsHost:
- metadata.sag.channel: kickEvents
DocumentSubmissionEvent:
towardsHost:
mapFrom:
- payload.data: payload
defaultValue:
- metadata.sag.channel: submissionEvents
DocumentUpdateEvent:
towardsHost:
mapFrom:
- payload.data: payload
defaultValue:
- metadata.sag.channel: updateEvents
- classifierCodec:
rules:
- KickEvent:
- metadata.http.method: GET
- metadata.http.path: /kick
- DocumentSubmissionEvent:
- metadata.http.method: PUT
- metadata.http.path: /submit
- DocumentUpdateEvent:
- metadata.http.method: PUT
- metadata.http.path: /update
- stringCodec
- HTTPServerTransport:
authenticationType: none
allowedUsersFile: ${PARENT_DIR}/userfile.txt
automaticResponses: true
allowedMethods: [PUT, GET]
EPL events:
event KickEvent { }
event DocumentSubmissionEvent { string data; }
event DocumentUpdateEvent { string data; }
Delivering Apama event strings
This example is using the string form of the event native to Apama. You should only use this example if you have a system that encodes events in that format.
YAML dynamic chain:
dynamicChains:
HTTPServerChain:
- apama.eventString
- mapperCodec:
"*":
towardsHost:
mapFrom:
- metadata.sag.channel: metadata.http.path
- stringCodec
- HTTPServerTransport:
authenticationType: none
allowedUsersFile: ${PARENT_DIR}/userfile.txt
automaticResponses: true
allowedMethods: [PUT]
EPL:
monitor.subscribe("/channel/ChannelName");
on all Temperature() as e {... }
Curl example:
curl -X PUT http://host:port/channel/ChannelName -d 'Temperature(10, "Baz",
6.022e23)'
EPL-controlled responses
This example generates responses to the HTTP requests in EPL. Requests should be JSON objects containing objectId
and requestType
. Responses are arbitrary JSON objects. See also Handling responses in EPL.
YAML dynamic chain:
dynamicChains:
HTTPServerChain:
- apama.eventMap:
defaultChannel: requests
defaultEventType: HTTPRequest
- mapperCodec:
"*":
towardsHost:
mapFrom:
- payload.requestId: metadata.requestId
defaultValue:
- payload.channel: "@{httpServer.responseChannel}"
towardsTransport:
mapFrom:
- metadata.requestId: payload.requestId
- payload: payload.responseData
defaultValue:
- metadata.http.statusCode: 200
- jsonCodec
- stringCodec
- HTTPServerTransport:
automaticResponses: false
allowedMethods: [ PUT ]
EPL:
monitor.subscribe("requests");
on all HTTPRequest() as r {
send HTTPResponse(r.requestId, getResponseData(r.requestType, r.objectId))
to r.channel;
}
EPL events:
event HTTPRequest {
integer requestId;
integer objectId;
string requestType;
string channel;
}
event HTTPResponse {
integer requestId;
any responseData;
}
HTTP server security
TLS
We provide TLS-based security with the HTTP server and we recommend that you use this in production. In order to be compatible with our system, you must use TLS version 1.2 or above.
We also recommend that your internet deployment is behind a reverse proxy for optimum security.
In order to use this, you must enable TLS in the YAML configuration file and supply a TLS server certificate file and corresponding key file, as shown in the following example:
dynamicChainManagers:
HTTPServerManager:
transport: HTTPServerTransport
managerConfig:
port: 443
tls: true
tlsKeyFile: ${PARENT_DIR}/servername.key.pem
tlsCertificateFile: ${PARENT_DIR}/servername.cert.pem
Authentication
HTTP basic authentication support is provided by comparing the request authentication contents against an authentication password file supplied during configuration. We recommend that you only use this if you also have TLS enabled. For more complex use cases, webMethods Integration Server should be used.
If you are using HTTP basic authentication, you must provide a valid authentication password file using the allowedUsersFile
configuration option.
This password file expected by the HTTP server for HTTP basic authentication is compatible with the output of Apache’s htpasswd -B
. There is also a bundled application called httpserver_passman
which can create and update password files. You can find the executable for this tool in the bin
folder of your Apama installation. The syntax for this is:
httpserver_passman password_file [options] username [password]
If you only provide a username and no password, then the password is prompted for interactively. This adds the specified user with the given password, or replaces the password if the user already exists in the password file.
The options are:
Option |
Description |
---|---|
|
Displays usage information. |
|
Creates a new file and overwrites anything currently there. |
|
Deletes the given user, rather than updating or adding the user. |
|
Does not treat subsequent arguments as options. Thus, it is possible to enter a username that starts with one or two minus signs. |
If HTTP basic authentication is enabled, then the authorization
header is removed from metadata.http.headers
, but in this case the user name is still available in metadata.http.user
. If authorization
is none
, then the authorization type is passed through verbatim.
HTTP_BASIC
requires verifying credentials on every request. It is not suitable for high-throughput applications.Using the configuration options maxAttempts
and coolDownSecs
, you can protect against brute force attacks on users and passwords (see also Configuring the HTTP server transport). The initial response to a failed authentication attempt is a “401 Unauthorized” response. This response occurs until the defined number of failed login attempts (maxAttempts
) has been reached. After this, the HTTP server ignores authentication attempts for the defined cool-down period (coolDownSecs
). During that period, the HTTP server returns “429 Too Many Requests” with a reason of “Too many failed authentication requests, please try again later.”. When the cool-down period has expired, the HTTP server attempts to authenticate any further request. If it fails that attempt, the user is immediately placed back into a cool-down period without retries.
To protect the security of personal data, see Protecting personal data in Apama applications.
Monitoring status for the HTTP server
The HTTP server component provides status values via the user status mechanism. It provides the following metrics (where prefix
is the name of the dynamic chain manager, typically HTTPServerManager
):
Key | Description |
---|---|
prefix.status |
Moves from STARTING to ONLINE when hostReady is called. |
prefix.eventsTowardsHost |
Number of requests resulting in events being sent to the correlator. This is the primary KPI for this component. |
prefix.failedRequests |
Number of non-2xx responses sent to clients, including errors generated from EPL. This is expected to be 0 and is a KPI with a warning threshold at 1. |
prefix.staticFileRequests |
Number of static files served to clients. This is a KPI. |
prefix.authenticationFailures |
Number of requests with invalid credentials. |
prefix.numChains |
Number of active chains for connections into this HTTP server instance. The chains can be reused between connections, but a single connection only uses one chain. This is expected to be between 0 and the maximum number of simultaneous connections which can be handled (see also maxConnections in Configuring the HTTP server transport). |
prefix.requestSizeEWMAShortBytes |
A quickly-evolving exponentially-weighted moving average of request sizes, in bytes. |
prefix.requestSizeEWMALongBytes |
A longer-term exponentially-weighted moving average of request sizes, in bytes. |
prefix.requestSizeMaxInLastHourBytes |
The maximum request size in bytes since the start of the last 1 hour measurement period. |
prefix.responseSizeEWMAShortBytes |
A quickly-evolving exponentially-weighted moving average of response sizes, in bytes. |
prefix.responseSizeEWMALongBytes |
A longer-term exponentially-weighted moving average of response sizes, in bytes. |
prefix.responseSizeMaxInLastHourBytes |
The maximum response size in bytes since the start of the last 1 hour measurement period. |
For each request/response that is processed, the above MaxInLastHour
values are updated if either of the following conditions is true:
- The size of the current message is greater than the existing maximum.
- The existing maximum value was set more than 1 hour ago.
Automatic responses are not included in the response size metrics.
Error responses are not included in the response size metrics. The request size metrics are calculated before compression and the response size metrics are calculated after decompression.
For more information about monitor status information published by the correlator, see Managing and monitoring over REST and Watching correlator runtime status.