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 "HTTP.h" 61 #include "HttpConfig.h" 62 #include "HttpCompat.h" 63 #include "HttpTransact.h" 64 #include "tscore/ink_sprintf.h" 65 66 #include <memory> 67 #include <unordered_map> 68 69 #define HTTP_BODY_TEMPLATE_MAGIC 0xB0DFAC00 70 #define HTTP_BODY_SET_MAGIC 0xB0DFAC55 71 #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 is_sane()93 is_sane() 94 { 95 return (magic == HTTP_BODY_TEMPLATE_MAGIC); 96 } 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 struct HttpBodySetRawData { 114 using TemplateTable = std::unordered_map<std::string, HttpBodyTemplate *>; 115 unsigned int magic = 0; 116 char *set_name; 117 char *content_language; 118 char *content_charset; 119 std::unique_ptr<TemplateTable> table_of_pages; 120 }; 121 122 //////////////////////////////////////////////////////////////////////// 123 // 124 // class HttpBodySet 125 // 126 // An HttpBodySet object represents a set of body factory 127 // templates. It includes operators to get the hash table of 128 // templates, and the associated metadata for the set. 129 // 130 // The raw data members come from HttpBodySetRawData above 131 // 132 //////////////////////////////////////////////////////////////////////// 133 134 class HttpBodySet : public HttpBodySetRawData 135 { 136 public: 137 HttpBodySet(); 138 ~HttpBodySet(); 139 140 int init(char *set_name, char *dir); 141 bool is_sane()142 is_sane() 143 { 144 return (magic == HTTP_BODY_SET_MAGIC); 145 } 146 147 HttpBodyTemplate *get_template_by_name(const char *name); 148 void set_template_by_name(const char *name, HttpBodyTemplate *t); 149 }; 150 151 //////////////////////////////////////////////////////////////////////// 152 // 153 // class HttpBodyFactory 154 // 155 // An HttpBodyFactory object is the main object which keeps track 156 // of all the response body templates, and which provides the 157 // methods to create response bodies. 158 // 159 // Once an HttpBodyFactory object is initialized, and the template 160 // data has been loaded, the HttpBodyFactory object allows the 161 // caller to make error message bodies w/fabricate_with_old_api 162 // 163 //////////////////////////////////////////////////////////////////////// 164 165 class HttpBodyFactory 166 { 167 public: 168 using BodySetTable = std::unordered_map<std::string, HttpBodySetRawData *>; 169 HttpBodyFactory(); 170 ~HttpBodyFactory(); 171 172 /////////////////////// 173 // primary user APIs // 174 /////////////////////// 175 char *fabricate_with_old_api(const char *type, HttpTransact::State *context, int64_t max_buffer_length, 176 int64_t *resulting_buffer_length, char *content_language_out_buf, size_t content_language_buf_size, 177 char *content_type_out_buf, size_t content_type_buf_size, int format_size, const char *format); 178 179 char * getFormat(int64_t max_buffer_length,int64_t * resulting_buffer_length,const char * format,...)180 getFormat(int64_t max_buffer_length, int64_t *resulting_buffer_length, const char *format, ...) 181 { 182 char *msg = nullptr; 183 if (format) { 184 va_list ap; 185 186 va_start(ap, format); 187 188 // The length from ink_bvsprintf includes the trailing NUL, so adjust the final 189 // length accordingly. Note that ink_bvsprintf() copies the va_list, so we only 190 // have to set it up once. 191 int l = ink_bvsprintf(nullptr, format, ap); 192 193 if (l <= max_buffer_length) { 194 msg = (char *)ats_malloc(l); 195 *resulting_buffer_length = ink_bvsprintf(msg, format, ap) - 1; 196 } 197 va_end(ap); 198 } 199 return msg; 200 } 201 202 void dump_template_tables(FILE *fp = stderr); 203 void reconfigure(); 204 static const char *determine_set_by_language(std::unique_ptr<BodySetTable> &table_of_sets, StrList *acpt_language_list, 205 StrList *acpt_charset_list, float *Q_best_ptr, int *La_best_ptr, int *Lc_best_ptr, 206 int *I_best_ptr); 207 208 private: 209 char *fabricate(StrList *acpt_language_list, StrList *acpt_charset_list, const char *type, HttpTransact::State *context, 210 int64_t *resulting_buffer_length, const char **content_language_return, const char **content_charset_return, 211 const char **set_return = nullptr); 212 213 const char *determine_set_by_language(StrList *acpt_language_list, StrList *acpt_charset_list); 214 const char *determine_set_by_host(HttpTransact::State *context); 215 HttpBodyTemplate *find_template(const char *set, const char *type, HttpBodySet **body_set_return); 216 bool is_response_suppressed(HttpTransact::State *context); 217 bool is_sane()218 is_sane() 219 { 220 return (magic == HTTP_BODY_FACTORY_MAGIC); 221 } 222 void sanity_check()223 sanity_check() 224 { 225 ink_assert(is_sane()); 226 } 227 228 private: 229 //////////////////////////// 230 // initialization methods // 231 //////////////////////////// 232 void nuke_template_tables(); 233 std::unique_ptr<BodySetTable> load_sets_from_directory(char *set_dir); 234 HttpBodySet *load_body_set_from_directory(char *set_name, char *tmpl_dir); 235 236 ///////////////////////////////////////////////// 237 // internal data structure concurrency control // 238 ///////////////////////////////////////////////// 239 void lock()240 lock() 241 { 242 ink_mutex_acquire(&mutex); 243 } 244 void unlock()245 unlock() 246 { 247 ink_mutex_release(&mutex); 248 } 249 250 ///////////////////////////////////// 251 // manager configuration variables // 252 ///////////////////////////////////// 253 int enable_customizations = 0; // 0:no custom,1:custom,2:language-targeted 254 bool enable_logging = true; // the user wants body factory logging 255 int response_suppression_mode = 0; // when to suppress responses 256 257 //////////////////// 258 // internal state // 259 //////////////////// 260 unsigned int magic = HTTP_BODY_FACTORY_MAGIC; // magic for sanity checks/debugging 261 ink_mutex mutex; // prevents reconfig/read races 262 bool callbacks_established = false; // all config variables present 263 std::unique_ptr<BodySetTable> table_of_sets; // sets of template hash tables 264 }; 265