Coverage Report

Created: 2026-10-23 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/trafficserver/include/proxy/http/HttpBodyFactory.h
Line
Count
Source
1
/** @file
2
3
  A brief file description
4
5
  @section license License
6
7
  Licensed to the Apache Software Foundation (ASF) under one
8
  or more contributor license agreements.  See the NOTICE file
9
  distributed with this work for additional information
10
  regarding copyright ownership.  The ASF licenses this file
11
  to you under the Apache License, Version 2.0 (the
12
  "License"); you may not use this file except in compliance
13
  with the License.  You may obtain a copy of the License at
14
15
      http://www.apache.org/licenses/LICENSE-2.0
16
17
  Unless required by applicable law or agreed to in writing, software
18
  distributed under the License is distributed on an "AS IS" BASIS,
19
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
  See the License for the specific language governing permissions and
21
  limitations under the License.
22
 */
23
24
/****************************************************************************
25
26
  HttpBodyFactory.h
27
28
  This implements a user-customizable response message generation system.
29
30
  The concept is simple.  Error/response messages are classified into
31
  several types, each given a name, such as "request/header_error".
32
33
  The HttpBodyFactory can build a message body for each response type.
34
  The user can create custom message body text for each type (stored
35
  in a text file directory), containing templates with space-holders for
36
  variables which are inline-substituted with current values.  The resulting
37
  body is dynamically allocated and returned.
38
39
  The major data types implemented in this file are:
40
41
    HttpBodyFactory       The main data structure which is the machine
42
                          that maintains configuration information, reads
43
                          user error message template files, and performs
44
                          the substitution to generate the message bodies.
45
46
    HttpBodySet           The data structure representing a set of
47
                          templates, including the templates and metadata.
48
49
    HttpBodyTemplate      The template loaded from the directory to be
50
                          instantiated with variables, producing a body.
51
52
53
 ****************************************************************************/
54
55
#pragma once
56
57
#include <strings.h>
58
#include <sys/types.h>
59
#include "tscore/ink_platform.h"
60
#include "proxy/hdrs/HTTP.h"
61
#include "proxy/http/HttpConfig.h"
62
#include "proxy/hdrs/HttpCompat.h"
63
#include "proxy/http/HttpTransact.h"
64
#include "tscore/ink_sprintf.h"
65
66
#include <memory>
67
#include <unordered_map>
68
69
0
#define HTTP_BODY_TEMPLATE_MAGIC 0xB0DFAC00
70
0
#define HTTP_BODY_SET_MAGIC      0xB0DFAC55
71
0
#define HTTP_BODY_FACTORY_MAGIC  0xB0DFACFF
72
73
////////////////////////////////////////////////////////////////////////
74
//
75
//      class HttpBodyTemplate
76
//
77
//      An HttpBodyTemplate object represents a template with HTML
78
//      text, and unexpanded log fields.  The object also has methods
79
//      to dump out the contents of the template, and to instantiate
80
//      the template into a buffer given a context.
81
//
82
////////////////////////////////////////////////////////////////////////
83
84
class HttpBodyTemplate
85
{
86
public:
87
  HttpBodyTemplate();
88
  ~HttpBodyTemplate();
89
90
  void reset();
91
  int  load_from_file(char *dir, char *file);
92
  bool
93
  is_sane()
94
0
  {
95
0
    return (magic == HTTP_BODY_TEMPLATE_MAGIC);
96
0
  }
97
  char *build_instantiated_buffer(HttpTransact::State *context, int64_t *length_return);
98
99
  unsigned int magic;
100
  int64_t      byte_count;
101
  char        *template_buffer;
102
  char        *template_pathname;
103
};
104
105
////////////////////////////////////////////////////////////////////////
106
//
107
//      class HttpBodySetRawData
108
//
109
//      Raw data members of HttpBodySet
110
//
111
////////////////////////////////////////////////////////////////////////
112
113
class HttpBodySetRawData
114
{
115
public:
116
  using TemplateTable = std::unordered_map<std::string, std::unique_ptr<HttpBodyTemplate>>;
117
118
0
  virtual ~HttpBodySetRawData() {}
119
120
  unsigned int                   magic = 0;
121
  char                          *set_name;
122
  char                          *content_language;
123
  char                          *content_charset;
124
  char                          *content_type;
125
  std::unique_ptr<TemplateTable> table_of_pages;
126
};
127
128
////////////////////////////////////////////////////////////////////////
129
//
130
//      class HttpBodySet
131
//
132
//      An HttpBodySet object represents a set of body factory
133
//      templates.  It includes operators to get the hash table of
134
//      templates, and the associated metadata for the set.
135
//
136
//      The raw data members come from HttpBodySetRawData above
137
//
138
////////////////////////////////////////////////////////////////////////
139
140
class HttpBodySet : public HttpBodySetRawData
141
{
142
public:
143
  HttpBodySet();
144
  ~HttpBodySet();
145
146
  int init(char *set_name, char *dir);
147
  bool
148
  is_sane()
149
0
  {
150
0
    return (magic == HTTP_BODY_SET_MAGIC);
151
0
  }
152
153
  HttpBodyTemplate *get_template_by_name(const char *name);
154
  void              set_template_by_name(const char *name, std::unique_ptr<HttpBodyTemplate> t);
155
};
156
157
////////////////////////////////////////////////////////////////////////
158
//
159
//      class HttpBodyFactory
160
//
161
//      An HttpBodyFactory object is the main object which keeps track
162
//      of all the response body templates, and which provides the
163
//      methods to create response bodies.
164
//
165
//      Once an HttpBodyFactory object is initialized, and the template
166
//      data has been loaded, the HttpBodyFactory object allows the
167
//      caller to make error message bodies w/fabricate_with_old_api
168
//
169
////////////////////////////////////////////////////////////////////////
170
171
class HttpBodyFactory
172
{
173
public:
174
  using BodySetTable = std::unordered_map<std::string, HttpBodySetRawData *>;
175
  HttpBodyFactory();
176
  ~HttpBodyFactory();
177
178
  ///////////////////////
179
  // primary user APIs //
180
  ///////////////////////
181
  char *fabricate_with_old_api(const char *type, HttpTransact::State *context, int64_t max_buffer_length,
182
                               int64_t *resulting_buffer_length, char *content_language_out_buf, size_t content_language_buf_size,
183
                               char *content_type_out_buf, size_t content_type_buf_size, int format_size, const char *format);
184
185
  char *
186
  getFormat(int64_t max_buffer_length, int64_t *resulting_buffer_length, const char *format, ...)
187
0
  {
188
0
    char *msg = nullptr;
189
0
    if (format) {
190
0
      va_list ap;
191
192
0
      va_start(ap, format);
193
194
      // The length from ink_bvsprintf includes the trailing NUL, so adjust the final
195
      // length accordingly. Note that ink_bvsprintf() copies the va_list, so we only
196
      // have to set it up once.
197
0
      int l = ink_bvsprintf(nullptr, format, ap);
198
199
0
      if (l <= max_buffer_length) {
200
0
        msg                      = (char *)ats_malloc(l);
201
0
        *resulting_buffer_length = ink_bvsprintf(msg, format, ap) - 1;
202
0
      }
203
0
      va_end(ap);
204
0
    }
205
0
    return msg;
206
0
  }
207
208
  void               dump_template_tables(FILE *fp = stderr);
209
  void               reconfigure();
210
  static const char *determine_set_by_language(std::unique_ptr<BodySetTable> &table_of_sets, StrList *acpt_language_list,
211
                                               StrList *acpt_charset_list, float *Q_best_ptr, int *La_best_ptr, int *Lc_best_ptr,
212
                                               int *I_best_ptr);
213
214
  bool is_response_suppressed(HttpTransact::State *context);
215
216
private:
217
  char *fabricate(StrList *acpt_language_list, StrList *acpt_charset_list, const char *type, HttpTransact::State *context,
218
                  int64_t *resulting_buffer_length, const char **content_language_return, const char **content_charset_return,
219
                  const char **content_type_return, const char **set_return = nullptr);
220
221
  const char       *determine_set_by_language(StrList *acpt_language_list, StrList *acpt_charset_list);
222
  const char       *determine_set_by_host(HttpTransact::State *context);
223
  HttpBodyTemplate *find_template(const char *set, const char *type, HttpBodySet **body_set_return);
224
  bool
225
  is_sane()
226
0
  {
227
0
    return (magic == HTTP_BODY_FACTORY_MAGIC);
228
0
  }
229
  void
230
  sanity_check()
231
0
  {
232
0
    ink_assert(is_sane());
233
0
  }
234
235
private:
236
  ////////////////////////////
237
  // initialization methods //
238
  ////////////////////////////
239
  void                          nuke_template_tables();
240
  std::unique_ptr<BodySetTable> load_sets_from_directory(char *set_dir);
241
  HttpBodySet                  *load_body_set_from_directory(char *set_name, char *tmpl_dir);
242
243
  /////////////////////////////////////////////////
244
  // internal data structure concurrency control //
245
  /////////////////////////////////////////////////
246
  void
247
  lock()
248
0
  {
249
0
    ink_mutex_acquire(&mutex);
250
0
  }
251
  void
252
  unlock()
253
0
  {
254
0
    ink_mutex_release(&mutex);
255
0
  }
256
257
  /////////////////////////////////////
258
  // manager configuration variables //
259
  /////////////////////////////////////
260
  int  enable_customizations = 0;    // 0:no custom,1:custom,2:language-targeted
261
  bool enable_logging        = true; // the user wants body factory logging
262
263
  ////////////////////
264
  // internal state //
265
  ////////////////////
266
  unsigned int                  magic = HTTP_BODY_FACTORY_MAGIC; // magic for sanity checks/debugging
267
  ink_mutex                     mutex;                           // prevents reconfig/read races
268
  bool                          callbacks_established = false;   // all config variables present
269
  std::unique_ptr<BodySetTable> table_of_sets;                   // sets of template hash tables
270
};