1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "net/url_request/view_cache_helper.h" 6 7 #include "base/string_util.h" 8 #include "net/base/escape.h" 9 #include "net/base/io_buffer.h" 10 #include "net/disk_cache/disk_cache.h" 11 #include "net/http/http_cache.h" 12 #include "net/http/http_response_headers.h" 13 #include "net/http/http_response_info.h" 14 #include "net/url_request/url_request_context.h" 15 16 #define VIEW_CACHE_HEAD \ 17 "<html><body><table>" 18 19 #define VIEW_CACHE_TAIL \ 20 "</table></body></html>" 21 22 static void HexDump(const char *buf, size_t buf_len, std::string* result) { 23 const size_t kMaxRows = 16; 24 int offset = 0; 25 26 const unsigned char *p; 27 while (buf_len) { 28 StringAppendF(result, "%08x: ", offset); 29 offset += kMaxRows; 30 31 p = (const unsigned char *) buf; 32 33 size_t i; 34 size_t row_max = std::min(kMaxRows, buf_len); 35 36 // print hex codes: 37 for (i = 0; i < row_max; ++i) 38 StringAppendF(result, "%02x ", *p++); 39 for (i = row_max; i < kMaxRows; ++i) 40 result->append(" "); 41 42 // print ASCII glyphs if possible: 43 p = (const unsigned char *) buf; 44 for (i = 0; i < row_max; ++i, ++p) { 45 if (*p < 0x7F && *p > 0x1F) { 46 AppendEscapedCharForHTML(*p, result); 47 } else { 48 result->push_back('.'); 49 } 50 } 51 52 result->push_back('\n'); 53 54 buf += row_max; 55 buf_len -= row_max; 56 } 57 } 58 59 static std::string FormatEntryInfo(disk_cache::Entry* entry, 60 const std::string& url_prefix) { 61 std::string key = entry->GetKey(); 62 GURL url = GURL(url_prefix + key); 63 std::string row = 64 "<tr><td><a href=\"" + url.spec() + "\">" + EscapeForHTML(key) + 65 "</a></td></tr>"; 66 return row; 67 } 68 69 static std::string FormatEntryDetails(disk_cache::Entry* entry) { 70 std::string result = EscapeForHTML(entry->GetKey()); 71 72 net::HttpResponseInfo response; 73 bool truncated; 74 if (net::HttpCache::ReadResponseInfo(entry, &response, &truncated) && 75 response.headers) { 76 if (truncated) 77 result.append("<pre>RESPONSE_INFO_TRUNCATED</pre>"); 78 79 result.append("<hr><pre>"); 80 result.append(EscapeForHTML(response.headers->GetStatusLine())); 81 result.push_back('\n'); 82 83 void* iter = NULL; 84 std::string name, value; 85 while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) { 86 result.append(EscapeForHTML(name)); 87 result.append(": "); 88 result.append(EscapeForHTML(value)); 89 result.push_back('\n'); 90 } 91 result.append("</pre>"); 92 } 93 94 for (int i = 0; i < 2; ++i) { 95 result.append("<hr><pre>"); 96 97 int data_size = entry->GetDataSize(i); 98 99 if (data_size) { 100 scoped_refptr<net::IOBuffer> buffer = new net::IOBuffer(data_size); 101 if (entry->ReadData(i, 0, buffer, data_size, NULL) == data_size) 102 HexDump(buffer->data(), data_size, &result); 103 } 104 105 result.append("</pre>"); 106 } 107 108 return result; 109 } 110 111 static disk_cache::Backend* GetDiskCache(URLRequestContext* context) { 112 if (!context) 113 return NULL; 114 115 if (!context->http_transaction_factory()) 116 return NULL; 117 118 net::HttpCache* http_cache = context->http_transaction_factory()->GetCache(); 119 if (!http_cache) 120 return NULL; 121 122 return http_cache->GetBackend(); 123 } 124 125 static std::string FormatStatistics(disk_cache::Backend* disk_cache) { 126 std::vector<std::pair<std::string, std::string> > stats; 127 disk_cache->GetStats(&stats); 128 std::string result; 129 130 for (size_t index = 0; index < stats.size(); index++) { 131 result.append(stats[index].first); 132 result.append(": "); 133 result.append(stats[index].second); 134 result.append("<br/>\n"); 135 } 136 137 return result; 138 } 139 140 // static 141 void ViewCacheHelper::GetEntryInfoHTML(const std::string& key, 142 URLRequestContext* context, 143 const std::string& url_prefix, 144 std::string* data) { 145 disk_cache::Backend* disk_cache = GetDiskCache(context); 146 if (!disk_cache) { 147 data->assign("no disk cache"); 148 return; 149 } 150 151 if (key.empty()) { 152 data->assign(VIEW_CACHE_HEAD); 153 void* iter = NULL; 154 disk_cache::Entry* entry; 155 while (disk_cache->OpenNextEntry(&iter, &entry)) { 156 data->append(FormatEntryInfo(entry, url_prefix)); 157 entry->Close(); 158 } 159 data->append(VIEW_CACHE_TAIL); 160 } else { 161 disk_cache::Entry* entry; 162 if (disk_cache->OpenEntry(key, &entry)) { 163 data->assign(FormatEntryDetails(entry)); 164 entry->Close(); 165 } else { 166 data->assign("no matching cache entry for: " + key); 167 } 168 } 169 } 170 171 // static 172 void ViewCacheHelper::GetStatisticsHTML(URLRequestContext* context, 173 std::string* data) { 174 disk_cache::Backend* disk_cache = GetDiskCache(context); 175 if (!disk_cache) { 176 data->append("no disk cache"); 177 return; 178 } 179 data->append(FormatStatistics(disk_cache)); 180 } 181