Skip to content

feat: Body transformer plugin#8766

Merged
spacewander merged 19 commits into
apache:masterfrom
kingluo:body_transformer_plugin
Feb 10, 2023
Merged

feat: Body transformer plugin#8766
spacewander merged 19 commits into
apache:masterfrom
kingluo:body_transformer_plugin

Conversation

@kingluo

@kingluo kingluo commented Feb 1, 2023

Copy link
Copy Markdown
Contributor

Description

This plugin is used to transform the request or response body from one
format to another format, e.g. JSON to XML.

It depends on xml2lua and lua-resty-template.

Use cases:

  • simple SOAP proxy
  • generic template-based transform

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (If not, please discuss on the APISIX mailing list first)

@kingluo
kingluo marked this pull request as ready for review February 6, 2023 09:27
Comment thread apisix/plugins/body-transformer.lua Outdated


-- luacheck: ignore
function string.escape_xml(s)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we register these methods before we use them and deregister once the job is done? So we can avoid affecting other modules.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

luacheck has no inline option to depress "setting undefine field of global" warning. But depress the whole lua file is not proper. And escape_* has no conflict so far, so I think it's ok to use these names.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The solution is not about making luacheck happy, but limiting the scope of the injection. If we don't deregister the methods, it will affect other modules including those not written by us.
Anyway, it is not a good idea to allow the monkey patch of the std lib outside our scope.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I know. But setting methods on demand on the global object will make luacheck warns: setting undefined field escape_xml of global string, which could not be depressed via inline comment, so ignore the whole file in .luacheckrc instead?

function _M.body_filter(conf, ctx)
if conf.response then
local body = core.response.hold_body_chunk(ctx)
if ngx.arg[2] == false and not body then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ngx.arg[2] == false and not body then
if not body then

hold_body_chunk returns a body only when ngx.arg[2] is true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, this plugiin needs to handle body=nil case.

Comment thread apisix/plugins/body-transformer.lua Outdated
if type(k) == "string" then
k = k:match(".*:(.*)")
if k then
tbl[k] = v

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems this code just inserts a new k

end


function _M.rewrite(conf, ctx)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rewrite is only for plugins that require running before other plugins. For example, plugins to select consumers, plugins for tracing, plugins to set real IP, and so on. Most of the other plugin use access phase.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This plugin needs to use original content-type header before proxy-rewrite plugin overrrdes it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this plugin is just doing rewrite job, just like proxy-rewrite plugin.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We used to have a discussion to unify the "rewrite/access" methods in 2020.
Since this is not the only plugin that has inconsistent "rewrite/access" methods, and you insist on it, I am OK to accept it.



local function set_input_format(conf, typ, ct)
if conf[typ].input_format == nil and ct then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The conf is shared between reqs. Is there a race if the previous request set the input format different from the current one?

Comment thread t/plugin/body-transformer.t Outdated
local httpc = http.new()
local res, err = httpc:request_uri(uri, opt)
if not res then
ngx.say(err)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should check --- response_body to ensure no err happens. Please update other similar places.

Comment thread t/plugin/body-transformer.t Outdated
}
}
--- error_log
attempt to call global 'name' (a string value)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add log prefix to ensure it comes from an expected log

Comment thread t/plugin/body-transformer.t Outdated
local uri = "http://127.0.0.1:" .. ngx.var.server_port .. "/foobar?name=hello"
local opt = {method = "GET"}
local httpc = http.new()
httpc:request_uri(uri, opt)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to check the res here?

| ----------- | ----------- | ----------- | ----------- |
| `request` | object | False | request body transformation configuration |
| `request.input_format` | string | False | request body original format, if not specified, it would be determined from `Content-Type` header. |
| `request.template` | string | False | request body transformation template |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The template is required

| `request.template` | string | False | request body transformation template |
| `response` | object | False | response body transformation configuration |
| `response.input_format` | string | False | response body original format |
| `response.template` | string | False | response body transformation template, if not specified, it would be determined from `Content-Type` header. |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean determining the input_format from Content-Type header?


function _M.body_filter(_, ctx)
local conf = ctx.body_transformer_conf
if conf.response then

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems if neither conf.request nor conf.response are given, the conf will be nil here.
We should check if one of them is configured at least in check_schema.

@spacewander
spacewander merged commit cfeadfb into apache:master Feb 10, 2023
hongbinhsu added a commit to fitphp/apix that referenced this pull request Feb 13, 2023
* upstream/master:
  docs: change the file name to 'create-ssl.py'.If 'ssl.py' is used as … (apache#8623)
  feat: Body transformer plugin (apache#8766)
  fix: mocking plugin panic when response_example contain $ (apache#8810) (apache#8816)
  feat: file logger plugin support response body in variable (apache#8711)
  docs(getting-started): rewrite the install section (apache#8807)
  feat: allow each logger to define custom log format in its conf (apache#8806)
  fix(etcd): reloaded data may be in res.body.node (apache#8736)
  fix: fix fetch all service info from consul (apache#8651)
  docs: fix global-rule.md wrong curl  address (apache#8793)
  feat: stream subsystem support consul service discovery (apache#8696)
  chore(kafka-logger): support configuration `meta_refresh_interval` parameter (apache#8762)
  feat: ready to release 2.15.2 (apache#8783)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants