xref: /trafficserver/iocore/cache/CachePages.cc (revision 4cfd5a73)
1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #include "P_Cache.h"
25 
26 #include "Show.h"
27 #include "I_Tasks.h"
28 #include "CacheControl.h"
29 
30 struct ShowCache : public ShowCont {
31   enum scan_type {
32     scan_type_lookup,
33     scan_type_delete,
34     scan_type_invalidate,
35   };
36 
37   int vol_index;
38   int seg_index;
39   scan_type scan_flag;
40   int urlstrs_index;
41   int linecount;
42   char (*show_cache_urlstrs)[500];
43   URL url;
44   CacheKey show_cache_key;
45   CacheVC *cache_vc;
46   MIOBuffer *buffer;
47   IOBufferReader *buffer_reader;
48   int64_t content_length;
49   VIO *cvio;
50   int showMain(int event, Event *e);
51   int lookup_url_form(int event, Event *e);
52   int delete_url_form(int event, Event *e);
53   int lookup_regex_form(int event, Event *e);
54   int delete_regex_form(int event, Event *e);
55   int invalidate_regex_form(int event, Event *e);
56 
57   int lookup_url(int event, Event *e);
58   int delete_url(int event, Event *e);
59   int lookup_regex(int event, Event *e);
60   int delete_regex(int event, Event *e);
61   int invalidate_regex(int event, Event *e);
62 
63   int handleCacheEvent(int event, Event *e);
64   int handleCacheDeleteComplete(int event, Event *e);
65   int handleCacheScanCallback(int event, Event *e);
66 
ShowCacheShowCache67   ShowCache(Continuation *c, HTTPHdr *h)
68     : ShowCont(c, h),
69       vol_index(0),
70       seg_index(0),
71       scan_flag(scan_type_lookup),
72       cache_vc(nullptr),
73       buffer(nullptr),
74       buffer_reader(nullptr),
75       content_length(0),
76       cvio(nullptr)
77   {
78     urlstrs_index = 0;
79     linecount     = 0;
80     int query_len;
81     char query[4096];
82     char unescapedQuery[sizeof(query)];
83     show_cache_urlstrs = nullptr;
84     URL *u             = h->url_get();
85 
86     // process the query string
87     if (u->query_get(&query_len) && query_len < static_cast<int>(sizeof(query))) {
88       strncpy(query, u->query_get(&query_len), query_len);
89       strncpy(unescapedQuery, u->query_get(&query_len), query_len);
90 
91       query[query_len] = unescapedQuery[query_len] = '\0';
92 
93       query_len = unescapifyStr(query);
94 
95       Debug("cache_inspector", "query params: '%s' len %d [unescaped]", unescapedQuery, query_len);
96       Debug("cache_inspector", "query params: '%s' len %d [escaped]", query, query_len);
97 
98       // remove 'C-m' s
99       unsigned l, m;
100       for (l = 0, m = 0; l < static_cast<unsigned>(query_len); l++) {
101         if (query[l] != '\015') {
102           query[m++] = query[l];
103         }
104       }
105       query[m] = '\0';
106 
107       unsigned nstrings = 1;
108       char *p           = strstr(query, "url=");
109       // count the no of urls
110       if (p) {
111         while ((p = strstr(p, "\n"))) {
112           nstrings++;
113           if (static_cast<size_t>(p - query) >= strlen(query) - 1) {
114             break;
115           } else {
116             p++;
117           }
118         }
119       }
120       // initialize url array
121       show_cache_urlstrs = new char[nstrings + 1][500];
122       memset(show_cache_urlstrs, '\0', (nstrings + 1) * 500 * sizeof(char));
123 
124       char *q, *t;
125       p = strstr(unescapedQuery, "url=");
126       if (p) {
127         p += 4; // 4 ==> strlen("url=")
128         t = strchr(p, '&');
129         if (!t) {
130           t = (char *)unescapedQuery + strlen(unescapedQuery);
131         }
132         for (int s = 0; p < t; s++) {
133           show_cache_urlstrs[s][0] = '\0';
134           q                        = strstr(p, "%0D%0A" /* \r\n */); // we used this in the JS to separate urls
135           if (!q) {
136             q = t;
137           }
138           ink_strlcpy(show_cache_urlstrs[s], p, q - p + 1);
139           p = q + 6; // +6 ==> strlen(%0D%0A)
140         }
141       }
142 
143       Debug("cache_inspector", "there were %d url(s) passed in", nstrings == 1 ? 1 : nstrings - 1);
144 
145       for (unsigned i = 0; i < nstrings; i++) {
146         if (show_cache_urlstrs[i][0] == '\0') {
147           continue;
148         }
149         Debug("cache_inspector", "URL %d: '%s'", i + 1, show_cache_urlstrs[i]);
150         unescapifyStr(show_cache_urlstrs[i]);
151         Debug("cache_inspector", "URL %d: '%s'", i + 1, show_cache_urlstrs[i]);
152       }
153     }
154 
155     SET_HANDLER(&ShowCache::showMain);
156   }
157 
~ShowCacheShowCache158   ~ShowCache() override
159   {
160     if (show_cache_urlstrs) {
161       delete[] show_cache_urlstrs;
162     }
163     url.destroy();
164   }
165 };
166 
167 #define STREQ_PREFIX(_x, _s) (!strncasecmp(_x, _s, sizeof(_s) - 1))
168 #define STREQ_LEN_PREFIX(_x, _l, _s) (path_len < sizeof(_s) && !strncasecmp(_x, _s, sizeof(_s) - 1))
169 
170 Action *
register_ShowCache(Continuation * c,HTTPHdr * h)171 register_ShowCache(Continuation *c, HTTPHdr *h)
172 {
173   ShowCache *theshowcache = new ShowCache(c, h);
174   URL *u                  = h->url_get();
175   int path_len;
176   const char *path = u->path_get(&path_len);
177 
178   if (!path) {
179   } else if (STREQ_PREFIX(path, "lookup_url_form")) {
180     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_url_form);
181   } else if (STREQ_PREFIX(path, "delete_url_form")) {
182     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_url_form);
183   } else if (STREQ_PREFIX(path, "lookup_regex_form")) {
184     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_regex_form);
185   } else if (STREQ_PREFIX(path, "delete_regex_form")) {
186     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_regex_form);
187   } else if (STREQ_PREFIX(path, "invalidate_regex_form")) {
188     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::invalidate_regex_form);
189   }
190 
191   else if (STREQ_PREFIX(path, "lookup_url")) {
192     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_url);
193   } else if (STREQ_PREFIX(path, "delete_url")) {
194     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_url);
195   } else if (STREQ_PREFIX(path, "lookup_regex")) {
196     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::lookup_regex);
197   } else if (STREQ_PREFIX(path, "delete_regex")) {
198     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::delete_regex);
199   } else if (STREQ_PREFIX(path, "invalidate_regex")) {
200     SET_CONTINUATION_HANDLER(theshowcache, &ShowCache::invalidate_regex);
201   }
202 
203   if (theshowcache->mutex->thread_holding) {
204     CONT_SCHED_LOCK_RETRY(theshowcache);
205   } else {
206     eventProcessor.schedule_imm(theshowcache, ET_TASK);
207   }
208 
209   return &theshowcache->action;
210 }
211 
212 int
showMain(int event,Event * e)213 ShowCache::showMain(int event, Event *e)
214 {
215   CHECK_SHOW(begin("Cache"));
216   CHECK_SHOW(show("<H3><A HREF=\"./lookup_url_form\">Lookup url</A></H3>\n"
217                   "<H3><A HREF=\"./delete_url_form\">Delete url</A></H3>\n"
218                   "<H3><A HREF=\"./lookup_regex_form\">Regex lookup</A></H3>\n"
219                   "<H3><A HREF=\"./delete_regex_form\">Regex delete</A></H3>\n"
220                   "<H3><A HREF=\"./invalidate_regex_form\">Regex invalidate</A></H3>\n\n"));
221   return complete(event, e);
222 }
223 
224 int
lookup_url_form(int event,Event * e)225 ShowCache::lookup_url_form(int event, Event *e)
226 {
227   CHECK_SHOW(begin("Cache Lookup"));
228   CHECK_SHOW(show("<FORM METHOD=\"GET\" ACTION=\"./lookup_url\">\n"
229                   "<H3>Lookup</H3>\n"
230                   "<INPUT TYPE=\"TEXT\" NAME=\"url\" value=\"http://\">\n"
231                   "<INPUT TYPE=\"SUBMIT\" value=\"Lookup\">\n"
232                   "</FORM>\n\n"));
233   return complete(event, e);
234 }
235 
236 int
delete_url_form(int event,Event * e)237 ShowCache::delete_url_form(int event, Event *e)
238 {
239   CHECK_SHOW(begin("Cache Delete"));
240   CHECK_SHOW(show("<FORM METHOD=\"GET\" ACTION=\"./delete_url\">\n"
241                   "<P><B>Type the list urls that you want to delete\n"
242                   "in the box below. The urls MUST be separated by\n"
243                   "new lines</B></P>\n\n"
244                   "<TEXTAREA NAME=\"url\" rows=10 cols=50>"
245                   "http://"
246                   "</TEXTAREA>\n"
247                   "<INPUT TYPE=\"SUBMIT\" value=\"Delete\">\n"
248                   "</FORM>\n\n"));
249   return complete(event, e);
250 }
251 
252 int
lookup_regex_form(int event,Event * e)253 ShowCache::lookup_regex_form(int event, Event *e)
254 {
255   CHECK_SHOW(begin("Cache Regex Lookup"));
256   CHECK_SHOW(show("<FORM METHOD=\"GET\" ACTION=\"./lookup_regex\">\n"
257                   "<P><B>Type the list of regular expressions that you want to lookup\n"
258                   "in the box below. The regular expressions MUST be separated by\n"
259                   "new lines</B></P>\n\n"
260                   "<TEXTAREA NAME=\"url\" rows=10 cols=50>"
261                   "http://"
262                   "</TEXTAREA>\n"
263                   "<INPUT TYPE=\"SUBMIT\" value=\"Lookup\">\n"
264                   "</FORM>\n\n"));
265   return complete(event, e);
266 }
267 
268 int
delete_regex_form(int event,Event * e)269 ShowCache::delete_regex_form(int event, Event *e)
270 {
271   CHECK_SHOW(begin("Cache Regex delete"));
272   CHECK_SHOW(show("<FORM METHOD=\"GET\" ACTION=\"./delete_regex\">\n"
273                   "<P><B>Type the list of regular expressions that you want to delete\n"
274                   "in the box below. The regular expressions MUST be separated by\n"
275                   "new lines</B></P>\n\n"
276                   "<TEXTAREA NAME=\"url\" rows=10 cols=50>"
277                   "http://"
278                   "</TEXTAREA>\n"
279                   "<INPUT TYPE=\"SUBMIT\" value=\"Delete\">\n"
280                   "</FORM>\n\n"));
281   return complete(event, e);
282 }
283 
284 int
invalidate_regex_form(int event,Event * e)285 ShowCache::invalidate_regex_form(int event, Event *e)
286 {
287   CHECK_SHOW(begin("Cache Regex Invalidate"));
288   CHECK_SHOW(show("<FORM METHOD=\"GET\" ACTION=\"./invalidate_regex\">\n"
289                   "<P><B>Type the list of regular expressions that you want to invalidate\n"
290                   "in the box below. The regular expressions MUST be separated by\n"
291                   "new lines</B></P>\n\n"
292                   "<TEXTAREA NAME=\"url\" rows=10 cols=50>"
293                   "http://"
294                   "</TEXTAREA>\n"
295                   "<INPUT TYPE=\"SUBMIT\" value=\"Invalidate\">\n"
296                   "</FORM>\n"));
297   return complete(event, e);
298 }
299 
300 int
handleCacheEvent(int event,Event * e)301 ShowCache::handleCacheEvent(int event, Event *e)
302 {
303   // we use VC_EVENT_xxx to finish the cluster read in cluster mode
304   switch (event) {
305   case VC_EVENT_EOS:
306   case VC_EVENT_READ_COMPLETE: {
307     // cluster read done, we just print hit in cluster
308     CHECK_SHOW(show("<P><TABLE border=1 width=100%%>"));
309     CHECK_SHOW(show("<TR><TH bgcolor=\"#FFF0E0\" colspan=2>Doc Hit from Cluster</TH></TR>\n"));
310     CHECK_SHOW(show("<tr><td>Size</td><td>%" PRId64 "</td>\n", content_length));
311 
312     // delete button
313     CHECK_SHOW(show("<tr><td>Action</td>\n"
314                     "<td><FORM action=\"./delete_url\" method=get>\n"
315                     "<Input type=HIDDEN name=url value=\"%s\">\n"
316                     "<input type=submit value=\"Delete URL\">\n"
317                     "</FORM></td></tr>\n",
318                     show_cache_urlstrs[0]));
319     CHECK_SHOW(show("</TABLE></P>"));
320 
321     if (buffer_reader) {
322       buffer->dealloc_reader(buffer_reader);
323       buffer_reader = nullptr;
324     }
325     if (buffer) {
326       free_MIOBuffer(buffer);
327       buffer = nullptr;
328     }
329     cvio = nullptr;
330     cache_vc->do_io_close(-1);
331     cache_vc = nullptr;
332     return complete(event, e);
333   }
334   case CACHE_EVENT_OPEN_READ: {
335     // get the vector
336     cache_vc                 = reinterpret_cast<CacheVC *>(e);
337     CacheHTTPInfoVector *vec = &(cache_vc->vector);
338     int alt_count            = vec->count();
339     if (alt_count) {
340       // check cache_vc->first_buf is NULL, response cache lookup busy.
341       if (cache_vc->first_buf == nullptr) {
342         cache_vc->do_io_close(-1);
343         CHECK_SHOW(show("<H3>Cache Lookup Busy, please try again</H3>\n"));
344         return complete(event, e);
345       }
346 
347       Doc *d = reinterpret_cast<Doc *>(cache_vc->first_buf->data());
348       time_t t;
349       char tmpstr[4096];
350 
351       // print the Doc
352       CHECK_SHOW(show("<P><TABLE border=1 width=100%%>"));
353       CHECK_SHOW(show("<TR><TH bgcolor=\"#FFF0E0\" colspan=2>Doc</TH></TR>\n"));
354       CHECK_SHOW(
355         show("<TR><TD>Volume</td> <td>#%d - store='%s'</td></tr>\n", cache_vc->vol->cache_vol->vol_number, cache_vc->vol->path));
356       CHECK_SHOW(show("<TR><TD>first key</td> <td>%s</td></tr>\n", d->first_key.toHexStr(tmpstr)));
357       CHECK_SHOW(show("<TR><TD>key</td> <td>%s</td></tr>\n", d->key.toHexStr(tmpstr)));
358       CHECK_SHOW(show("<tr><td>sync_serial</td><td>%lu</tr>\n", d->sync_serial));
359       CHECK_SHOW(show("<tr><td>write_serial</td><td>%lu</tr>\n", d->write_serial));
360       CHECK_SHOW(show("<tr><td>header length</td><td>%lu</tr>\n", d->hlen));
361       CHECK_SHOW(show("<tr><td>fragment type</td><td>%lu</tr>\n", d->doc_type));
362       CHECK_SHOW(show("<tr><td>No of Alternates</td><td>%d</td></tr>\n", alt_count));
363 
364       CHECK_SHOW(show("<tr><td>Action</td>\n"
365                       "<td><FORM action=\"./delete_url\" method=get>\n"
366                       "<Input type=HIDDEN name=url value=\"%s\">\n"
367                       "<input type=submit value=\"Delete URL\">\n"
368                       "</FORM></td></tr>\n",
369                       show_cache_urlstrs[0]));
370       CHECK_SHOW(show("</TABLE></P>"));
371 
372       for (int i = 0; i < alt_count; i++) {
373         // unmarshal the alternate??
374         CHECK_SHOW(show("<p><table border=1>\n"));
375         CHECK_SHOW(show("<tr><th bgcolor=\"#FFF0E0\" colspan=2>Alternate %d</th></tr>\n", i + 1));
376         CacheHTTPInfo *obj       = vec->get(i);
377         CacheKey obj_key         = obj->object_key_get();
378         HTTPHdr *cached_request  = obj->request_get();
379         HTTPHdr *cached_response = obj->response_get();
380         int64_t obj_size         = obj->object_size_get();
381         int offset, tmp, used, done;
382         char b[4096];
383 
384         // print request header
385         CHECK_SHOW(show("<tr><td>Request Header</td><td><PRE>"));
386         offset = 0;
387         do {
388           used = 0;
389           tmp  = offset;
390           done = cached_request->print(b, 4095, &used, &tmp);
391           offset += used;
392           b[used] = '\0';
393           CHECK_SHOW(show("%s", b));
394         } while (!done);
395         CHECK_SHOW(show("</PRE></td><tr>\n"));
396 
397         // print response header
398         CHECK_SHOW(show("<tr><td>Response Header</td><td><PRE>"));
399         offset = 0;
400         do {
401           used = 0;
402           tmp  = offset;
403           done = cached_response->print(b, 4095, &used, &tmp);
404           offset += used;
405           b[used] = '\0';
406           CHECK_SHOW(show("%s", b));
407         } while (!done);
408         CHECK_SHOW(show("</PRE></td></tr>\n"));
409         CHECK_SHOW(show("<tr><td>Size</td><td>%" PRId64 "</td>\n", obj_size));
410         CHECK_SHOW(show("<tr><td>Key</td><td>%s</td>\n", obj_key.toHexStr(tmpstr)));
411         t = obj->request_sent_time_get();
412         ink_ctime_r(&t, tmpstr);
413         CHECK_SHOW(show("<tr><td>Request sent time</td><td>%s</td></tr>\n", tmpstr));
414         t = obj->response_received_time_get();
415         ink_ctime_r(&t, tmpstr);
416 
417         CHECK_SHOW(show("<tr><td>Response received time</td><td>%s</td></tr>\n", tmpstr));
418         CHECK_SHOW(show("</TABLE></P>"));
419       }
420 
421       cache_vc->do_io_close(-1);
422       return complete(event, e);
423     }
424     // open success but no vector, that is the Cluster open read, pass through
425   }
426     // fallthrough
427 
428   case VC_EVENT_READ_READY:
429     if (!cvio) {
430       buffer         = new_empty_MIOBuffer();
431       buffer_reader  = buffer->alloc_reader();
432       content_length = cache_vc->get_object_size();
433       cvio           = cache_vc->do_io_read(this, content_length, buffer);
434     } else {
435       buffer_reader->consume(buffer_reader->read_avail());
436     }
437     return EVENT_DONE;
438   case CACHE_EVENT_OPEN_READ_FAILED:
439     // something strange happen, or cache miss in cluster mode.
440     CHECK_SHOW(show("<H3>Cache Lookup Failed, or missing in cluster</H3>\n"));
441     return complete(event, e);
442   default:
443     CHECK_SHOW(show("<H3>Cache Miss</H3>\n"));
444     return complete(event, e);
445   }
446 }
447 
448 int
lookup_url(int event,Event * e)449 ShowCache::lookup_url(int event, Event *e)
450 {
451   char header_str[300];
452   HttpCacheKey key;
453   cache_generation_t generation = -1;
454 
455   snprintf(header_str, sizeof(header_str), "<font color=red>%s</font>", show_cache_urlstrs[0]);
456   CHECK_SHOW(begin(header_str));
457   url.create(nullptr);
458   const char *s;
459   s = show_cache_urlstrs[0];
460   url.parse(&s, s + strlen(s));
461 
462   RecGetRecordInt("proxy.config.http.cache.generation", &generation);
463   Cache::generate_key(&key, &url, generation);
464 
465   SET_HANDLER(&ShowCache::handleCacheEvent);
466   Action *lookup_result = cacheProcessor.open_read(this, &key.hash, CACHE_FRAG_TYPE_HTTP, key.hostname, key.hostlen);
467   if (!lookup_result) {
468     lookup_result = ACTION_IO_ERROR;
469   }
470   if (lookup_result == ACTION_RESULT_DONE) {
471     return EVENT_DONE; // callback complete
472   } else if (lookup_result == ACTION_IO_ERROR) {
473     handleEvent(CACHE_EVENT_OPEN_READ_FAILED, nullptr);
474     return EVENT_DONE; // callback complete
475   } else {
476     return EVENT_CONT; // callback pending, will be a cluster read.
477   }
478 }
479 
480 int
delete_url(int event,Event * e)481 ShowCache::delete_url(int event, Event *e)
482 {
483   if (urlstrs_index == 0) {
484     // print the header the first time delete_url is called
485     CHECK_SHOW(begin("Delete URL"));
486     CHECK_SHOW(show("<B><TABLE border=1>\n"));
487   }
488 
489   if (strcmp(show_cache_urlstrs[urlstrs_index], "") == 0) {
490     // close the page when you reach the end of the
491     // url list
492     CHECK_SHOW(show("</TABLE></B>\n"));
493     return complete(event, e);
494   }
495   url.create(nullptr);
496   const char *s;
497   s = show_cache_urlstrs[urlstrs_index];
498   CHECK_SHOW(show("<TR><TD>%s</TD>", s));
499   url.parse(&s, s + strlen(s));
500   SET_HANDLER(&ShowCache::handleCacheDeleteComplete);
501   // increment the index so that the next time
502   // delete_url is called you delete the next url
503   urlstrs_index++;
504 
505   HttpCacheKey key;
506   Cache::generate_key(&key, &url); // XXX choose a cache generation number ...
507 
508   cacheProcessor.remove(this, &key, CACHE_FRAG_TYPE_HTTP);
509   return EVENT_DONE;
510 }
511 
512 int
handleCacheDeleteComplete(int event,Event * e)513 ShowCache::handleCacheDeleteComplete(int event, Event *e)
514 {
515   if (event == CACHE_EVENT_REMOVE) {
516     CHECK_SHOW(show("<td>Delete <font color=green>succeeded</font></td></tr>\n"));
517   } else {
518     CHECK_SHOW(show("<td>Delete <font color=red>failed</font></td></tr>\n"));
519   }
520   return delete_url(event, e);
521 }
522 
523 int
lookup_regex(int event,Event * e)524 ShowCache::lookup_regex(int event, Event *e)
525 {
526   CHECK_SHOW(begin("Regex Lookup"));
527   CHECK_SHOW(show("<SCRIPT LANGIAGE=\"Javascript1.2\">\n"
528                   "urllist = new Array(100);\n"
529                   "index = 0;\n"
530                   "function addToUrlList(input) {\n"
531                   "	for (c=0; c < index; c++) {\n"
532                   "		if (urllist[c] == encodeURIComponent(input.name)) {\n"
533                   "			urllist.splice(c,1);\n"
534                   "			index--;\n"
535                   "			return true;\n"
536                   "		}\n"
537                   "	}\n"
538                   "	urllist[index++] = encodeURIComponent(input.name);\n"
539                   "	return true;\n"
540                   "}\n"
541                   "function setUrls(form) {\n"
542                   "	form.elements[0].value=\"\";\n"
543                   "   if (index > 10) {\n"
544                   "           alert(\"Can't choose more than 10 urls for deleting\");\n"
545                   "           return true;\n"
546                   "}\n"
547                   "	for (c=0; c < index; c++){\n"
548                   "		form.elements[0].value += urllist[c]+ \"%%0D%%0A\";\n"
549                   "	}\n"
550                   "   if (form.elements[0].value == \"\"){\n"
551                   "	    alert(\"Please select at least one url before clicking delete\");\n"
552                   "       return true;\n"
553                   "}\n"
554                   "   srcfile=\"./delete_url?url=\" + form.elements[0].value;\n"
555                   "   document.location=srcfile;\n "
556                   "	return true;\n"
557                   "}\n"
558                   "</SCRIPT>\n"));
559 
560   CHECK_SHOW(show("<FORM NAME=\"f\" ACTION=\"./delete_url\" METHOD=GET> \n"
561                   "<INPUT TYPE=HIDDEN NAME=\"url\">\n"
562                   "<B><TABLE border=1>\n"));
563 
564   scan_flag = scan_type_lookup; // lookup
565   SET_HANDLER(&ShowCache::handleCacheScanCallback);
566   cacheProcessor.scan(this);
567   return EVENT_DONE;
568 }
569 
570 int
delete_regex(int event,Event * e)571 ShowCache::delete_regex(int event, Event *e)
572 {
573   CHECK_SHOW(begin("Regex Delete"));
574   CHECK_SHOW(show("<B><TABLE border=1>\n"));
575   scan_flag = scan_type_delete; // delete
576   SET_HANDLER(&ShowCache::handleCacheScanCallback);
577   cacheProcessor.scan(this);
578   return EVENT_DONE;
579 }
580 
581 int
invalidate_regex(int event,Event * e)582 ShowCache::invalidate_regex(int event, Event *e)
583 {
584   CHECK_SHOW(begin("Regex Invalidate"));
585   CHECK_SHOW(show("<B><TABLE border=1>\n"));
586   scan_flag = scan_type_invalidate; // invalidate
587   SET_HANDLER(&ShowCache::handleCacheScanCallback);
588   cacheProcessor.scan(this);
589   return EVENT_DONE;
590 }
591 
592 int
handleCacheScanCallback(int event,Event * e)593 ShowCache::handleCacheScanCallback(int event, Event *e)
594 {
595   switch (event) {
596   case CACHE_EVENT_SCAN: {
597     cache_vc = reinterpret_cast<CacheVC *>(e);
598     return EVENT_CONT;
599   }
600   case CACHE_EVENT_SCAN_OBJECT: {
601     HTTPInfo *alt = reinterpret_cast<HTTPInfo *>(e);
602     char xx[501], m[501];
603     int ib = 0, xd = 0, ml = 0;
604 
605     alt->request_get()->url_print(xx, 500, &ib, &xd);
606     xx[ib] = '\0';
607 
608     const char *mm = alt->request_get()->method_get(&ml);
609 
610     memcpy(m, mm, ml);
611     m[ml] = 0;
612 
613     int res = CACHE_SCAN_RESULT_CONTINUE;
614 
615     for (unsigned s = 0; show_cache_urlstrs[s][0] != '\0'; s++) {
616       const char *error;
617       int erroffset;
618       pcre *preq = pcre_compile(show_cache_urlstrs[s], 0, &error, &erroffset, nullptr);
619 
620       Debug("cache_inspector", "matching url '%s' '%s' with regex '%s'", m, xx, show_cache_urlstrs[s]);
621 
622       if (preq) {
623         int r = pcre_exec(preq, nullptr, xx, ib, 0, 0, nullptr, 0);
624 
625         pcre_free(preq);
626         if (r != -1) {
627           linecount++;
628           if ((linecount % 5) == 0) {
629             CHECK_SHOW(show("<TR bgcolor=\"#FFF0E0\">"));
630           } else {
631             CHECK_SHOW(show("<TR>"));
632           }
633 
634           switch (scan_flag) {
635           case scan_type_lookup:
636             /*Y! Bug: 2249781: using onClick() because i need encodeURIComponent() and YTS doesn't have something like that */
637             CHECK_SHOW(show("<TD><INPUT TYPE=CHECKBOX NAME=\"%s\" "
638                             "onClick=\"addToUrlList(this)\"></TD>"
639                             "<TD><A onClick='window.location.href=\"./lookup_url?url=\"+ encodeURIComponent(\"%s\");' HREF=\"#\">"
640                             "<B>%s</B></A></br></TD></TR>\n",
641                             xx, xx, xx));
642             break;
643           case scan_type_delete:
644             CHECK_SHOW(show("<TD><B>%s</B></TD>"
645                             "<TD><font color=red>deleted</font></TD></TR>\n",
646                             xx));
647             res = CACHE_SCAN_RESULT_DELETE;
648             break;
649           case scan_type_invalidate:
650             HTTPInfo new_info;
651             res = CACHE_SCAN_RESULT_UPDATE;
652             new_info.copy(alt);
653             new_info.response_get()->set_cooked_cc_need_revalidate_once();
654             CHECK_SHOW(show("<TD><B>%s</B></TD>"
655                             "<TD><font color=red>Invalidate</font></TD>"
656                             "</TR>\n",
657                             xx));
658             cache_vc->set_http_info(&new_info);
659           }
660 
661           break;
662         }
663       } else {
664         // TODO: Regex didn't compile, show errors ?
665         Debug("cache_inspector", "regex '%s' didn't compile", show_cache_urlstrs[s]);
666       }
667     }
668     return res;
669   }
670   case CACHE_EVENT_SCAN_DONE:
671     CHECK_SHOW(show("</TABLE></B>\n"));
672     if (scan_flag == 0) {
673       if (linecount) {
674         CHECK_SHOW(show("<P><INPUT TYPE=button value=\"Delete\" "
675                         "onClick=\"setUrls(window.document.f)\"></P>"
676                         "</FORM>\n"));
677       }
678     }
679     CHECK_SHOW(show("<H3>Done</H3>\n"));
680     Debug("cache_inspector", "scan done");
681     complete(event, e);
682     return EVENT_DONE;
683   case CACHE_EVENT_SCAN_FAILED:
684   default:
685     CHECK_SHOW(show("<H3>Error while scanning disk</H3>\n"));
686     return EVENT_DONE;
687   }
688 }
689