Add Content-Type directive to body factory .body_factory_info#12947
Add Content-Type directive to body factory .body_factory_info#12947bryancall wants to merge 9 commits intoapache:masterfrom
Conversation
The body factory previously only supported Content-Language and Content-Charset directives in .body_factory_info. This adds a Content-Type directive so operators can control the MIME type of error responses (e.g. text/plain instead of the default text/html). Also fixes HttpSM::setup_internal_transfer which was unconditionally overwriting Content-Type to text/html, masking any type set by the body factory. Now uses the presence bit check to only set the default when Content-Type is not already present in the response.
The :file: role with nitpicky mode causes an unresolved reference warning for .body_factory_info. Use literal markup instead.
There was a problem hiding this comment.
Pull request overview
This PR extends Apache Traffic Server’s body factory error-page customization to support a configurable Content-Type via .body_factory_info, and prevents HttpSM from overwriting an already-set Content-Type during internal transfers.
Changes:
- Add parsing/storage of a new
Content-Typedirective in.body_factory_infoand use it when generating body-factory responses. - Update
HttpSM::setup_internal_transfer()to only apply thetext/htmldefault whenContent-Typeis not already present. - Add documentation and a gold test covering both default and custom
Content-Typebehavior.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/gold_tests/body_factory/body_factory_content_type.test.py | New autest validating default (text/html) vs custom (text/plain) body-factory Content-Type. |
| src/proxy/http/HttpSM.cc | Avoids unconditional Content-Type: text/html overwrite by checking the presence bit. |
| src/proxy/http/HttpBodyFactory.cc | Parses Content-Type from .body_factory_info and incorporates it into generated response headers. |
| include/proxy/http/HttpBodyFactory.h | Extends internal fabricate() signature and body set metadata to include content_type. |
| doc/admin-guide/monitoring/error-messages.en.rst | Documents .body_factory_info directives, including the new Content-Type. |
| configs/body_factory/default/.body_factory_info | Updates shipped template metadata comments to include the new directive. |
You can also share your feedback on Copilot code review. Take the survey.
- Rename type_ptr to content_type_ptr to avoid confusion with the type parameter (error template name) - Fix docs: .body_factory_info is required for a template set to load, not optional. Absent file causes the directory to be skipped. - Use literal markup for .body_factory_info to fix Sphinx nitpick warning
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
You can also share your feedback on Copilot code review. Take the survey.
tests/gold_tests/body_factory/body_factory_content_type.test.py
Outdated
Show resolved
Hide resolved
|
[approve ci autest 0 autest 1 autest 2 autest 3] |
Only include "; charset=X" when a custom Content-Type is configured in .body_factory_info. Default responses emit just "text/html" to preserve backward-compatible header behavior.
Avoid duplicating charset when a custom body-factory Content-Type already sets one, normalize Korean language-tag examples to BCP47, and make the autest Content-Type matching more formatting-tolerant.
|
[approve ci autest 3] |
The body factory Content-Type feature changes how error page headers are generated: charset is no longer appended when no explicit Content-Type directive exists, and setup_internal_transfer now preserves existing Content-Type instead of always overwriting with text/html.
Use internal_msg_buffer_type to carry the body factory Content-Type through to setup_internal_transfer, which applies it after plugin hooks run. This prevents plugins (e.g. xdebug) from overwriting the Content-Type during SEND_RESPONSE_HDR on error pages. Reverts the MIME_PRESENCE_CONTENT_TYPE check in setup_internal_transfer since internal_msg_buffer_type is the correct mechanism for this. Also fixes the x_remap gold file: Content-Type stays text/html (the body is HTML), only X-Original-Content-Type drops the charset suffix.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
src/proxy/http/HttpTransact.cc:8367
- When
len == 0,internal_msg_buffer_typeis left unchanged. Sincefree_internal_msg_buffer()does not clear it, this can leave a stale MIME type associated with an empty error body untilState::destroy()runs (and potentially returned via TSHttpTxnErrorBodyGet). Consider freeing and nullings->internal_msg_buffer_typein this branch as well.
} else {
s->hdr_info.client_response.field_delete(static_cast<std::string_view>(MIME_FIELD_CONTENT_TYPE));
s->hdr_info.client_response.field_delete(static_cast<std::string_view>(MIME_FIELD_CONTENT_LANGUAGE));
}
| if (len > 0) { | ||
| s->hdr_info.client_response.value_set(static_cast<std::string_view>(MIME_FIELD_CONTENT_TYPE), body_type); | ||
| s->hdr_info.client_response.value_set(static_cast<std::string_view>(MIME_FIELD_CONTENT_LANGUAGE), body_language); | ||
| ats_free(s->internal_msg_buffer_type); | ||
| s->internal_msg_buffer_type = ats_strdup(body_type); |
There was a problem hiding this comment.
The PR description mentions fixing HttpSM::setup_internal_transfer to only apply the text/html default when Content-Type is not already present, but setup_internal_transfer() still unconditionally sets Content-Type: text/html when internal_msg_buffer_type is null. If the intent is to preserve a Content-Type set earlier in the response pipeline (e.g., by a plugin), this behavior still overwrites it unless the plugin also populates internal_msg_buffer_type.
| ``Content-Charset`` | ||
| The character encoding of the error pages. This value is appended to the ``Content-Type`` header | ||
| as a ``charset`` parameter. Default: ``utf-8``. | ||
|
|
There was a problem hiding this comment.
The Content-Charset directive is documented as always being appended to the Content-Type header as a charset parameter, but the current implementation only appends ; charset=... when a Content-Type directive is present and does not already include charset=. Consider updating this section to reflect the actual behavior (including what happens when Content-Type is omitted or already has a charset parameter).
| body factory error responses instead of the hardcoded text/html default. | ||
|
|
||
| Two scenarios: | ||
| 1. Default: no Content-Type directive -> text/html; charset=utf-8 |
There was a problem hiding this comment.
The scenario description in this docstring says the default case returns text/html; charset=utf-8, but the test below only asserts text/html (no charset) for the default path. Please update the docstring to match the behavior being tested.
| 1. Default: no Content-Type directive -> text/html; charset=utf-8 | |
| 1. Default: no Content-Type directive -> text/html |
Don't silently append "; charset=X" to a custom Content-Type. If the operator writes "Content-Type: text/plain", that's what the client gets. If they want charset, they write "Content-Type: text/plain; charset=utf-8" explicitly.
The error page templates are UTF-8, so the default Content-Type should declare it: "text/html; charset=utf-8". This is more correct per HTTP specs and matches what the body factory was originally producing before setup_internal_transfer was stripping it.
|
[approve ci autest] |
Problem
Body factory error responses are always served with
Content-Type: text/htmland there is no way to change this. The.body_factory_infometadata file supportsContent-LanguageandContent-Charsetdirectives but has noContent-Typedirective. Operators who serve non-HTML error pages (plain text, JSON, etc.) have no mechanism to set the correct MIME type.Additionally,
HttpSM::setup_internal_transferunconditionally overwritesContent-Typetotext/htmlwheninternal_msg_buffer_typeis NULL, which would mask any type set earlier in the response pipeline.Summary
Add
Content-Typedirective to.body_factory_info-- Operators can now set the MIME type for body factory error responses (e.g.Content-Type: text/plain) instead of the hardcodedtext/htmldefault. The directive is parsed alongside the existingContent-LanguageandContent-Charsetdirectives.Fix Content-Type overwrite in
HttpSM::setup_internal_transfer-- Now uses theMIME_PRESENCE_CONTENT_TYPEpresence bit to only apply thetext/htmldefault when Content-Type is not already present in the response.Add documentation for
.body_factory_infometadata file -- The admin guide's error messages page now documents all three supported directives (Content-Language,Content-Charset,Content-Type) with examples.Add autest -- New
body_factory_content_type.test.pyverifies both default (text/html) and custom (text/plain) Content-Type behavior.Testing
Fixes: #10893