bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / common / jk_status.c
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 /***************************************************************************
19  * Description: Status worker, display and manages JK workers              *
20  * Author:      Mladen Turk <mturk@jboss.com>                              *
21  * Author:      Rainer Jung <rjung@apache.org>                             *
22  * Version:     $Revision: 1054603 $                                        *
23  ***************************************************************************/
24
25 #include "jk_pool.h"
26 #include "jk_service.h"
27 #include "jk_util.h"
28 #include "jk_worker.h"
29 #include "jk_status.h"
30 #include "jk_mt.h"
31 #include "jk_shm.h"
32 #include "jk_ajp_common.h"
33 #include "jk_lb_worker.h"
34 #include "jk_ajp13_worker.h"
35 #include "jk_ajp14_worker.h"
36 #include "jk_connect.h"
37 #include "jk_uri_worker_map.h"
38
39 #define HUGE_BUFFER_SIZE (8*1024)
40
41 /**
42  * Command line reference:
43  * cmd=list (default) display configuration
44  * cmd=show display detailed configuration
45  * cmd=edit form to change configuration
46  * cmd=update commit update configuration
47  * cmd=reset reset lb runtime states, or lb member runtime states
48  * cmd=version show only software version
49  * Query arguments:
50  * re=n (refresh time in seconds, n=0: disabled)
51  * w=worker (cmd should be executed for worker "worker")
52  * sw=sub_worker (cmd should be executed for "sub_worker" of worker "worker")
53  * from=lastcmd (the last viewing command was "lastcmd")
54  * opt=option (changes meaning of edit and list/show)
55  */
56
57 #define JK_STATUS_ARG_CMD                  "cmd"
58 #define JK_STATUS_ARG_MIME                 "mime"
59 #define JK_STATUS_ARG_FROM                 "from"
60 #define JK_STATUS_ARG_REFRESH              "re"
61 #define JK_STATUS_ARG_WORKER               "w"
62 #define JK_STATUS_ARG_SUB_WORKER           "sw"
63 #define JK_STATUS_ARG_PREV_SUB_WORKER      "psw"
64 #define JK_STATUS_ARG_ATTRIBUTE            "att"
65 #define JK_STATUS_ARG_MULT_VALUE_BASE      "val"
66 #define JK_STATUS_ARG_OPTIONS              "opt"
67
68 #define JK_STATUS_ARG_OPTION_NO_MEMBERS    0x0001
69 #define JK_STATUS_ARG_OPTION_NO_MAPS       0x0002
70 #define JK_STATUS_ARG_OPTION_NO_LEGEND     0x0004
71 #define JK_STATUS_ARG_OPTION_NO_LB         0x0008
72 #define JK_STATUS_ARG_OPTION_NO_AJP        0x0010
73 #define JK_STATUS_ARG_OPTION_READ_ONLY     0x0020
74 #define JK_STATUS_ARG_OPTION_NO_LB_CONF    0x0040
75 #define JK_STATUS_ARG_OPTION_NO_LB_SUMMARY 0x0080
76 #define JK_STATUS_ARG_OPTION_NO_AJP_CONF   0x0100
77
78 #define JK_STATUS_ARG_LB_RETRIES           ("vlr")
79 #define JK_STATUS_ARG_LB_RETRY_INT         ("vlri")
80 #define JK_STATUS_ARG_LB_RECOVER_TIME      ("vlt")
81 #define JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME ("vlee")
82 #define JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS ("vlx")
83 #define JK_STATUS_ARG_LB_STICKY            ("vls")
84 #define JK_STATUS_ARG_LB_STICKY_FORCE      ("vlf")
85 #define JK_STATUS_ARG_LB_METHOD            ("vlm")
86 #define JK_STATUS_ARG_LB_LOCK              ("vll")
87
88 #define JK_STATUS_ARG_LB_TEXT_RETRIES      "Retries"
89 #define JK_STATUS_ARG_LB_TEXT_RETRY_INT    "Retry Interval"
90 #define JK_STATUS_ARG_LB_TEXT_RECOVER_TIME "Recover Wait Time"
91 #define JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME "Error Escalation Time"
92 #define JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS "Max Reply Timeouts"
93 #define JK_STATUS_ARG_LB_TEXT_STICKY       "Sticky Sessions"
94 #define JK_STATUS_ARG_LB_TEXT_STICKY_FORCE "Force Sticky Sessions"
95 #define JK_STATUS_ARG_LB_TEXT_METHOD       "LB Method"
96 #define JK_STATUS_ARG_LB_TEXT_LOCK         "Locking"
97
98 #define JK_STATUS_ARG_LBM_ACTIVATION       ("vwa")
99 #define JK_STATUS_ARG_LBM_FACTOR           ("vwf")
100 #define JK_STATUS_ARG_LBM_ROUTE            ("vwn")
101 #define JK_STATUS_ARG_LBM_REDIRECT         ("vwr")
102 #define JK_STATUS_ARG_LBM_DOMAIN           ("vwc")
103 #define JK_STATUS_ARG_LBM_DISTANCE         ("vwd")
104
105 #define JK_STATUS_ARG_LBM_TEXT_ACTIVATION  "Activation"
106 #define JK_STATUS_ARG_LBM_TEXT_FACTOR      "LB Factor"
107 #define JK_STATUS_ARG_LBM_TEXT_ROUTE       "Route"
108 #define JK_STATUS_ARG_LBM_TEXT_REDIRECT    "Redirect Route"
109 #define JK_STATUS_ARG_LBM_TEXT_DOMAIN      "Cluster Domain"
110 #define JK_STATUS_ARG_LBM_TEXT_DISTANCE    "Distance"
111
112 #define JK_STATUS_ARG_AJP_CACHE_TO         "vacpt"
113 #define JK_STATUS_ARG_AJP_PING_TO          "vapng"
114 #define JK_STATUS_ARG_AJP_CONNECT_TO       "vact"
115 #define JK_STATUS_ARG_AJP_PREPOST_TO       "vapt"
116 #define JK_STATUS_ARG_AJP_REPLY_TO         "vart"
117 #define JK_STATUS_ARG_AJP_RETRIES          "var"
118 #define JK_STATUS_ARG_AJP_RETRY_INT        "vari"
119 #define JK_STATUS_ARG_AJP_REC_OPTS         "varo"
120 #define JK_STATUS_ARG_AJP_MAX_PK_SZ        "vamps"
121 #define JK_STATUS_ARG_AJP_CPING_INT        "vacpi"
122 #define JK_STATUS_ARG_AJP_HOST_STR         "vahst"
123 #define JK_STATUS_ARG_AJP_PORT             "vaprt"
124
125 #define JK_STATUS_ARG_AJP_TEXT_CACHE_TO    "Connection Pool Timeout"
126 #define JK_STATUS_ARG_AJP_TEXT_PING_TO     "Ping Timeout"
127 #define JK_STATUS_ARG_AJP_TEXT_CONNECT_TO  "Connect Timeout"
128 #define JK_STATUS_ARG_AJP_TEXT_PREPOST_TO  "Prepost Timeout"
129 #define JK_STATUS_ARG_AJP_TEXT_REPLY_TO    "Reply Timeout"
130 #define JK_STATUS_ARG_AJP_TEXT_RETRIES     "Retries"
131 #define JK_STATUS_ARG_AJP_TEXT_RETRY_INT   "Retry Interval"
132 #define JK_STATUS_ARG_AJP_TEXT_REC_OPTS    "Recovery Options"
133 #define JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ   "Max Packet Size"
134 #define JK_STATUS_ARG_AJP_TEXT_CPING_INT   "Connection Ping Interval"
135 #define JK_STATUS_ARG_AJP_TEXT_HOST_STR    "Hostname"
136 #define JK_STATUS_ARG_AJP_TEXT_PORT        "Port"
137 #define JK_STATUS_ARG_AJP_TEXT_ADDR_STR    "Address:Port"
138
139 #define JK_STATUS_CMD_UNKNOWN              (0)
140 #define JK_STATUS_CMD_LIST                 (1)
141 #define JK_STATUS_CMD_SHOW                 (2)
142 #define JK_STATUS_CMD_EDIT                 (3)
143 #define JK_STATUS_CMD_UPDATE               (4)
144 #define JK_STATUS_CMD_RESET                (5)
145 #define JK_STATUS_CMD_VERSION              (6)
146 #define JK_STATUS_CMD_RECOVER              (7)
147 #define JK_STATUS_CMD_DUMP                 (8)
148 #define JK_STATUS_CMD_DEF                  (JK_STATUS_CMD_LIST)
149 #define JK_STATUS_CMD_MAX                  (JK_STATUS_CMD_DUMP)
150 #define JK_STATUS_CMD_TEXT_UNKNOWN         ("unknown")
151 #define JK_STATUS_CMD_TEXT_LIST            ("list")
152 #define JK_STATUS_CMD_TEXT_SHOW            ("show")
153 #define JK_STATUS_CMD_TEXT_EDIT            ("edit")
154 #define JK_STATUS_CMD_TEXT_UPDATE          ("update")
155 #define JK_STATUS_CMD_TEXT_RESET           ("reset")
156 #define JK_STATUS_CMD_TEXT_VERSION         ("version")
157 #define JK_STATUS_CMD_TEXT_RECOVER         ("recover")
158 #define JK_STATUS_CMD_TEXT_DUMP            ("dump")
159 #define JK_STATUS_CMD_TEXT_DEF             (JK_STATUS_CMD_TEXT_LIST)
160
161 #define JK_STATUS_CMD_PROP_CHECK_WORKER    0x00000001
162 #define JK_STATUS_CMD_PROP_READONLY        0x00000002
163 #define JK_STATUS_CMD_PROP_HEAD            0x00000004
164 #define JK_STATUS_CMD_PROP_REFRESH         0x00000008
165 #define JK_STATUS_CMD_PROP_BACK_LINK       0x00000010
166 #define JK_STATUS_CMD_PROP_BACK_LIST       0x00000020
167 #define JK_STATUS_CMD_PROP_FMT             0x00000040
168 #define JK_STATUS_CMD_PROP_SWITCH_RO       0x00000080
169 #define JK_STATUS_CMD_PROP_DUMP_LINK       0x00000100
170 #define JK_STATUS_CMD_PROP_LINK_HELP       0x00000200
171 #define JK_STATUS_CMD_PROP_LEGEND          0x00000400
172 #define JK_STATUS_CMD_PROP_WILDCARD        0x00000800
173
174 #define JK_STATUS_MIME_UNKNOWN             (0)
175 #define JK_STATUS_MIME_HTML                (1)
176 #define JK_STATUS_MIME_XML                 (2)
177 #define JK_STATUS_MIME_TXT                 (3)
178 #define JK_STATUS_MIME_PROP                (4)
179 #define JK_STATUS_MIME_DEF                 (JK_STATUS_MIME_HTML)
180 #define JK_STATUS_MIME_MAX                 (JK_STATUS_MIME_PROP)
181 #define JK_STATUS_MIME_TEXT_UNKNOWN        ("unknown")
182 #define JK_STATUS_MIME_TEXT_HTML           ("html")
183 #define JK_STATUS_MIME_TEXT_XML            ("xml")
184 #define JK_STATUS_MIME_TEXT_TXT            ("txt")
185 #define JK_STATUS_MIME_TEXT_PROP           ("prop")
186 #define JK_STATUS_MIME_TEXT_DEF            (JK_STATUS_MIME_TEXT_HTML)
187
188 #define JK_STATUS_MASK_ACTIVE              0x000000FF
189 #define JK_STATUS_MASK_DISABLED            0x0000FF00
190 #define JK_STATUS_MASK_STOPPED             0x00FF0000
191 #define JK_STATUS_MASK_OK                  0x00010101
192 #define JK_STATUS_MASK_IDLE                0x00020202
193 #define JK_STATUS_MASK_BUSY                0x00040404
194 #define JK_STATUS_MASK_RECOVER             0x00080808
195 #define JK_STATUS_MASK_ERROR               0x00101010
196 #define JK_STATUS_MASK_GOOD_DEF            0x0000000F
197 #define JK_STATUS_MASK_BAD_DEF             0x00FF1010
198
199 #define JK_STATUS_NEEDS_PUSH               0x00000001
200 #define JK_STATUS_NEEDS_RESET_LB_VALUES    0x00000002
201 #define JK_STATUS_NEEDS_UPDATE_MULT        0x00000004
202 #define JK_STATUS_NEEDS_ADDR_PUSH          0x00000008
203
204 #define JK_STATUS_WAIT_AFTER_UPDATE        "3"
205 #define JK_STATUS_REFRESH_DEF              "10"
206 #define JK_STATUS_ESC_CHARS                ("<>?\"")
207 #define JK_STATUS_TIME_FMT_HTML            "%a, %d %b %Y %X %Z"
208 #define JK_STATUS_TIME_FMT_TEXT            "%Y%m%d%H%M%S"
209 #define JK_STATUS_TIME_FMT_TZ              "%Z"
210 #define JK_STATUS_TIME_BUF_SZ              (80)
211
212 #define JK_STATUS_HEAD                     "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n" \
213                                            "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"" \
214                                            " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n" \
215                                            "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">" \
216                                            "<head><title>JK Status Manager</title>"
217
218 #define JK_STATUS_COPYRIGHT                "Copyright &#169; 1999-2011, The Apache Software Foundation<br />" \
219                                            "Licensed under the <a href=\"http://www.apache.org/licenses/LICENSE-2.0\">" \
220                                            "Apache License, Version 2.0</a>."
221
222 #define JK_STATUS_HEND                     "</head>\n<body>\n"
223 #define JK_STATUS_BEND                     "</body>\n</html>\n"
224
225 #define JK_STATUS_XMLH                     "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n"
226
227 #define JK_STATUS_NS_DEF                   "jk:"
228 #define JK_STATUS_XMLNS_DEF                "xmlns:jk=\"http://tomcat.apache.org\""
229 #define JK_STATUS_PREFIX_DEF               "worker"
230
231 #define JK_STATUS_FORM_START               "<form method=\"%s\" action=\"%s\">\n"
232 #define JK_STATUS_FORM_HIDDEN_INT          "<input type=\"hidden\" name=\"%s\" value=\"%d\"/>\n"
233 #define JK_STATUS_FORM_HIDDEN_STRING       "<input type=\"hidden\" name=\"%s\" value=\"%s\"/>\n"
234 #define JK_STATUS_URI_MAP_TABLE_HEAD       "<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n"
235 #define JK_STATUS_URI_MAP_TABLE_ROW        "<tr><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td></tr>\n"
236 #define JK_STATUS_URI_MAP_TABLE_HEAD2      "<tr><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th><th>%s</th></tr>\n"
237 #define JK_STATUS_URI_MAP_TABLE_ROW2       "<tr><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td><td>%s</td><td>%s</td><td>%s</td><td>%s</td><td>%d</td></tr>\n"
238 #define JK_STATUS_SHOW_AJP_CONF_HEAD       "<tr>" \
239                                            "<th>Type</th>" \
240                                            "<th>" JK_STATUS_ARG_AJP_TEXT_HOST_STR "</th>" \
241                                            "<th>" JK_STATUS_ARG_AJP_TEXT_ADDR_STR "</th>" \
242                                            "<th>" JK_STATUS_ARG_AJP_TEXT_CACHE_TO "</th>" \
243                                            "<th>" JK_STATUS_ARG_AJP_TEXT_CONNECT_TO "</th>" \
244                                            "<th>" JK_STATUS_ARG_AJP_TEXT_PREPOST_TO "</th>" \
245                                            "<th>" JK_STATUS_ARG_AJP_TEXT_REPLY_TO "</th>" \
246                                            "<th>" JK_STATUS_ARG_AJP_TEXT_RETRIES "</th>" \
247                                            "<th>" JK_STATUS_ARG_AJP_TEXT_REC_OPTS "</th>" \
248                                            "<th>" JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ "</th>" \
249                                            "<th>\n"
250 #define JK_STATUS_SHOW_AJP_CONF_ROW        "<tr>" \
251                                            "<td>%s</td>" \
252                                            "<td>%s</td>" \
253                                            "<td>%s</td>" \
254                                            "<td>%d</td>" \
255                                            "<td>%d</td>" \
256                                            "<td>%d</td>" \
257                                            "<td>%d</td>" \
258                                            "<td>%u</td>" \
259                                            "<td>%u</td>" \
260                                            "<td></td>" \
261                                            "</tr>\n"
262 #define JK_STATUS_SHOW_AJP_HEAD            "<tr>" \
263                                            "<th>State</th>" \
264                                            "<th>Acc</th>" \
265                                            "<th>Err</th><th>CE</th><th>RE</th>" \
266                                            "<th>Wr</th><th>Rd</th><th>Busy</th><th>Max</th><th>Con</th><th>LR</th><th>LE</th>" \
267                                            "</tr>\n"
268 #define JK_STATUS_SHOW_AJP_ROW             "<tr>" \
269                                            "<td>%s</td>" \
270                                            "<td>%" JK_UINT64_T_FMT " (%d/sec)</td>" \
271                                            "<td>%" JK_UINT32_T_FMT "</td>" \
272                                            "<td>%" JK_UINT32_T_FMT "</td>" \
273                                            "<td>%" JK_UINT32_T_FMT "</td>" \
274                                            "<td>%s (%s/sec)</td>" \
275                                            "<td>%s (%s/sec)</td>" \
276                                            "<td>%d</td>" \
277                                            "<td>%d</td>" \
278                                            "<td>%d</td>" \
279                                            "<td>%d</td>" \
280                                            "<td>%s</td>" \
281                                            "</tr>\n"
282 #define JK_STATUS_SHOW_LB_HEAD             "<tr>" \
283                                            "<th>Type</th>" \
284                                            "<th>" JK_STATUS_ARG_LB_TEXT_STICKY "</th>" \
285                                            "<th>" JK_STATUS_ARG_LB_TEXT_STICKY_FORCE "</th>" \
286                                            "<th>" JK_STATUS_ARG_LB_TEXT_RETRIES "</th>" \
287                                            "<th>" JK_STATUS_ARG_LB_TEXT_METHOD "</th>" \
288                                            "<th>" JK_STATUS_ARG_LB_TEXT_LOCK "</th>" \
289                                            "<th>" JK_STATUS_ARG_LB_TEXT_RECOVER_TIME "</th>" \
290                                            "<th>" JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME "</th>" \
291                                            "<th>" JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS "</th>" \
292                                            "<th>\n"
293 #define JK_STATUS_SHOW_LB_ROW              "<tr>" \
294                                            "<td>%s</td>" \
295                                            "<td>%s</td>" \
296                                            "<td>%s</td>" \
297                                            "<td>%d</td>" \
298                                            "<td>%s</td>" \
299                                            "<td>%s</td>" \
300                                            "<td>%d</td>" \
301                                            "<td>%d</td>" \
302                                            "<td>%d</td>" \
303                                            "<td></td>" \
304                                            "</tr>\n"
305 #define JK_STATUS_SHOW_MEMBER_HEAD         "<tr>" \
306                                            "<th>&nbsp;</th><th>Name</th>" \
307                                            "<th>Act</th><th>State</th>" \
308                                            "<th>D</th><th>F</th><th>M</th>" \
309                                            "<th>V</th><th>Acc</th>" \
310                                            "<th>Err</th><th>CE</th><th>RE</th>" \
311                                            "<th>Wr</th><th>Rd</th><th>Busy</th><th>Max</th><th>Con</th>" \
312                                            "<th>" JK_STATUS_ARG_LBM_TEXT_ROUTE "</th>" \
313                                            "<th>RR</th><th>Cd</th><th>Rs</th><th>LR</th><th>LE</th>" \
314                                            "</tr>\n"
315 #define JK_STATUS_SHOW_MEMBER_ROW          "<td>%s</td>" \
316                                            "<td>%s</td>" \
317                                            "<td>%s</td>" \
318                                            "<td>%d</td>" \
319                                            "<td>%d</td>" \
320                                            "<td>%" JK_UINT64_T_FMT "</td>" \
321                                            "<td>%" JK_UINT64_T_FMT "</td>" \
322                                            "<td>%" JK_UINT64_T_FMT " (%d/sec)</td>" \
323                                            "<td>%" JK_UINT32_T_FMT "</td>" \
324                                            "<td>%" JK_UINT32_T_FMT "</td>" \
325                                            "<td>%" JK_UINT32_T_FMT "</td>" \
326                                            "<td>%s (%s/sec)</td>" \
327                                            "<td>%s (%s/sec)</td>" \
328                                            "<td>%d</td>" \
329                                            "<td>%d</td>" \
330                                            "<td>%d</td>" \
331                                            "<td>%s</td>" \
332                                            "<td>%s</td>" \
333                                            "<td>%s</td>" \
334                                            "<td>%d/%d</td>" \
335                                            "<td>%d</td>" \
336                                            "<td>%s</td>" \
337                                            "</tr>\n"
338 #define JK_STATUS_SHOW_MEMBER_CONF_HEAD    "<tr>" \
339                                            "<th>Name</th><th>Type</th>" \
340                                            "<th>" JK_STATUS_ARG_AJP_TEXT_HOST_STR "</th>" \
341                                            "<th>" JK_STATUS_ARG_AJP_TEXT_ADDR_STR "</th>" \
342                                            "<th>" JK_STATUS_ARG_AJP_TEXT_CACHE_TO "</th>" \
343                                            "<th>" JK_STATUS_ARG_AJP_TEXT_CONNECT_TO "</th>" \
344                                            "<th>" JK_STATUS_ARG_AJP_TEXT_PREPOST_TO "</th>" \
345                                            "<th>" JK_STATUS_ARG_AJP_TEXT_REPLY_TO "</th>" \
346                                            "<th>" JK_STATUS_ARG_AJP_TEXT_RETRIES "</th>" \
347                                            "<th>" JK_STATUS_ARG_AJP_TEXT_REC_OPTS "</th>" \
348                                            "<th>" JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ "</th>" \
349                                            "<th>\n"
350 #define JK_STATUS_SHOW_MEMBER_CONF_ROW     "<tr>" \
351                                            "<td>%s</td>" \
352                                            "<td>%s</td>" \
353                                            "<td>%s</td>" \
354                                            "<td>%s</td>" \
355                                            "<td>%d</td>" \
356                                            "<td>%d</td>" \
357                                            "<td>%d</td>" \
358                                            "<td>%d</td>" \
359                                            "<td>%d</td>" \
360                                            "<td>%u</td>" \
361                                            "<td>%u</td>" \
362                                            "<td></td>" \
363                                            "</tr>\n"
364
365 typedef struct status_worker status_worker_t;
366
367 struct status_endpoint
368 {
369     status_worker_t *worker;
370
371     char            *query_string;
372     jk_map_t        *req_params;
373     char            *msg;
374
375     jk_endpoint_t   endpoint;
376
377 };
378
379 typedef struct status_endpoint status_endpoint_t;
380
381 struct status_worker
382 {
383     jk_pool_t         p;
384     jk_pool_atom_t    buf[TINY_POOL_SIZE];
385     const char        *name;
386     const char        *css;
387     const char        *ns;
388     const char        *xmlns;
389     const char        *doctype;
390     const char        *prefix;
391     int               read_only;
392     char              **user_names;
393     unsigned int      num_of_users;
394     int               user_case_insensitive;
395     jk_uint32_t       good_mask;
396     jk_uint32_t       bad_mask;
397     jk_worker_t       worker;
398     jk_worker_env_t   *we;
399 };
400
401 static const char *worker_type[] = {
402     "unknown",
403     "ajp12",
404     "ajp13",
405     "ajp14",
406     "jni",
407     "lb",
408     "status",
409     NULL
410 };
411
412 static const char *headers_names[] = {
413     "Content-Type",
414     "Cache-Control",
415     "Pragma",
416     NULL
417 };
418
419 static const char *cmd_type[] = {
420     JK_STATUS_CMD_TEXT_UNKNOWN,
421     JK_STATUS_CMD_TEXT_LIST,
422     JK_STATUS_CMD_TEXT_SHOW,
423     JK_STATUS_CMD_TEXT_EDIT,
424     JK_STATUS_CMD_TEXT_UPDATE,
425     JK_STATUS_CMD_TEXT_RESET,
426     JK_STATUS_CMD_TEXT_VERSION,
427     JK_STATUS_CMD_TEXT_RECOVER,
428     JK_STATUS_CMD_TEXT_DUMP,
429     NULL
430 };
431
432 static const char *mime_type[] = {
433     JK_STATUS_MIME_TEXT_UNKNOWN,
434     JK_STATUS_MIME_TEXT_HTML,
435     JK_STATUS_MIME_TEXT_XML,
436     JK_STATUS_MIME_TEXT_TXT,
437     JK_STATUS_MIME_TEXT_PROP,
438     NULL
439 };
440
441 #define HEADERS_NO_CACHE "no-cache", "no-cache", NULL
442
443 static const char *headers_vhtml[] = {
444     "text/html",
445     HEADERS_NO_CACHE
446 };
447
448 static const char *headers_vxml[] = {
449     "text/xml",
450     HEADERS_NO_CACHE
451 };
452
453 static const char *headers_vtxt[] = {
454     "text/plain",
455     HEADERS_NO_CACHE
456 };
457
458 static void jk_puts(jk_ws_service_t *s, const char *str)
459 {
460     if (str)
461         s->write(s, str, (unsigned int)strlen(str));
462     else
463         s->write(s, "(null)", 6);
464 }
465
466 static void jk_putv(jk_ws_service_t *s, ...)
467 {
468     va_list va;
469     const char *str;
470
471     va_start(va, s);
472     while (1) {
473         str = va_arg(va, const char *);
474         if (str == NULL)
475             break;
476         s->write(s, str, (unsigned int)strlen(str));
477     }
478     va_end(va);
479 }
480
481 static int jk_printf(jk_ws_service_t *s, const char *fmt, ...)
482 {
483     int rc = 0;
484     va_list args;
485 #ifdef NETWARE
486 /* On NetWare, this can get called on a thread that has a limited stack so */
487 /* we will allocate and free the temporary buffer in this function         */
488         char *buf;
489 #else
490         char buf[HUGE_BUFFER_SIZE];
491 #endif
492
493     if (!s || !fmt) {
494         return -1;
495     }
496     va_start(args, fmt);
497
498 #ifdef NETWARE
499         buf = (char *)malloc(HUGE_BUFFER_SIZE);
500         if (NULL == buf)
501             return -1;
502 #endif
503     rc = vsnprintf(buf, HUGE_BUFFER_SIZE, fmt, args);
504     va_end(args);
505     if (rc > 0)
506         s->write(s, buf, rc);
507 #ifdef NETWARE
508         free(buf);
509 #endif
510     return rc;
511 }
512
513 static void jk_print_xml_start_elt(jk_ws_service_t *s, status_worker_t *w,
514                                    int indentation, int close_tag,
515                                    const char *name)
516 {
517     if (close_tag) {
518         jk_printf(s, "%*s<%s%s>\n", indentation, "", w->ns, name);
519     }
520     else {
521         jk_printf(s, "%*s<%s%s\n", indentation, "", w->ns, name);
522     }
523 }
524
525 static void jk_print_xml_close_elt(jk_ws_service_t *s, status_worker_t *w,
526                                    int indentation,
527                                    const char *name)
528 {
529     jk_printf(s, "%*s</%s%s>\n", indentation, "", w->ns, name);
530 }
531
532 static void jk_print_xml_stop_elt(jk_ws_service_t *s,
533                                   int indentation, int close_tag)
534 {
535     if (close_tag) {
536         jk_printf(s, "%*s/>\n", indentation, "");
537     }
538     else {
539         jk_printf(s, "%*s>\n", indentation, "");
540     }
541 }
542
543 static void jk_print_xml_att_string(jk_ws_service_t *s,
544                                     int indentation,
545                                     const char *key, const char *value)
546 {
547     jk_printf(s, "%*s%s=\"%s\"\n", indentation, "", key, value ? value : "");
548 }
549
550 static void jk_print_xml_att_int(jk_ws_service_t *s,
551                                  int indentation,
552                                  const char *key, int value)
553 {
554     jk_printf(s, "%*s%s=\"%d\"\n", indentation, "", key, value);
555 }
556
557 static void jk_print_xml_att_uint(jk_ws_service_t *s,
558                                   int indentation,
559                                   const char *key, unsigned int value)
560 {
561     jk_printf(s, "%*s%s=\"%u\"\n", indentation, "", key, value);
562 }
563
564 static void jk_print_xml_att_long(jk_ws_service_t *s,
565                                   int indentation,
566                                   const char *key, long value)
567 {
568     jk_printf(s, "%*s%s=\"%ld\"\n", indentation, "", key, value);
569 }
570
571 static void jk_print_xml_att_uint32(jk_ws_service_t *s,
572                                     int indentation,
573                                     const char *key, jk_uint32_t value)
574 {
575     jk_printf(s, "%*s%s=\"%" JK_UINT32_T_FMT "\"\n", indentation, "", key, value);
576 }
577
578 static void jk_print_xml_att_uint64(jk_ws_service_t *s,
579                                     int indentation,
580                                     const char *key, jk_uint64_t value)
581 {
582     jk_printf(s, "%*s%s=\"%" JK_UINT64_T_FMT "\"\n", indentation, "", key, value);
583 }
584
585 static void jk_print_prop_att_string(jk_ws_service_t *s, status_worker_t *w,
586                                      const char *name,
587                                      const char *key, const char *value)
588 {
589     if (name) {
590         jk_printf(s, "%s.%s.%s=%s\n", w->prefix, name, key, value ? value : "");
591     }
592     else {
593         jk_printf(s, "%s.%s=%s\n", w->prefix, key, value ? value : "");
594     }
595 }
596
597 static void jk_print_prop_att_int(jk_ws_service_t *s, status_worker_t *w,
598                                   const char *name,
599                                   const char *key, int value)
600 {
601     if (name) {
602         jk_printf(s, "%s.%s.%s=%d\n", w->prefix, name, key, value);
603     }
604     else {
605         jk_printf(s, "%s.%s=%d\n", w->prefix, key, value);
606     }
607 }
608
609 static void jk_print_prop_att_uint(jk_ws_service_t *s, status_worker_t *w,
610                                    const char *name,
611                                    const char *key, unsigned int value)
612 {
613     if (name) {
614         jk_printf(s, "%s.%s.%s=%u\n", w->prefix, name, key, value);
615     }
616     else {
617         jk_printf(s, "%s.%s=%u\n", w->prefix, key, value);
618     }
619 }
620
621 static void jk_print_prop_att_long(jk_ws_service_t *s, status_worker_t *w,
622                                    const char *name,
623                                    const char *key, long value)
624 {
625     if (name) {
626         jk_printf(s, "%s.%s.%s=%ld\n", w->prefix, name, key, value);
627     }
628     else {
629         jk_printf(s, "%s.%s=%ld\n", w->prefix, key, value);
630     }
631 }
632
633 static void jk_print_prop_att_uint32(jk_ws_service_t *s, status_worker_t *w,
634                                      const char *name,
635                                      const char *key, jk_uint32_t value)
636 {
637     if (name) {
638         jk_printf(s, "%s.%s.%s=%" JK_UINT32_T_FMT "\n", w->prefix, name, key, value);
639     }
640     else {
641         jk_printf(s, "%s.%s=%" JK_UINT32_T_FMT "\n", w->prefix, key, value);
642     }
643 }
644
645 static void jk_print_prop_att_uint64(jk_ws_service_t *s, status_worker_t *w,
646                                      const char *name,
647                                      const char *key, jk_uint64_t value)
648 {
649     if (name) {
650         jk_printf(s, "%s.%s.%s=%" JK_UINT64_T_FMT "\n", w->prefix, name, key, value);
651     }
652     else {
653         jk_printf(s, "%s.%s=%" JK_UINT64_T_FMT "\n", w->prefix, key, value);
654     }
655 }
656
657 static void jk_print_prop_item_int(jk_ws_service_t *s, status_worker_t *w,
658                                    const char *name, const char *list, int num,
659                                    const char *key, int value)
660 {
661     if (name) {
662         jk_printf(s, "%s.%s.%s.%d.%s=%d\n", w->prefix, name, list, num, key, value);
663     }
664     else {
665         jk_printf(s, "%s.%s.%d.%s=%d\n", w->prefix, list, num, key, value);
666     }
667 }
668
669 static void jk_print_prop_item_string(jk_ws_service_t *s, status_worker_t *w,
670                                       const char *name, const char *list, int num,
671                                       const char *key, const char *value)
672 {
673     if (name) {
674         jk_printf(s, "%s.%s.%s.%d.%s=%s\n", w->prefix, name, list, num, key, value ? value : "");
675     }
676     else {
677         jk_printf(s, "%s.%s.%d.%s=%s\n", w->prefix, list, num, key, value ? value : "");
678     }
679 }
680
681 /* Actually APR's apr_strfsize */
682 static char *status_strfsize(jk_uint64_t size, char *buf)
683 {
684     const char ord[] = "KMGTPE";
685     const char *o = ord;
686     unsigned int remain, siz;
687
688     if (size < 973) {
689         if (sprintf(buf, "%d ", (int) size) < 0)
690             return strcpy(buf, "****");
691         return buf;
692     }
693     do {
694         remain = (unsigned int)(size & 0x03FF);
695         size >>= 10;
696         if (size >= 973) {
697             ++o;
698             continue;
699         }
700         siz = (unsigned int)(size & 0xFFFF);
701         if (siz < 9 || (siz == 9 && remain < 973)) {
702             if ((remain = ((remain * 5) + 256) / 512) >= 10)
703                 ++siz, remain = 0;
704             if (sprintf(buf, "%d.%d%c", siz, remain, *o) < 0)
705                 return strcpy(buf, "****");
706             return buf;
707         }
708         if (remain >= 512)
709             ++siz;
710         if (sprintf(buf, "%d%c", siz, *o) < 0)
711             return strcpy(buf, "****");
712         return buf;
713     } while (1);
714 }
715
716 static int status_strftime(time_t clock, int mime, char *buf_time, char *buf_tz,
717                            jk_logger_t *l)
718 {
719     size_t rc_time;
720 #ifdef _MT_CODE_PTHREAD
721     struct tm res;
722     struct tm *tms = localtime_r(&clock, &res);
723 #else
724     struct tm *tms = localtime(&clock);
725 #endif
726
727     JK_TRACE_ENTER(l);
728
729     if (mime == JK_STATUS_MIME_HTML)
730         rc_time = strftime(buf_time, JK_STATUS_TIME_BUF_SZ, JK_STATUS_TIME_FMT_HTML, tms);
731     else {
732         rc_time = strftime(buf_time, JK_STATUS_TIME_BUF_SZ, JK_STATUS_TIME_FMT_TEXT, tms);
733     }
734     strftime(buf_tz, JK_STATUS_TIME_BUF_SZ, JK_STATUS_TIME_FMT_TZ, tms);
735
736     JK_TRACE_EXIT(l);
737     return (int)rc_time;
738
739 }
740
741 static int status_rate(lb_sub_worker_t *wr, status_worker_t *w,
742                        jk_logger_t *l)
743 {
744     jk_uint32_t mask = 0;
745     int activation = wr->activation;
746     int state = wr->s->state;
747     jk_uint32_t good = w->good_mask;
748     jk_uint32_t bad = w->bad_mask;
749     int rv = 0;
750
751     switch (activation)
752     {
753     case JK_LB_ACTIVATION_ACTIVE:
754         mask = JK_STATUS_MASK_ACTIVE;
755         break;
756     case JK_LB_ACTIVATION_DISABLED:
757         mask = JK_STATUS_MASK_DISABLED;
758         break;
759     case JK_LB_ACTIVATION_STOPPED:
760         mask = JK_STATUS_MASK_STOPPED;
761         break;
762     default:
763         jk_log(l, JK_LOG_WARNING,
764                "Status worker '%s' unknown activation type '%d'",
765                w->name, activation);
766     }
767     switch (state)
768     {
769     case JK_LB_STATE_IDLE:
770         mask &= JK_STATUS_MASK_IDLE;
771         break;
772     case JK_LB_STATE_OK:
773         mask &= JK_STATUS_MASK_OK;
774         break;
775     case JK_LB_STATE_RECOVER:
776         mask &= JK_STATUS_MASK_RECOVER;
777         break;
778     case JK_LB_STATE_FORCE:
779         mask &= JK_STATUS_MASK_RECOVER;
780         break;
781     case JK_LB_STATE_BUSY:
782         mask &= JK_STATUS_MASK_BUSY;
783         break;
784     case JK_LB_STATE_ERROR:
785         mask &= JK_STATUS_MASK_ERROR;
786         break;
787     case JK_LB_STATE_PROBE:
788         mask &= JK_STATUS_MASK_RECOVER;
789         break;
790     default:
791         jk_log(l, JK_LOG_WARNING,
792                "Status worker '%s' unknown state type '%d'",
793                w->name, state);
794     }
795     if (mask&bad)
796         rv = -1;
797     else if (mask&good)
798         rv = 1;
799     else
800         rv = 0;
801     if (JK_IS_DEBUG_LEVEL(l))
802         jk_log(l, JK_LOG_DEBUG,
803                "Status worker '%s' rating of activation '%s' and state '%s' for good '%08" JK_UINT32_T_HEX_FMT
804                "' and bad '%08" JK_UINT32_T_HEX_FMT "' is %d",
805                w->name, jk_lb_get_activation(wr, l), jk_lb_get_state(wr, l),
806                good, bad, rv);
807     return rv;
808 }
809
810 static jk_uint32_t status_get_single_rating(const char rating, jk_logger_t *l)
811 {
812     if (JK_IS_DEBUG_LEVEL(l))
813         jk_log(l, JK_LOG_DEBUG,
814                "rating retrieval for '%c'",
815                rating);
816     switch (rating)
817     {
818     case 'A':
819     case 'a':
820         return JK_STATUS_MASK_ACTIVE;
821     case 'D':
822     case 'd':
823         return JK_STATUS_MASK_DISABLED;
824     case 'S':
825     case 's':
826         return JK_STATUS_MASK_STOPPED;
827     case 'O':
828     case 'o':
829         return JK_STATUS_MASK_OK;
830     case 'I':
831     case 'i':
832     case 'N':
833     case 'n':
834         return JK_STATUS_MASK_IDLE;
835     case 'B':
836     case 'b':
837         return JK_STATUS_MASK_BUSY;
838     case 'R':
839     case 'r':
840         return JK_STATUS_MASK_RECOVER;
841     case 'E':
842     case 'e':
843         return JK_STATUS_MASK_ERROR;
844     default:
845         jk_log(l, JK_LOG_WARNING,
846                "Unknown rating type '%c'",
847                rating);
848         return 0;
849     }
850 }
851
852 static jk_uint32_t status_get_rating(const char *rating,
853                                      jk_logger_t *l)
854 {
855     int off = 0;
856     jk_uint32_t mask = 0;
857
858     while (rating[off] == ' ' || rating[off] == '\t' || rating[off] == '.') {
859         off++;
860     }
861     mask = status_get_single_rating(rating[off], l);
862     while (rating[off] != '\0' && rating[off] != '.') {
863         off++;
864     }
865     if (rating[off] == '.') {
866         off++;
867     }
868     if (rating[off] != '\0') {
869         mask &= status_get_single_rating(rating[off], l);
870     }
871     if (JK_IS_DEBUG_LEVEL(l))
872         jk_log(l, JK_LOG_DEBUG,
873                "rating for '%s' is '%08" JK_UINT32_T_HEX_FMT "'",
874                rating, mask);
875     return mask;
876 }
877
878 static const char *status_worker_type(int t)
879 {
880     if (t < 0 || t > 6)
881         t = 0;
882     return worker_type[t];
883 }
884
885
886 static int status_get_string(status_endpoint_t *p,
887                              const char *param,
888                              const char *def,
889                              const char **result,
890                              jk_logger_t *l)
891 {
892     int rv;
893
894     *result = jk_map_get_string(p->req_params,
895                                 param, NULL);
896     if (*result) {
897         rv = JK_TRUE;
898     }
899     else {
900         *result = def;
901         rv = JK_FALSE;
902     }
903     if (JK_IS_DEBUG_LEVEL(l))
904         jk_log(l, JK_LOG_DEBUG,
905                "retrieved string arg '%s' as '%s'%s",
906                param, *result ? *result : "(null)",
907                rv == JK_FALSE ? " (default)" : "");
908     return rv;
909 }
910
911 static int status_get_int(status_endpoint_t *p,
912                           const char *param,
913                           int def,
914                           jk_logger_t *l)
915 {
916     const char *arg;
917     int rv = def;
918
919     if (status_get_string(p, param, NULL, &arg, l) == JK_TRUE) {
920         rv = atoi(arg);
921     }
922     return rv;
923 }
924
925 static int status_get_bool(status_endpoint_t *p,
926                            const char *param,
927                            int def,
928                            jk_logger_t *l)
929 {
930     const char *arg;
931
932     if (status_get_string(p, param, NULL, &arg, l) == JK_TRUE) {
933         return jk_get_bool_code(arg, def);
934     }
935     return def;
936 }
937
938 static const char *status_cmd_text(int cmd)
939 {
940     return cmd_type[cmd];
941 }
942
943 static int status_cmd_int(const char *cmd)
944 {
945     if (!cmd)
946         return JK_STATUS_CMD_DEF;
947     if (!strcmp(cmd, JK_STATUS_CMD_TEXT_LIST))
948         return JK_STATUS_CMD_LIST;
949     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_SHOW))
950         return JK_STATUS_CMD_SHOW;
951     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_EDIT))
952         return JK_STATUS_CMD_EDIT;
953     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_UPDATE))
954         return JK_STATUS_CMD_UPDATE;
955     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_RESET))
956         return JK_STATUS_CMD_RESET;
957     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_VERSION))
958         return JK_STATUS_CMD_VERSION;
959     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_RECOVER))
960         return JK_STATUS_CMD_RECOVER;
961     else if (!strcmp(cmd, JK_STATUS_CMD_TEXT_DUMP))
962         return JK_STATUS_CMD_DUMP;
963     return JK_STATUS_CMD_UNKNOWN;
964 }
965
966 static const char *status_mime_text(int mime)
967 {
968     return mime_type[mime];
969 }
970
971 static int status_mime_int(const char *mime)
972 {
973     if (!mime)
974         return JK_STATUS_MIME_DEF;
975     if (!strcmp(mime, JK_STATUS_MIME_TEXT_HTML))
976         return JK_STATUS_MIME_HTML;
977     else if (!strcmp(mime, JK_STATUS_MIME_TEXT_XML))
978         return JK_STATUS_MIME_XML;
979     else if (!strcmp(mime, JK_STATUS_MIME_TEXT_TXT))
980         return JK_STATUS_MIME_TXT;
981     else if (!strcmp(mime, JK_STATUS_MIME_TEXT_PROP))
982         return JK_STATUS_MIME_PROP;
983     return JK_STATUS_MIME_UNKNOWN;
984 }
985
986 static jk_uint32_t status_cmd_props(int cmd)
987 {
988     jk_uint32_t props = 0;
989
990     if (cmd == JK_STATUS_CMD_LIST ||
991         cmd == JK_STATUS_CMD_SHOW)
992         props |= JK_STATUS_CMD_PROP_REFRESH |
993                  JK_STATUS_CMD_PROP_SWITCH_RO |
994                  JK_STATUS_CMD_PROP_LINK_HELP |
995                  JK_STATUS_CMD_PROP_LEGEND;
996     if (cmd == JK_STATUS_CMD_LIST ||
997         cmd == JK_STATUS_CMD_SHOW ||
998         cmd == JK_STATUS_CMD_VERSION)
999         props |= JK_STATUS_CMD_PROP_DUMP_LINK;
1000     if (cmd == JK_STATUS_CMD_LIST ||
1001         cmd == JK_STATUS_CMD_SHOW ||
1002         cmd == JK_STATUS_CMD_VERSION ||
1003         cmd == JK_STATUS_CMD_DUMP)
1004         props |= JK_STATUS_CMD_PROP_HEAD |
1005                  JK_STATUS_CMD_PROP_FMT;
1006     if (cmd == JK_STATUS_CMD_SHOW ||
1007         cmd == JK_STATUS_CMD_VERSION ||
1008         cmd == JK_STATUS_CMD_DUMP)
1009         props |= JK_STATUS_CMD_PROP_BACK_LIST;
1010     if (cmd == JK_STATUS_CMD_SHOW ||
1011         cmd == JK_STATUS_CMD_EDIT ||
1012         cmd == JK_STATUS_CMD_VERSION ||
1013         cmd == JK_STATUS_CMD_DUMP)
1014         props |= JK_STATUS_CMD_PROP_BACK_LINK;
1015     if (cmd == JK_STATUS_CMD_UPDATE)
1016         props |= JK_STATUS_CMD_PROP_WILDCARD;
1017     if (cmd != JK_STATUS_CMD_EDIT &&
1018         cmd != JK_STATUS_CMD_UPDATE &&
1019         cmd != JK_STATUS_CMD_RESET &&
1020         cmd != JK_STATUS_CMD_RECOVER)
1021         props |= JK_STATUS_CMD_PROP_READONLY;
1022     if (cmd != JK_STATUS_CMD_LIST &&
1023         cmd != JK_STATUS_CMD_VERSION &&
1024         cmd != JK_STATUS_CMD_DUMP)
1025         props |= JK_STATUS_CMD_PROP_CHECK_WORKER;
1026
1027     return props;
1028 }
1029
1030 static void status_start_form(jk_ws_service_t *s,
1031                               status_endpoint_t *p,
1032                               const char *method,
1033                               int cmd,
1034                               const char *overwrite,
1035                               jk_logger_t *l)
1036 {
1037
1038     int i;
1039     int sz;
1040     jk_map_t *m = p->req_params;
1041
1042     if (method)
1043         jk_printf(s, JK_STATUS_FORM_START, method, s->req_uri);
1044     else
1045         return;
1046     if (cmd != JK_STATUS_CMD_UNKNOWN) {
1047         jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING,
1048                   JK_STATUS_ARG_CMD, status_cmd_text(cmd));
1049     }
1050
1051     sz = jk_map_size(m);
1052     for (i = 0; i < sz; i++) {
1053         const char *k = jk_map_name_at(m, i);
1054         const char *v = jk_map_value_at(m, i);
1055         if ((strcmp(k, JK_STATUS_ARG_CMD) ||
1056             cmd == JK_STATUS_CMD_UNKNOWN) &&
1057             (!overwrite ||
1058             strcmp(k, overwrite))) {
1059             jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING, k, v);
1060         }
1061     }
1062 }
1063
1064 static void status_write_uri(jk_ws_service_t *s,
1065                              status_endpoint_t *p,
1066                              const char *text,
1067                              int cmd, int mime,
1068                              const char *worker, const char *sub_worker,
1069                              unsigned int add_options, unsigned int rm_options,
1070                              const char *attribute,
1071                              jk_logger_t *l)
1072 {
1073     int i;
1074     int sz;
1075     int started = 0;
1076     int from;
1077     int restore_sub_worker = JK_FALSE;
1078     int save_sub_worker = JK_FALSE;
1079     int prev;
1080     unsigned int opt = 0;
1081     const char *arg;
1082     jk_map_t *m = p->req_params;
1083
1084     if (text)
1085         jk_puts(s, "<a href=\"");
1086     jk_puts(s, s->req_uri);
1087     status_get_string(p, JK_STATUS_ARG_FROM, NULL, &arg, l);
1088     from = status_cmd_int(arg);
1089     status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l);
1090     prev = status_cmd_int(arg);
1091     if (cmd == JK_STATUS_CMD_SHOW && prev == JK_STATUS_CMD_EDIT) {
1092         restore_sub_worker = JK_TRUE;
1093     }
1094     if (cmd == JK_STATUS_CMD_UNKNOWN) {
1095         if (prev == JK_STATUS_CMD_UPDATE ||
1096             prev == JK_STATUS_CMD_RESET ||
1097             prev == JK_STATUS_CMD_RECOVER) {
1098             cmd = from;
1099             restore_sub_worker = JK_TRUE;
1100         }
1101     }
1102     if (cmd != JK_STATUS_CMD_UNKNOWN) {
1103         jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
1104                   JK_STATUS_ARG_CMD, status_cmd_text(cmd));
1105         if (cmd == JK_STATUS_CMD_EDIT ||
1106             cmd == JK_STATUS_CMD_RESET ||
1107             cmd == JK_STATUS_CMD_RECOVER) {
1108             jk_printf(s, "%s%s=%s", "&amp;",
1109                       JK_STATUS_ARG_FROM, status_cmd_text(prev));
1110             save_sub_worker = JK_TRUE;
1111         }
1112         started=1;
1113     }
1114     if (mime != JK_STATUS_MIME_UNKNOWN) {
1115         jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
1116                   JK_STATUS_ARG_MIME, status_mime_text(mime));
1117         started=1;
1118     }
1119     if (worker && worker[0]) {
1120         jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
1121                   JK_STATUS_ARG_WORKER, worker);
1122         started=1;
1123     }
1124     if (sub_worker && sub_worker[0] && cmd != JK_STATUS_CMD_LIST) {
1125         jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
1126                   JK_STATUS_ARG_SUB_WORKER, sub_worker);
1127         started=1;
1128     }
1129     if (attribute && attribute[0]) {
1130         jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
1131                   JK_STATUS_ARG_ATTRIBUTE, attribute);
1132         started=1;
1133     }
1134
1135     sz = jk_map_size(m);
1136     for (i = 0; i < sz; i++) {
1137         const char *k = jk_map_name_at(m, i);
1138         const char *v = jk_map_value_at(m, i);
1139         if (!strcmp(k, JK_STATUS_ARG_CMD) && cmd != JK_STATUS_CMD_UNKNOWN) {
1140             continue;
1141         }
1142         if (!strcmp(k, JK_STATUS_ARG_MIME) && mime != JK_STATUS_MIME_UNKNOWN) {
1143             continue;
1144         }
1145         if (!strcmp(k, JK_STATUS_ARG_FROM)) {
1146             continue;
1147         }
1148         if (!strcmp(k, JK_STATUS_ARG_WORKER) && worker) {
1149             continue;
1150         }
1151         if (!strcmp(k, JK_STATUS_ARG_SUB_WORKER)) {
1152             if (save_sub_worker == JK_TRUE) {
1153                 jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
1154                           JK_STATUS_ARG_PREV_SUB_WORKER, v);
1155                 started=1;
1156                 continue;
1157             }
1158             else if (sub_worker || cmd == JK_STATUS_CMD_LIST) {
1159                 continue;
1160             }
1161             else if (restore_sub_worker == JK_TRUE) {
1162                 continue;
1163             }
1164         }
1165         if (!strcmp(k, JK_STATUS_ARG_PREV_SUB_WORKER) && restore_sub_worker == JK_TRUE && cmd != JK_STATUS_CMD_LIST) {
1166             jk_printf(s, "%s%s=%s", started ? "&amp;" : "?",
1167                       JK_STATUS_ARG_SUB_WORKER, v);
1168             started=1;
1169             continue;
1170         }
1171         if (!strcmp(k, JK_STATUS_ARG_ATTRIBUTE) && attribute) {
1172             continue;
1173         }
1174         if (!strcmp(k, JK_STATUS_ARG_ATTRIBUTE) && cmd != JK_STATUS_CMD_UPDATE && cmd != JK_STATUS_CMD_EDIT) {
1175             continue;
1176         }
1177         if (!strncmp(k, JK_STATUS_ARG_MULT_VALUE_BASE, 3) && cmd != JK_STATUS_CMD_UPDATE) {
1178             continue;
1179         }
1180         if (k[0] == 'v' && cmd != JK_STATUS_CMD_UPDATE) {
1181             continue;
1182         }
1183         if (!strcmp(k, JK_STATUS_ARG_OPTIONS)) {
1184             opt = atoi(v);
1185             continue;
1186         }
1187         jk_printf(s, "%s%s=%s", started ? "&amp;" : "?", k, v);
1188         started=1;
1189     }
1190     if (opt | add_options | rm_options)
1191         jk_printf(s, "%s%s=%u", started ? "&amp;" : "?",
1192                   JK_STATUS_ARG_OPTIONS, (opt | add_options) & ~rm_options);
1193     if (text)
1194         jk_putv(s, "\">", text, "</a>", NULL);
1195 }
1196
1197 static int status_parse_uri(jk_ws_service_t *s,
1198                             status_endpoint_t *p,
1199                             jk_logger_t *l)
1200 {
1201     jk_map_t *m;
1202     status_worker_t *w = p->worker;
1203 #ifdef _MT_CODE_PTHREAD
1204     char *lasts;
1205 #endif
1206     char *param;
1207     char *query;
1208
1209     JK_TRACE_ENTER(l);
1210
1211     if (!s->query_string) {
1212         if (JK_IS_DEBUG_LEVEL(l))
1213             jk_log(l, JK_LOG_DEBUG,
1214                    "Status worker '%s' query string is empty",
1215                    w->name);
1216         JK_TRACE_EXIT(l);
1217         return JK_TRUE;
1218     }
1219
1220     p->query_string = jk_pool_strdup(s->pool, s->query_string);
1221     if (!p->query_string) {
1222         jk_log(l, JK_LOG_ERROR,
1223                "Status worker '%s' could not copy query string",
1224                w->name);
1225         JK_TRACE_EXIT(l);
1226         return JK_FALSE;
1227     }
1228
1229     /* XXX We simply mask special chars n the query string with '@' to prevent cross site scripting */
1230     query = p->query_string;
1231     while ((query = strpbrk(query, JK_STATUS_ESC_CHARS)))
1232         query[0] = '@';
1233
1234     if (!jk_map_alloc(&(p->req_params))) {
1235         jk_log(l, JK_LOG_ERROR,
1236                "Status worker '%s' could not alloc map for request parameters",
1237                w->name);
1238         JK_TRACE_EXIT(l);
1239         return JK_FALSE;
1240     }
1241     m = p->req_params;
1242
1243     query = jk_pool_strdup(s->pool, p->query_string);
1244     if (!query) {
1245         jk_log(l, JK_LOG_ERROR,
1246                "Status worker '%s' could not copy query string",
1247                w->name);
1248         JK_TRACE_EXIT(l);
1249         return JK_FALSE;
1250     }
1251
1252 #ifdef _MT_CODE_PTHREAD
1253     for (param = strtok_r(query, "&", &lasts);
1254          param; param = strtok_r(NULL, "&", &lasts)) {
1255 #else
1256     for (param = strtok(query, "&"); param; param = strtok(NULL, "&")) {
1257 #endif
1258         char *key = jk_pool_strdup(s->pool, param);
1259         char *value;
1260         if (!key) {
1261             jk_log(l, JK_LOG_ERROR,
1262                    "Status worker '%s' could not copy string",
1263                    w->name);
1264             JK_TRACE_EXIT(l);
1265             return JK_FALSE;
1266         }
1267         value = strchr(key, '=');
1268         if (value) {
1269             *value = '\0';
1270             value++;
1271             /* XXX Depending on the params values, we might need to trim and decode */
1272             if (strlen(key)) {
1273                 if (JK_IS_DEBUG_LEVEL(l))
1274                     jk_log(l, JK_LOG_DEBUG,
1275                            "Status worker '%s' adding request param '%s' with value '%s'",
1276                            w->name, key, value);
1277                 jk_map_put(m, key, value, NULL);
1278             }
1279         }
1280     }
1281
1282     JK_TRACE_EXIT(l);
1283     return JK_TRUE;
1284 }
1285
1286 static void write_html_refresh_response(jk_ws_service_t *s,
1287                                         status_endpoint_t *p,
1288                                         const char *err,
1289                                         jk_logger_t *l)
1290 {
1291     if (!err) {
1292         jk_puts(s, "\n<meta http-equiv=\"Refresh\" content=\""
1293                 JK_STATUS_WAIT_AFTER_UPDATE ";url=");
1294         status_write_uri(s, p, NULL, JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
1295                          NULL, NULL, 0, 0, NULL, l);
1296         jk_puts(s, "\">");
1297         jk_putv(s, "<p><b>Result: OK - You will be redirected in "
1298                 JK_STATUS_WAIT_AFTER_UPDATE " seconds.</b><p/>", NULL);
1299     }
1300 }
1301
1302 static int fetch_worker_and_sub_worker(status_endpoint_t *p,
1303                                        const char *operation,
1304                                        const char **worker,
1305                                        const char **sub_worker,
1306                                        jk_logger_t *l)
1307 {
1308     status_worker_t *w = p->worker;
1309
1310     JK_TRACE_ENTER(l);
1311     status_get_string(p, JK_STATUS_ARG_WORKER, NULL, worker, l);
1312     status_get_string(p, JK_STATUS_ARG_SUB_WORKER, NULL, sub_worker, l);
1313     if (JK_IS_DEBUG_LEVEL(l))
1314         jk_log(l, JK_LOG_DEBUG,
1315                "Status worker '%s' %s worker '%s' sub worker '%s'",
1316                w->name, operation,
1317                *worker ? *worker : "(null)", *sub_worker ? *sub_worker : "(null)");
1318     if (!*worker || !(*worker)[0]) {
1319         jk_log(l, JK_LOG_WARNING,
1320                "Status worker '%s' NULL or EMPTY worker param",
1321                w->name);
1322         p->msg = "NULL or EMPTY worker param";
1323         JK_TRACE_EXIT(l);
1324         return JK_FALSE;
1325     }
1326     if (*sub_worker && !(*sub_worker)[0]) {
1327         jk_log(l, JK_LOG_WARNING,
1328                "Status worker '%s' EMPTY sub worker param",
1329                w->name);
1330         p->msg = "EMPTY sub worker param";
1331         JK_TRACE_EXIT(l);
1332         return JK_FALSE;
1333     }
1334     JK_TRACE_EXIT(l);
1335     return JK_TRUE;
1336 }
1337
1338 static int check_valid_lb(jk_ws_service_t *s,
1339                           status_endpoint_t *p,
1340                           jk_worker_t *jw,
1341                           const char *worker,
1342                           lb_worker_t **lbp,
1343                           int implemented,
1344                           jk_logger_t *l)
1345 {
1346     status_worker_t *w = p->worker;
1347
1348     JK_TRACE_ENTER(l);
1349     if (jw->type != JK_LB_WORKER_TYPE) {
1350         if (implemented) {
1351             jk_log(l, JK_LOG_WARNING,
1352                    "Status worker '%s' worker type of worker '%s' has no sub workers",
1353                    w->name, worker);
1354             p->msg = "worker type has no sub workers";
1355         }
1356         else {
1357             jk_log(l, JK_LOG_WARNING,
1358                    "Status worker '%s' worker type of worker '%s' not implemented",
1359                    w->name, worker);
1360                    p->msg = "worker type not implemented";
1361         }
1362         JK_TRACE_EXIT(l);
1363         return JK_FALSE;
1364     }
1365     *lbp = (lb_worker_t *)jw->worker_private;
1366     if (!*lbp) {
1367         jk_log(l, JK_LOG_WARNING,
1368                "Status worker '%s' lb structure of worker '%s' is (null)",
1369                w->name, worker);
1370         p->msg = "lb structure is (null)";
1371         JK_TRACE_EXIT(l);
1372         return JK_FALSE;
1373     }
1374     p->msg = "OK";
1375     JK_TRACE_EXIT(l);
1376     return JK_TRUE;
1377 }
1378
1379 static int search_worker(jk_ws_service_t *s,
1380                          status_endpoint_t *p,
1381                          jk_worker_t **jwp,
1382                          const char *worker,
1383                          jk_logger_t *l)
1384 {
1385     status_worker_t *w = p->worker;
1386
1387     JK_TRACE_ENTER(l);
1388     *jwp = NULL;
1389     if (JK_IS_DEBUG_LEVEL(l))
1390         jk_log(l, JK_LOG_DEBUG,
1391                "Status worker '%s' searching worker '%s'",
1392                w->name, worker ? worker : "(null)");
1393     if (!worker || !worker[0]) {
1394         jk_log(l, JK_LOG_WARNING,
1395                "Status worker '%s' NULL or EMPTY worker param",
1396                w->name);
1397         p->msg = "NULL or EMPTY worker param";
1398         JK_TRACE_EXIT(l);
1399         return JK_FALSE;
1400     }
1401     *jwp = wc_get_worker_for_name(worker, l);
1402     if (!*jwp) {
1403         jk_log(l, JK_LOG_WARNING,
1404                "Status worker '%s' could not find worker '%s'",
1405                w->name, worker);
1406         p->msg = "Could not find given worker";
1407         JK_TRACE_EXIT(l);
1408         return JK_FALSE;
1409     }
1410     p->msg = "OK";
1411     JK_TRACE_EXIT(l);
1412     return JK_TRUE;
1413 }
1414
1415 static int search_sub_worker(jk_ws_service_t *s,
1416                              status_endpoint_t *p,
1417                              jk_worker_t *jw,
1418                              const char *worker,
1419                              lb_sub_worker_t **wrp,
1420                              const char *sub_worker,
1421                              unsigned int *idx,
1422                              jk_logger_t *l)
1423 {
1424     lb_worker_t *lb = NULL;
1425     lb_sub_worker_t *wr = NULL;
1426     status_worker_t *w = p->worker;
1427     unsigned int i = 0;
1428
1429     JK_TRACE_ENTER(l);
1430     if (JK_IS_DEBUG_LEVEL(l))
1431         jk_log(l, JK_LOG_DEBUG,
1432                "Status worker '%s' searching sub worker '%s' of worker '%s'",
1433                w->name, sub_worker ? sub_worker : "(null)",
1434                worker ? worker : "(null)");
1435     if (!sub_worker || !sub_worker[0]) {
1436         jk_log(l, JK_LOG_WARNING,
1437                "Status worker '%s' NULL or EMPTY sub_worker param",
1438                w->name);
1439         p->msg = "NULL or EMPTY sub_worker param";
1440         JK_TRACE_EXIT(l);
1441         return JK_FALSE;
1442     }
1443     if (check_valid_lb(s, p, jw, worker, &lb, 1, l) == JK_FALSE) {
1444         JK_TRACE_EXIT(l);
1445         return JK_FALSE;
1446     }
1447     if (idx)
1448         i = *idx;
1449     for (; i < lb->num_of_workers; i++) {
1450         wr = &(lb->lb_workers[i]);
1451         if (idx) {
1452             if (jk_wildchar_match(wr->name, sub_worker, 0) == 0) {
1453                 *idx = i + 1;
1454                 break;
1455             }
1456         }
1457         else if (strcmp(sub_worker, wr->name) == 0)
1458             break;
1459     }
1460     *wrp = wr;
1461     if (!wr || i == lb->num_of_workers) {
1462         jk_log(l, JK_LOG_WARNING,
1463                "Status worker '%s' could not find sub worker '%s' of worker '%s'",
1464                w->name, sub_worker, worker ? worker : "(null)");
1465         p->msg = "could not find sub worker";
1466         JK_TRACE_EXIT(l);
1467         return JK_FALSE;
1468     }
1469     p->msg = "OK";
1470     JK_TRACE_EXIT(l);
1471     return JK_TRUE;
1472 }
1473
1474 static int count_map(jk_uri_worker_map_t *uw_map,
1475                       const char *worker,
1476                       jk_logger_t *l)
1477 {
1478     unsigned int i;
1479     int count=0;
1480
1481     JK_TRACE_ENTER(l);
1482     if (uw_map) {
1483         for (i = 0; i < uw_map->size[uw_map->index]; i++) {
1484             uri_worker_record_t *uwr = uw_map->maps[uw_map->index][i];
1485             if (strcmp(uwr->worker_name, worker) &&
1486                 strcmp(uwr->worker_name, "*")) {
1487                 continue;
1488             }
1489             count++;
1490         }
1491     }
1492     JK_TRACE_EXIT(l);
1493     return count;
1494 }
1495
1496 static int count_maps(jk_ws_service_t *s,
1497                       const char *worker,
1498                       jk_logger_t *l)
1499 {
1500     int count=0;
1501
1502     JK_TRACE_ENTER(l);
1503     if (s->next_vhost) {
1504         void *srv;
1505         for (srv = s->next_vhost(NULL); srv; srv = s->next_vhost(srv)) {
1506             count += count_map(s->vhost_to_uw_map(srv), worker, l);
1507         }
1508     }
1509     else if (s->uw_map)
1510         count = count_map(s->uw_map, worker, l);
1511     JK_TRACE_EXIT(l);
1512     return count;
1513 }
1514
1515 static void display_map(jk_ws_service_t *s,
1516                         status_endpoint_t *p,
1517                         jk_uri_worker_map_t *uw_map,
1518                         const char *worker,
1519                         const char *server_name,
1520                         int *count_ptr,
1521                         int mime,
1522                         jk_logger_t *l)
1523 {
1524     char buf[64];
1525     unsigned int i;
1526     int count;
1527     status_worker_t *w = p->worker;
1528
1529     JK_TRACE_ENTER(l);
1530
1531     if (uw_map->fname) {
1532         uri_worker_map_update(uw_map, 1, l);
1533     }
1534     for (i = 0; i < uw_map->size[uw_map->index]; i++) {
1535         uri_worker_record_t *uwr = uw_map->maps[uw_map->index][i];
1536
1537         if (strcmp(uwr->worker_name, worker) &&
1538             strcmp(uwr->worker_name, "*")) {
1539             continue;
1540         }
1541         (*count_ptr)++;
1542         count = *count_ptr;
1543
1544         if (mime == JK_STATUS_MIME_HTML) {
1545             if (server_name)
1546                 jk_printf(s, JK_STATUS_URI_MAP_TABLE_ROW2,
1547                           server_name,
1548                           uwr->uri,
1549                           uri_worker_map_get_match(uwr, buf, l),
1550                           uri_worker_map_get_source(uwr, l),
1551                           uwr->extensions.reply_timeout,
1552                           uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : "-",
1553                           uwr->extensions.active ? uwr->extensions.active : "-",
1554                           uwr->extensions.disabled ? uwr->extensions.disabled : "-",
1555                           uwr->extensions.stopped ? uwr->extensions.stopped : "-",
1556                           uwr->extensions.use_server_error_pages);
1557             else
1558                 jk_printf(s, JK_STATUS_URI_MAP_TABLE_ROW,
1559                           uwr->uri,
1560                           uri_worker_map_get_match(uwr, buf, l),
1561                           uri_worker_map_get_source(uwr, l),
1562                           uwr->extensions.reply_timeout,
1563                           uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : "-",
1564                           uwr->extensions.active ? uwr->extensions.active : "-",
1565                           uwr->extensions.disabled ? uwr->extensions.disabled : "-",
1566                           uwr->extensions.stopped ? uwr->extensions.stopped : "-",
1567                           uwr->extensions.use_server_error_pages);
1568         }
1569         else if (mime == JK_STATUS_MIME_XML) {
1570             jk_print_xml_start_elt(s, w, 6, 0, "map");
1571             jk_print_xml_att_int(s, 8, "id", count);
1572             if (server_name)
1573                 jk_print_xml_att_string(s, 8, "server", server_name);
1574             jk_print_xml_att_string(s, 8, "uri", uwr->uri);
1575             jk_print_xml_att_string(s, 8, "type", uri_worker_map_get_match(uwr, buf, l));
1576             jk_print_xml_att_string(s, 8, "source", uri_worker_map_get_source(uwr, l));
1577             jk_print_xml_att_int(s, 8, "reply_timeout", uwr->extensions.reply_timeout);
1578             jk_print_xml_att_string(s, 8, "fail_on_status", uwr->extensions.fail_on_status_str);
1579             jk_print_xml_att_string(s, 8, "active", uwr->extensions.active);
1580             jk_print_xml_att_string(s, 8, "disabled", uwr->extensions.disabled);
1581             jk_print_xml_att_string(s, 8, "stopped", uwr->extensions.stopped);
1582             jk_print_xml_att_int(s, 8, "use_server_errors", uwr->extensions.use_server_error_pages);
1583             jk_print_xml_stop_elt(s, 6, 1);
1584         }
1585         else if (mime == JK_STATUS_MIME_TXT) {
1586             jk_puts(s, "Map:");
1587             jk_printf(s, " id=%d", count);
1588             if (server_name)
1589                 jk_printf(s, " server=\"%s\"", server_name);
1590             jk_printf(s, " uri=\"%s\"", uwr->uri);
1591             jk_printf(s, " type=\"%s\"", uri_worker_map_get_match(uwr, buf, l));
1592             jk_printf(s, " source=\"%s\"", uri_worker_map_get_source(uwr, l));
1593             jk_printf(s, " reply_timeout=\"%d\"", uwr->extensions.reply_timeout);
1594             jk_printf(s, " fail_on_status=\"%s\"", uwr->extensions.fail_on_status_str ? uwr->extensions.fail_on_status_str : "");
1595             jk_printf(s, " active=\"%s\"", uwr->extensions.active ? uwr->extensions.active : "");
1596             jk_printf(s, " disabled=\"%s\"", uwr->extensions.disabled ? uwr->extensions.disabled : "");
1597             jk_printf(s, " stopped=\"%s\"", uwr->extensions.stopped ? uwr->extensions.stopped : "");
1598             jk_printf(s, " use_server_errors=\"%d\"", uwr->extensions.use_server_error_pages);
1599             jk_puts(s, "\n");
1600         }
1601         else if (mime == JK_STATUS_MIME_PROP) {
1602             if (server_name)
1603                jk_print_prop_item_string(s, w, worker, "map", count, "server", server_name);
1604             jk_print_prop_item_string(s, w, worker, "map", count, "uri", uwr->uri);
1605             jk_print_prop_item_string(s, w, worker, "map", count, "type", uri_worker_map_get_match(uwr, buf, l));
1606             jk_print_prop_item_string(s, w, worker, "map", count, "source", uri_worker_map_get_source(uwr, l));
1607             jk_print_prop_item_int(s, w, worker, "map", count, "reply_timeout", uwr->extensions.reply_timeout);
1608             jk_print_prop_item_string(s, w, worker, "map", count, "fail_on_status", uwr->extensions.fail_on_status_str);
1609             jk_print_prop_item_string(s, w, worker, "map", count, "active", uwr->extensions.active);
1610             jk_print_prop_item_string(s, w, worker, "map", count, "disabled", uwr->extensions.disabled);
1611             jk_print_prop_item_string(s, w, worker, "map", count, "stopped", uwr->extensions.stopped);
1612             jk_print_prop_item_int(s, w, worker, "map", count, "use_server_errors", uwr->extensions.use_server_error_pages);
1613         }
1614     }
1615     JK_TRACE_EXIT(l);
1616 }
1617
1618 static void display_maps(jk_ws_service_t *s,
1619                          status_endpoint_t *p,
1620                          const char *worker,
1621                          jk_logger_t *l)
1622 {
1623     int mime;
1624     unsigned int hide;
1625     int has_server_iterator = 0;
1626     int count=0;
1627     const char *arg;
1628     status_worker_t *w = p->worker;
1629     jk_uri_worker_map_t *uw_map;
1630     char server_name[80];
1631     void *srv;
1632
1633     JK_TRACE_ENTER(l);
1634     status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l);
1635     mime = status_mime_int(arg);
1636     hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
1637                           JK_STATUS_ARG_OPTION_NO_MAPS;
1638     if (s->next_vhost)
1639         has_server_iterator = 1;
1640
1641     count = count_maps(s, worker, l);
1642
1643     if (hide) {
1644         if (count && mime == JK_STATUS_MIME_HTML) {
1645             jk_puts(s, "<p>\n");
1646             status_write_uri(s, p, "Show URI Mappings", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
1647                              NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MAPS, NULL, l);
1648             jk_puts(s, "</p>\n");
1649         }
1650         JK_TRACE_EXIT(l);
1651         return;
1652     }
1653
1654     if (count) {
1655         if (mime == JK_STATUS_MIME_HTML) {
1656             jk_printf(s, "<hr/><h3>URI Mappings for %s (%d maps) [", worker, count);
1657             status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
1658                              NULL, NULL, JK_STATUS_ARG_OPTION_NO_MAPS, 0, NULL, l);
1659             jk_puts(s, "]</h3><table>\n");
1660             if (has_server_iterator)
1661                 jk_printf(s, JK_STATUS_URI_MAP_TABLE_HEAD2,
1662                           "Server", "URI", "Match Type", "Source", "Reply Timeout", "Fail on Status", "Active", "Disabled", "Stopped", "Use Server Errors");
1663             else
1664                 jk_printf(s, JK_STATUS_URI_MAP_TABLE_HEAD,
1665                           "URI", "Match Type", "Source", "Reply Timeout", "Fail on Status", "Active", "Disabled", "Stopped", "Use Server Errors");
1666         }
1667         count = 0;
1668         if (has_server_iterator) {
1669             for (srv = s->next_vhost(NULL); srv; srv = s->next_vhost(srv)) {
1670                 uw_map = s->vhost_to_uw_map(srv);
1671                 if (uw_map) {
1672                     s->vhost_to_text(srv, server_name, 80);
1673                     display_map(s, p, uw_map, worker, server_name, &count, mime, l);
1674                 }
1675             }
1676         }
1677         else {
1678             uw_map = s->uw_map;
1679             if (uw_map) {
1680                 display_map(s, p, uw_map, worker, NULL, &count, mime, l);
1681             }
1682         }
1683         if (mime == JK_STATUS_MIME_HTML) {
1684             jk_puts(s, "</table>\n");
1685         }
1686     }
1687     else {
1688         if (mime == JK_STATUS_MIME_HTML) {
1689             jk_putv(s, "<hr/><h3>Warning: No URI Mappings defined for ",
1690                     worker, " !</h3>\n", NULL);
1691         }
1692     }
1693     if (JK_IS_DEBUG_LEVEL(l))
1694         jk_log(l, JK_LOG_DEBUG,
1695                "Status worker '%s' displayed %d maps for worker '%s'",
1696                w->name, count, worker);
1697     JK_TRACE_EXIT(l);
1698 }
1699
1700 static const char *dump_ajp_addr(ajp_worker_t *aw, char *buf)
1701 {
1702     if (aw->port > 0)
1703         return jk_dump_hinfo(&aw->worker_inet_addr, buf);
1704     else {
1705         if (aw->addr_sequence != aw->s->addr_sequence)
1706             return "unresolved";
1707         else
1708             return "invalid";
1709     }
1710 }
1711
1712 static void display_worker_ajp_conf_details(jk_ws_service_t *s,
1713                                             status_endpoint_t *p,
1714                                             ajp_worker_t *aw,
1715                                             int is_member,
1716                                             int type,
1717                                             jk_logger_t *l)
1718 {
1719     char buf[32];
1720
1721     JK_TRACE_ENTER(l);
1722
1723     if (is_member)
1724         jk_printf(s, JK_STATUS_SHOW_MEMBER_CONF_ROW,
1725                   aw->name,
1726                   status_worker_type(type),
1727                   aw->host,
1728                   dump_ajp_addr(aw, buf),
1729                   aw->cache_timeout,
1730                   aw->connect_timeout,
1731                   aw->prepost_timeout,
1732                   aw->reply_timeout,
1733                   aw->retries,
1734                   aw->recovery_opts,
1735                   aw->max_packet_size);
1736     else
1737         jk_printf(s, JK_STATUS_SHOW_AJP_CONF_ROW,
1738                   status_worker_type(type),
1739                   aw->host,
1740                   dump_ajp_addr(aw, buf),
1741                   aw->cache_timeout,
1742                   aw->connect_timeout,
1743                   aw->prepost_timeout,
1744                   aw->reply_timeout,
1745                   aw->retries,
1746                   aw->recovery_opts,
1747                   aw->max_packet_size);
1748     JK_TRACE_EXIT(l);
1749
1750 }
1751
1752 static void display_worker_ajp_details(jk_ws_service_t *s,
1753                                        status_endpoint_t *p,
1754                                        ajp_worker_t *aw,
1755                                        lb_sub_worker_t *wr,
1756                                        lb_worker_t *lb,
1757                                        int ms_min,
1758                                        int ms_max,
1759                                        int map_count,
1760                                        jk_logger_t *l)
1761 {
1762     char buf[32];
1763     char buf_rd[32];
1764     char buf_rd_sec[32];
1765     char buf_wr[32];
1766     char buf_wr_sec[32];
1767     int mime;
1768     const char *arg;
1769     time_t now = time(NULL);
1770     const char *name = NULL;
1771     const char *sub_name = NULL;
1772     const char *ajp_name = NULL;
1773     status_worker_t *w = p->worker;
1774     int rs_min = 0;
1775     int rs_max = 0;
1776     int delta_reset = (int)difftime(now, aw->s->last_reset);
1777     int delta_error = -1;
1778     char buf_time[JK_STATUS_TIME_BUF_SZ];
1779     char buf_tz[JK_STATUS_TIME_BUF_SZ];
1780     time_t error_time = 0;
1781     int rc_time = -1;
1782
1783     JK_TRACE_ENTER(l);
1784
1785     status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l);
1786     mime = status_mime_int(arg);
1787
1788     if (lb) {
1789         name = lb->name;
1790         sub_name = wr->name;
1791         ajp_name = wr->name;
1792         error_time = wr->s->error_time;
1793         if (wr->s->state == JK_LB_STATE_ERROR) {
1794             rs_min = lb->recover_wait_time - (int)difftime(now, wr->s->error_time);
1795             if (rs_min < 0) {
1796                 rs_min = 0;
1797             }
1798             rs_max = rs_min + lb->maintain_time;
1799             if (rs_min < ms_min) {
1800                 rs_min = ms_min;
1801             }
1802         }
1803     }
1804     else {
1805         name = aw->name;
1806         sub_name = NULL;
1807         ajp_name = aw->name;
1808         error_time = aw->s->error_time;
1809     }
1810
1811     if (error_time > 0) {
1812         delta_error = (int)difftime(now, error_time);
1813         rc_time = status_strftime(error_time, mime, buf_time, buf_tz, l);
1814     }
1815
1816     if (mime == JK_STATUS_MIME_HTML) {
1817
1818         if (lb)
1819             jk_printf(s, JK_STATUS_SHOW_MEMBER_ROW,
1820                       sub_name,
1821                       jk_lb_get_activation(wr, l),
1822                       jk_lb_get_state(wr, l),
1823                       wr->distance,
1824                       wr->lb_factor,
1825                       wr->lb_mult,
1826                       wr->s->lb_value,
1827                       aw->s->used,
1828                       delta_reset > 0 ? (int)(aw->s->used / delta_reset) : -1,
1829                       wr->s->errors,
1830                       aw->s->client_errors,
1831                       aw->s->reply_timeouts,
1832                       status_strfsize(aw->s->transferred, buf_wr),
1833                       delta_reset > 0 ? status_strfsize(aw->s->transferred / delta_reset, buf_wr_sec) : "-",
1834                       status_strfsize(aw->s->readed, buf_rd),
1835                       delta_reset > 0 ? status_strfsize(aw->s->readed / delta_reset , buf_rd_sec) : "-",
1836                       aw->s->busy,
1837                       aw->s->max_busy,
1838                       aw->s->connected,
1839                       wr->route,
1840                       wr->redirect ? (*wr->redirect ? wr->redirect : "&nbsp;") : "&nbsp",
1841                       wr->domain ? (*wr->domain ? wr->domain : "&nbsp;") : "&nbsp",
1842                       rs_min,
1843                       rs_max,
1844                       delta_reset,
1845                       rc_time > 0 ? buf_time : "&nbsp;");
1846         else {
1847             jk_printf(s, JK_STATUS_SHOW_AJP_ROW,
1848                       jk_ajp_get_state(aw, l),
1849                       aw->s->used,
1850                       delta_reset > 0 ? (int)(aw->s->used / delta_reset) : -1,
1851                       aw->s->errors,
1852                       aw->s->client_errors,
1853                       aw->s->reply_timeouts,
1854                       status_strfsize(aw->s->transferred, buf_wr),
1855                       delta_reset > 0 ? status_strfsize(aw->s->transferred / delta_reset, buf_wr_sec) : "-",
1856                       status_strfsize(aw->s->readed, buf_rd),
1857                       delta_reset > 0 ? status_strfsize(aw->s->readed / delta_reset , buf_rd_sec) : "-",
1858                       aw->s->busy,
1859                       aw->s->max_busy,
1860                       aw->s->connected,
1861                       delta_reset,
1862                       rc_time > 0 ? buf_time : "&nbsp;");
1863         }
1864
1865     }
1866     else if (mime == JK_STATUS_MIME_XML) {
1867
1868         int off = 2;
1869         if (lb)
1870             off = 6;
1871         if (lb) {
1872             jk_print_xml_start_elt(s, w, off, 0, "member");
1873             jk_print_xml_att_string(s, off+2, "name", sub_name);
1874             jk_print_xml_att_string(s, off+2, "type", status_worker_type(wr->worker->type));
1875         }
1876         else {
1877             jk_print_xml_start_elt(s, w, off, 0, "ajp");
1878             jk_print_xml_att_string(s, off+2, "name", ajp_name);
1879             jk_print_xml_att_string(s, off+2, "type", status_worker_type(aw->worker.type));
1880         }
1881         jk_print_xml_att_string(s, off+2, "host", aw->host);
1882         jk_print_xml_att_int(s, off+2, "port", aw->port);
1883         jk_print_xml_att_string(s, off+2, "address", dump_ajp_addr(aw, buf));
1884         jk_print_xml_att_int(s, off+2, "connection_pool_timeout", aw->cache_timeout);
1885         jk_print_xml_att_int(s, off+2, "ping_timeout", aw->ping_timeout);
1886         jk_print_xml_att_int(s, off+2, "connect_timeout", aw->connect_timeout);
1887         jk_print_xml_att_int(s, off+2, "prepost_timeout", aw->prepost_timeout);
1888         jk_print_xml_att_int(s, off+2, "reply_timeout", aw->reply_timeout);
1889         jk_print_xml_att_int(s, off+2, "connection_ping_interval", aw->conn_ping_interval);
1890         jk_print_xml_att_int(s, off+2, "retries", aw->retries);
1891         jk_print_xml_att_uint(s, off+2, "recovery_options", aw->recovery_opts);
1892         jk_print_xml_att_uint(s, off+2, "max_packet_size", aw->max_packet_size);
1893         if (lb) {
1894             jk_print_xml_att_string(s, off+2, "activation", jk_lb_get_activation(wr, l));
1895             jk_print_xml_att_int(s, off+2, "lbfactor", wr->lb_factor);
1896             jk_print_xml_att_string(s, off+2, "route", wr->route);
1897             jk_print_xml_att_string(s, off+2, "redirect", wr->redirect);
1898             jk_print_xml_att_string(s, off+2, "domain", wr->domain);
1899             jk_print_xml_att_int(s, off+2, "distance", wr->distance);
1900             jk_print_xml_att_string(s, off+2, "state", jk_lb_get_state(wr, l));
1901             jk_print_xml_att_uint64(s, off+2, "lbmult", wr->lb_mult);
1902             jk_print_xml_att_uint64(s, off+2, "lbvalue", wr->s->lb_value);
1903             jk_print_xml_att_uint64(s, off+2, "elected", aw->s->used);
1904             jk_print_xml_att_uint32(s, off+2, "errors", wr->s->errors);
1905         }
1906         else {
1907             jk_print_xml_att_uint64(s, off+2, "used", aw->s->used);
1908             jk_print_xml_att_uint32(s, off+2, "errors", aw->s->errors);
1909         }
1910         jk_print_xml_att_uint32(s, off+2, "client_errors", aw->s->client_errors);
1911         jk_print_xml_att_uint32(s, off+2, "reply_timeouts", aw->s->reply_timeouts);
1912         jk_print_xml_att_uint64(s, off+2, "transferred", aw->s->transferred);
1913         jk_print_xml_att_uint64(s, off+2, "read", aw->s->readed);
1914         jk_print_xml_att_int(s, off+2, "busy", aw->s->busy);
1915         jk_print_xml_att_int(s, off+2, "max_busy", aw->s->max_busy);
1916         jk_print_xml_att_int(s, off+2, "connected", aw->s->connected);
1917         if (lb) {
1918             jk_print_xml_att_int(s, off+2, "time_to_recover_min", rs_min);
1919             jk_print_xml_att_int(s, off+2, "time_to_recover_max", rs_max);
1920         }
1921         else
1922             jk_print_xml_att_int(s, off+2, "map_count", map_count);
1923         jk_print_xml_att_long(s, off+2, "last_reset_at", (long)aw->s->last_reset);
1924         jk_print_xml_att_int(s, off+2, "last_reset_ago", delta_reset);
1925         if (rc_time > 0 ) {
1926             jk_print_xml_att_string(s, off+2, "error_time_datetime", buf_time);
1927             jk_print_xml_att_string(s, off+2, "error_time_tz", buf_tz);
1928             jk_print_xml_att_int(s, off+2, "error_time_unix_seconds", (int)error_time);
1929             jk_print_xml_att_int(s, off+2, "error_time_ago", delta_error);
1930         }
1931         /* Terminate the tag */
1932         jk_print_xml_stop_elt(s, off, 1);
1933
1934     }
1935     else if (mime == JK_STATUS_MIME_TXT) {
1936
1937         if (lb) {
1938             jk_puts(s, "Member:");
1939             jk_printf(s, " name=%s", sub_name);
1940             jk_printf(s, " type=%s", status_worker_type(wr->worker->type));
1941         }
1942         else {
1943             jk_puts(s, "AJP Worker:");
1944             jk_printf(s, " name=%s", ajp_name);
1945             jk_printf(s, " type=%s", status_worker_type(aw->worker.type));
1946         }
1947         jk_printf(s, " host=%s", aw->host);
1948         jk_printf(s, " port=%d", aw->port);
1949         jk_printf(s, " address=%s", dump_ajp_addr(aw, buf));
1950         jk_printf(s, " connection_pool_timeout=%d", aw->cache_timeout);
1951         jk_printf(s, " ping_timeout=%d", aw->ping_timeout);
1952         jk_printf(s, " connect_timeout=%d", aw->connect_timeout);
1953         jk_printf(s, " prepost_timeout=%d", aw->prepost_timeout);
1954         jk_printf(s, " reply_timeout=%d", aw->reply_timeout);
1955         jk_printf(s, " retries=%d", aw->retries);
1956         jk_printf(s, " connection_ping_interval=%d", aw->conn_ping_interval);
1957         jk_printf(s, " recovery_options=%u", aw->recovery_opts);
1958         jk_printf(s, " max_packet_size=%u", aw->max_packet_size);
1959         if (lb) {
1960             jk_printf(s, " activation=%s", jk_lb_get_activation(wr, l));
1961             jk_printf(s, " lbfactor=%d", wr->lb_factor);
1962             jk_printf(s, " route=\"%s\"", wr->route ? wr->route : "");
1963             jk_printf(s, " redirect=\"%s\"", wr->redirect ? wr->redirect : "");
1964             jk_printf(s, " domain=\"%s\"", wr->domain ? wr->domain : "");
1965             jk_printf(s, " distance=%d", wr->distance);
1966             jk_printf(s, " state=%s", jk_lb_get_state(wr, l));
1967             jk_printf(s, " lbmult=%" JK_UINT64_T_FMT, wr->lb_mult);
1968             jk_printf(s, " lbvalue=%" JK_UINT64_T_FMT, wr->s->lb_value);
1969             jk_printf(s, " elected=%" JK_UINT64_T_FMT, aw->s->used);
1970             jk_printf(s, " errors=%" JK_UINT32_T_FMT, wr->s->errors);
1971         }
1972         else {
1973             jk_printf(s, " used=%" JK_UINT64_T_FMT, aw->s->used);
1974             jk_printf(s, " errors=%" JK_UINT32_T_FMT, aw->s->errors);
1975         }
1976         jk_printf(s, " client_errors=%" JK_UINT32_T_FMT, aw->s->client_errors);
1977         jk_printf(s, " reply_timeouts=%" JK_UINT32_T_FMT, aw->s->reply_timeouts);
1978         jk_printf(s, " transferred=%" JK_UINT64_T_FMT, aw->s->transferred);
1979         jk_printf(s, " read=%" JK_UINT64_T_FMT, aw->s->readed);
1980         jk_printf(s, " busy=%d", aw->s->busy);
1981         jk_printf(s, " max_busy=%d", aw->s->max_busy);
1982         jk_printf(s, " connected=%d", aw->s->connected);
1983         if (lb) {
1984             jk_printf(s, " time_to_recover_min=%d", rs_min);
1985             jk_printf(s, " time_to_recover_max=%d", rs_max);
1986         }
1987         else
1988             jk_printf(s, " map_count=%d", map_count);
1989         jk_printf(s, " last_reset_at=%ld", (long)aw->s->last_reset);
1990         jk_printf(s, " last_reset_ago=%d", delta_reset);
1991         if (rc_time > 0) {
1992             jk_printf(s, " error_time_datetime=%s", buf_time);
1993             jk_printf(s, " error_time_tz=%s", buf_tz);
1994             jk_printf(s, " error_time_unix_seconds=%d", error_time);
1995             jk_printf(s, " error_time_ago=%d", delta_error);
1996         }
1997         jk_puts(s, "\n");
1998
1999     }
2000     else if (mime == JK_STATUS_MIME_PROP) {
2001
2002         if (lb) {
2003             jk_print_prop_att_string(s, w, name, "balance_workers", sub_name);
2004             jk_print_prop_att_string(s, w, ajp_name, "type", status_worker_type(wr->worker->type));
2005         }
2006         else {
2007             jk_print_prop_att_string(s, w, name, "list", ajp_name);
2008             jk_print_prop_att_string(s, w, ajp_name, "type", status_worker_type(aw->worker.type));
2009         }
2010         jk_print_prop_att_string(s, w, ajp_name, "host", aw->host);
2011         jk_print_prop_att_int(s, w, ajp_name, "port", aw->port);
2012         jk_print_prop_att_string(s, w, ajp_name, "address", dump_ajp_addr(aw, buf));
2013         jk_print_prop_att_int(s, w, ajp_name, "connection_pool_timeout", aw->cache_timeout);
2014         jk_print_prop_att_int(s, w, ajp_name, "ping_timeout", aw->ping_timeout);
2015         jk_print_prop_att_int(s, w, ajp_name, "connect_timeout", aw->connect_timeout);
2016         jk_print_prop_att_int(s, w, ajp_name, "prepost_timeout", aw->prepost_timeout);
2017         jk_print_prop_att_int(s, w, ajp_name, "reply_timeout", aw->reply_timeout);
2018         jk_print_prop_att_int(s, w, ajp_name, "retries", aw->retries);
2019         jk_print_prop_att_int(s, w, ajp_name, "connection_ping_interval", aw->conn_ping_interval);
2020         jk_print_prop_att_uint(s, w, ajp_name, "recovery_options", aw->recovery_opts);
2021         jk_print_prop_att_uint(s, w, ajp_name, "max_packet_size", aw->max_packet_size);
2022         if (lb) {
2023             jk_print_prop_att_string(s, w, ajp_name, "activation", jk_lb_get_activation(wr, l));
2024             jk_print_prop_att_int(s, w, ajp_name, "lbfactor", wr->lb_factor);
2025             jk_print_prop_att_string(s, w, ajp_name, "route", wr->route);
2026             jk_print_prop_att_string(s, w, ajp_name, "redirect", wr->redirect);
2027             jk_print_prop_att_string(s, w, ajp_name, "domain", wr->domain);
2028             jk_print_prop_att_int(s, w, ajp_name, "distance", wr->distance);
2029             jk_print_prop_att_string(s, w, ajp_name, "state", jk_lb_get_state(wr, l));
2030             jk_print_prop_att_uint64(s, w, ajp_name, "lbmult", wr->lb_mult);
2031             jk_print_prop_att_uint64(s, w, ajp_name, "lbvalue", wr->s->lb_value);
2032             jk_print_prop_att_uint64(s, w, ajp_name, "elected", aw->s->used);
2033             jk_print_prop_att_uint32(s, w, ajp_name, "errors", wr->s->errors);
2034         }
2035         else {
2036             jk_print_prop_att_uint64(s, w, ajp_name, "used", aw->s->used);
2037             jk_print_prop_att_uint32(s, w, ajp_name, "errors", aw->s->errors);
2038         }
2039         jk_print_prop_att_uint32(s, w, ajp_name, "client_errors", aw->s->client_errors);
2040         jk_print_prop_att_uint32(s, w, ajp_name, "reply_timeouts", aw->s->reply_timeouts);
2041         jk_print_prop_att_uint64(s, w, ajp_name, "transferred", aw->s->transferred);
2042         jk_print_prop_att_uint64(s, w, ajp_name, "read", aw->s->readed);
2043         jk_print_prop_att_int(s, w, ajp_name, "busy", aw->s->busy);
2044         jk_print_prop_att_int(s, w, ajp_name, "max_busy", aw->s->max_busy);
2045         jk_print_prop_att_int(s, w, ajp_name, "connected", aw->s->connected);
2046         if (lb) {
2047             jk_print_prop_att_int(s, w, ajp_name, "time_to_recover_min", rs_min);
2048             jk_print_prop_att_int(s, w, ajp_name, "time_to_recover_max", rs_max);
2049         }
2050         else
2051             jk_print_prop_att_int(s, w, name, "map_count", map_count);
2052         jk_print_prop_att_long(s, w, name, "last_reset_at", (long)aw->s->last_reset);
2053         jk_print_prop_att_int(s, w, name, "last_reset_ago", delta_reset);
2054         if (rc_time > 0) {
2055             jk_print_prop_att_string(s, w, name, "error_time_datetime", buf_time);
2056             jk_print_prop_att_string(s, w, name, "error_time_tz", buf_tz);
2057             jk_print_prop_att_int(s, w, name, "error_time_unix seconds", (int)error_time);
2058             jk_print_prop_att_int(s, w, name, "error_time_ago seconds", delta_error);
2059         }
2060
2061     }
2062     JK_TRACE_EXIT(l);
2063
2064 }
2065
2066 static void display_worker_lb(jk_ws_service_t *s,
2067                               status_endpoint_t *p,
2068                               lb_worker_t *lb,
2069                               lb_sub_worker_t *swr,
2070                               jk_logger_t *l)
2071 {
2072     int cmd;
2073     int mime;
2074     int read_only = 0;
2075     int single = 0;
2076     unsigned int hide_members;
2077     unsigned int hide_lb_conf;
2078     unsigned int hide_lb_summary;
2079     unsigned int hide_ajp_conf;
2080     const char *arg;
2081     time_t now = time(NULL);
2082     unsigned int good = 0;
2083     unsigned int degraded = 0;
2084     unsigned int bad = 0;
2085     int map_count;
2086     int ms_min;
2087     int ms_max;
2088     unsigned int j;
2089     int pstart = JK_FALSE;
2090     const char *name = lb->name;
2091     status_worker_t *w = p->worker;
2092
2093     JK_TRACE_ENTER(l);
2094     status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l);
2095     cmd = status_cmd_int(arg);
2096     status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l);
2097     mime = status_mime_int(arg);
2098     hide_members = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
2099                                   JK_STATUS_ARG_OPTION_NO_MEMBERS;
2100     hide_lb_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
2101                                   JK_STATUS_ARG_OPTION_NO_LB_CONF;
2102     hide_lb_summary = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
2103                                      JK_STATUS_ARG_OPTION_NO_LB_SUMMARY;
2104     hide_ajp_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
2105                                    JK_STATUS_ARG_OPTION_NO_AJP_CONF;
2106     if (w->read_only) {
2107         read_only = 1;
2108     }
2109     else {
2110         read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
2111                     JK_STATUS_ARG_OPTION_READ_ONLY;
2112     }
2113     if (cmd == JK_STATUS_CMD_SHOW) {
2114         single = 1;
2115     }
2116
2117     if (lb->sequence != lb->s->h.sequence)
2118         jk_lb_pull(lb, JK_FALSE, l);
2119
2120     for (j = 0; j < lb->num_of_workers; j++) {
2121         lb_sub_worker_t *wr = &(lb->lb_workers[j]);
2122         int rate;
2123         rate = status_rate(wr, w, l);
2124         if (rate > 0 )
2125            good++;
2126         else if (rate < 0 )
2127            bad++;
2128         else
2129            degraded++;
2130     }
2131
2132     map_count = count_maps(s, name, l);
2133     ms_min = lb->maintain_time - (int)difftime(now, lb->s->last_maintain_time);
2134     ms_max = ms_min + lb->maintain_time;
2135     ms_min -= JK_LB_MAINTAIN_TOLERANCE;
2136     if (ms_min < 0) {
2137         ms_min = 0;
2138     }
2139     if (ms_max < 0) {
2140         ms_max = 0;
2141     }
2142
2143     if (mime == JK_STATUS_MIME_HTML) {
2144
2145         jk_puts(s, "<hr/><h3>[");
2146         if (single) {
2147             jk_puts(s, "S");
2148         }
2149         else {
2150             status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2151                              name, "", 0, 0, "", l);
2152         }
2153         if (!read_only) {
2154             jk_puts(s, "|");
2155             status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN,
2156                              name, "", 0, 0, "", l);
2157             jk_puts(s, "|");
2158             status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN,
2159                              name, "", 0, 0, "", l);
2160         }
2161         jk_puts(s, "]&nbsp;&nbsp;");
2162         jk_putv(s, "Worker Status for ", name, "</h3>\n", NULL);
2163         if (hide_lb_conf) {
2164             pstart = JK_TRUE;
2165             jk_puts(s, "<p>\n");
2166             if (single) {
2167                 status_write_uri(s, p, "Show LB Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2168                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_CONF, "", l);
2169             }
2170             else {
2171                 status_write_uri(s, p, "Show LB Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN,
2172                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_CONF, "", l);
2173             }
2174         }
2175         if (hide_lb_summary) {
2176             if (pstart == JK_FALSE)
2177                 jk_puts(s, "<p>\n");
2178             else
2179                 jk_puts(s, "&nbsp;&nbsp;|&nbsp;&nbsp;");
2180             pstart = JK_TRUE;
2181             if (single) {
2182                 status_write_uri(s, p, "Show LB Summary", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2183                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, "", l);
2184             }
2185             else {
2186                 status_write_uri(s, p, "Show LB Summary", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN,
2187                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, "", l);
2188             }
2189         }
2190         if (!hide_members && hide_ajp_conf) {
2191             if (pstart == JK_FALSE)
2192                 jk_puts(s, "<p>\n");
2193             else
2194                 jk_puts(s, "&nbsp;&nbsp;|&nbsp;&nbsp;");
2195             pstart = JK_TRUE;
2196             if (single) {
2197                 status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2198                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l);
2199             }
2200             else {
2201                 status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN,
2202                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l);
2203             }
2204         }
2205         if (hide_members) {
2206             if (pstart == JK_FALSE)
2207                 jk_puts(s, "<p>\n");
2208             else
2209                 jk_puts(s, "&nbsp;&nbsp;|&nbsp;&nbsp;");
2210             pstart = JK_TRUE;
2211             if (single) {
2212                 status_write_uri(s, p, "Show Balancer Members", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2213                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MEMBERS, "", l);
2214             }
2215             else {
2216                 status_write_uri(s, p, "Show Balancer Members", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN,
2217                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_MEMBERS, "", l);
2218             }
2219         }
2220         if (pstart == JK_TRUE)
2221             jk_puts(s, "</p>\n");
2222
2223         if (!hide_lb_conf) {
2224             jk_puts(s, "<table>" JK_STATUS_SHOW_LB_HEAD);
2225             jk_puts(s, "[");
2226             status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
2227                              NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB_CONF, 0, NULL, l);
2228             jk_puts(s, "]</th></tr>");
2229             jk_printf(s, JK_STATUS_SHOW_LB_ROW,
2230                       status_worker_type(JK_LB_WORKER_TYPE),
2231                       jk_get_bool(lb->sticky_session),
2232                       jk_get_bool(lb->sticky_session_force),
2233                       lb->retries,
2234                       jk_lb_get_method(lb, l),
2235                       jk_lb_get_lock(lb, l),
2236                       lb->recover_wait_time,
2237                       lb->error_escalation_time,
2238                       lb->max_reply_timeouts);
2239             jk_puts(s, "</table>\n<br/>\n");
2240         }
2241
2242         if (!hide_lb_summary) {
2243             jk_puts(s, "<table><tr>"
2244                     "<th>Good</th><th>Degraded</th><th>Bad/Stopped</th><th>Busy</th><th>Max Busy</th><th>Next Maintenance</th><th>Last Reset</th><th>[");
2245             status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
2246                              NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB_SUMMARY, 0, NULL, l);
2247             jk_puts(s, "]</th></tr>\n<tr>");
2248             jk_printf(s, "<td>%d</td>", good);
2249             jk_printf(s, "<td>%d</td>", degraded);
2250             jk_printf(s, "<td>%d</td>", bad);
2251             jk_printf(s, "<td>%d</td>", lb->s->busy);
2252             jk_printf(s, "<td>%d</td>", lb->s->max_busy);
2253             jk_printf(s, "<td>%d/%d</td>", ms_min, ms_max);
2254             jk_printf(s, "<td>%d</td>", (int)difftime(now, lb->s->last_reset));
2255             jk_puts(s, "<td></td></tr>\n</table>\n\n");
2256         }
2257     }
2258     else if (mime == JK_STATUS_MIME_XML) {
2259
2260         jk_print_xml_start_elt(s, w, 2, 0, "balancer");
2261         jk_print_xml_att_string(s, 4, "name", name);
2262         jk_print_xml_att_string(s, 4, "type", status_worker_type(JK_LB_WORKER_TYPE));
2263         jk_print_xml_att_string(s, 4, "sticky_session", jk_get_bool(lb->sticky_session));
2264         jk_print_xml_att_string(s, 4, "sticky_session_force", jk_get_bool(lb->sticky_session_force));
2265         jk_print_xml_att_int(s, 4, "retries", lb->retries);
2266         jk_print_xml_att_int(s, 4, "recover_time", lb->recover_wait_time);
2267         jk_print_xml_att_int(s, 4, "error_escalation_time", lb->error_escalation_time);
2268         jk_print_xml_att_int(s, 4, "max_reply_timeouts", lb->max_reply_timeouts);
2269         jk_print_xml_att_string(s, 4, "method", jk_lb_get_method(lb, l));
2270         jk_print_xml_att_string(s, 4, "lock", jk_lb_get_lock(lb, l));
2271         jk_print_xml_att_int(s, 4, "member_count", lb->num_of_workers);
2272         jk_print_xml_att_int(s, 4, "good", good);
2273         jk_print_xml_att_int(s, 4, "degraded", degraded);
2274         jk_print_xml_att_int(s, 4, "bad", bad);
2275         jk_print_xml_att_int(s, 4, "busy", lb->s->busy);
2276         jk_print_xml_att_int(s, 4, "max_busy", lb->s->max_busy);
2277         jk_print_xml_att_int(s, 4, "map_count", map_count);
2278         jk_print_xml_att_int(s, 4, "time_to_maintenance_min", ms_min);
2279         jk_print_xml_att_int(s, 4, "time_to_maintenance_max", ms_max);
2280         jk_print_xml_att_long(s, 4, "last_reset_at", (long)lb->s->last_reset);
2281         jk_print_xml_att_int(s, 4, "last_reset_ago", (int)difftime(now, lb->s->last_reset));
2282         jk_print_xml_stop_elt(s, 2, 0);
2283
2284     }
2285     else if (mime == JK_STATUS_MIME_TXT) {
2286
2287         jk_puts(s, "Balancer Worker:");
2288         jk_printf(s, " name=%s", name);
2289         jk_printf(s, " type=%s", status_worker_type(JK_LB_WORKER_TYPE));
2290         jk_printf(s, " sticky_session=%s", jk_get_bool(lb->sticky_session));
2291         jk_printf(s, " sticky_session_force=%s", jk_get_bool(lb->sticky_session_force));
2292         jk_printf(s, " retries=%d", lb->retries);
2293         jk_printf(s, " recover_time=%d", lb->recover_wait_time);
2294         jk_printf(s, " error_escalation_time=%d", lb->error_escalation_time);
2295         jk_printf(s, " max_reply_timeouts=%d", lb->max_reply_timeouts);
2296         jk_printf(s, " method=%s", jk_lb_get_method(lb, l));
2297         jk_printf(s, " lock=%s", jk_lb_get_lock(lb, l));
2298         jk_printf(s, " member_count=%d", lb->num_of_workers);
2299         jk_printf(s, " good=%d", good);
2300         jk_printf(s, " degraded=%d", degraded);
2301         jk_printf(s, " bad=%d", bad);
2302         jk_printf(s, " busy=%d", lb->s->busy);
2303         jk_printf(s, " max_busy=%d", lb->s->max_busy);
2304         jk_printf(s, " map_count=%d", map_count);
2305         jk_printf(s, " time_to_maintenance_min=%d", ms_min);
2306         jk_printf(s, " time_to_maintenance_max=%d", ms_max);
2307         jk_printf(s, " last_reset_at=%ld", (long)lb->s->last_reset);
2308         jk_printf(s, " last_reset_ago=%d", (int)difftime(now, lb->s->last_reset));
2309         jk_puts(s, "\n");
2310
2311     }
2312     else if (mime == JK_STATUS_MIME_PROP) {
2313
2314         jk_print_prop_att_string(s, w, NULL, "list", name);
2315         jk_print_prop_att_string(s, w, name, "type", status_worker_type(JK_LB_WORKER_TYPE));
2316         jk_print_prop_att_string(s, w, name, "sticky_session", jk_get_bool(lb->sticky_session));
2317         jk_print_prop_att_string(s, w, name, "sticky_session_force", jk_get_bool(lb->sticky_session_force));
2318         jk_print_prop_att_int(s, w, name, "retries", lb->retries);
2319         jk_print_prop_att_int(s, w, name, "recover_time", lb->recover_wait_time);
2320         jk_print_prop_att_int(s, w, name, "error_escalation_time", lb->error_escalation_time);
2321         jk_print_prop_att_int(s, w, name, "max_reply_timeouts", lb->max_reply_timeouts);
2322         jk_print_prop_att_string(s, w, name, "method", jk_lb_get_method(lb, l));
2323         jk_print_prop_att_string(s, w, name, "lock", jk_lb_get_lock(lb, l));
2324         jk_print_prop_att_int(s, w, name, "member_count", lb->num_of_workers);
2325         jk_print_prop_att_int(s, w, name, "good", good);
2326         jk_print_prop_att_int(s, w, name, "degraded", degraded);
2327         jk_print_prop_att_int(s, w, name, "bad", bad);
2328         jk_print_prop_att_int(s, w, name, "busy", lb->s->busy);
2329         jk_print_prop_att_int(s, w, name, "max_busy", lb->s->max_busy);
2330         jk_print_prop_att_int(s, w, name, "map_count", map_count);
2331         jk_print_prop_att_int(s, w, name, "time_to_maintenance_min", ms_min);
2332         jk_print_prop_att_int(s, w, name, "time_to_maintenance_max", ms_max);
2333         jk_print_prop_att_long(s, w, name, "last_reset_at", (long)lb->s->last_reset);
2334         jk_print_prop_att_int(s, w, name, "last_reset_ago", (int)difftime(now, lb->s->last_reset));
2335
2336     }
2337
2338     if (!hide_members) {
2339
2340         if (mime == JK_STATUS_MIME_HTML) {
2341
2342             jk_puts(s, "<h4>Balancer Members [");
2343             if (swr) {
2344                 status_write_uri(s, p, "Show All Members", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2345                                  name, "", 0, 0, "", l);
2346                 jk_puts(s, "]&nbsp;&nbsp;[");
2347             }
2348             if (single) {
2349                 status_write_uri(s, p, "Hide", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2350                                  NULL, NULL, JK_STATUS_ARG_OPTION_NO_MEMBERS, 0, "", l);
2351             }
2352             else {
2353                 status_write_uri(s, p, "Hide", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN,
2354                                  NULL, NULL, JK_STATUS_ARG_OPTION_NO_MEMBERS, 0, "", l);
2355             }
2356             jk_puts(s, "]</h4>\n");
2357             if (!hide_ajp_conf) {
2358                 jk_puts(s, "<table>" JK_STATUS_SHOW_MEMBER_CONF_HEAD);
2359                 jk_puts(s, "[");
2360                 status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
2361                                  NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP_CONF, 0, NULL, l);
2362                 jk_puts(s, "]</td></tr>");
2363                 if (swr) {
2364                     jk_worker_t *jw = (jk_worker_t *)swr->worker;
2365                     ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;
2366                     display_worker_ajp_conf_details(s, p, aw, 1, jw->type, l);
2367                 }
2368                 else
2369                     for (j = 0; j < lb->num_of_workers; j++) {
2370                         lb_sub_worker_t *wr = &(lb->lb_workers[j]);
2371                         jk_worker_t *jw = (jk_worker_t *)wr->worker;
2372                         ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;
2373                         display_worker_ajp_conf_details(s, p, aw, 1, jw->type, l);
2374                     }
2375                 jk_puts(s, "</table>\n<br/>\n");
2376             }
2377             jk_puts(s, "<table>" JK_STATUS_SHOW_MEMBER_HEAD);
2378
2379         }
2380
2381         if (swr) {
2382             const char *sub_name = swr->name;
2383             ajp_worker_t *aw = (ajp_worker_t *)swr->worker->worker_private;
2384
2385             if (mime == JK_STATUS_MIME_HTML) {
2386                 jk_puts(s, "<tr>\n<td>[");
2387                 jk_puts(s, "S");
2388                 if (!read_only) {
2389                     jk_puts(s, "|");
2390                     status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN,
2391                                      name, sub_name, 0, 0, "", l);
2392                     jk_puts(s, "|");
2393                     status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN,
2394                                      name, sub_name, 0, 0, "", l);
2395                     if (swr->s->state == JK_LB_STATE_ERROR) {
2396                         jk_puts(s, "|");
2397                         status_write_uri(s, p, "T", JK_STATUS_CMD_RECOVER, JK_STATUS_MIME_UNKNOWN,
2398                                          name, sub_name, 0, 0, "", l);
2399                     }
2400                 }
2401                 jk_puts(s, "]");
2402                 jk_puts(s, "&nbsp;</td>");
2403             }
2404             display_worker_ajp_details(s, p, aw, swr, lb, ms_min, ms_max, 0, l);
2405         } else
2406             for (j = 0; j < lb->num_of_workers; j++) {
2407                 lb_sub_worker_t *wr = &(lb->lb_workers[j]);
2408                 const char *sub_name = wr->name;
2409                 ajp_worker_t *aw = (ajp_worker_t *)wr->worker->worker_private;
2410
2411                 if (mime == JK_STATUS_MIME_HTML) {
2412                     jk_puts(s, "<tr>\n<td>[");
2413                     status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2414                                  name, sub_name, 0, 0, "", l);
2415                     if (!read_only) {
2416                         jk_puts(s, "|");
2417                         status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN,
2418                                          name, sub_name, 0, 0, "", l);
2419                         jk_puts(s, "|");
2420                         status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN,
2421                                          name, sub_name, 0, 0, "", l);
2422                         if (wr->s->state == JK_LB_STATE_ERROR) {
2423                             jk_puts(s, "|");
2424                             status_write_uri(s, p, "T", JK_STATUS_CMD_RECOVER, JK_STATUS_MIME_UNKNOWN,
2425                                              name, sub_name, 0, 0, "", l);
2426                         }
2427                     }
2428                     jk_puts(s, "]");
2429                     jk_puts(s, "&nbsp;</td>");
2430                 }
2431                 display_worker_ajp_details(s, p, aw, wr, lb, ms_min, ms_max, 0, l);
2432             }
2433
2434         if (mime == JK_STATUS_MIME_HTML) {
2435
2436             jk_puts(s, "</table><br/>\n");
2437             if (!read_only) {
2438                 const char *arg;
2439                 status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l);
2440                 status_start_form(s, p, "get", JK_STATUS_CMD_EDIT, NULL, l);
2441                 jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING, JK_STATUS_ARG_WORKER, name);
2442                 if (arg)
2443                     jk_printf(s, JK_STATUS_FORM_HIDDEN_STRING, JK_STATUS_ARG_FROM, arg);
2444                 jk_puts(s, "<table><tr><td><b>E</b>dit this attribute for all members:</td><td>");
2445                 jk_putv(s, "<select name=\"", JK_STATUS_ARG_ATTRIBUTE,
2446                         "\" size=\"1\">\n", NULL);
2447                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_ACTIVATION, "\">", JK_STATUS_ARG_LBM_TEXT_ACTIVATION, "</option>\n", NULL);
2448                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_FACTOR, "\">", JK_STATUS_ARG_LBM_TEXT_FACTOR, "</option>\n", NULL);
2449                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_ROUTE, "\">", JK_STATUS_ARG_LBM_TEXT_ROUTE, "</option>\n", NULL);
2450                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_REDIRECT, "\">", JK_STATUS_ARG_LBM_TEXT_REDIRECT, "</option>\n", NULL);
2451                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_DOMAIN, "\">", JK_STATUS_ARG_LBM_TEXT_DOMAIN, "</option>\n", NULL);
2452                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_LBM_DISTANCE, "\">", JK_STATUS_ARG_LBM_TEXT_DISTANCE, "</option>\n", NULL);
2453                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_CACHE_TO, "\">", JK_STATUS_ARG_AJP_TEXT_CACHE_TO, "</option>\n", NULL);
2454                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_PING_TO, "\">", JK_STATUS_ARG_AJP_TEXT_PING_TO, "</option>\n", NULL);
2455                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_CONNECT_TO, "\">", JK_STATUS_ARG_AJP_TEXT_CONNECT_TO, "</option>\n", NULL);
2456                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_PREPOST_TO, "\">", JK_STATUS_ARG_AJP_TEXT_PREPOST_TO, "</option>\n", NULL);
2457                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_REPLY_TO, "\">", JK_STATUS_ARG_AJP_TEXT_REPLY_TO, "</option>\n", NULL);
2458                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_RETRIES, "\">", JK_STATUS_ARG_AJP_TEXT_RETRIES, "</option>\n", NULL);
2459                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_RETRY_INT, "\">", JK_STATUS_ARG_AJP_TEXT_RETRY_INT, "</option>\n", NULL);
2460                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_CPING_INT, "\">", JK_STATUS_ARG_AJP_TEXT_CPING_INT, "</option>\n", NULL);
2461                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_REC_OPTS, "\">", JK_STATUS_ARG_AJP_TEXT_REC_OPTS, "</option>\n", NULL);
2462                 jk_putv(s, "<option value=\"", JK_STATUS_ARG_AJP_MAX_PK_SZ, "\">", JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ, "</option>\n", NULL);
2463                 jk_puts(s, "</select></td><td><input type=\"submit\" value=\"Go\"/></tr></table></form>\n");
2464             }
2465
2466         }
2467
2468     }
2469
2470     if (name)
2471         display_maps(s, p, name, l);
2472
2473     if (mime == JK_STATUS_MIME_XML) {
2474         jk_print_xml_close_elt(s, w, 2, "balancer");
2475     }
2476
2477     JK_TRACE_EXIT(l);
2478 }
2479
2480 static void display_worker_ajp(jk_ws_service_t *s,
2481                                status_endpoint_t *p,
2482                                ajp_worker_t *aw,
2483                                int type,
2484                                jk_logger_t *l)
2485 {
2486     int cmd;
2487     int mime;
2488     int read_only = 0;
2489     int single = 0;
2490     unsigned int hide_ajp_conf;
2491     const char *arg;
2492     int map_count;
2493     const char *name = aw->name;
2494     status_worker_t *w = p->worker;
2495
2496     JK_TRACE_ENTER(l);
2497     status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l);
2498     cmd = status_cmd_int(arg);
2499     status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l);
2500     mime = status_mime_int(arg);
2501     hide_ajp_conf = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
2502                                    JK_STATUS_ARG_OPTION_NO_AJP_CONF;
2503     if (w->read_only) {
2504         read_only = 1;
2505     }
2506     else {
2507         read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
2508                     JK_STATUS_ARG_OPTION_READ_ONLY;
2509     }
2510     if (cmd == JK_STATUS_CMD_SHOW) {
2511         single = 1;
2512     }
2513
2514     if (aw->sequence != aw->s->h.sequence)
2515         jk_ajp_pull(aw, JK_FALSE, l);
2516
2517     map_count = count_maps(s, name, l);
2518
2519     if (mime == JK_STATUS_MIME_HTML) {
2520
2521         jk_puts(s, "<hr/><h3>[");
2522         if (single)
2523             jk_puts(s, "S");
2524         else
2525             status_write_uri(s, p, "S", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2526                              name, "", 0, 0, "", l);
2527         if (!read_only) {
2528             jk_puts(s, "|");
2529             status_write_uri(s, p, "E", JK_STATUS_CMD_EDIT, JK_STATUS_MIME_UNKNOWN,
2530                              name, "", 0, 0, "", l);
2531             jk_puts(s, "|");
2532             status_write_uri(s, p, "R", JK_STATUS_CMD_RESET, JK_STATUS_MIME_UNKNOWN,
2533                              name, "", 0, 0, "", l);
2534         }
2535         jk_puts(s, "]&nbsp;&nbsp;");
2536         jk_putv(s, "Worker Status for ", name, "</h3>\n", NULL);
2537         if (!hide_ajp_conf) {
2538             jk_puts(s, "<table>" JK_STATUS_SHOW_AJP_CONF_HEAD);
2539             jk_puts(s, "[");
2540             status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
2541                              NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP_CONF, 0, NULL, l);
2542             jk_puts(s, "]</td></tr>");
2543             display_worker_ajp_conf_details(s, p, aw, 0, type, l);
2544             jk_puts(s, "</table>\n<br/>\n");
2545         }
2546         else {
2547             jk_puts(s, "<p>\n");
2548             if (single) {
2549                 status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
2550                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l);
2551             }
2552             else {
2553                 status_write_uri(s, p, "Show AJP Configuration", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN,
2554                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP_CONF, "", l);
2555             }
2556             jk_puts(s, "</p>\n");
2557         }
2558         jk_puts(s, "<table>" JK_STATUS_SHOW_AJP_HEAD);
2559     }
2560     display_worker_ajp_details(s, p, aw, NULL, NULL, 0, 0, map_count, l);
2561
2562     if (mime == JK_STATUS_MIME_HTML) {
2563         jk_puts(s, "</table>\n");
2564     }
2565     if (name)
2566         display_maps(s, p, name, l);
2567
2568     JK_TRACE_EXIT(l);
2569 }
2570
2571 static void display_worker(jk_ws_service_t *s,
2572                            status_endpoint_t *p,
2573                            jk_worker_t *jw,
2574                            lb_sub_worker_t *swr,
2575                            jk_logger_t *l)
2576 {
2577     status_worker_t *w = p->worker;
2578
2579     JK_TRACE_ENTER(l);
2580     if (jw->type == JK_LB_WORKER_TYPE) {
2581         lb_worker_t *lb = (lb_worker_t *)jw->worker_private;
2582         if (lb) {
2583             if (JK_IS_DEBUG_LEVEL(l))
2584                 jk_log(l, JK_LOG_DEBUG,
2585                        "Status worker '%s' %s lb worker '%s'",
2586                        w->name, "displaying", lb->name);
2587             display_worker_lb(s, p, lb, swr, l);
2588         }
2589         else {
2590             jk_log(l, JK_LOG_WARNING,
2591                    "Status worker '%s' lb worker is (null)",
2592                    w->name);
2593         }
2594     }
2595     else if (jw->type == JK_AJP13_WORKER_TYPE ||
2596              jw->type == JK_AJP14_WORKER_TYPE) {
2597         ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;
2598         if (aw) {
2599             if (JK_IS_DEBUG_LEVEL(l))
2600                 jk_log(l, JK_LOG_DEBUG,
2601                        "Status worker '%s' %s ajp worker '%s'",
2602                        w->name, "displaying", aw->name);
2603             display_worker_ajp(s, p, aw, jw->type, l);
2604         }
2605         else {
2606             jk_log(l, JK_LOG_WARNING,
2607                    "Status worker '%s' aw worker is (null)",
2608                    w->name);
2609         }
2610     }
2611     else {
2612         if (JK_IS_DEBUG_LEVEL(l))
2613             jk_log(l, JK_LOG_DEBUG,
2614                    "Status worker '%s' worker type not implemented",
2615                    w->name);
2616         JK_TRACE_EXIT(l);
2617         return;
2618     }
2619 }
2620
2621 static void form_worker(jk_ws_service_t *s,
2622                         status_endpoint_t *p,
2623                         jk_worker_t *jw,
2624                         jk_logger_t *l)
2625 {
2626     const char *name = NULL;
2627     lb_worker_t *lb = NULL;
2628     status_worker_t *w = p->worker;
2629
2630     JK_TRACE_ENTER(l);
2631     if (jw->type == JK_LB_WORKER_TYPE) {
2632         lb = (lb_worker_t *)jw->worker_private;
2633         name = lb->name;
2634         if (JK_IS_DEBUG_LEVEL(l))
2635             jk_log(l, JK_LOG_DEBUG,
2636                    "Status worker '%s' producing edit form for lb worker '%s'",
2637                    w->name, name);
2638     }
2639     else {
2640         jk_log(l, JK_LOG_WARNING,
2641                "Status worker '%s' worker type not implemented",
2642                w->name);
2643         JK_TRACE_EXIT(l);
2644         return;
2645     }
2646
2647     if (!lb) {
2648         jk_log(l, JK_LOG_WARNING,
2649                "Status worker '%s' lb structure is (null)",
2650                w->name);
2651         JK_TRACE_EXIT(l);
2652         return;
2653     }
2654
2655     jk_putv(s, "<hr/><h3>Edit load balancer settings for ",
2656             name, "</h3>\n", NULL);
2657
2658     status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l);
2659
2660     jk_putv(s, "<table>\n<tr><td>", JK_STATUS_ARG_LB_TEXT_RETRIES,
2661             ":</td><td><input name=\"",
2662             JK_STATUS_ARG_LB_RETRIES, "\" type=\"text\" ", NULL);
2663     jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->retries);
2664     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_RETRY_INT,
2665             ":</td><td><input name=\"",
2666             JK_STATUS_ARG_LB_RETRY_INT, "\" type=\"text\" ", NULL);
2667     jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->retry_interval);
2668     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_RECOVER_TIME,
2669             ":</td><td><input name=\"",
2670             JK_STATUS_ARG_LB_RECOVER_TIME, "\" type=\"text\" ", NULL);
2671     jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->recover_wait_time);
2672     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_ERROR_ESCALATION_TIME,
2673             ":</td><td><input name=\"",
2674             JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME, "\" type=\"text\" ", NULL);
2675     jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->error_escalation_time);
2676     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_MAX_REPLY_TIMEOUTS,
2677             ":</td><td><input name=\"",
2678             JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS, "\" type=\"text\" ", NULL);
2679     jk_printf(s, "value=\"%d\"/></td></tr>\n", lb->max_reply_timeouts);
2680     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_STICKY,
2681             ":</td><td><input name=\"",
2682             JK_STATUS_ARG_LB_STICKY, "\" type=\"checkbox\"", NULL);
2683     if (lb->sticky_session)
2684         jk_puts(s, " checked=\"checked\"");
2685     jk_puts(s, "/></td></tr>\n");
2686     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_STICKY_FORCE,
2687             ":</td><td><input name=\"",
2688             JK_STATUS_ARG_LB_STICKY_FORCE, "\" type=\"checkbox\"", NULL);
2689     if (lb->sticky_session_force)
2690         jk_puts(s, " checked=\"checked\"");
2691     jk_puts(s, "/></td></tr>\n");
2692     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_METHOD,
2693             ":</td><td></td></tr>\n", NULL);
2694     jk_putv(s, "<tr><td>&nbsp;&nbsp;Requests</td><td><input name=\"",
2695             JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL);
2696     jk_printf(s, " value=\"%d\"", JK_LB_METHOD_REQUESTS);
2697     if (lb->lbmethod == JK_LB_METHOD_REQUESTS)
2698         jk_puts(s, " checked=\"checked\"");
2699     jk_puts(s, "/></td></tr>\n");
2700     jk_putv(s, "<tr><td>&nbsp;&nbsp;Traffic</td><td><input name=\"",
2701             JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL);
2702     jk_printf(s, " value=\"%d\"", JK_LB_METHOD_TRAFFIC);
2703     if (lb->lbmethod == JK_LB_METHOD_TRAFFIC)
2704         jk_puts(s, " checked=\"checked\"");
2705     jk_puts(s, "/></td></tr>\n");
2706     jk_putv(s, "<tr><td>&nbsp;&nbsp;Busyness</td><td><input name=\"",
2707             JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL);
2708     jk_printf(s, " value=\"%d\"", JK_LB_METHOD_BUSYNESS);
2709     if (lb->lbmethod == JK_LB_METHOD_BUSYNESS)
2710         jk_puts(s, " checked=\"checked\"");
2711     jk_puts(s, "/></td></tr>\n");
2712     jk_putv(s, "<tr><td>&nbsp;&nbsp;Sessions</td><td><input name=\"",
2713             JK_STATUS_ARG_LB_METHOD, "\" type=\"radio\"", NULL);
2714     jk_printf(s, " value=\"%d\"", JK_LB_METHOD_SESSIONS);
2715     if (lb->lbmethod == JK_LB_METHOD_SESSIONS)
2716         jk_puts(s, " checked=\"checked\"");
2717     jk_puts(s, "/></td></tr>\n");
2718     jk_putv(s, "<tr><td>", JK_STATUS_ARG_LB_TEXT_LOCK,
2719             ":</td><td></td></tr>\n", NULL);
2720     jk_putv(s, "<tr><td>&nbsp;&nbsp;Optimistic</td><td><input name=\"",
2721             JK_STATUS_ARG_LB_LOCK, "\" type=\"radio\"", NULL);
2722     jk_printf(s, " value=\"%d\"", JK_LB_LOCK_OPTIMISTIC);
2723     if (lb->lblock == JK_LB_LOCK_OPTIMISTIC)
2724         jk_puts(s, " checked=\"checked\"");
2725     jk_puts(s, "/></td></tr>\n");
2726     jk_putv(s, "<tr><td>&nbsp;&nbsp;Pessimistic</td><td><input name=\"",
2727             JK_STATUS_ARG_LB_LOCK, "\" type=\"radio\"", NULL);
2728     jk_printf(s, " value=\"%d\"", JK_LB_LOCK_PESSIMISTIC);
2729     if (lb->lblock == JK_LB_LOCK_PESSIMISTIC)
2730         jk_puts(s, " checked=\"checked\"");
2731     jk_puts(s, "/></td></tr>\n");
2732     jk_puts(s, "</table>\n");
2733     jk_puts(s, "<br/><input type=\"submit\" value=\"Update Balancer\"/></form>\n");
2734
2735     JK_TRACE_EXIT(l);
2736 }
2737
2738 static void form_member(jk_ws_service_t *s,
2739                         status_endpoint_t *p,
2740                         lb_sub_worker_t *wr,
2741                         ajp_worker_t *aw,
2742                         const char *lb_name,
2743                         jk_logger_t *l)
2744 {
2745     status_worker_t *w = p->worker;
2746
2747     JK_TRACE_ENTER(l);
2748
2749     if (JK_IS_DEBUG_LEVEL(l))
2750         jk_log(l, JK_LOG_DEBUG,
2751                "Status worker '%s' producing edit form for sub worker '%s' of lb worker '%s'",
2752                w->name, wr? wr->name : aw->name, lb_name);
2753
2754     jk_putv(s, "<hr/><h3>Edit worker settings for ",
2755             wr? wr->name : aw->name, "</h3>\n", NULL);
2756     status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l);
2757
2758     if (wr) {
2759         jk_puts(s, "<table><tbody valign=\"baseline\"><tr><th>Balancing related settings</th>\n");
2760         jk_puts(s, "<th>&nbsp;&nbsp;</th><th>AJP settings</th>\n");
2761         jk_puts(s, "</tr>\n");
2762         jk_puts(s, "<tr><td><table>\n");
2763         jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_ACTIVATION,
2764                 ":</td><td></td></tr>\n", NULL);
2765         jk_putv(s, "<tr><td>&nbsp;&nbsp;Active</td><td><input name=\"",
2766                 JK_STATUS_ARG_LBM_ACTIVATION, "\" type=\"radio\"", NULL);
2767         jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_ACTIVE);
2768         if (wr->activation == JK_LB_ACTIVATION_ACTIVE)
2769             jk_puts(s, " checked=\"checked\"");
2770         jk_puts(s, "/></td></tr>\n");
2771         jk_putv(s, "<tr><td>&nbsp;&nbsp;Disabled</td><td><input name=\"",
2772                 JK_STATUS_ARG_LBM_ACTIVATION, "\" type=\"radio\"", NULL);
2773         jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_DISABLED);
2774         if (wr->activation == JK_LB_ACTIVATION_DISABLED)
2775             jk_puts(s, " checked=\"checked\"");
2776         jk_puts(s, "/></td></tr>\n");
2777         jk_putv(s, "<tr><td>&nbsp;&nbsp;Stopped</td><td><input name=\"",
2778                 JK_STATUS_ARG_LBM_ACTIVATION, "\" type=\"radio\"", NULL);
2779         jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_STOPPED);
2780         if (wr->activation == JK_LB_ACTIVATION_STOPPED)
2781             jk_puts(s, " checked=\"checked\"");
2782         jk_puts(s, "/></td></tr>\n");
2783         jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_FACTOR,
2784                 ":</td><td><input name=\"",
2785                 JK_STATUS_ARG_LBM_FACTOR, "\" type=\"text\" ", NULL);
2786         jk_printf(s, "value=\"%d\"/></td></tr>\n", wr->lb_factor);
2787         jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_ROUTE,
2788                 ":</td><td><input name=\"",
2789                 JK_STATUS_ARG_LBM_ROUTE, "\" type=\"text\" ", NULL);
2790         jk_printf(s, "value=\"%s\"/></td></tr>\n", wr->route);
2791         jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_REDIRECT,
2792                 ":</td><td><input name=\"",
2793                 JK_STATUS_ARG_LBM_REDIRECT, "\" type=\"text\" ", NULL);
2794         jk_putv(s, "value=\"", wr->redirect, NULL);
2795         jk_puts(s, "\"/></td></tr>\n");
2796         jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_DOMAIN,
2797                 ":</td><td><input name=\"",
2798                 JK_STATUS_ARG_LBM_DOMAIN, "\" type=\"text\" ", NULL);
2799         jk_putv(s, "value=\"", wr->domain, NULL);
2800         jk_puts(s, "\"/></td></tr>\n");
2801         jk_putv(s, "<tr><td>", JK_STATUS_ARG_LBM_TEXT_DISTANCE,
2802                 ":</td><td><input name=\"",
2803                 JK_STATUS_ARG_LBM_DISTANCE, "\" type=\"text\" ", NULL);
2804         jk_printf(s, "value=\"%d\"/></td></tr>\n", wr->distance);
2805         jk_puts(s, "</table>\n");
2806         jk_puts(s, "</td><td></td><td>\n");
2807     }
2808
2809     jk_puts(s, "<table>\n");
2810     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_HOST_STR,
2811             ":</td><td><input name=\"",
2812             JK_STATUS_ARG_AJP_HOST_STR, "\" type=\"text\" ", NULL);
2813     jk_printf(s, "value=\"%s\"/></td></tr>\n", aw->host);
2814     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_PORT,
2815             ":</td><td><input name=\"",
2816             JK_STATUS_ARG_AJP_PORT, "\" type=\"text\" ", NULL);
2817     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->port);
2818
2819     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_CACHE_TO,
2820             ":</td><td><input name=\"",
2821             JK_STATUS_ARG_AJP_CACHE_TO, "\" type=\"text\" ", NULL);
2822     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->cache_timeout);
2823     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_PING_TO,
2824             ":</td><td><input name=\"",
2825             JK_STATUS_ARG_AJP_PING_TO, "\" type=\"text\" ", NULL);
2826     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->ping_timeout);
2827     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_CONNECT_TO,
2828             ":</td><td><input name=\"",
2829             JK_STATUS_ARG_AJP_CONNECT_TO, "\" type=\"text\" ", NULL);
2830     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->connect_timeout);
2831     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_PREPOST_TO,
2832             ":</td><td><input name=\"",
2833             JK_STATUS_ARG_AJP_PREPOST_TO, "\" type=\"text\" ", NULL);
2834     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->prepost_timeout);
2835     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_REPLY_TO,
2836             ":</td><td><input name=\"",
2837             JK_STATUS_ARG_AJP_REPLY_TO, "\" type=\"text\" ", NULL);
2838     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->reply_timeout);
2839     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_RETRIES,
2840             ":</td><td><input name=\"",
2841             JK_STATUS_ARG_AJP_RETRIES, "\" type=\"text\" ", NULL);
2842     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->retries);
2843     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_RETRY_INT,
2844             ":</td><td><input name=\"",
2845             JK_STATUS_ARG_AJP_RETRY_INT, "\" type=\"text\" ", NULL);
2846     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->retry_interval);
2847     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_CPING_INT,
2848             ":</td><td><input name=\"",
2849             JK_STATUS_ARG_AJP_CPING_INT, "\" type=\"text\" ", NULL);
2850     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->conn_ping_interval);
2851     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_REC_OPTS,
2852             ":</td><td><input name=\"",
2853             JK_STATUS_ARG_AJP_REC_OPTS, "\" type=\"text\" ", NULL);
2854     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->recovery_opts);
2855     jk_putv(s, "<tr><td>", JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ,
2856             ":</td><td><input name=\"",
2857             JK_STATUS_ARG_AJP_MAX_PK_SZ, "\" type=\"text\" ", NULL);
2858     jk_printf(s, "value=\"%d\"/></td></tr>\n", aw->max_packet_size);
2859     jk_puts(s, "</table>\n");
2860     if (wr)
2861         jk_puts(s, "</td></tr></table>\n");
2862     jk_puts(s, "<br/><input type=\"submit\" value=\"Update Worker\"/>\n</form>\n");
2863     JK_TRACE_EXIT(l);
2864 }
2865
2866 static void form_all_members(jk_ws_service_t *s,
2867                              status_endpoint_t *p,
2868                              jk_worker_t *jw,
2869                              const char *attribute,
2870                              jk_logger_t *l)
2871 {
2872     const char *name = NULL;
2873     lb_worker_t *lb = NULL;
2874     status_worker_t *w = p->worker;
2875     const char *aname;
2876     unsigned int i;
2877
2878     JK_TRACE_ENTER(l);
2879     if (!attribute) {
2880         jk_log(l, JK_LOG_WARNING,
2881                "Status worker '%s' missing request parameter '%s'",
2882                w->name, JK_STATUS_ARG_ATTRIBUTE);
2883         JK_TRACE_EXIT(l);
2884         return;
2885     }
2886     else {
2887         if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION))
2888             aname=JK_STATUS_ARG_LBM_TEXT_ACTIVATION;
2889         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR))
2890             aname=JK_STATUS_ARG_LBM_TEXT_FACTOR;
2891         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE))
2892             aname=JK_STATUS_ARG_LBM_TEXT_ROUTE;
2893         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT))
2894             aname=JK_STATUS_ARG_LBM_TEXT_REDIRECT;
2895         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN))
2896             aname=JK_STATUS_ARG_LBM_TEXT_DOMAIN;
2897         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE))
2898             aname=JK_STATUS_ARG_LBM_TEXT_DISTANCE;
2899         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO))
2900             aname=JK_STATUS_ARG_AJP_TEXT_CACHE_TO;
2901         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO))
2902             aname=JK_STATUS_ARG_AJP_TEXT_PING_TO;
2903         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO))
2904             aname=JK_STATUS_ARG_AJP_TEXT_CONNECT_TO;
2905         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO))
2906             aname=JK_STATUS_ARG_AJP_TEXT_PREPOST_TO;
2907         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO))
2908             aname=JK_STATUS_ARG_AJP_TEXT_REPLY_TO;
2909         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES))
2910             aname=JK_STATUS_ARG_AJP_TEXT_RETRIES;
2911         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT))
2912             aname=JK_STATUS_ARG_AJP_TEXT_RETRY_INT;
2913         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT))
2914             aname=JK_STATUS_ARG_AJP_TEXT_CPING_INT;
2915         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS))
2916             aname=JK_STATUS_ARG_AJP_TEXT_REC_OPTS;
2917         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ))
2918             aname=JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ;
2919         else {
2920             jk_log(l, JK_LOG_WARNING,
2921                    "Status worker '%s' unknown attribute '%s'",
2922                    w->name, attribute);
2923             JK_TRACE_EXIT(l);
2924             return;
2925         }
2926     }
2927     if (jw->type == JK_LB_WORKER_TYPE) {
2928         lb = (lb_worker_t *)jw->worker_private;
2929         name = lb->name;
2930         if (JK_IS_DEBUG_LEVEL(l))
2931             jk_log(l, JK_LOG_DEBUG,
2932                    "Status worker '%s' producing edit form for attribute '%s' [%s] of all members of lb worker '%s'",
2933                    w->name, attribute, aname, name);
2934     }
2935     else {
2936         jk_log(l, JK_LOG_WARNING,
2937                "Status worker '%s' worker type not implemented",
2938                w->name);
2939         JK_TRACE_EXIT(l);
2940         return;
2941     }
2942
2943     if (lb) {
2944         jk_putv(s, "<hr/><h3>Edit attribute '", aname,
2945                 "' for all members of load balancer ",
2946                 name, "</h3>\n", NULL);
2947
2948         status_start_form(s, p, "get", JK_STATUS_CMD_UPDATE, NULL, l);
2949
2950         jk_putv(s, "<table><tr>"
2951                 "<th>Balanced Worker</th><th>", aname, "</th>"
2952                 "</tr>", NULL);
2953
2954         for (i = 0; i < lb->num_of_workers; i++) {
2955             lb_sub_worker_t *wr = &(lb->lb_workers[i]);
2956             jk_worker_t *jw = wr->worker;
2957             ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;;
2958
2959             jk_putv(s, "<tr><td>", wr->name, "</td><td>\n", NULL);
2960
2961             if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) {
2962
2963                 jk_printf(s, "Active:&nbsp;<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"radio\"", i);
2964                 jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_ACTIVE);
2965                 if (wr->activation == JK_LB_ACTIVATION_ACTIVE)
2966                     jk_puts(s, " checked=\"checked\"");
2967                 jk_puts(s, "/>&nbsp;|&nbsp;\n");
2968                 jk_printf(s, "Disabled:&nbsp;<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"radio\"", i);
2969                 jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_DISABLED);
2970                 if (wr->activation == JK_LB_ACTIVATION_DISABLED)
2971                     jk_puts(s, " checked=\"checked\"");
2972                 jk_puts(s, "/>&nbsp;|&nbsp;\n");
2973                 jk_printf(s, "Stopped:&nbsp;<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"radio\"", i);
2974                 jk_printf(s, " value=\"%d\"", JK_LB_ACTIVATION_STOPPED);
2975                 if (wr->activation == JK_LB_ACTIVATION_STOPPED)
2976                     jk_puts(s, " checked=\"checked\"");
2977                 jk_puts(s, "/>\n");
2978
2979             }
2980             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) {
2981                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
2982                 jk_printf(s, "value=\"%d\"/>\n", wr->lb_factor);
2983             }
2984             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) {
2985                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
2986                 jk_putv(s, "value=\"", wr->route, "\"/>\n", NULL);
2987             }
2988             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) {
2989                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
2990                 jk_putv(s, "value=\"", wr->redirect, "\"/>\n", NULL);
2991             }
2992             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) {
2993                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
2994                 jk_putv(s, "value=\"", wr->domain, "\"/>\n", NULL);
2995             }
2996             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) {
2997                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
2998                 jk_printf(s, "value=\"%d\"/>\n", wr->distance);
2999             }
3000             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) {
3001                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3002                 jk_printf(s, "value=\"%d\"/>\n", aw->cache_timeout);
3003             }
3004             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) {
3005                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3006                 jk_printf(s, "value=\"%d\"/>\n", aw->ping_timeout);
3007             }
3008             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) {
3009                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3010                 jk_printf(s, "value=\"%d\"/>\n", aw->connect_timeout);
3011             }
3012             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) {
3013                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3014                 jk_printf(s, "value=\"%d\"/>\n", aw->prepost_timeout);
3015             }
3016             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) {
3017                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3018                 jk_printf(s, "value=\"%d\"/>\n", aw->reply_timeout);
3019             }
3020             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) {
3021                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3022                 jk_printf(s, "value=\"%d\"/>\n", aw->retries);
3023             }
3024             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) {
3025                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3026                 jk_printf(s, "value=\"%d\"/>\n", aw->retry_interval);
3027             }
3028             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) {
3029                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3030                 jk_printf(s, "value=\"%d\"/>\n", aw->conn_ping_interval);
3031             }
3032             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) {
3033                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3034                 jk_printf(s, "value=\"%d\"/>\n", aw->recovery_opts);
3035             }
3036             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) {
3037                 jk_printf(s, "<input name=\"" JK_STATUS_ARG_MULT_VALUE_BASE "%d\" type=\"text\"", i);
3038                 jk_printf(s, "value=\"%d\"/>\n", aw->max_packet_size);
3039             }
3040
3041             jk_puts(s, "</td></tr>");
3042         }
3043
3044         jk_puts(s, "</table>\n");
3045         jk_puts(s, "<br/><input type=\"submit\" value=\"Update Balancer\"/></form>\n");
3046     }
3047     JK_TRACE_EXIT(l);
3048 }
3049
3050 static void commit_worker(jk_ws_service_t *s,
3051                           status_endpoint_t *p,
3052                           jk_worker_t *jw,
3053                           jk_logger_t *l)
3054 {
3055     const char *name = NULL;
3056     lb_worker_t *lb = NULL;
3057     status_worker_t *w = p->worker;
3058     const char *arg;
3059     int sync_needed = JK_FALSE;
3060     int i;
3061
3062     JK_TRACE_ENTER(l);
3063     if (jw->type == JK_LB_WORKER_TYPE) {
3064         lb = (lb_worker_t *)jw->worker_private;
3065         name = lb->name;
3066         if (JK_IS_DEBUG_LEVEL(l))
3067             jk_log(l, JK_LOG_DEBUG,
3068                    "Status worker '%s' committing changes for lb worker '%s'",
3069                    w->name, name);
3070     }
3071     else {
3072         jk_log(l, JK_LOG_WARNING,
3073                "Status worker '%s' worker type not implemented",
3074                w->name);
3075         JK_TRACE_EXIT(l);
3076         return;
3077     }
3078
3079     if (!lb) {
3080         jk_log(l, JK_LOG_WARNING,
3081                "Status worker '%s' lb structure is (null)",
3082                w->name);
3083         JK_TRACE_EXIT(l);
3084         return;
3085     }
3086
3087     i = status_get_int(p, JK_STATUS_ARG_LB_RETRIES,
3088                        lb->retries, l);
3089     if (i != lb->retries && i > 0) {
3090         jk_log(l, JK_LOG_INFO,
3091                "Status worker '%s' setting 'retries' for lb worker '%s' to '%i'",
3092                w->name, name, i);
3093         lb->retries = i;
3094         sync_needed = JK_TRUE;
3095     }
3096     i = status_get_int(p, JK_STATUS_ARG_LB_RETRY_INT,
3097                        lb->retry_interval, l);
3098     if (i != lb->retry_interval && i > 0) {
3099         jk_log(l, JK_LOG_INFO,
3100                "Status worker '%s' setting 'retry_interval' for lb worker '%s' to '%i'",
3101                w->name, name, i);
3102         lb->retry_interval = i;
3103         sync_needed = JK_TRUE;
3104     }
3105     i = status_get_int(p, JK_STATUS_ARG_LB_RECOVER_TIME,
3106                        lb->recover_wait_time, l);
3107     if (i != lb->recover_wait_time && i > 0) {
3108         jk_log(l, JK_LOG_INFO,
3109                "Status worker '%s' setting 'recover_time' for lb worker '%s' to '%i'",
3110                w->name, name, i);
3111         lb->recover_wait_time = i;
3112         sync_needed = JK_TRUE;
3113     }
3114     i = status_get_int(p, JK_STATUS_ARG_LB_ERROR_ESCALATION_TIME,
3115                        lb->error_escalation_time, l);
3116     if (i != lb->error_escalation_time && i > 0) {
3117         jk_log(l, JK_LOG_INFO,
3118                "Status worker '%s' setting 'error_escalation_time' for lb worker '%s' to '%i'",
3119                w->name, name, i);
3120         lb->error_escalation_time = i;
3121         sync_needed = JK_TRUE;
3122     }
3123     i = status_get_int(p, JK_STATUS_ARG_LB_MAX_REPLY_TIMEOUTS,
3124                        lb->max_reply_timeouts, l);
3125     if (i != lb->max_reply_timeouts && i >= 0) {
3126         jk_log(l, JK_LOG_INFO,
3127                "Status worker '%s' setting 'max_reply_timeouts' for lb worker '%s' to '%i'",
3128                w->name, name, i);
3129         lb->max_reply_timeouts = i;
3130         sync_needed = JK_TRUE;
3131     }
3132     i = status_get_bool(p, JK_STATUS_ARG_LB_STICKY, lb->sticky_session, l);
3133     if (i != lb->sticky_session) {
3134         jk_log(l, JK_LOG_INFO,
3135                "Status worker '%s' setting 'sticky_session' for lb worker '%s' to '%i'",
3136                w->name, name, i);
3137         lb->sticky_session = i;
3138         sync_needed = JK_TRUE;
3139     }
3140     i = status_get_bool(p, JK_STATUS_ARG_LB_STICKY_FORCE, lb->sticky_session_force, l);
3141     if (i != lb->sticky_session_force) {
3142         jk_log(l, JK_LOG_INFO,
3143                "Status worker '%s' setting 'sticky_session_force' for lb worker '%s' to '%i'",
3144                w->name, name, i);
3145         lb->sticky_session_force = i;
3146         sync_needed = JK_TRUE;
3147     }
3148     if (status_get_string(p, JK_STATUS_ARG_LB_METHOD, NULL, &arg, l) == JK_TRUE) {
3149         i = jk_lb_get_method_code(arg);
3150         if (i != lb->lbmethod && i >= 0 && i <= JK_LB_METHOD_MAX) {
3151             jk_log(l, JK_LOG_INFO,
3152                    "Status worker '%s' setting 'method' for lb worker '%s' to '%s'",
3153                    w->name, name, jk_lb_get_method(lb, l));
3154             lb->lbmethod = i;
3155             sync_needed = JK_TRUE;
3156         }
3157     }
3158     if (status_get_string(p, JK_STATUS_ARG_LB_LOCK, NULL, &arg, l) == JK_TRUE) {
3159         i = jk_lb_get_lock_code(arg);
3160         if (i != lb->lblock && i >= 0 && i <= JK_LB_LOCK_MAX) {
3161             jk_log(l, JK_LOG_INFO,
3162                    "Status worker '%s' setting 'lock' for lb worker '%s' to '%s'",
3163                    w->name, name, jk_lb_get_lock(lb, l));
3164             lb->lblock = i;
3165             sync_needed = JK_TRUE;
3166         }
3167     }
3168     if (sync_needed == JK_TRUE) {
3169         lb->sequence++;
3170         jk_lb_push(lb, JK_TRUE, l);
3171     }
3172 }
3173
3174 static int set_int_if_changed(status_endpoint_t *p,
3175                               const char *name,
3176                               const char *att,
3177                               const char *arg,
3178                               int min,
3179                               int max,
3180                               int *param,
3181                               const char *lb_name,
3182                               jk_logger_t *l)
3183 {
3184     int i;
3185     status_worker_t *w = p->worker;
3186     i = status_get_int(p, arg, *param, l);
3187     if (i != *param && i >= min && i <= max) {
3188         if (lb_name)
3189             jk_log(l, JK_LOG_INFO,
3190                    "Status worker '%s' setting '%s' for sub worker '%s' of lb worker '%s' to '%i'",
3191                    w->name, att, name, lb_name, i);
3192         else
3193             jk_log(l, JK_LOG_INFO,
3194                    "Status worker '%s' setting '%s' for ajp worker '%s' to '%i'",
3195                    w->name, att, name, i);
3196         *param = i;
3197         return JK_TRUE;
3198     }
3199     return JK_FALSE;
3200 }
3201
3202 static int set_uint_if_changed(status_endpoint_t *p,
3203                                const char *name,
3204                                const char *att,
3205                                const char *arg,
3206                                unsigned int min,
3207                                unsigned int max,
3208                                unsigned int *param,
3209                                const char *lb_name,
3210                               jk_logger_t *l)
3211 {
3212     unsigned i;
3213     status_worker_t *w = p->worker;
3214     i = (unsigned)status_get_int(p, arg, *param, l);
3215     if (i != *param && i >= min && i <= max) {
3216         if (lb_name)
3217             jk_log(l, JK_LOG_INFO,
3218                    "Status worker '%s' setting '%s' for sub worker '%s' of lb worker '%s' to '%u'",
3219                    w->name, att, name, lb_name, i);
3220         else
3221             jk_log(l, JK_LOG_INFO,
3222                    "Status worker '%s' setting '%s' for ajp worker '%s' to '%u'",
3223                    w->name, att, name, i);
3224         *param = i;
3225         return JK_TRUE;
3226     }
3227     return JK_FALSE;
3228 }
3229
3230 static int commit_member(jk_ws_service_t *s,
3231                          status_endpoint_t *p,
3232                          lb_worker_t *lb,
3233                          lb_sub_worker_t *wr,
3234                          ajp_worker_t *aw,
3235                          int *side_effect,
3236                          jk_logger_t *l)
3237 {
3238     const char *arg;
3239     const char *lb_name = NULL;
3240     status_worker_t *w = p->worker;
3241     int rc = JK_TRUE;
3242     int rv;
3243     int i;
3244     int old;
3245     int resolve = JK_FALSE;
3246     char host[JK_SHM_STR_SIZ+1];
3247     int  port = 0;
3248
3249     JK_TRACE_ENTER(l);
3250     if (lb) {
3251         lb_name = lb->name;
3252         if (JK_IS_DEBUG_LEVEL(l))
3253             jk_log(l, JK_LOG_DEBUG,
3254                    "Status worker '%s' committing changes for sub worker '%s' of lb worker '%s'",
3255                    w->name, wr->name, lb_name);
3256     }
3257     else {
3258         if (JK_IS_DEBUG_LEVEL(l))
3259             jk_log(l, JK_LOG_DEBUG,
3260                    "Status worker '%s' committing changes for ajp worker '%s'",
3261                    w->name, aw->name);
3262     }
3263
3264     if (lb) {
3265         if (status_get_string(p, JK_STATUS_ARG_LBM_ACTIVATION, NULL, &arg, l) == JK_TRUE) {
3266             i = jk_lb_get_activation_code(arg);
3267             if (i != wr->activation && i >= 0 && i <= JK_LB_ACTIVATION_MAX) {
3268                 wr->activation = i;
3269                 jk_log(l, JK_LOG_INFO,
3270                        "Status worker '%s' setting 'activation' for sub worker '%s' of lb worker '%s' to '%s'",
3271                        w->name, wr->name, lb_name, jk_lb_get_activation(wr, l));
3272                 *side_effect |= JK_STATUS_NEEDS_RESET_LB_VALUES | JK_STATUS_NEEDS_PUSH;
3273             }
3274         }
3275         if (set_int_if_changed(p, wr->name, "lbfactor", JK_STATUS_ARG_LBM_FACTOR,
3276                                1, INT_MAX, &wr->lb_factor, lb_name, l))
3277             /* Recalculate the load multiplicators wrt. lb_factor */
3278             *side_effect |= JK_STATUS_NEEDS_UPDATE_MULT | JK_STATUS_NEEDS_PUSH;
3279         if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_ROUTE,
3280                                     NULL, &arg, l)) == JK_TRUE) {
3281             if (strncmp(wr->route, arg, JK_SHM_STR_SIZ)) {
3282                 jk_log(l, JK_LOG_INFO,
3283                        "Status worker '%s' setting 'route' for sub worker '%s' of lb worker '%s' to '%s'",
3284                        w->name, wr->name, lb_name, arg);
3285                 strncpy(wr->route, arg, JK_SHM_STR_SIZ);
3286                 *side_effect |= JK_STATUS_NEEDS_PUSH;
3287                 if (!wr->domain[0]) {
3288                     char * id_domain = strchr(wr->route, '.');
3289                     if (id_domain) {
3290                         *id_domain = '\0';
3291                         strcpy(wr->domain, wr->route);
3292                         *id_domain = '.';
3293                     }
3294                 }
3295             }
3296         }
3297         if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_REDIRECT,
3298                                     NULL, &arg, l)) == JK_TRUE) {
3299             if (strncmp(wr->redirect, arg, JK_SHM_STR_SIZ)) {
3300                 jk_log(l, JK_LOG_INFO,
3301                        "Status worker '%s' setting 'redirect' for sub worker '%s' of lb worker '%s' to '%s'",
3302                        w->name, wr->name, lb_name, arg);
3303                 strncpy(wr->redirect, arg, JK_SHM_STR_SIZ);
3304                 *side_effect |= JK_STATUS_NEEDS_PUSH;
3305             }
3306         }
3307         if ((rv = status_get_string(p, JK_STATUS_ARG_LBM_DOMAIN,
3308                                     NULL, &arg, l)) == JK_TRUE) {
3309             if (strncmp(wr->domain, arg, JK_SHM_STR_SIZ)) {
3310                 jk_log(l, JK_LOG_INFO,
3311                        "Status worker '%s' setting 'domain' for sub worker '%s' of lb worker '%s' to '%s'",
3312                        w->name, wr->name, lb_name, arg);
3313                 strncpy(wr->domain, arg, JK_SHM_STR_SIZ);
3314                 *side_effect |= JK_STATUS_NEEDS_PUSH;
3315             }
3316         }
3317         if (set_int_if_changed(p, wr->name, "distance", JK_STATUS_ARG_LBM_DISTANCE,
3318                                0, INT_MAX, &wr->distance, lb_name, l))
3319             *side_effect |= JK_STATUS_NEEDS_PUSH;
3320     }
3321     old = aw->cache_timeout;
3322     if (set_int_if_changed(p, aw->name, "connection_pool_timeout", JK_STATUS_ARG_AJP_CACHE_TO,
3323                            0, INT_MAX, &aw->cache_timeout, lb_name, l)) {
3324         *side_effect |= JK_STATUS_NEEDS_PUSH;
3325         if (old == 0) {
3326             unsigned int i;
3327             for (i = 0; i < aw->ep_cache_sz; i++) {
3328                 ajp_endpoint_t *ae = (ajp_endpoint_t *) aw->ep_cache[i];
3329                 if (ae)
3330                     ae->last_access = time(NULL);
3331             }
3332         }
3333     }
3334     port = aw->port;
3335     if (set_int_if_changed(p, aw->name, "port", JK_STATUS_ARG_AJP_PORT,
3336                            0, INT_MAX, &port, lb_name, l)) {
3337         strncpy(host, aw->host, JK_SHM_STR_SIZ);
3338         resolve = JK_TRUE;
3339     }
3340     if ((rv = status_get_string(p, JK_STATUS_ARG_AJP_HOST_STR,
3341                                 NULL, &arg, l)) == JK_TRUE) {
3342         if (strncmp(aw->host, arg, JK_SHM_STR_SIZ)) {
3343             jk_log(l, JK_LOG_INFO,
3344                     "Status worker '%s' setting 'host' for sub worker '%s' to '%s'",
3345                     w->name, aw->name, arg);
3346             strncpy(host, arg, JK_SHM_STR_SIZ);
3347             resolve = JK_TRUE;
3348         }
3349     }
3350     if (resolve == JK_TRUE) {
3351         struct sockaddr_in inet_addr;
3352         if (!jk_resolve(host, port, &inet_addr,
3353                         aw->worker.we->pool, l)) {
3354             const char *msg = "Update failed (at least partially): could not resolve address '%s:%d' for sub worker '%s'.";
3355             size_t size = strlen(msg) + strlen(host) + strlen(aw->name) + 10 + 1;
3356             p->msg = jk_pool_alloc(s->pool, size);
3357             snprintf(p->msg, size, msg, host, port, aw->name);
3358             jk_log(l, JK_LOG_ERROR,
3359                    "Status worker '%s' failed resolving address '%s:%d' for sub worker '%s'.",
3360                    w->name, host, port, aw->name);
3361             rc = JK_FALSE;
3362         }
3363         else {
3364             /* This is not atomic and not thread safe */
3365             aw->port = port;
3366             strncpy(aw->host, host, JK_SHM_STR_SIZ);
3367             memcpy(&(aw->worker_inet_addr), &inet_addr, sizeof(inet_addr));
3368             *side_effect |= JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH;
3369         }
3370     }
3371     if (set_int_if_changed(p, aw->name, "ping_timeout", JK_STATUS_ARG_AJP_PING_TO,
3372                            0, INT_MAX, &aw->ping_timeout, lb_name, l))
3373         *side_effect |= JK_STATUS_NEEDS_PUSH;
3374     if (set_int_if_changed(p, aw->name, "connect_timeout", JK_STATUS_ARG_AJP_CONNECT_TO,
3375                            0, INT_MAX, &aw->connect_timeout, lb_name, l))
3376         *side_effect |= JK_STATUS_NEEDS_PUSH;
3377     if (set_int_if_changed(p, aw->name, "prepost_timeout", JK_STATUS_ARG_AJP_PREPOST_TO,
3378                            0, INT_MAX, &aw->prepost_timeout, lb_name, l))
3379         *side_effect |= JK_STATUS_NEEDS_PUSH;
3380     if (set_int_if_changed(p, aw->name, "reply_timeout", JK_STATUS_ARG_AJP_REPLY_TO,
3381                            0, INT_MAX, &aw->reply_timeout, lb_name, l))
3382         *side_effect |= JK_STATUS_NEEDS_PUSH;
3383     if (set_int_if_changed(p, aw->name, "retries", JK_STATUS_ARG_AJP_RETRIES,
3384                            1, INT_MAX, &aw->retries, lb_name, l))
3385         *side_effect |= JK_STATUS_NEEDS_PUSH;
3386     if (set_int_if_changed(p, aw->name, "retry_interval", JK_STATUS_ARG_AJP_RETRY_INT,
3387                            1, INT_MAX, &aw->retry_interval, lb_name, l))
3388         *side_effect |= JK_STATUS_NEEDS_PUSH;
3389     if (set_int_if_changed(p, aw->name, "connection_ping_interval", JK_STATUS_ARG_AJP_CPING_INT,
3390                            1, INT_MAX, &aw->conn_ping_interval, lb_name, l))
3391         *side_effect |= JK_STATUS_NEEDS_PUSH;
3392     if (set_uint_if_changed(p, aw->name, "recovery_options", JK_STATUS_ARG_AJP_REC_OPTS,
3393                            0, INT_MAX, &aw->recovery_opts, lb_name, l))
3394         *side_effect |= JK_STATUS_NEEDS_PUSH;
3395     if (set_uint_if_changed(p, aw->name, "max_packet_size", JK_STATUS_ARG_AJP_MAX_PK_SZ,
3396                            8*1024, 64*1024, &aw->max_packet_size, lb_name, l)) {
3397         *side_effect |= JK_STATUS_NEEDS_PUSH;
3398         if (aw->max_packet_size > lb->max_packet_size) {
3399             lb->max_packet_size = aw->max_packet_size;
3400         }
3401     }
3402     return rc;
3403 }
3404
3405 static void commit_all_members(jk_ws_service_t *s,
3406                                status_endpoint_t *p,
3407                                jk_worker_t *jw,
3408                                const char *attribute,
3409                                jk_logger_t *l)
3410 {
3411     const char *arg;
3412     char vname[32];
3413     const char *name = NULL;
3414     lb_worker_t *lb = NULL;
3415     status_worker_t *w = p->worker;
3416     const char *aname;
3417     int i;
3418     int rc = 0;
3419     unsigned int j;
3420
3421     JK_TRACE_ENTER(l);
3422     if (!attribute) {
3423         jk_log(l, JK_LOG_WARNING,
3424                "Status worker '%s' missing request parameter '%s'",
3425                w->name, JK_STATUS_ARG_ATTRIBUTE);
3426         JK_TRACE_EXIT(l);
3427         return;
3428     }
3429     else {
3430         if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION))
3431             aname=JK_STATUS_ARG_LBM_TEXT_ACTIVATION;
3432         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR))
3433             aname=JK_STATUS_ARG_LBM_TEXT_FACTOR;
3434         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE))
3435             aname=JK_STATUS_ARG_LBM_TEXT_ROUTE;
3436         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT))
3437             aname=JK_STATUS_ARG_LBM_TEXT_REDIRECT;
3438         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN))
3439             aname=JK_STATUS_ARG_LBM_TEXT_DOMAIN;
3440         else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE))
3441             aname=JK_STATUS_ARG_LBM_TEXT_DISTANCE;
3442         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO))
3443             aname=JK_STATUS_ARG_AJP_TEXT_CACHE_TO;
3444         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO))
3445             aname=JK_STATUS_ARG_AJP_TEXT_PING_TO;
3446         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO))
3447             aname=JK_STATUS_ARG_AJP_TEXT_CONNECT_TO;
3448         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO))
3449             aname=JK_STATUS_ARG_AJP_TEXT_PREPOST_TO;
3450         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO))
3451             aname=JK_STATUS_ARG_AJP_TEXT_REPLY_TO;
3452         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES))
3453             aname=JK_STATUS_ARG_AJP_TEXT_RETRIES;
3454         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT))
3455             aname=JK_STATUS_ARG_AJP_TEXT_RETRY_INT;
3456         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT))
3457             aname=JK_STATUS_ARG_AJP_TEXT_CPING_INT;
3458         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS))
3459             aname=JK_STATUS_ARG_AJP_TEXT_REC_OPTS;
3460         else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ))
3461             aname=JK_STATUS_ARG_AJP_TEXT_MAX_PK_SZ;
3462         else {
3463             jk_log(l, JK_LOG_WARNING,
3464                    "Status worker '%s' unknown attribute '%s'",
3465                    w->name, attribute);
3466             JK_TRACE_EXIT(l);
3467             return;
3468         }
3469     }
3470     if (jw->type == JK_LB_WORKER_TYPE) {
3471         lb = (lb_worker_t *)jw->worker_private;
3472         name = lb->name;
3473         if (JK_IS_DEBUG_LEVEL(l))
3474             jk_log(l, JK_LOG_DEBUG,
3475                    "Status worker '%s' committing changes for attribute '%s' [%s] of all members of lb worker '%s'",
3476                    w->name, attribute, aname, name);
3477     }
3478     else {
3479         jk_log(l, JK_LOG_WARNING,
3480                "Status worker '%s' worker type not implemented",
3481                w->name);
3482         JK_TRACE_EXIT(l);
3483         return;
3484     }
3485
3486     if (lb) {
3487         for (j = 0; j < lb->num_of_workers; j++) {
3488             int sync_needed = JK_FALSE;
3489             lb_sub_worker_t *wr = &(lb->lb_workers[j]);
3490             jk_worker_t *jw = wr->worker;
3491             ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;;
3492             snprintf(vname, 32-1, "" JK_STATUS_ARG_MULT_VALUE_BASE "%d", j);
3493
3494             if (!strcmp(attribute, JK_STATUS_ARG_LBM_FACTOR)) {
3495                 if (set_int_if_changed(p, wr->name, "lbfactor", vname,
3496                                        1, INT_MAX, &wr->lb_factor, name, l)) {
3497                     rc = 2;
3498                     sync_needed = JK_TRUE;
3499                 }
3500             }
3501             else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DISTANCE)) {
3502                 if (set_int_if_changed(p, wr->name, "distance", vname,
3503                                        0, INT_MAX, &wr->distance, name, l))
3504                     sync_needed = JK_TRUE;
3505             }
3506             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CACHE_TO)) {
3507                 int old = aw->cache_timeout;
3508                 if (set_int_if_changed(p, aw->name, "connection_pool_timeout", vname,
3509                                        0, INT_MAX, &aw->cache_timeout, name, l)) {
3510                     sync_needed = JK_TRUE;
3511                     if (old == 0) {
3512                         unsigned int i;
3513                         for (i = 0; i < aw->ep_cache_sz; i++) {
3514                             ajp_endpoint_t *ae = (ajp_endpoint_t *) aw->ep_cache[i];
3515                             if (ae)
3516                                 ae->last_access = time(NULL);
3517                         }
3518                     }
3519                 }
3520             }
3521             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PING_TO)) {
3522                 if (set_int_if_changed(p, aw->name, "ping_timeout", vname,
3523                                        0, INT_MAX, &aw->ping_timeout, name, l))
3524                     sync_needed = JK_TRUE;
3525             }
3526             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CONNECT_TO)) {
3527                 if (set_int_if_changed(p, aw->name, "connect_timeout", vname,
3528                                        0, INT_MAX, &aw->connect_timeout, name, l))
3529                     sync_needed = JK_TRUE;
3530             }
3531             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_PREPOST_TO)) {
3532                 if (set_int_if_changed(p, aw->name, "prepost_timeout", vname,
3533                                        0, INT_MAX, &aw->prepost_timeout, name, l))
3534                     sync_needed = JK_TRUE;
3535             }
3536             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REPLY_TO)) {
3537                 if (set_int_if_changed(p, aw->name, "reply_timeout", vname,
3538                                        0, INT_MAX, &aw->reply_timeout, name, l))
3539                     sync_needed = JK_TRUE;
3540             }
3541             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRIES)) {
3542                 if (set_int_if_changed(p, aw->name, "retries", vname,
3543                                        1, INT_MAX, &aw->retries, name, l))
3544                     sync_needed = JK_TRUE;
3545             }
3546             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_RETRY_INT)) {
3547                 if (set_int_if_changed(p, aw->name, "retry_interval", vname,
3548                                        1, INT_MAX, &aw->retry_interval, name, l))
3549                     sync_needed = JK_TRUE;
3550             }
3551             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_CPING_INT)) {
3552                 if (set_int_if_changed(p, aw->name, "connection_ping_interval", vname,
3553                                        1, INT_MAX, &aw->conn_ping_interval, name, l))
3554                     sync_needed = JK_TRUE;
3555             }
3556             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_REC_OPTS)) {
3557                 if (set_uint_if_changed(p, aw->name, "recovery_options", vname,
3558                                        0, INT_MAX, &aw->recovery_opts, name, l))
3559                     sync_needed = JK_TRUE;
3560             }
3561             else if (!strcmp(attribute, JK_STATUS_ARG_AJP_MAX_PK_SZ)) {
3562                 if (set_uint_if_changed(p, aw->name, "max_packet_size", vname,
3563                                        8*1024, 64*1024, &aw->max_packet_size, name, l)) {
3564                     sync_needed = JK_TRUE;
3565                     if (aw->max_packet_size > lb->max_packet_size) {
3566                         lb->max_packet_size = aw->max_packet_size;
3567                     }
3568                 }
3569             }
3570             else {
3571                 int rv = status_get_string(p, vname, NULL, &arg, l);
3572                 if (!strcmp(attribute, JK_STATUS_ARG_LBM_ACTIVATION)) {
3573                     if (rv == JK_TRUE) {
3574                         i = jk_lb_get_activation_code(arg);
3575                         if (i != wr->activation && i >= 0 && i <= JK_LB_ACTIVATION_MAX) {
3576                             jk_log(l, JK_LOG_INFO,
3577                                    "Status worker '%s' setting 'activation' for sub worker '%s' of lb worker '%s' to '%s'",
3578                                    w->name, wr->name, name, jk_lb_get_activation(wr, l));
3579                             wr->activation = i;
3580                             rc = 1;
3581                             sync_needed = JK_TRUE;
3582                         }
3583                     }
3584                 }
3585                 else if (!strcmp(attribute, JK_STATUS_ARG_LBM_ROUTE)) {
3586                     if (rv == JK_TRUE) {
3587                         if (strncmp(wr->route, arg, JK_SHM_STR_SIZ)) {
3588                             jk_log(l, JK_LOG_INFO,
3589                                    "Status worker '%s' setting 'route' for sub worker '%s' of lb worker '%s' to '%s'",
3590                                    w->name, wr->name, name, arg);
3591                             strncpy(wr->route, arg, JK_SHM_STR_SIZ);
3592                             sync_needed = JK_TRUE;
3593                             if (!wr->domain[0]) {
3594                                 char * id_domain = strchr(wr->route, '.');
3595                                 if (id_domain) {
3596                                     *id_domain = '\0';
3597                                     strcpy(wr->domain, wr->route);
3598                                     *id_domain = '.';
3599                                 }
3600                             }
3601                         }
3602                     }
3603                 }
3604                 else if (!strcmp(attribute, JK_STATUS_ARG_LBM_REDIRECT)) {
3605                     if (rv == JK_TRUE) {
3606                         if (strncmp(wr->redirect, arg, JK_SHM_STR_SIZ)) {
3607                             jk_log(l, JK_LOG_INFO,
3608                                    "Status worker '%s' setting 'redirect' for sub worker '%s' of lb worker '%s' to '%s'",
3609                                    w->name, wr->name, name, arg);
3610                             strncpy(wr->redirect, arg, JK_SHM_STR_SIZ);
3611                             sync_needed = JK_TRUE;
3612                         }
3613                     }
3614                 }
3615                 else if (!strcmp(attribute, JK_STATUS_ARG_LBM_DOMAIN)) {
3616                     if (rv == JK_TRUE) {
3617                         if (strncmp(wr->domain, arg, JK_SHM_STR_SIZ)) {
3618                             jk_log(l, JK_LOG_INFO,
3619                                    "Status worker '%s' setting 'domain' for sub worker '%s' of lb worker '%s' to '%s'",
3620                                    w->name, wr->name, name, arg);
3621                             strncpy(wr->domain, arg, JK_SHM_STR_SIZ);
3622                             sync_needed = JK_TRUE;
3623                         }
3624                     }
3625                 }
3626             }
3627             if (sync_needed == JK_TRUE) {
3628                 wr->sequence++;
3629                 if (!rc)
3630                     rc = 3;
3631             }
3632         }
3633         if (rc == 1)
3634             reset_lb_values(lb, l);
3635         else if (rc == 2)
3636             /* Recalculate the load multiplicators wrt. lb_factor */
3637             update_mult(lb, l);
3638         if (rc) {
3639             lb->sequence++;
3640             jk_lb_push(lb, JK_TRUE, l);
3641         }
3642     }
3643     JK_TRACE_EXIT(l);
3644 }
3645
3646 static void display_legend(jk_ws_service_t *s,
3647                            status_endpoint_t *p,
3648                            jk_logger_t *l)
3649 {
3650
3651     int mime;
3652     const char *arg;
3653     unsigned int hide_legend;
3654
3655     JK_TRACE_ENTER(l);
3656     status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l);
3657     mime = status_mime_int(arg);
3658     if (mime != JK_STATUS_MIME_HTML) {
3659         JK_TRACE_EXIT(l);
3660         return;
3661     }
3662     hide_legend = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
3663                                JK_STATUS_ARG_OPTION_NO_LEGEND;
3664     if (hide_legend) {
3665         jk_puts(s, "<p>\n");
3666         status_write_uri(s, p, "Show Legend", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
3667                          NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LEGEND, NULL, l);
3668         jk_puts(s, "</p>\n");
3669     }
3670     else {
3671         jk_puts(s, "<h2>Legend [");
3672         status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
3673                          NULL, NULL, JK_STATUS_ARG_OPTION_NO_LEGEND, 0, NULL, l);
3674         jk_puts(s, "]</h2>\n");
3675
3676         jk_puts(s, "<table>\n"
3677             "<tbody valign=\"baseline\">\n"
3678             "<tr><th>Name</th><td>Worker name</td></tr>\n"
3679             "<tr><th>Type</th><td>Worker type</td></tr>\n"
3680             "<tr><th>Route</th><td>Worker route</td></tr>\n"
3681             "<tr><th>Act</th><td>Worker activation configuration<br/>\n"
3682             "ACT=Active, DIS=Disabled, STP=Stopped</td></tr>\n"
3683             "<tr><th>State</th><td>Worker error status<br/>\n"
3684             "OK=OK, ERR=Error with substates<br/>\n"
3685             "IDLE=No requests handled, BUSY=All connections busy,<br/>\n"
3686             "REC=Recovering, PRB=Probing, FRC=Forced Recovery</td></tr>\n"
3687             "<tr><th>D</th><td>Worker distance</td></tr>\n"
3688             "<tr><th>F</th><td>Load Balancer factor</td></tr>\n"
3689             "<tr><th>M</th><td>Load Balancer multiplicity</td></tr>\n"
3690             "<tr><th>V</th><td>Load Balancer value</td></tr>\n"
3691             "<tr><th>Acc</th><td>Number of requests</td></tr>\n"
3692             "<tr><th>Err</th><td>Number of failed requests</td></tr>\n"
3693             "<tr><th>CE</th><td>Number of client errors</td></tr>\n"
3694             "<tr><th>RE</th><td>Number of reply timeouts (decayed)</td></tr>\n"
3695             "<tr><th>Wr</th><td>Number of bytes transferred</td></tr>\n"
3696             "<tr><th>Rd</th><td>Number of bytes read</td></tr>\n"
3697             "<tr><th>Busy</th><td>Current number of busy connections</td></tr>\n"
3698             "<tr><th>Max</th><td>Maximum number of busy connections</td></tr>\n"
3699             "<tr><th>Con</th><td>Current number of backend connections</td></tr>\n"
3700             "<tr><th>RR</th><td>Route redirect</td></tr>\n"
3701             "<tr><th>Cd</th><td>Cluster domain</td></tr>\n"
3702             "<tr><th>Rs</th><td>Recovery scheduled in app. min/max seconds</td></tr>\n"
3703             "<tr><th>LR</th><td>Seconds since last reset of statistics counters</td></tr>\n"
3704             "<tr><th>LE</th><td>Timestamp of the last error</td></tr>\n"
3705             "</tbody>\n"
3706             "</table>\n");
3707     }
3708
3709     JK_TRACE_EXIT(l);
3710 }
3711
3712 static int check_worker(jk_ws_service_t *s,
3713                         status_endpoint_t *p,
3714                         jk_uint32_t allow_wildchars,
3715                         jk_logger_t *l)
3716 {
3717     const char *worker;
3718     const char *sub_worker;
3719     status_worker_t *w = p->worker;
3720     jk_worker_t *jw = NULL;
3721     lb_sub_worker_t *wr = NULL;
3722
3723     JK_TRACE_ENTER(l);
3724     if (fetch_worker_and_sub_worker(p, "checking", &worker, &sub_worker, l) == JK_FALSE ||
3725         search_worker(s, p, &jw, worker, l) == JK_FALSE) {
3726         JK_TRACE_EXIT(l);
3727         return JK_FALSE;
3728     }
3729
3730     if (sub_worker && sub_worker[0]) {
3731         unsigned int idx = 0;
3732         unsigned int *wi = NULL;
3733         if (strchr(sub_worker, '*') || strchr(sub_worker, '?')) {
3734             /* We have a wildchar matching rule */
3735             if (!allow_wildchars) {
3736                 jk_log(l, JK_LOG_ERROR,
3737                        "Status worker '%s' wildcards in sub worker '%s' of worker '%s' not allowed for this command",
3738                        w->name, sub_worker, worker ? worker : "(null)");
3739                 p->msg = "wildcard not allowed in sub worker for this command";
3740                 JK_TRACE_EXIT(l);
3741                 return JK_FALSE;
3742             }
3743             else {
3744                 wi = &idx;
3745             }
3746         }
3747         if (search_sub_worker(s, p, jw, worker, &wr, sub_worker,
3748                               wi, l) == JK_FALSE) {
3749             JK_TRACE_EXIT(l);
3750             return JK_FALSE;
3751         }
3752     }
3753
3754     JK_TRACE_EXIT(l);
3755     return JK_TRUE;
3756 }
3757
3758 static void count_workers(jk_ws_service_t *s,
3759                           status_endpoint_t *p,
3760                           int *lb_cnt, int *ajp_cnt,
3761                           jk_logger_t *l)
3762 {
3763     unsigned int i;
3764     jk_worker_t *jw = NULL;
3765     status_worker_t *w = p->worker;
3766
3767     JK_TRACE_ENTER(l);
3768     *lb_cnt = 0;
3769     *ajp_cnt = 0;
3770     for (i = 0; i < w->we->num_of_workers; i++) {
3771         jw = wc_get_worker_for_name(w->we->worker_list[i], l);
3772         if (!jw) {
3773             jk_log(l, JK_LOG_WARNING,
3774                    "Status worker '%s' could not find worker '%s'",
3775                    w->name, w->we->worker_list[i]);
3776             continue;
3777         }
3778         if (jw->type == JK_LB_WORKER_TYPE) {
3779             (*lb_cnt)++;
3780         }
3781         else if (jw->type == JK_AJP13_WORKER_TYPE ||
3782                  jw->type == JK_AJP14_WORKER_TYPE) {
3783             (*ajp_cnt)++;
3784         }
3785     }
3786     JK_TRACE_EXIT(l);
3787 }
3788
3789 static void list_workers_type(jk_ws_service_t *s,
3790                               status_endpoint_t *p,
3791                               int list_lb, int count,
3792                               jk_logger_t *l)
3793 {
3794
3795     const char *arg;
3796     unsigned int i;
3797     int mime;
3798     unsigned int hide;
3799     jk_worker_t *jw = NULL;
3800     status_worker_t *w = p->worker;
3801
3802     JK_TRACE_ENTER(l);
3803
3804     status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l);
3805     mime = status_mime_int(arg);
3806     if (list_lb) {
3807         hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
3808                               JK_STATUS_ARG_OPTION_NO_LB;
3809         if (hide) {
3810             if (mime == JK_STATUS_MIME_HTML) {
3811                 jk_puts(s, "<p>\n");
3812                 status_write_uri(s, p, "Show Load Balancing Workers", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
3813                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_LB, NULL, l);
3814                 jk_puts(s, "</p>\n");
3815             }
3816         }
3817         else {
3818             if (mime == JK_STATUS_MIME_XML) {
3819                 jk_print_xml_start_elt(s, w, 0, 0, "balancers");
3820                 jk_print_xml_att_int(s, 2, "count", count);
3821                 jk_print_xml_stop_elt(s, 0, 0);
3822             }
3823             else if (mime == JK_STATUS_MIME_TXT) {
3824                 jk_printf(s, "Balancer Workers: count=%d\n", count);
3825             }
3826             else if (mime == JK_STATUS_MIME_PROP) {
3827                 jk_print_prop_att_int(s, w, NULL, "lb_count", count);
3828             }
3829             else {
3830                 jk_printf(s, "<hr/><h2>Listing Load Balancing Worker%s (%d Worker%s) [",
3831                           count>1 ? "s" : "", count, count>1 ? "s" : "");
3832                 status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
3833                                  NULL, NULL, JK_STATUS_ARG_OPTION_NO_LB, 0, NULL, l);
3834                 jk_puts(s, "]</h2>\n");
3835             }
3836         }
3837     }
3838     else {
3839         hide = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
3840                               JK_STATUS_ARG_OPTION_NO_AJP;
3841         if (hide) {
3842             if (mime == JK_STATUS_MIME_HTML) {
3843                 jk_puts(s, "<p>\n");
3844                 status_write_uri(s, p, "Show AJP Workers", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
3845                                  NULL, NULL, 0, JK_STATUS_ARG_OPTION_NO_AJP, NULL, l);
3846                 jk_puts(s, "</p>\n");
3847             }
3848         }
3849         else {
3850             if (mime == JK_STATUS_MIME_XML) {
3851                 jk_print_xml_start_elt(s, w, 0, 0, "ajp_workers");
3852                 jk_print_xml_att_int(s, 2, "count", count);
3853                 jk_print_xml_stop_elt(s, 0, 0);
3854             }
3855             else if (mime == JK_STATUS_MIME_TXT) {
3856                 jk_printf(s, "AJP Workers: count=%d\n", count);
3857             }
3858             else if (mime == JK_STATUS_MIME_PROP) {
3859                 jk_print_prop_att_int(s, w, NULL, "ajp_count", count);
3860             }
3861             else {
3862                 jk_printf(s, "<hr/><h2>Listing AJP Worker%s (%d Worker%s) [",
3863                           count>1 ? "s" : "", count, count>1 ? "s" : "");
3864                 status_write_uri(s, p, "Hide", JK_STATUS_CMD_UNKNOWN, JK_STATUS_MIME_UNKNOWN,
3865                                  NULL, NULL, JK_STATUS_ARG_OPTION_NO_AJP, 0, NULL, l);
3866                 jk_puts(s, "]</h2>\n");
3867             }
3868         }
3869     }
3870
3871     if (hide) {
3872         JK_TRACE_EXIT(l);
3873         return;
3874     }
3875
3876     for (i = 0; i < w->we->num_of_workers; i++) {
3877         jw = wc_get_worker_for_name(w->we->worker_list[i], l);
3878         if (!jw) {
3879             jk_log(l, JK_LOG_WARNING,
3880                    "Status worker '%s' could not find worker '%s'",
3881                    w->name, w->we->worker_list[i]);
3882             continue;
3883         }
3884         if ((list_lb && jw->type == JK_LB_WORKER_TYPE) ||
3885             (!list_lb && jw->type != JK_LB_WORKER_TYPE)) {
3886             display_worker(s, p, jw, NULL, l);
3887         }
3888     }
3889
3890     if (list_lb) {
3891         if (mime == JK_STATUS_MIME_XML) {
3892             jk_print_xml_close_elt(s, w, 0, "balancers");
3893         }
3894         else if (mime == JK_STATUS_MIME_TXT) {
3895         }
3896         else if (mime == JK_STATUS_MIME_PROP) {
3897         }
3898         else if (mime == JK_STATUS_MIME_HTML) {
3899         }
3900     }
3901     else {
3902         if (mime == JK_STATUS_MIME_XML) {
3903             jk_print_xml_close_elt(s, w, 0, "ajp_workers");
3904         }
3905         else if (mime == JK_STATUS_MIME_TXT) {
3906         }
3907         else if (mime == JK_STATUS_MIME_PROP) {
3908         }
3909         else if (mime == JK_STATUS_MIME_HTML) {
3910         }
3911     }
3912
3913     JK_TRACE_EXIT(l);
3914 }
3915
3916 static int list_workers(jk_ws_service_t *s,
3917                         status_endpoint_t *p,
3918                         jk_logger_t *l)
3919 {
3920     int lb_cnt = 0;
3921     int ajp_cnt = 0;
3922
3923     JK_TRACE_ENTER(l);
3924     count_workers(s, p, &lb_cnt, &ajp_cnt, l);
3925
3926     if (lb_cnt) {
3927         list_workers_type(s, p, 1, lb_cnt, l);
3928     }
3929
3930     if (ajp_cnt) {
3931         list_workers_type(s, p, 0, ajp_cnt, l);
3932     }
3933
3934     JK_TRACE_EXIT(l);
3935     return JK_TRUE;
3936 }
3937
3938 static int show_worker(jk_ws_service_t *s,
3939                        status_endpoint_t *p,
3940                        jk_logger_t *l)
3941 {
3942     const char *worker;
3943     const char *sub_worker;
3944     jk_worker_t *jw = NULL;
3945     lb_sub_worker_t *wr = NULL;
3946
3947     JK_TRACE_ENTER(l);
3948     if (fetch_worker_and_sub_worker(p, "showing", &worker, &sub_worker, l) == JK_FALSE ||
3949         search_worker(s, p, &jw, worker, l) == JK_FALSE) {
3950         JK_TRACE_EXIT(l);
3951         return JK_FALSE;
3952     }
3953     if (sub_worker && sub_worker[0]) {
3954         if (search_sub_worker(s, p, jw, worker, &wr, sub_worker,
3955                              NULL, l) == JK_FALSE) {
3956             JK_TRACE_EXIT(l);
3957             return JK_FALSE;
3958         }
3959     }
3960     display_worker(s, p, jw, wr, l);
3961
3962     JK_TRACE_EXIT(l);
3963     return JK_TRUE;
3964 }
3965
3966 static int edit_worker(jk_ws_service_t *s,
3967                        status_endpoint_t *p,
3968                        jk_logger_t *l)
3969 {
3970     const char *worker;
3971     const char *sub_worker;
3972     status_worker_t *w = p->worker;
3973     jk_worker_t *jw = NULL;
3974     lb_worker_t *lb = NULL;
3975     lb_sub_worker_t *wr = NULL;
3976     ajp_worker_t *aw = NULL;
3977
3978     JK_TRACE_ENTER(l);
3979     if (fetch_worker_and_sub_worker(p, "editing", &worker, &sub_worker, l) == JK_FALSE ||
3980         search_worker(s, p, &jw, worker, l) == JK_FALSE) {
3981         JK_TRACE_EXIT(l);
3982         return JK_FALSE;
3983     }
3984
3985     if (jw->type == JK_LB_WORKER_TYPE) {
3986         if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) {
3987             JK_TRACE_EXIT(l);
3988             return JK_FALSE;
3989         }
3990
3991         if (lb->sequence != lb->s->h.sequence)
3992             jk_lb_pull(lb, JK_FALSE, l);
3993         if (!sub_worker || !sub_worker[0]) {
3994             const char *arg;
3995             if (status_get_string(p, JK_STATUS_ARG_ATTRIBUTE,
3996                                   NULL, &arg, l) == JK_TRUE) {
3997                 if (JK_IS_DEBUG_LEVEL(l))
3998                     jk_log(l, JK_LOG_DEBUG,
3999                            "Status worker '%s' %s lb worker '%s' with all sub workers",
4000                            w->name, "editing", lb->name);
4001                 form_all_members(s, p, jw, arg, l);
4002             }
4003             else {
4004                 if (JK_IS_DEBUG_LEVEL(l))
4005                     jk_log(l, JK_LOG_DEBUG,
4006                            "Status worker '%s' %s lb worker '%s'",
4007                            w->name, "editing", lb->name);
4008                 form_worker(s, p, jw, l);
4009             }
4010             JK_TRACE_EXIT(l);
4011             return JK_TRUE;
4012         }
4013         else {
4014             if (search_sub_worker(s, p, jw, worker, &wr, sub_worker,
4015                                  NULL, l) == JK_FALSE) {
4016                 JK_TRACE_EXIT(l);
4017                 return JK_FALSE;
4018             }
4019             if (JK_IS_DEBUG_LEVEL(l))
4020                 jk_log(l, JK_LOG_DEBUG,
4021                        "Status worker '%s' %s lb worker '%s' sub worker '%s'",
4022                        w->name, "editing", lb->name, wr->name);
4023             aw = (ajp_worker_t *)wr->worker->worker_private;
4024             form_member(s, p, wr, aw, worker, l);
4025             JK_TRACE_EXIT(l);
4026             return JK_TRUE;
4027         }
4028     }
4029     else if (jw->type == JK_AJP13_WORKER_TYPE ||
4030              jw->type == JK_AJP14_WORKER_TYPE) {
4031         ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;
4032         if (aw) {
4033             if (JK_IS_DEBUG_LEVEL(l))
4034                 jk_log(l, JK_LOG_DEBUG,
4035                        "Status worker '%s' %s ajp worker '%s'",
4036                        w->name, "editing", aw->name);
4037             if (aw->sequence != aw->s->h.sequence)
4038                 jk_ajp_pull(aw, JK_FALSE, l);
4039             form_member(s, p, NULL, aw, worker, l);
4040             JK_TRACE_EXIT(l);
4041             return JK_TRUE;
4042         }
4043         else {
4044             jk_log(l, JK_LOG_WARNING,
4045                    "Status worker '%s' aw worker is (null)",
4046                    w->name);
4047         }
4048     }
4049     else {
4050         if (JK_IS_DEBUG_LEVEL(l))
4051             jk_log(l, JK_LOG_DEBUG,
4052                    "Status worker '%s' worker type not implemented",
4053                    w->name);
4054     }
4055     JK_TRACE_EXIT(l);
4056     return JK_FALSE;
4057 }
4058
4059 static int update_worker(jk_ws_service_t *s,
4060                          status_endpoint_t *p,
4061                          jk_logger_t *l)
4062 {
4063     const char *worker;
4064     const char *sub_worker;
4065     status_worker_t *w = p->worker;
4066     jk_worker_t *jw = NULL;
4067     lb_worker_t *lb = NULL;
4068     lb_sub_worker_t *wr = NULL;
4069     ajp_worker_t *aw = NULL;
4070     int rc = JK_TRUE;
4071     int rv;
4072
4073     JK_TRACE_ENTER(l);
4074     if (fetch_worker_and_sub_worker(p, "updating", &worker, &sub_worker, l) == JK_FALSE ||
4075         search_worker(s, p, &jw, worker, l) == JK_FALSE) {
4076         JK_TRACE_EXIT(l);
4077         return JK_FALSE;
4078     }
4079
4080     if (jw->type == JK_LB_WORKER_TYPE) {
4081         if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) {
4082             JK_TRACE_EXIT(l);
4083             return JK_FALSE;
4084         }
4085
4086         if (lb->sequence != lb->s->h.sequence)
4087             jk_lb_pull(lb, JK_TRUE, l);
4088         if (!sub_worker || !sub_worker[0]) {
4089             const char *arg;
4090             if (status_get_string(p, JK_STATUS_ARG_ATTRIBUTE,
4091                                   NULL, &arg, l) == JK_TRUE) {
4092                 if (JK_IS_DEBUG_LEVEL(l))
4093                     jk_log(l, JK_LOG_DEBUG,
4094                            "Status worker '%s' %s lb worker '%s' with all sub workers",
4095                            w->name, "updating", lb->name);
4096                 commit_all_members(s, p, jw, arg, l);
4097             }
4098             else {
4099                 if (JK_IS_DEBUG_LEVEL(l))
4100                     jk_log(l, JK_LOG_DEBUG,
4101                            "Status worker '%s' %s lb worker '%s'",
4102                            w->name, "updating", lb->name);
4103                 commit_worker(s, p, jw, l);
4104             }
4105             JK_TRACE_EXIT(l);
4106             return JK_TRUE;
4107         }
4108         else {
4109             unsigned int idx = 0;
4110             unsigned int *wi = NULL;
4111             int is_wildchar = JK_FALSE;
4112
4113             if (strchr(sub_worker, '*') || strchr(sub_worker, '?')) {
4114                 /* We have a wildchar matching rule */
4115                 wi = &idx;
4116                 is_wildchar = JK_TRUE;
4117             }
4118             for (;;) {
4119                 if (search_sub_worker(s, p, jw, worker, &wr, sub_worker,
4120                                       wi, l) == JK_FALSE) {
4121                     if (!idx) {
4122                         JK_TRACE_EXIT(l);
4123                         return JK_FALSE;
4124                     }
4125                     else {
4126                         /* We have found at least one match previously */
4127                         p->msg = "OK";
4128                         break;
4129                     }
4130                 }
4131                 if (JK_IS_DEBUG_LEVEL(l))
4132                     jk_log(l, JK_LOG_DEBUG,
4133                        "Status worker '%s' %s lb worker '%s' sub worker '%s'",
4134                        w->name, "updating", lb->name, wr->name);
4135                 aw = (ajp_worker_t *)wr->worker->worker_private;
4136                 rv = 0;
4137                 rc = commit_member(s, p, lb, wr, aw, &rv, l);
4138                 if (rv & JK_STATUS_NEEDS_ADDR_PUSH) {
4139                     aw->addr_sequence++;
4140                 }
4141                 if (rv & (JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH)) {
4142                     wr->sequence++;
4143                     lb->sequence++;
4144                     jk_lb_push(lb, JK_TRUE, l);
4145                 }
4146                 if (rv & JK_STATUS_NEEDS_RESET_LB_VALUES)
4147                     reset_lb_values(lb, l);
4148                 if (rv & JK_STATUS_NEEDS_UPDATE_MULT)
4149                     /* Recalculate the load multiplicators wrt. lb_factor */
4150                     update_mult(lb, l);
4151                 if (rc == JK_FALSE) {
4152                     jk_log(l, JK_LOG_ERROR,
4153                            "Status worker '%s' failed updating sub worker '%s' (at least partially).%s",
4154                            w->name, aw->name, (is_wildchar == JK_TRUE) ? " Aborting further wildcard updates." : "");
4155                     if (!strncmp("OK", p->msg, 3)) {
4156                         const char *msg = "Update failed (at least partially) for sub worker '%s'";
4157                         size_t size = strlen(msg) + strlen(aw->name) + 1;
4158                         p->msg = jk_pool_alloc(s->pool, size);
4159                         snprintf(p->msg, size, msg, aw->name);
4160                     }
4161                     if (is_wildchar == JK_TRUE) {
4162                         const char *msg = " Aborting further wildcard updates.";
4163                         size_t size = strlen(msg) + strlen(p->msg) + 1;
4164                         p->msg = jk_pool_realloc(s->pool, size, p->msg, strlen(p->msg) + 1);
4165                         strcat(p->msg, msg);
4166                     }
4167                     break;
4168                 }
4169                 if (!wi)
4170                     break;
4171             }
4172             JK_TRACE_EXIT(l);
4173             return rc;
4174         }
4175     }
4176     else if (jw->type == JK_AJP13_WORKER_TYPE ||
4177              jw->type == JK_AJP14_WORKER_TYPE) {
4178         ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;
4179         if (aw) {
4180             if (JK_IS_DEBUG_LEVEL(l))
4181                 jk_log(l, JK_LOG_DEBUG,
4182                        "Status worker '%s' %s ajp worker '%s'",
4183                        w->name, "updating", aw->name);
4184             if (aw->sequence != aw->s->h.sequence)
4185                 jk_ajp_pull(aw, JK_TRUE, l);
4186             rv = 0;
4187             rc = commit_member(s, p, NULL, NULL, aw, &rv, l);
4188             if (rv & JK_STATUS_NEEDS_ADDR_PUSH) {
4189                 aw->addr_sequence++;
4190             }
4191             if (rv & (JK_STATUS_NEEDS_PUSH | JK_STATUS_NEEDS_ADDR_PUSH)) {
4192                 aw->sequence++;
4193                 jk_ajp_push(aw, JK_TRUE, l);
4194             }
4195             if (rc == JK_FALSE) {
4196                 jk_log(l, JK_LOG_ERROR,
4197                        "Status worker '%s' failed updating worker '%s' (at least partially).",
4198                        w->name, aw->name);
4199                 if (!strncmp("OK", p->msg, 3)) {
4200                     const char *msg = "Update failed (at least partially) for worker '%s'";
4201                     size_t size = strlen(msg) + strlen(aw->name) + 1;
4202                     p->msg = jk_pool_alloc(s->pool, size);
4203                     snprintf(p->msg, size, msg, aw->name);
4204                 }
4205             }
4206             JK_TRACE_EXIT(l);
4207             return rc;
4208         }
4209         else {
4210             jk_log(l, JK_LOG_WARNING,
4211                    "Status worker '%s' aw worker is (null)",
4212                    w->name);
4213         }
4214     }
4215     else {
4216         if (JK_IS_DEBUG_LEVEL(l))
4217             jk_log(l, JK_LOG_DEBUG,
4218                    "Status worker '%s' worker type not implemented",
4219                    w->name);
4220     }
4221     JK_TRACE_EXIT(l);
4222     return JK_FALSE;
4223 }
4224
4225 static int reset_worker(jk_ws_service_t *s,
4226                         status_endpoint_t *p,
4227                         jk_logger_t *l)
4228 {
4229     unsigned int i;
4230     const char *worker;
4231     const char *sub_worker;
4232     status_worker_t *w = p->worker;
4233     jk_worker_t *jw = NULL;
4234     lb_worker_t *lb = NULL;
4235     lb_sub_worker_t *wr = NULL;
4236     ajp_worker_t *aw = NULL;
4237     time_t now = 0;
4238
4239     JK_TRACE_ENTER(l);
4240     if (fetch_worker_and_sub_worker(p, "resetting", &worker, &sub_worker, l) == JK_FALSE ||
4241         search_worker(s, p, &jw, worker, l) == JK_FALSE) {
4242         JK_TRACE_EXIT(l);
4243         return JK_FALSE;
4244     }
4245
4246     now = time(NULL);
4247     if (jw->type == JK_LB_WORKER_TYPE) {
4248         if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) {
4249             JK_TRACE_EXIT(l);
4250             return JK_FALSE;
4251         }
4252
4253         if (!sub_worker || !sub_worker[0]) {
4254             if (JK_IS_DEBUG_LEVEL(l))
4255                 jk_log(l, JK_LOG_DEBUG,
4256                        "Status worker '%s' %s lb worker '%s' with all sub workers",
4257                        w->name, "resetting", lb->name);
4258             lb->s->max_busy = 0;
4259             lb->s->last_reset = now;
4260             for (i = 0; i < lb->num_of_workers; i++) {
4261                 wr = &(lb->lb_workers[i]);
4262                 aw = (ajp_worker_t *)wr->worker->worker_private;
4263                 wr->s->state            = JK_LB_STATE_IDLE;
4264                 wr->s->elected_snapshot = 0;
4265                 wr->s->error_time       = 0;
4266                 wr->s->errors           = 0;
4267                 wr->s->lb_value         = 0;
4268                 aw->s->used             = 0;
4269                 aw->s->client_errors    = 0;
4270                 aw->s->reply_timeouts   = 0;
4271                 aw->s->transferred      = 0;
4272                 aw->s->readed           = 0;
4273                 aw->s->max_busy         = 0;
4274                 aw->s->last_reset       = now;
4275             }
4276             JK_TRACE_EXIT(l);
4277             return JK_TRUE;
4278         }
4279         else {
4280             if (search_sub_worker(s, p, jw, worker, &wr, sub_worker,
4281                                  NULL, l) == JK_FALSE) {
4282                 JK_TRACE_EXIT(l);
4283                 return JK_FALSE;
4284             }
4285             if (JK_IS_DEBUG_LEVEL(l))
4286                 jk_log(l, JK_LOG_DEBUG,
4287                        "Status worker '%s' %s lb worker '%s' sub worker '%s'",
4288                        w->name, "resetting", lb->name, wr->name);
4289             aw = (ajp_worker_t *)wr->worker->worker_private;
4290             wr->s->state            = JK_LB_STATE_IDLE;
4291             wr->s->elected_snapshot = 0;
4292             wr->s->error_time       = 0;
4293             wr->s->errors           = 0;
4294             wr->s->lb_value         = 0;
4295             aw->s->used             = 0;
4296             aw->s->client_errors    = 0;
4297             aw->s->reply_timeouts   = 0;
4298             aw->s->transferred      = 0;
4299             aw->s->readed           = 0;
4300             aw->s->max_busy         = 0;
4301             aw->s->last_reset       = now;
4302             JK_TRACE_EXIT(l);
4303             return JK_TRUE;
4304         }
4305     }
4306     else if (jw->type == JK_AJP13_WORKER_TYPE ||
4307              jw->type == JK_AJP14_WORKER_TYPE) {
4308         ajp_worker_t *aw = (ajp_worker_t *)jw->worker_private;
4309         if (aw) {
4310             if (JK_IS_DEBUG_LEVEL(l))
4311                 jk_log(l, JK_LOG_DEBUG,
4312                        "Status worker '%s' %s ajp worker '%s'",
4313                        w->name, "resetting", aw->name);
4314             aw->s->errors           = 0;
4315             aw->s->used             = 0;
4316             aw->s->client_errors    = 0;
4317             aw->s->reply_timeouts   = 0;
4318             aw->s->transferred      = 0;
4319             aw->s->readed           = 0;
4320             aw->s->max_busy         = 0;
4321             aw->s->last_reset       = now;
4322             JK_TRACE_EXIT(l);
4323             return JK_TRUE;
4324         }
4325         else {
4326             jk_log(l, JK_LOG_WARNING,
4327                    "Status worker '%s' aw worker is (null)",
4328                    w->name);
4329         }
4330     }
4331     else {
4332         if (JK_IS_DEBUG_LEVEL(l))
4333             jk_log(l, JK_LOG_DEBUG,
4334                    "Status worker '%s' worker type not implemented",
4335                    w->name);
4336     }
4337     JK_TRACE_EXIT(l);
4338     return JK_FALSE;
4339 }
4340
4341 static int recover_worker(jk_ws_service_t *s,
4342                           status_endpoint_t *p,
4343                           jk_logger_t *l)
4344 {
4345     const char *worker;
4346     const char *sub_worker;
4347     jk_worker_t *jw = NULL;
4348     lb_sub_worker_t *wr = NULL;
4349     ajp_worker_t *aw = NULL;
4350     status_worker_t *w = p->worker;
4351
4352     JK_TRACE_ENTER(l);
4353     if (fetch_worker_and_sub_worker(p, "recovering", &worker, &sub_worker, l) == JK_FALSE ||
4354         search_worker(s, p, &jw, worker, l) == JK_FALSE) {
4355         JK_TRACE_EXIT(l);
4356         return JK_FALSE;
4357     }
4358
4359     if (search_sub_worker(s, p, jw, worker, &wr, sub_worker,
4360                          NULL, l) == JK_FALSE) {
4361         JK_TRACE_EXIT(l);
4362         return JK_FALSE;
4363     }
4364
4365     aw = (ajp_worker_t *)wr->worker->worker_private;
4366     if (wr->s->state == JK_LB_STATE_ERROR) {
4367         lb_worker_t *lb = NULL;
4368
4369         /* We need an lb to correct the lb_value */
4370         if (check_valid_lb(s, p, jw, worker, &lb, 0, l) == JK_FALSE) {
4371             JK_TRACE_EXIT(l);
4372             return JK_FALSE;
4373         }
4374
4375         if (lb->lbmethod != JK_LB_METHOD_BUSYNESS) {
4376             unsigned int i;
4377             jk_uint64_t curmax = 0;
4378
4379             for (i = 0; i < lb->num_of_workers; i++) {
4380                 if (lb->lb_workers[i].s->lb_value > curmax) {
4381                     curmax = lb->lb_workers[i].s->lb_value;
4382                 }
4383             }
4384             wr->s->lb_value = curmax;
4385         }
4386
4387         aw->s->reply_timeouts = 0;
4388         wr->s->state = JK_LB_STATE_RECOVER;
4389         jk_log(l, JK_LOG_INFO,
4390                "Status worker '%s' marked worker '%s' sub worker '%s' for recovery",
4391                w->name, worker ? worker : "(null)", sub_worker ? sub_worker : "(null)");
4392         JK_TRACE_EXIT(l);
4393         return JK_TRUE;
4394     }
4395     jk_log(l, JK_LOG_WARNING,
4396            "Status worker '%s' could not mark worker '%s' sub worker '%s' for recovery - state %s is not an error state",
4397            w->name, worker ? worker : "(null)", sub_worker ? sub_worker : "(null)",
4398            jk_lb_get_state(wr, l));
4399     JK_TRACE_EXIT(l);
4400     return JK_FALSE;
4401 }
4402
4403 static int dump_config(jk_ws_service_t *s,
4404                        status_endpoint_t *p,
4405                        int mime, jk_logger_t *l)
4406 {
4407     status_worker_t *w = p->worker;
4408     jk_worker_env_t *we = w->we;
4409     jk_map_t *init_data = we->init_data;
4410
4411     JK_TRACE_ENTER(l);
4412
4413     if (init_data) {
4414         int l = jk_map_size(init_data);
4415         int i;
4416         if (mime == JK_STATUS_MIME_HTML) {
4417             jk_puts(s, "<hr/><h2>Configuration Data</h2><hr/>\n");
4418             jk_puts(s, "This dump does not include any changes applied by the status worker\n");
4419             jk_puts(s, "to the configuration after the initial startup\n");
4420             jk_puts(s, "<PRE>\n");
4421         }
4422         else if (mime == JK_STATUS_MIME_XML) {
4423             jk_print_xml_start_elt(s, w, 2, 0, "configuration");
4424         }
4425         else if (mime == JK_STATUS_MIME_TXT) {
4426             jk_puts(s, "Configuration:\n");
4427         }
4428         for (i=0;i<l;i++) {
4429             const char *name = jk_map_name_at(init_data, i);
4430             if (name) {
4431                 const char *value;
4432                 size_t nl = strlen(name);
4433                 if (nl > sizeof(".secret") &&
4434                     strcmp(name + nl - 7, ".secret") == 0) {
4435                     continue;
4436                 }
4437                 value = jk_map_value_at(init_data, i);
4438                 if (!value)
4439                     value = "(null)";
4440                 if (mime == JK_STATUS_MIME_HTML ||
4441                     mime == JK_STATUS_MIME_PROP ||
4442                     mime == JK_STATUS_MIME_TXT) {
4443                     jk_putv(s, name, "=", value, "\n", NULL);
4444                 }
4445                 else if (mime == JK_STATUS_MIME_XML) {
4446                      jk_print_xml_att_string(s, 4, name, value);
4447                 }
4448             }
4449         }
4450         if (mime == JK_STATUS_MIME_HTML) {
4451             jk_puts(s, "</PRE>\n");
4452         }
4453         else if (mime == JK_STATUS_MIME_XML) {
4454             jk_print_xml_stop_elt(s, 2, 1);
4455         }
4456     }
4457     else {
4458         JK_TRACE_EXIT(l);
4459         return JK_FALSE;
4460     }
4461
4462     JK_TRACE_EXIT(l);
4463     return JK_TRUE;
4464 }
4465
4466 /*
4467  * Return values of service() method for status worker:
4468  * return value  is_error              reason
4469  * JK_FALSE      JK_HTTP_SERVER_ERROR  Invalid parameters (null values)
4470  * JK_TRUE       JK_HTTP_OK            All other cases
4471  */
4472 static int JK_METHOD service(jk_endpoint_t *e,
4473                              jk_ws_service_t *s,
4474                              jk_logger_t *l, int *is_error)
4475 {
4476     int cmd;
4477     jk_uint32_t cmd_props;
4478     int mime;
4479     int refresh;
4480     int read_only = 0;
4481     const char *arg;
4482     char *err = NULL;
4483     status_endpoint_t *p;
4484     status_worker_t *w;
4485     int denied = 0;
4486
4487     JK_TRACE_ENTER(l);
4488
4489     if (!e || !e->endpoint_private || !s || !is_error) {
4490         JK_LOG_NULL_PARAMS(l);
4491         if (is_error)
4492             *is_error = JK_HTTP_SERVER_ERROR;
4493         JK_TRACE_EXIT(l);
4494         return JK_FALSE;
4495     }
4496
4497     p = e->endpoint_private;
4498     w = p->worker;
4499
4500     /* Set returned error to OK */
4501     *is_error = JK_HTTP_OK;
4502
4503     if (w->num_of_users) {
4504         if (s->remote_user) {
4505             unsigned int i;
4506             denied = 1;
4507             for (i = 0; i < w->num_of_users; i++) {
4508                 if (w->user_case_insensitive) {
4509                     if (!strcasecmp(s->remote_user, w->user_names[i])) {
4510                         denied = 0;
4511                         break;
4512                     }
4513                 }
4514                 else {
4515                     if (!strcmp(s->remote_user, w->user_names[i])) {
4516                         denied = 0;
4517                         break;
4518                     }
4519                 }
4520             }
4521         }
4522         else {
4523             denied = 2;
4524         }
4525     }
4526
4527     /* Step 1: Process GET params and update configuration */
4528     if (status_parse_uri(s, p, l) != JK_TRUE) {
4529         err = "Error during parsing of URI";
4530     }
4531     status_get_string(p, JK_STATUS_ARG_CMD, NULL, &arg, l);
4532     cmd = status_cmd_int(arg);
4533     cmd_props = status_cmd_props(cmd);
4534     status_get_string(p, JK_STATUS_ARG_MIME, NULL, &arg, l);
4535     mime = status_mime_int(arg);
4536     refresh = status_get_int(p, JK_STATUS_ARG_REFRESH, 0, l);
4537     if (w->read_only) {
4538         read_only = 1;
4539     }
4540     else {
4541         read_only = status_get_int(p, JK_STATUS_ARG_OPTIONS, 0, l) &
4542                     JK_STATUS_ARG_OPTION_READ_ONLY;
4543     }
4544
4545     if (mime == JK_STATUS_MIME_HTML) {
4546         s->start_response(s, 200, "OK", headers_names, headers_vhtml, 3);
4547         jk_puts(s, JK_STATUS_HEAD);
4548     }
4549     else if (mime == JK_STATUS_MIME_XML) {
4550         s->start_response(s, 200, "OK", headers_names, headers_vxml, 3);
4551         jk_puts(s, JK_STATUS_XMLH);
4552         if (w->doctype) {
4553             jk_putv(s, w->doctype, "\n", NULL);
4554         }
4555         jk_print_xml_start_elt(s, w, 0, 0, "status");
4556         if (w->xmlns && strlen(w->xmlns))
4557             jk_putv(s, "  ", w->xmlns, NULL);
4558         jk_print_xml_stop_elt(s, 0, 0);
4559     }
4560     else {
4561         s->start_response(s, 200, "OK", headers_names, headers_vtxt, 3);
4562     }
4563
4564     if (denied == 0) {
4565         if (JK_IS_DEBUG_LEVEL(l))
4566             jk_log(l, JK_LOG_DEBUG,
4567                    "Status worker '%s' service allowed for user '%s' [%s] from %s [%s]",
4568                    w->name,
4569                    s->remote_user ? s->remote_user : "(null)",
4570                    s->auth_type ? s->auth_type : "(null)",
4571                    s->remote_addr ? s->remote_addr : "(null)",
4572                    s->remote_host ? s->remote_host : "(null)");
4573     }
4574     else if (denied == 1) {
4575         err = "Access denied.";
4576         jk_log(l, JK_LOG_WARNING,
4577                "Status worker '%s' service denied for user '%s' [%s] from %s [%s]",
4578                w->name,
4579                s->remote_user ? s->remote_user : "(null)",
4580                s->auth_type ? s->auth_type : "(null)",
4581                s->remote_addr ? s->remote_addr : "(null)",
4582                s->remote_host ? s->remote_host : "(null)");
4583     }
4584     else if (denied == 2) {
4585         err = "Access denied.";
4586         jk_log(l, JK_LOG_WARNING,
4587                "Status worker '%s' service denied (no user) [%s] from %s [%s]",
4588                w->name,
4589                s->remote_user ? s->remote_user : "(null)",
4590                s->auth_type ? s->auth_type : "(null)",
4591                s->remote_addr ? s->remote_addr : "(null)",
4592                s->remote_host ? s->remote_host : "(null)");
4593     }
4594     else {
4595         err = "Access denied.";
4596         jk_log(l, JK_LOG_WARNING,
4597                "Status worker '%s' service denied (unknown reason) for user '%s' [%s] from %s [%s]",
4598                w->name,
4599                s->remote_user ? s->remote_user : "(null)",
4600                s->auth_type ? s->auth_type : "(null)",
4601                s->remote_addr ? s->remote_addr : "(null)",
4602                s->remote_host ? s->remote_host : "(null)");
4603     }
4604
4605     if (!err) {
4606         if (read_only && !(cmd_props & JK_STATUS_CMD_PROP_READONLY)) {
4607             err = "This command is not allowed in read only mode.";
4608         }
4609     }
4610
4611     if (!err) {
4612         if (cmd == JK_STATUS_CMD_UNKNOWN) {
4613             err = "Invalid command.";
4614         }
4615         else if (mime == JK_STATUS_MIME_UNKNOWN) {
4616             err = "Invalid mime type.";
4617         }
4618         else if (cmd_props & JK_STATUS_CMD_PROP_CHECK_WORKER &&
4619                  (check_worker(s, p, cmd_props & JK_STATUS_CMD_PROP_WILDCARD, l) != JK_TRUE)) {
4620             err = p->msg;
4621         }
4622     }
4623
4624     if (!err) {
4625         char buf_time[JK_STATUS_TIME_BUF_SZ];
4626         char buf_tz[JK_STATUS_TIME_BUF_SZ];
4627         time_t clock = time(NULL);
4628         long unix_seconds = (long)clock;
4629         int rc_time = status_strftime(clock, mime, buf_time, buf_tz, l);
4630         if (cmd == JK_STATUS_CMD_UPDATE) {
4631             /* lock shared memory */
4632             jk_shm_lock();
4633             if (update_worker(s, p, l) == JK_FALSE) {
4634                 if (strncmp("OK", p->msg, 3))
4635                     err = p->msg;
4636                 else
4637                     err = "Update failed";
4638             }
4639             /* unlock the shared memory */
4640             jk_shm_unlock();
4641             if (mime == JK_STATUS_MIME_HTML) {
4642                 write_html_refresh_response(s, p, err, l);
4643             }
4644         }
4645         else if (cmd == JK_STATUS_CMD_RESET) {
4646             /* lock shared memory */
4647             jk_shm_lock();
4648             if (reset_worker(s, p, l) == JK_FALSE) {
4649                 err = "Reset failed";
4650             }
4651             /* unlock the shared memory */
4652             jk_shm_unlock();
4653             if (mime == JK_STATUS_MIME_HTML) {
4654                 write_html_refresh_response(s, p, err, l);
4655             }
4656         }
4657         else if (cmd == JK_STATUS_CMD_RECOVER) {
4658             /* lock shared memory */
4659             jk_shm_lock();
4660             if (recover_worker(s, p, l) == JK_FALSE) {
4661                 err = "Marking worker for recovery failed";
4662             }
4663             /* unlock the shared memory */
4664             jk_shm_unlock();
4665             if (mime == JK_STATUS_MIME_HTML) {
4666                 write_html_refresh_response(s, p, err, l);
4667             }
4668         }
4669         else {
4670             if (mime == JK_STATUS_MIME_XML) {
4671                 jk_print_xml_start_elt(s, w, 0, 0, "server");
4672                 jk_print_xml_att_string(s, 2, "name", s->server_name);
4673                 jk_print_xml_att_int(s, 2, "port", s->server_port);
4674                 jk_print_xml_stop_elt(s, 0, 1);
4675                 if (cmd_props & JK_STATUS_CMD_PROP_HEAD) {
4676                     if (rc_time > 0 ) {
4677                         jk_print_xml_start_elt(s, w, 0, 0, "time");
4678                         jk_print_xml_att_string(s, 2, "datetime", buf_time);
4679                         jk_print_xml_att_string(s, 2, "tz", buf_tz);
4680                         jk_print_xml_att_long(s, 2, "unix", unix_seconds);
4681                         jk_print_xml_stop_elt(s, 0, 1);
4682                     }
4683                     jk_print_xml_start_elt(s, w, 0, 0, "software");
4684                     jk_print_xml_att_string(s, 2, "web_server", s->server_software);
4685                     jk_print_xml_att_string(s, 2, "jk_version", JK_FULL_EXPOSED_VERSION);
4686                     jk_print_xml_stop_elt(s, 0, 1);
4687                 }
4688                 if (cmd == JK_STATUS_CMD_LIST) {
4689                     /* Step 2: Display configuration */
4690                     if (list_workers(s, p, l) != JK_TRUE) {
4691                         err = "Error in listing the workers.";
4692                     }
4693                 }
4694                 else if (cmd == JK_STATUS_CMD_SHOW) {
4695                     /* Step 2: Display detailed configuration */
4696                     if (show_worker(s, p, l) != JK_TRUE) {
4697                         err = "Error in showing this worker.";
4698                     }
4699                 }
4700             }
4701             else if (mime == JK_STATUS_MIME_TXT) {
4702                 jk_puts(s, "Server:");
4703                 jk_printf(s, " name=%s", s->server_name);
4704                 jk_printf(s, " port=%d", s->server_port);
4705                 jk_puts(s, "\n");
4706                 if (cmd_props & JK_STATUS_CMD_PROP_HEAD) {
4707                     if (rc_time > 0) {
4708                         jk_puts(s, "Time:");
4709                         jk_printf(s, " datetime=%s", buf_time);
4710                         jk_printf(s, " tz=%s", buf_tz);
4711                         jk_printf(s, " unix=%ld", unix_seconds);
4712                         jk_puts(s, "\n");
4713                     }
4714                     jk_puts(s, "Software:");
4715                     jk_printf(s, " web_server=\"%s\"", s->server_software);
4716                     jk_printf(s, " jk_version=%s", JK_FULL_EXPOSED_VERSION);
4717                     jk_puts(s, "\n");
4718                 }
4719                 if (cmd == JK_STATUS_CMD_LIST) {
4720                     /* Step 2: Display configuration */
4721                     if (list_workers(s, p, l) != JK_TRUE) {
4722                         err = "Error in listing the workers.";
4723                     }
4724                 }
4725                 else if (cmd == JK_STATUS_CMD_SHOW) {
4726                     /* Step 2: Display detailed configuration */
4727                     if (show_worker(s, p, l) != JK_TRUE) {
4728                         err = "Error in showing this worker.";
4729                     }
4730                 }
4731             }
4732             else if (mime == JK_STATUS_MIME_PROP) {
4733                 jk_print_prop_att_string(s, w, NULL, "server_name", s->server_name);
4734                 jk_print_prop_att_int(s, w, NULL, "server_port", s->server_port);
4735                 if (cmd_props & JK_STATUS_CMD_PROP_HEAD) {
4736                     if (rc_time > 0) {
4737                         jk_print_prop_att_string(s, w, NULL, "time_datetime", buf_time);
4738                         jk_print_prop_att_string(s, w, NULL, "time_tz", buf_tz);
4739                         jk_print_prop_att_long(s, w, NULL, "time_unix", unix_seconds);
4740                     }
4741                     jk_print_prop_att_string(s, w, NULL, "web_server", s->server_software);
4742                     jk_print_prop_att_string(s, w, NULL, "jk_version", JK_FULL_EXPOSED_VERSION);
4743                 }
4744                 if (cmd == JK_STATUS_CMD_LIST) {
4745                     /* Step 2: Display configuration */
4746                     if (list_workers(s, p, l) != JK_TRUE) {
4747                         err = "Error in listing the workers.";
4748                     }
4749                 }
4750                 else if (cmd == JK_STATUS_CMD_SHOW) {
4751                     /* Step 2: Display detailed configuration */
4752                     if (show_worker(s, p, l) != JK_TRUE) {
4753                         err = "Error in showing this worker.";
4754                     }
4755                 }
4756             }
4757             else if (mime == JK_STATUS_MIME_HTML) {
4758                 if (cmd_props & JK_STATUS_CMD_PROP_REFRESH &&
4759                     refresh > 0) {
4760                     jk_printf(s, "\n<meta http-equiv=\"Refresh\" content=\"%d;url=%s?%s\">",
4761                           refresh, s->req_uri, p->query_string);
4762                 }
4763                 if (w->css) {
4764                     jk_putv(s, "\n<link rel=\"stylesheet\" type=\"text/css\" href=\"",
4765                             w->css, "\" />\n", NULL);
4766                 }
4767                 jk_puts(s, JK_STATUS_HEND);
4768                 jk_puts(s, "<h1>JK Status Manager for ");
4769                 jk_puts(s, s->server_name);
4770                 jk_printf(s, ":%d", s->server_port);
4771                 if (read_only) {
4772                     jk_puts(s, " (read only)");
4773                 }
4774                 jk_puts(s, "</h1>\n\n");
4775                 if (cmd_props & JK_STATUS_CMD_PROP_HEAD) {
4776                     jk_putv(s, "<table><tr><td>Server Version:</td><td>",
4777                             s->server_software, "</td><td>&nbsp;&nbsp;&nbsp;</td><td>", NULL);
4778                     if (rc_time > 0) {
4779                         jk_putv(s, "Server Time:</td><td>", buf_time, NULL);
4780                     }
4781                     jk_puts(s, "</td></tr>\n");
4782                     jk_putv(s, "<tr><td>JK Version:</td><td>",
4783                             JK_FULL_EXPOSED_VERSION, "</td><td></td><td>", NULL);
4784                     jk_printf(s, "Unix Seconds:</td><td>%d", unix_seconds);
4785                     jk_puts(s, "</td></tr></table>\n<hr/>\n");
4786                 }
4787                 jk_puts(s, "<table><tbody valign=\"baseline\"><tr>\n");
4788                 if (cmd_props & JK_STATUS_CMD_PROP_REFRESH) {
4789                     jk_puts(s, "<td>");
4790                     if (refresh > 0) {
4791                         const char *str = p->query_string;
4792                         char *buf = jk_pool_alloc(s->pool, sizeof(char *) * (strlen(str)+1));
4793                         int result = 0;
4794                         size_t scan = 0;
4795                         size_t len = strlen(JK_STATUS_ARG_REFRESH);
4796
4797                         while (str[scan] != '\0') {
4798                             if (strncmp(&str[scan], JK_STATUS_ARG_REFRESH, len) == 0 &&
4799                                 str[scan+len] == '=') {
4800                                 scan += len + 1;
4801                                 while (str[scan] != '\0' && str[scan] != '&')
4802                                     scan++;
4803                                 if (str[scan] == '&')
4804                                     scan++;
4805                             }
4806                             else {
4807                                 if (result > 0 && str[scan] != '\0' && str[scan] != '&') {
4808                                     buf[result] = '&';
4809                                     result++;
4810                                 }
4811                                 while (str[scan] != '\0' && str[scan] != '&') {
4812                                     buf[result] = str[scan];
4813                                     result++;
4814                                     scan++;
4815                                 }
4816                                 if (str[scan] == '&')
4817                                     scan++;
4818                             }
4819                         }
4820                         buf[result] = '\0';
4821
4822                         jk_putv(s, "[<a href=\"", s->req_uri, NULL);
4823                         if (buf && buf[0])
4824                             jk_putv(s, "?", buf, NULL);
4825                         jk_puts(s, "\">Stop auto refresh</a>]");
4826                     }
4827                     else {
4828                         status_start_form(s, p, "get", JK_STATUS_CMD_UNKNOWN, JK_STATUS_ARG_REFRESH, l);
4829                         jk_puts(s, "<input type=\"submit\" value=\"Start auto refresh\"/>\n");
4830                         jk_putv(s, "(every ",
4831                                 "<input name=\"", JK_STATUS_ARG_REFRESH,
4832                                 "\" type=\"text\" size=\"3\" value=\"",
4833                                 JK_STATUS_REFRESH_DEF "\"/> ",
4834                                 "seconds)", NULL);
4835                         jk_puts(s, "</form>\n");
4836                     }
4837                     jk_puts(s, "</td><td>&nbsp;&nbsp;|&nbsp;&nbsp;</td>\n");
4838                 }
4839                 if (cmd_props & JK_STATUS_CMD_PROP_FMT) {
4840                     jk_puts(s, "<td>\n");
4841                     status_start_form(s, p, "get", JK_STATUS_CMD_UNKNOWN, JK_STATUS_ARG_MIME, l);
4842                     jk_puts(s, "<input type=\"submit\" value=\"Change format\"/>\n");
4843                     jk_putv(s, "<select name=\"", JK_STATUS_ARG_MIME, "\" size=\"1\">", NULL);
4844                     jk_putv(s, "<option value=\"", JK_STATUS_MIME_TEXT_XML, "\">XML</option>", NULL);
4845                     jk_putv(s, "<option value=\"", JK_STATUS_MIME_TEXT_PROP, "\">Properties</option>", NULL);
4846                     jk_putv(s, "<option value=\"", JK_STATUS_MIME_TEXT_TXT, "\">Text</option>", NULL);
4847                     jk_puts(s, "</select></form>\n");
4848                     jk_puts(s, "</td>\n");
4849                 }
4850                 jk_puts(s, "</tr></table>\n");
4851                 jk_puts(s, "<table><tbody valign=\"baseline\"><tr>\n");
4852                 if (cmd_props & JK_STATUS_CMD_PROP_BACK_LINK) {
4853                     int from;
4854                     jk_puts(s, "<td>\n");
4855                     status_get_string(p, JK_STATUS_ARG_FROM, NULL, &arg, l);
4856                     from = status_cmd_int(arg);
4857                     jk_puts(s, "[");
4858                     if (cmd_props & JK_STATUS_CMD_PROP_BACK_LIST ||
4859                         from == JK_STATUS_CMD_LIST) {
4860                         status_write_uri(s, p, "Back to worker list", JK_STATUS_CMD_LIST, JK_STATUS_MIME_UNKNOWN,
4861                                          "", "", 0, 0, "", l);
4862                     }
4863                     else {
4864                         status_write_uri(s, p, "Back to worker view", JK_STATUS_CMD_SHOW, JK_STATUS_MIME_UNKNOWN,
4865                                          NULL, NULL, 0, 0, "", l);
4866                     }
4867                     jk_puts(s, "]&nbsp;&nbsp;");
4868                     jk_puts(s, "</td>\n");
4869                 }
4870                 if (cmd_props & JK_STATUS_CMD_PROP_SWITCH_RO) {
4871                     jk_puts(s, "<td>\n");
4872                     if (!w->read_only) {
4873                         jk_puts(s, "[");
4874                         if (read_only) {
4875                             status_write_uri(s, p, "Read/Write", 0, JK_STATUS_MIME_UNKNOWN,
4876                                              NULL, NULL, 0, JK_STATUS_ARG_OPTION_READ_ONLY, NULL, l);
4877                         }
4878                         else {
4879                             status_write_uri(s, p, "Read Only", 0, JK_STATUS_MIME_UNKNOWN,
4880                                              NULL, NULL, JK_STATUS_ARG_OPTION_READ_ONLY, 0, NULL, l);
4881                         }
4882                         jk_puts(s, "]&nbsp;&nbsp;\n");
4883                     }
4884                     jk_puts(s, "</td>\n");
4885                 }
4886                 if (cmd_props & JK_STATUS_CMD_PROP_DUMP_LINK) {
4887                     jk_puts(s, "<td>\n");
4888                     jk_puts(s, "[");
4889                     status_write_uri(s, p, "Dump", JK_STATUS_CMD_DUMP, JK_STATUS_MIME_UNKNOWN,
4890                                      NULL, NULL, 0, 0, NULL, l);
4891                     jk_puts(s, "]&nbsp;&nbsp;\n");
4892                     jk_puts(s, "</td>\n");
4893                 }
4894                 if (cmd_props & JK_STATUS_CMD_PROP_LINK_HELP &&
4895                     (cmd == JK_STATUS_CMD_LIST || !read_only)) {
4896                     jk_puts(s, "<td>\n");
4897                     jk_puts(s, "[");
4898                     if (cmd == JK_STATUS_CMD_LIST) {
4899                         jk_puts(s, "<b>S</b>=Show only this worker, ");
4900                     }
4901                     jk_puts(s, "<b>E</b>=Edit worker, <b>R</b>=Reset worker state, <b>T</b>=Try worker recovery");
4902                     jk_puts(s, "]<br/>\n");
4903                     jk_puts(s, "</td>\n");
4904                 }
4905                 jk_puts(s, "</tr></table>\n");
4906                 if (cmd == JK_STATUS_CMD_LIST) {
4907                     /* Step 2: Display configuration */
4908                     if (list_workers(s, p, l) != JK_TRUE) {
4909                         err = "Error in listing the workers.";
4910                     }
4911                 }
4912                 else if (cmd == JK_STATUS_CMD_SHOW) {
4913                     /* Step 2: Display detailed configuration */
4914                     if (show_worker(s, p, l) != JK_TRUE) {
4915                         err = "Error in showing this worker.";
4916                     }
4917                 }
4918                 else if (cmd == JK_STATUS_CMD_EDIT) {
4919                     /* Step 2: Display edit form */
4920                     if (edit_worker(s, p, l) != JK_TRUE) {
4921                         err = "Error in generating this worker's configuration form.";
4922                     }
4923                 }
4924             }
4925             if (cmd == JK_STATUS_CMD_DUMP) {
4926                 if (dump_config(s, p, mime, l) == JK_FALSE) {
4927                     err = "Dumping configuration failed";
4928                 }
4929             }
4930             if (cmd_props & JK_STATUS_CMD_PROP_LEGEND) {
4931                 display_legend(s, p, l);
4932             }
4933         }
4934     }
4935     if (err) {
4936         jk_log(l, JK_LOG_WARNING, "Status worker '%s': %s", w->name, err);
4937         if (mime == JK_STATUS_MIME_HTML) {
4938             jk_putv(s, "<p><b>Result: ERROR - ", err, "</b><br/>", NULL);
4939             jk_putv(s, "<a href=\"", s->req_uri, "\">JK Status Manager Start Page</a></p>", NULL);
4940         }
4941         else if (mime == JK_STATUS_MIME_XML) {
4942             jk_print_xml_start_elt(s, w, 2, 0, "result");
4943             jk_print_xml_att_string(s, 4, "type", "ERROR");
4944             jk_print_xml_att_string(s, 4, "message", err);
4945             jk_print_xml_stop_elt(s, 2, 1);
4946         }
4947         else if (mime == JK_STATUS_MIME_TXT) {
4948             jk_puts(s, "Result:");
4949             jk_printf(s, " type=%s", "ERROR");
4950             jk_printf(s, " message=\"%s\"", err);
4951             jk_puts(s, "\n");
4952         }
4953         else {
4954             jk_print_prop_att_string(s, w, "result", "type", "ERROR");
4955             jk_print_prop_att_string(s, w, "result", "message", err);
4956         }
4957     }
4958     else {
4959         if (mime == JK_STATUS_MIME_HTML) {
4960             jk_putv(s, "<p><a href=\"", s->req_uri, "\">JK Status Manager Start Page</a></p>", NULL);
4961         }
4962         else if (mime == JK_STATUS_MIME_XML) {
4963             jk_print_xml_start_elt(s, w, 2, 0, "result");
4964             jk_print_xml_att_string(s, 4, "type", "OK");
4965             jk_print_xml_att_string(s, 4, "message", "Action finished");
4966             jk_print_xml_stop_elt(s, 2, 1);
4967         }
4968         else if (mime == JK_STATUS_MIME_TXT) {
4969             jk_puts(s, "Result:");
4970             jk_printf(s, " type=%s", "OK");
4971             jk_printf(s, " message=\"%s\"", "Action finished");
4972             jk_puts(s, "\n");
4973         }
4974         else {
4975             jk_print_prop_att_string(s, w, "result", "type", "OK");
4976             jk_print_prop_att_string(s, w, "result", "message", "Action finished");
4977         }
4978     }
4979     if (mime == JK_STATUS_MIME_HTML) {
4980         if (w->css) {
4981             jk_putv(s, "<hr/><div class=\"footer\">", JK_STATUS_COPYRIGHT,
4982                     "</div>\n", NULL);
4983         }
4984         else {
4985             jk_putv(s, "<hr/><p align=\"center\"><small>", JK_STATUS_COPYRIGHT,
4986                     "</small></p>\n", NULL);
4987         }
4988         jk_puts(s, JK_STATUS_BEND);
4989     }
4990     else if (mime == JK_STATUS_MIME_XML) {
4991         jk_print_xml_close_elt(s, w, 0, "status");
4992     }
4993     JK_TRACE_EXIT(l);
4994     return JK_TRUE;
4995 }
4996
4997 static int JK_METHOD done(jk_endpoint_t **e, jk_logger_t *l)
4998 {
4999     JK_TRACE_ENTER(l);
5000
5001     if (e && *e && (*e)->endpoint_private) {
5002         status_endpoint_t *p = (*e)->endpoint_private;
5003
5004         jk_map_free(&(p->req_params));
5005         free(p);
5006         *e = NULL;
5007         JK_TRACE_EXIT(l);
5008         return JK_TRUE;
5009     }
5010
5011     JK_LOG_NULL_PARAMS(l);
5012     JK_TRACE_EXIT(l);
5013     return JK_FALSE;
5014 }
5015
5016 static int JK_METHOD validate(jk_worker_t *pThis,
5017                               jk_map_t *props,
5018                               jk_worker_env_t *we, jk_logger_t *l)
5019 {
5020     JK_TRACE_ENTER(l);
5021
5022     if (pThis && pThis->worker_private) {
5023         JK_TRACE_EXIT(l);
5024         return JK_TRUE;
5025     }
5026
5027     JK_LOG_NULL_PARAMS(l);
5028     JK_TRACE_EXIT(l);
5029     return JK_FALSE;
5030 }
5031
5032 static int JK_METHOD init(jk_worker_t *pThis,
5033                           jk_map_t *props,
5034                           jk_worker_env_t *we, jk_logger_t *l)
5035 {
5036     JK_TRACE_ENTER(l);
5037     if (pThis && pThis->worker_private) {
5038         status_worker_t *p = pThis->worker_private;
5039         char **good_rating;
5040         unsigned int num_of_good;
5041         char **bad_rating;
5042         unsigned int num_of_bad;
5043         unsigned int i;
5044         p->we = we;
5045         p->css = jk_get_worker_style_sheet(props, p->name, NULL);
5046         p->prefix = jk_get_worker_prop_prefix(props, p->name, JK_STATUS_PREFIX_DEF);
5047         p->ns = jk_get_worker_name_space(props, p->name, JK_STATUS_NS_DEF);
5048         p->xmlns = jk_get_worker_xmlns(props, p->name, JK_STATUS_XMLNS_DEF);
5049         p->doctype = jk_get_worker_xml_doctype(props, p->name, NULL);
5050         p->read_only = jk_get_is_read_only(props, p->name);
5051         p->user_case_insensitive = jk_get_worker_user_case_insensitive(props, p->name);
5052         if (JK_IS_DEBUG_LEVEL(l))
5053             jk_log(l, JK_LOG_DEBUG,
5054                    "Status worker '%s' is %s and has css '%s', prefix '%s', name space '%s', xml name space '%s', document type '%s'",
5055                    p->name,
5056                    p->read_only ? "read-only" : "read/write",
5057                    p->css ? p->css : "(null)",
5058                    p->prefix ? p->prefix : "(null)",
5059                    p->ns ? p->ns : "(null)",
5060                    p->xmlns ? p->xmlns : "(null)",
5061                    p->doctype ? p->doctype : "(null)");
5062         if (jk_get_worker_user_list(props, p->name,
5063                                     &(p->user_names),
5064                                     &(p->num_of_users)) && p->num_of_users) {
5065             for (i = 0; i < p->num_of_users; i++) {
5066                 if (JK_IS_DEBUG_LEVEL(l))
5067                     jk_log(l, JK_LOG_DEBUG,
5068                             "Status worker '%s' restricting access to user '%s' case %s",
5069                             p->name, p->user_names[i],
5070                             p->user_case_insensitive ? "insensitive" : "sensitive");
5071             }
5072         }
5073         if (jk_get_worker_good_rating(props, p->name,
5074                                       &good_rating,
5075                                       &num_of_good) && num_of_good) {
5076             p->good_mask = 0;
5077             for (i = 0; i < num_of_good; i++) {
5078                 if (JK_IS_DEBUG_LEVEL(l))
5079                     jk_log(l, JK_LOG_DEBUG,
5080                             "Status worker '%s' rating as good: '%s'",
5081                             p->name, good_rating[i]);
5082                 p->good_mask |= status_get_rating(good_rating[i], l);
5083             }
5084         }
5085         else {
5086             p->good_mask = JK_STATUS_MASK_GOOD_DEF;
5087         }
5088         if (jk_get_worker_bad_rating(props, p->name,
5089                                       &bad_rating,
5090                                       &num_of_bad) && num_of_bad) {
5091             p->bad_mask = 0;
5092             for (i = 0; i < num_of_bad; i++) {
5093                 if (JK_IS_DEBUG_LEVEL(l))
5094                     jk_log(l, JK_LOG_DEBUG,
5095                             "Status worker '%s' rating as bad: '%s'",
5096                             p->name, bad_rating[i]);
5097                 p->bad_mask |= status_get_rating(bad_rating[i], l);
5098             }
5099         }
5100         else {
5101             p->bad_mask = JK_STATUS_MASK_BAD_DEF;
5102         }
5103         if (JK_IS_DEBUG_LEVEL(l))
5104             jk_log(l, JK_LOG_DEBUG,
5105                    "Status worker '%s' has good rating for '%08" JK_UINT32_T_HEX_FMT
5106                    "' and bad rating for '%08" JK_UINT32_T_HEX_FMT "'",
5107                    p->name,
5108                    p->good_mask,
5109                    p->bad_mask);
5110         if (p->good_mask & p->bad_mask)
5111             jk_log(l, JK_LOG_WARNING,
5112                    "Status worker '%s' has non empty intersection '%08" JK_UINT32_T_HEX_FMT
5113                    "' between good rating for '%08" JK_UINT32_T_HEX_FMT
5114                    "' and bad rating for '%08" JK_UINT32_T_HEX_FMT "'",
5115                    p->name,
5116                    p->good_mask & p->bad_mask,
5117                    p->good_mask,
5118                    p->bad_mask);
5119     }
5120     JK_TRACE_EXIT(l);
5121     return JK_TRUE;
5122 }
5123
5124 static int JK_METHOD get_endpoint(jk_worker_t *pThis,
5125                                   jk_endpoint_t **pend, jk_logger_t *l)
5126 {
5127     JK_TRACE_ENTER(l);
5128
5129     if (pThis && pThis->worker_private && pend) {
5130         status_endpoint_t *p = (status_endpoint_t *) malloc(sizeof(status_endpoint_t));
5131         p->worker = pThis->worker_private;
5132         p->endpoint.endpoint_private = p;
5133         p->endpoint.service = service;
5134         p->endpoint.done = done;
5135         p->req_params = NULL;
5136         p->msg = NULL;
5137         *pend = &p->endpoint;
5138
5139         JK_TRACE_EXIT(l);
5140         return JK_TRUE;
5141     }
5142     else {
5143         JK_LOG_NULL_PARAMS(l);
5144     }
5145
5146     JK_TRACE_EXIT(l);
5147     return JK_FALSE;
5148 }
5149
5150 static int JK_METHOD destroy(jk_worker_t **pThis, jk_logger_t *l)
5151 {
5152     JK_TRACE_ENTER(l);
5153
5154     if (pThis && *pThis && (*pThis)->worker_private) {
5155         status_worker_t *private_data = (*pThis)->worker_private;
5156
5157         jk_close_pool(&private_data->p);
5158         free(private_data);
5159
5160         JK_TRACE_EXIT(l);
5161         return JK_TRUE;
5162     }
5163
5164     JK_LOG_NULL_PARAMS(l);
5165     JK_TRACE_EXIT(l);
5166     return JK_FALSE;
5167 }
5168
5169 int JK_METHOD status_worker_factory(jk_worker_t **w,
5170                                     const char *name, jk_logger_t *l)
5171 {
5172     JK_TRACE_ENTER(l);
5173
5174     if (NULL != name && NULL != w) {
5175         status_worker_t *private_data =
5176             (status_worker_t *) calloc(1, sizeof(status_worker_t));
5177
5178         jk_open_pool(&private_data->p,
5179                         private_data->buf,
5180                         sizeof(jk_pool_atom_t) * TINY_POOL_SIZE);
5181
5182         private_data->name = name;
5183
5184         private_data->worker.worker_private = private_data;
5185         private_data->worker.validate = validate;
5186         private_data->worker.init = init;
5187         private_data->worker.get_endpoint = get_endpoint;
5188         private_data->worker.destroy = destroy;
5189
5190         *w = &private_data->worker;
5191         JK_TRACE_EXIT(l);
5192         return JK_STATUS_WORKER_TYPE;
5193     }
5194     else {
5195         JK_LOG_NULL_PARAMS(l);
5196     }
5197
5198     JK_TRACE_EXIT(l);
5199     return 0;
5200 }