Source: builder.js

  1. /*
  2. * Copyright 2018-2022 the original author or authors.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. 'use strict'
  17. /**
  18. * Builder:
  19. * Utility module to export builder functions useful for creating
  20. * values (grouped or not) to use in Cloudevents.
  21. * Should not be used outside of the plugin.
  22. * @module utility
  23. */
  24. /**
  25. * Get a reference to CloudEvent class definition and related utilities.
  26. * See {@link CloudEvent}.
  27. * @private
  28. */
  29. const { CloudEvent, CloudEventTransformer } = require('cloudevent')
  30. /**
  31. * Utility function for creating grouped values to use in Cloudevents.
  32. * Should not be used outside of the plugin.
  33. *
  34. * @param {!object} options configuration options
  35. * @return {object} an object with builder functions (configured) to use
  36. * @private
  37. */
  38. function builder (options = {}) {
  39. const {
  40. pluginName,
  41. pluginVersion,
  42. serverUrl,
  43. serverUrlMode,
  44. baseNamespace,
  45. idGenerator,
  46. includeHeaders,
  47. includeRedundantAttributes,
  48. cloudEventOptions,
  49. cloudEventExtensions
  50. } = options
  51. return {
  52. /**
  53. * Build the value for the source field of the CloudEvent,
  54. * depending on the plugin configuration of options
  55. * `serverUrlMode`, `serverUrl`,
  56. * and the uri part of the current request.
  57. * Note that this is mainly for usage inside the plugin,
  58. * but in some cases could be useful even outside.
  59. *
  60. * @param {string} [url=''] the uri part of the current request
  61. * @return {string} the source value to use, as a string
  62. * @private
  63. */
  64. buildSourceUrl (url = '') {
  65. let sourceUrl
  66. switch (serverUrlMode) {
  67. case null:
  68. case 'pluginAndRequestSimplified':
  69. sourceUrl = serverUrl + CloudEventTransformer.uriStripArguments(url)
  70. break
  71. case 'pluginAndRequestUrl':
  72. sourceUrl = serverUrl + url
  73. break
  74. case 'pluginServerUrl':
  75. sourceUrl = serverUrl
  76. break
  77. case 'requestUrl':
  78. sourceUrl = url
  79. break
  80. default:
  81. throw new Error(`Illegal value for serverUrlMode: '${serverUrlMode}'`)
  82. }
  83. return sourceUrl
  84. },
  85. /**
  86. * Extract and build the value for the client IP address,
  87. * useful to add into the CloudEvent in a custom attribute inside data,
  88. * otherwise nothing.
  89. *
  90. * @param {!object} request the request
  91. * @return {string} the IP address, as a string or undefined
  92. * @private
  93. */
  94. buildClientIP (request) {
  95. if (request === undefined || request === null) {
  96. throw new Error('Illegal value for request: undefined or null')
  97. }
  98. return request.ip || undefined
  99. },
  100. /**
  101. * Extract and build the value for the HTTP headers,
  102. * useful to add into the CloudEvent in a custom attribute inside data.
  103. * If plugin flag 'includeHeaders' is enabled, headers will be returned,
  104. * otherwise nothing.
  105. * Note that some config options for builders are used here.
  106. *
  107. * @param {!object} request the request
  108. * @return {string} HTTP request headers, as a string, or undefined
  109. * @private
  110. */
  111. buildHeaders (request) {
  112. if (request === undefined || request === null) {
  113. throw new Error('Illegal value for request: undefined or null')
  114. }
  115. const headers = (includeHeaders === null || includeHeaders === false) ? undefined : request.headers
  116. return headers
  117. },
  118. /**
  119. * Extract and build values from the given arguments,
  120. * and returns them inside a wrapper object.
  121. *
  122. * @param {!object} request the request
  123. * @return {object} an object containing headers, source URL, the IP address
  124. * @private
  125. */
  126. buildValues (request) {
  127. const clientIp = this.buildClientIP(request)
  128. const headers = this.buildHeaders(request)
  129. const sourceUrl = this.buildSourceUrl(request.raw.url)
  130. return { clientIp, headers, sourceUrl }
  131. },
  132. /**
  133. * Extract some values from the given arguments,
  134. * and returns them inside a wrapper object
  135. * to be used in a CloudEvent data (sub-)property.
  136. *
  137. * @param {!object} request the request
  138. * @return {object} an object containing extracted attributes
  139. * @private
  140. */
  141. buildRequestDataForCE (request) {
  142. return {
  143. id: request.id,
  144. headers: this.buildHeaders(request),
  145. clientIp: this.buildClientIP(request),
  146. params: request.params,
  147. query: request.query,
  148. body: request.body,
  149. method: request.raw.method,
  150. url: request.raw.url
  151. }
  152. },
  153. /**
  154. * Extract some values from the given arguments,
  155. * and returns them inside a wrapper object
  156. * to be used in a CloudEvent data (sub-)property.
  157. *
  158. * @param {!object} reply the reply
  159. * @return {object} an object containing extracted attributes
  160. * @private
  161. */
  162. buildReplyDataForCE (reply) {
  163. return {
  164. statusCode: reply.raw.statusCode,
  165. statusMessage: reply.raw.statusMessage,
  166. finished: reply.raw.finished
  167. }
  168. },
  169. /**
  170. * Extract some values from the given arguments,
  171. * and returns them inside a wrapper object
  172. * to be used in a CloudEvent data (sub-)property.
  173. * Note that some config options for builders are used here.
  174. *
  175. * @param {object} [description=''] the description (maybe related to the event)
  176. * @return {object} an object containing extracted attributes
  177. * @private
  178. */
  179. buildPluginDataForCE (description = '') {
  180. return {
  181. timestamp: CloudEventTransformer.timestampToNumber(),
  182. description,
  183. name: pluginName,
  184. version: pluginVersion
  185. }
  186. },
  187. /**
  188. * Build a CloudEvent instance from the given arguments,
  189. * useful for simplify plugin hooks.
  190. * If plugin flag 'includeRedundantAttributes' is enabled,
  191. * some redundant attributes will be added to data.
  192. * Note that some config options for builders are used here.
  193. *
  194. * @param {!string} hookName the name of the hook
  195. * @param {!object} request the request
  196. * @param {object} reply the reply
  197. * @param {object} payload the payload
  198. * @return {object} the CloudEvent instance
  199. * @private
  200. */
  201. buildCloudEventForHook (hookName, request, reply, payload) {
  202. if (!hookName || !request) {
  203. throw new Error('Illegal arguments: mandatory argument undefined or null')
  204. }
  205. const ceData = {
  206. request: this.buildRequestDataForCE(request),
  207. reply: (reply === null) ? undefined : this.buildReplyDataForCE(reply),
  208. payload
  209. }
  210. if (includeRedundantAttributes !== null && includeRedundantAttributes === true) {
  211. ceData.id = request.id
  212. ceData.timestamp = CloudEventTransformer.timestampToNumber()
  213. }
  214. const ce = new CloudEvent(idGenerator.next().value,
  215. `${baseNamespace}.${hookName}`,
  216. this.buildSourceUrl(request.raw.url),
  217. ceData,
  218. cloudEventOptions,
  219. cloudEventExtensions
  220. )
  221. return ce
  222. }
  223. }
  224. }
  225. module.exports = builder