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 StatPages.cc
27
28
29 ****************************************************************************/
30
31 #include "tscore/ink_config.h"
32 #include "ProxyConfig.h"
33 #include "StatPages.h"
34 #include "HdrUtils.h"
35 #include "tscore/MatcherUtils.h"
36
37 #define MAX_STAT_PAGES 32
38
39 // Globals
40 StatPagesManager statPagesManager;
41
42 static struct {
43 char *module;
44 StatPagesFunc func;
45 } stat_pages[MAX_STAT_PAGES];
46
47 static int n_stat_pages;
48
49 void
init()50 StatPagesManager::init()
51 {
52 ink_mutex_init(&stat_pages_mutex);
53 REC_EstablishStaticConfigInt32(m_enabled, "proxy.config.http_ui_enabled");
54 }
55
56 void
register_http(const char * module,StatPagesFunc func)57 StatPagesManager::register_http(const char *module, StatPagesFunc func)
58 {
59 ink_mutex_acquire(&stat_pages_mutex);
60 ink_release_assert(n_stat_pages < MAX_STAT_PAGES);
61
62 stat_pages[n_stat_pages].module = static_cast<char *>(ats_malloc(strlen(module) + 3));
63 snprintf(stat_pages[n_stat_pages].module, strlen(module) + 3, "{%s}", module);
64 stat_pages[n_stat_pages++].func = func;
65 ink_mutex_release(&stat_pages_mutex);
66 }
67
68 Action *
handle_http(Continuation * cont,HTTPHdr * header)69 StatPagesManager::handle_http(Continuation *cont, HTTPHdr *header)
70 {
71 URL *url = header->url_get();
72
73 if (((m_enabled == 1 || m_enabled == 3) && is_cache_inspector_page(url)) ||
74 ((m_enabled == 2 || m_enabled == 3) && is_stat_page(url) && !is_cache_inspector_page(url))) {
75 int host_len;
76 char host[MAXDNAME + 1];
77 const char *h;
78 int i;
79
80 h = url->host_get(&host_len);
81 if (host_len > MAXDNAME) {
82 host_len = MAXDNAME;
83 }
84 memcpy(host, h, host_len);
85 host[host_len] = '\0';
86 host_len = unescapifyStr(host);
87
88 for (i = 0; i < n_stat_pages; i++) {
89 if (strlen(host) == strlen(stat_pages[i].module) && strncmp(host, stat_pages[i].module, host_len) == 0) {
90 return stat_pages[i].func(cont, header);
91 }
92 }
93 }
94
95 cont->handleEvent(STAT_PAGE_FAILURE, nullptr);
96 return ACTION_RESULT_DONE;
97 }
98
99 bool
is_stat_page(URL * url)100 StatPagesManager::is_stat_page(URL *url)
101 {
102 // This gets called from the state machine, so we should optimize here and not in caller.
103 if (m_enabled <= 0) {
104 return false;
105 }
106
107 int length;
108 const char *h = url->host_get(&length);
109 char host[MAXDNAME + 1];
110
111 if (h == nullptr || length < 2 || length > MAXDNAME) {
112 return false;
113 }
114
115 memcpy(host, h, length);
116 host[length] = '\0';
117 length = unescapifyStr(host);
118
119 if ((host[0] == '{') && (host[length - 1] == '}')) {
120 return true;
121 }
122
123 return false;
124 }
125
126 bool
is_cache_inspector_page(URL * url)127 StatPagesManager::is_cache_inspector_page(URL *url)
128 {
129 int length;
130 const char *h = url->host_get(&length);
131 char host[MAXDNAME + 1];
132
133 if (h == nullptr || length < 2 || length > MAXDNAME) {
134 return false;
135 }
136
137 memcpy(host, h, length);
138 host[length] = '\0';
139 length = unescapifyStr(host);
140
141 if (strncmp(host, "{cache}", length) == 0) {
142 return true;
143 } else {
144 return false;
145 }
146 }
147
148 void
resp_clear()149 BaseStatPagesHandler::resp_clear()
150 {
151 ats_free(response);
152 response = nullptr;
153 response_size = 0;
154 response_length = 0;
155 }
156
157 void
resp_add(const char * fmt,...)158 BaseStatPagesHandler::resp_add(const char *fmt, ...)
159 {
160 va_list args;
161 char buf[16384];
162 int length;
163 int size;
164
165 va_start(args, fmt);
166 length = vsnprintf(buf, 16384, fmt, args);
167 va_end(args);
168
169 size = response_size;
170 if (size == 0) {
171 size = 1024;
172 }
173 while ((response_length + length + 1) > size) {
174 size *= 2;
175 }
176
177 if (size != response_size) {
178 if (!response) {
179 response = static_cast<char *>(ats_malloc(size));
180 } else {
181 response = static_cast<char *>(ats_realloc(response, size));
182 }
183 response_size = size;
184 }
185
186 memcpy(&response[response_length], buf, length + 1);
187 response_length += length;
188 }
189
190 void
resp_add_sep()191 BaseStatPagesHandler::resp_add_sep()
192 {
193 resp_add("<hr width=\"100%%\">\n");
194 }
195
196 void
resp_begin(const char * title)197 BaseStatPagesHandler::resp_begin(const char *title)
198 {
199 resp_clear();
200 resp_add("<html>\n"
201 "<head><title>%s</title></head>\n"
202 "<body text=\"#000000\" bgcolor=\"#ffffff\" link=\"#0000ee\" vlink=\"#551a8b\" alink=\"#ff0000\">\n",
203 title);
204 }
205
206 void
resp_end()207 BaseStatPagesHandler::resp_end()
208 {
209 resp_add("</body>\n"
210 "</html>\n");
211 }
212
213 void
resp_begin_numbered()214 BaseStatPagesHandler::resp_begin_numbered()
215 {
216 resp_add("<ol>\n");
217 }
218
219 void
resp_end_numbered()220 BaseStatPagesHandler::resp_end_numbered()
221 {
222 resp_add("</ol>\n");
223 }
224
225 void
resp_begin_unnumbered()226 BaseStatPagesHandler::resp_begin_unnumbered()
227 {
228 resp_add("<ul>\n");
229 }
230
231 void
resp_end_unnumbered()232 BaseStatPagesHandler::resp_end_unnumbered()
233 {
234 resp_add("</ul>\n");
235 }
236
237 void
resp_begin_item()238 BaseStatPagesHandler::resp_begin_item()
239 {
240 resp_add("<li>\n");
241 }
242
243 void
resp_end_item()244 BaseStatPagesHandler::resp_end_item()
245 {
246 resp_add("</li>\n");
247 }
248
249 void
resp_begin_table(int border,int columns,int percent)250 BaseStatPagesHandler::resp_begin_table(int border, int columns, int percent)
251 {
252 resp_add("<table border=%d cols=%d width=\"%d%%\">\n", border, columns, percent);
253 }
254
255 void
resp_end_table()256 BaseStatPagesHandler::resp_end_table()
257 {
258 resp_add("</table>\n");
259 }
260
261 void
resp_begin_row()262 BaseStatPagesHandler::resp_begin_row()
263 {
264 resp_add("<tr>\n");
265 }
266
267 void
resp_end_row()268 BaseStatPagesHandler::resp_end_row()
269 {
270 resp_add("</tr>\n");
271 }
272
273 void
resp_begin_column(int percent,const char * align)274 BaseStatPagesHandler::resp_begin_column(int percent, const char *align)
275 {
276 if (percent == -1) {
277 resp_add("<td %s%s>\n", align ? "align=" : "", align ? align : "");
278 } else {
279 resp_add("<td width=\"%d%%\" %s%s>\n", percent, align ? "align=" : "", align ? align : "");
280 }
281 }
282
283 void
resp_end_column()284 BaseStatPagesHandler::resp_end_column()
285 {
286 resp_add("</td>\n");
287 }
288