Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <iostream> | 5 #include <iostream> |
| 6 #include <memory> | 6 #include <memory> |
| 7 | 7 |
| 8 #include "base/at_exit.h" | 8 #include "base/at_exit.h" |
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
| 10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
| 11 #include "base/logging.h" | 11 #include "base/logging.h" |
| 12 #include "base/macros.h" | |
| 12 #include "base/message_loop/message_loop.h" | 13 #include "base/message_loop/message_loop.h" |
| 13 #include "base/run_loop.h" | 14 #include "base/run_loop.h" |
| 14 #include "base/strings/string_number_conversions.h" | 15 #include "base/strings/string_number_conversions.h" |
| 15 #include "net/base/io_buffer.h" | 16 #include "net/base/io_buffer.h" |
| 16 #include "net/base/test_completion_callback.h" | 17 #include "net/base/test_completion_callback.h" |
| 17 #include "net/disk_cache/disk_cache.h" | 18 #include "net/disk_cache/disk_cache.h" |
| 18 #include "net/http/http_cache.h" | 19 #include "net/http/http_cache.h" |
| 19 #include "net/http/http_response_headers.h" | 20 #include "net/http/http_response_headers.h" |
| 20 #include "net/http/http_util.h" | 21 #include "net/http/http_util.h" |
| 21 | 22 |
| 22 using disk_cache::Backend; | 23 using disk_cache::Backend; |
| 23 using disk_cache::Entry; | 24 using disk_cache::Entry; |
| 24 | 25 |
| 25 namespace { | 26 namespace { |
| 26 | 27 |
| 27 int kResponseInfoIndex = 0; | 28 const int kResponseInfoIndex = 0; |
|
pasko
2016/07/05 15:13:30
constexpr is preferred now as of https://chromium-
gabadie
2016/07/06 09:25:53
Done.
| |
| 29 | |
| 30 const char* const kCommandNames[] = { | |
| 31 "stop", "get_size", "list_keys", "get_stream_for_key", | |
|
pasko
2016/07/05 15:13:30
any reason for these to be separated by multiple s
gabadie
2016/07/06 09:25:53
looks like `git cl format net` did it by itself...
pasko
2016/07/06 15:18:55
weird :) works for me then..
| |
| 32 "delete_stream", "delete_key", "update_raw_headers", | |
| 33 }; | |
| 34 | |
| 35 // Print the command line help. | |
|
pasko
2016/07/05 15:13:31
s/Print/Prints/
gabadie
2016/07/06 09:25:53
No, Gavin wanted in the previous reviews the comme
pasko
2016/07/06 15:18:55
Ack, this goes back to Gavin. Though I am not sure
| |
| 36 void PrintHelp() { | |
| 37 std::cout << "cachetool <cache_path> <cache_backend_type> <subcommand> ..." | |
|
pasko
2016/07/05 15:13:30
The '...' is slightly confusing, maybe should be:
gabadie
2016/07/06 09:25:53
No. the ... stands for sub-command specific parame
pasko
2016/07/06 15:18:55
Then the description is still incorrect. Subcomman
gabadie
2016/07/06 16:45:32
Done.
| |
| 38 << std::endl | |
| 39 << std::endl; | |
| 40 std::cout << "Available cache backend types: simple, blockfile" << std::endl; | |
| 41 std::cout << "Available subcommands:" << std::endl; | |
| 42 std::cout << " delete_key <key>: Delete key from cache." << std::endl; | |
| 43 std::cout << " delete_stream <key> <index>: Delete a particular stream of a" | |
| 44 << " given key." << std::endl; | |
| 45 std::cout << " get_size: Calculate the total size of the cache in bytes." | |
| 46 << std::endl; | |
| 47 std::cout << " get_stream <key> <index>: Print a particular stream for a" | |
| 48 << " given key." << std::endl; | |
| 49 std::cout << " list_keys: List all keys in the cache." << std::endl; | |
| 50 std::cout << " online: Starts cachetool to process serialized commands " | |
|
pasko
2016/07/05 15:13:31
Making "online" a subcommand is somewhat confusing
gabadie
2016/07/06 09:25:53
Command line tool only have one subcommand. Either
pasko
2016/07/06 15:18:55
Ah, ok, thanks for explaining.
| |
| 51 << "passed down by the standard input and return commands output " | |
| 52 << "in the stdout until the stop command is received." << std::endl; | |
| 53 std::cout << " update_raw_headers <key>: Update stdin as the key's raw " | |
| 54 << "response headers." << std::endl; | |
| 55 std::cout << " stop: Verify that the cache can be opened and return, " | |
| 56 << "confirming the cache exists and is of the right type." | |
| 57 << std::endl; | |
| 58 std::cout << "Expected values of <index> are:" << std::endl; | |
| 59 std::cout << " 0 (HTTP response headers)" << std::endl; | |
| 60 std::cout << " 1 (transport encoded content)" << std::endl; | |
| 61 std::cout << " 2 (compiled content)" << std::endl; | |
|
pasko
2016/07/05 15:13:31
there can be other things in stream 2, so we can s
gabadie
2016/07/06 09:25:53
Interesting, waiting for Gavin's opinion to change
| |
| 62 } | |
| 63 | |
| 64 // Generic command input/output. | |
| 65 class CachetoolIOBase { | |
|
pasko
2016/07/05 15:13:30
Ha, now I understand why you call it 'IO', basical
gabadie
2016/07/06 09:25:53
This is not for speed, but rather for reliability.
pasko
2016/07/06 15:18:55
Oh, that's actually a very good point, which I tot
gabadie
2016/07/06 16:45:32
Ok let's wait for Gavin's opinion. But your offlin
| |
| 66 public: | |
| 67 CachetoolIOBase(Backend* cache_backend) | |
| 68 : command_failed_(false), cache_backend_(cache_backend){}; | |
| 69 virtual ~CachetoolIOBase(){}; | |
| 70 | |
| 71 // Reads the next command's name to execute. | |
| 72 virtual std::string ReadCommandName() = 0; | |
| 73 | |
| 74 // Reads the next parameter as an integer. | |
| 75 virtual int ReadInt() = 0; | |
| 76 | |
| 77 // Reads the next parameter as stream index. | |
| 78 int ReadStreamIndex() { | |
| 79 if (has_failed()) | |
| 80 return -1; | |
| 81 int index = ReadInt(); | |
| 82 if (index < 0 || index > 2) { | |
| 83 ReturnFailure("Invalid stream index."); | |
| 84 return -1; | |
| 85 } | |
| 86 return index; | |
| 87 } | |
| 88 | |
| 89 // Reads the next parameter as an string. | |
| 90 virtual std::string ReadString() = 0; | |
| 91 | |
| 92 // Reads the next parameter from stdin as string. | |
| 93 virtual std::string ReadBufferedString() = 0; | |
| 94 | |
| 95 // Communicate back an integer. | |
| 96 virtual void ReturnInt(int integer) = 0; | |
| 97 | |
| 98 // Communicate back a string. | |
| 99 virtual void ReturnString(const std::string& string) = 0; | |
| 100 | |
| 101 // Communicate back a buffer. | |
| 102 virtual void ReturnBuffer(net::GrowableIOBuffer* buffer) = 0; | |
| 103 | |
| 104 // Communicate back command failure. | |
| 105 virtual void ReturnFailure(const std::string& error_msg) = 0; | |
| 106 | |
| 107 // Communicate back command success. | |
| 108 virtual void ReturnSuccess() { DCHECK(!command_failed_); }; | |
| 109 | |
| 110 // Returns weather the command has failed. | |
|
pasko
2016/07/05 15:13:31
s/weather/whether/
gabadie
2016/07/06 09:25:53
Done.
| |
| 111 inline bool has_failed() { return command_failed_; } | |
| 112 | |
| 113 // Returns the opened cache backend. | |
| 114 Backend* cache_backend() { return cache_backend_; } | |
| 115 | |
| 116 protected: | |
| 117 bool command_failed_; | |
| 118 Backend* const cache_backend_; | |
| 119 }; | |
| 120 | |
| 121 // Command line input/output that is user readable. | |
| 122 class CommandLineIO final : public CachetoolIOBase { | |
| 123 public: | |
| 124 CommandLineIO(Backend* cache_backend, base::CommandLine::StringVector args) | |
| 125 : CachetoolIOBase(cache_backend), command_line_args_(args), args_id_(0) {} | |
| 126 | |
| 127 // Implements CachetoolIOBase. | |
| 128 std::string ReadCommandName() override { | |
| 129 if (args_id_ == 0) | |
| 130 return ReadString(); | |
| 131 else if (args_id_ == command_line_args_.size()) | |
| 132 return "stop"; | |
| 133 else if (!has_failed()) | |
| 134 ReturnFailure("Command line arguments to long."); | |
| 135 return ""; | |
| 136 } | |
| 137 | |
| 138 // Implements CachetoolIOBase. | |
| 139 int ReadInt() override { | |
| 140 std::string interger_str = ReadString(); | |
| 141 int interger = -1; | |
| 142 if (!base::StringToInt(interger_str, &interger)) { | |
| 143 ReturnFailure("Couldn't parse integer."); | |
| 144 return 0; | |
| 145 } | |
| 146 return interger; | |
| 147 } | |
| 148 | |
| 149 // Implements CachetoolIOBase. | |
| 150 std::string ReadString() override { | |
| 151 if (args_id_ < command_line_args_.size()) | |
| 152 return command_line_args_[args_id_++]; | |
| 153 if (!has_failed()) | |
| 154 ReturnFailure("Command line arguments to short."); | |
| 155 return ""; | |
| 156 } | |
| 157 | |
| 158 // Implements CachetoolIOBase. | |
| 159 std::string ReadBufferedString() override { | |
| 160 std::ostringstream raw_headers_stream; | |
| 161 for (std::string line; std::getline(std::cin, line);) | |
| 162 raw_headers_stream << line << std::endl; | |
| 163 return raw_headers_stream.str(); | |
| 164 } | |
| 165 | |
| 166 // Implements CachetoolIOBase. | |
| 167 void ReturnInt(int integer) override { | |
| 168 DCHECK(!has_failed()); | |
| 169 std::cout << integer << std::endl; | |
| 170 } | |
| 171 | |
| 172 // Implements CachetoolIOBase. | |
| 173 void ReturnString(const std::string& string) override { | |
| 174 DCHECK(!has_failed()); | |
| 175 std::cout << string << std::endl; | |
| 176 } | |
| 177 | |
| 178 // Implements CachetoolIOBase. | |
| 179 void ReturnBuffer(net::GrowableIOBuffer* buffer) override { | |
| 180 DCHECK(!has_failed()); | |
| 181 std::cout.write(buffer->data(), buffer->offset()); | |
| 182 } | |
| 183 | |
| 184 // Implements CachetoolIOBase. | |
| 185 void ReturnFailure(const std::string& error_msg) override { | |
| 186 DCHECK(!has_failed()); | |
| 187 std::cerr << error_msg << std::endl; | |
| 188 command_failed_ = true; | |
| 189 } | |
| 190 | |
| 191 private: | |
| 192 const base::CommandLine::StringVector command_line_args_; | |
| 193 size_t args_id_; | |
| 194 }; | |
| 195 | |
| 196 // Online command input/output that receives pickled commands from stdin and | |
| 197 // returns their results back in stdout. Send the stop command to properly exit | |
| 198 // cachetool's main loop. | |
| 199 class OnlineCommandIO final : public CachetoolIOBase { | |
| 200 public: | |
| 201 OnlineCommandIO(Backend* cache_backend) : CachetoolIOBase(cache_backend) {} | |
| 202 | |
| 203 // Implements CachetoolIOBase. | |
| 204 std::string ReadCommandName() override { | |
| 205 if (has_failed()) | |
| 206 return ""; | |
| 207 std::cout.flush(); | |
| 208 size_t command_id = static_cast<size_t>(std::cin.get()); | |
| 209 if (command_id >= arraysize(kCommandNames)) { | |
| 210 ReturnFailure("Unknown command."); | |
| 211 return ""; | |
| 212 } | |
| 213 return kCommandNames[command_id]; | |
| 214 } | |
| 215 | |
| 216 // Implements CachetoolIOBase. | |
| 217 int ReadInt() override { | |
| 218 if (has_failed()) | |
| 219 return -1; | |
| 220 int integer = -1; | |
| 221 std::cin.read(reinterpret_cast<char*>(&integer), sizeof(integer)); | |
|
pasko
2016/07/05 15:13:30
read 4 bytes? why?
why not std::cin >> integer?
gabadie
2016/07/06 09:25:53
Because binary protocol, not ascii protocol.
| |
| 222 return integer; | |
| 223 } | |
| 224 | |
| 225 // Implements CachetoolIOBase. | |
| 226 std::string ReadString() override { | |
| 227 if (has_failed()) | |
| 228 return ""; | |
| 229 int string_size = ReadInt(); | |
| 230 if (string_size <= 0) { | |
| 231 if (string_size < 0) | |
| 232 ReturnFailure("Size of string is negative."); | |
| 233 return ""; | |
| 234 } | |
| 235 std::vector<char> tmp_buffer(string_size + 1); | |
| 236 std::cin.read(&tmp_buffer[0], string_size); | |
| 237 tmp_buffer[string_size] = 0; | |
| 238 return std::string(&tmp_buffer[0], string_size); | |
| 239 } | |
| 240 | |
| 241 // Implements CachetoolIOBase. | |
| 242 std::string ReadBufferedString() override { return ReadString(); } | |
| 243 | |
| 244 // Implements CachetoolIOBase. | |
| 245 void ReturnInt(int integer) override { | |
| 246 DCHECK(!command_failed_); | |
| 247 std::cout.write(reinterpret_cast<char*>(&integer), sizeof(integer)); | |
| 248 } | |
| 249 | |
| 250 // Implements CachetoolIOBase. | |
| 251 void ReturnString(const std::string& string) override { | |
| 252 ReturnInt(string.size()); | |
| 253 std::cout.write(string.c_str(), string.size()); | |
| 254 } | |
| 255 | |
| 256 // Implements CachetoolIOBase. | |
| 257 void ReturnBuffer(net::GrowableIOBuffer* buffer) override { | |
| 258 ReturnInt(buffer->offset()); | |
| 259 std::cout.write(buffer->StartOfBuffer(), buffer->offset()); | |
| 260 } | |
| 261 | |
| 262 // Implements CachetoolIOBase. | |
| 263 void ReturnFailure(const std::string& error_msg) override { | |
| 264 ReturnString(error_msg); | |
| 265 command_failed_ = true; | |
| 266 } | |
| 267 | |
| 268 // Implements CachetoolIOBase. | |
| 269 void ReturnSuccess() override { ReturnInt(0); } | |
| 270 }; | |
| 28 | 271 |
| 29 // Get the cache's size. | 272 // Get the cache's size. |
| 30 bool GetSize(Backend* cache_backend) { | 273 void GetSize(CachetoolIOBase* cachetool_io) { |
| 31 net::TestCompletionCallback cb; | 274 net::TestCompletionCallback cb; |
| 32 int rv = cache_backend->CalculateSizeOfAllEntries(cb.callback()); | 275 int rv = |
| 276 cachetool_io->cache_backend()->CalculateSizeOfAllEntries(cb.callback()); | |
| 33 rv = cb.GetResult(rv); | 277 rv = cb.GetResult(rv); |
| 34 if (rv < 0) { | 278 if (rv < 0) |
| 35 std::cerr << "Couldn't get cache size." << std::endl; | 279 return cachetool_io->ReturnFailure("Couldn't get cache size."); |
| 36 return false; | 280 cachetool_io->ReturnSuccess(); |
| 37 } | 281 cachetool_io->ReturnInt(rv); |
| 38 std::cout << rv << std::endl; | |
| 39 return true; | |
| 40 } | 282 } |
| 41 | 283 |
| 42 // Print all of a cache's keys to stdout. | 284 // Print all of a cache's keys to stdout. |
| 43 bool ListKeys(Backend* cache_backend) { | 285 bool ListKeys(CachetoolIOBase* cachetool_io) { |
| 44 std::unique_ptr<Backend::Iterator> entry_iterator = | 286 std::unique_ptr<Backend::Iterator> entry_iterator = |
| 45 cache_backend->CreateIterator(); | 287 cachetool_io->cache_backend()->CreateIterator(); |
| 46 Entry* entry = nullptr; | 288 Entry* entry = nullptr; |
| 47 net::TestCompletionCallback cb; | 289 net::TestCompletionCallback cb; |
| 48 int rv = entry_iterator->OpenNextEntry(&entry, cb.callback()); | 290 int rv = entry_iterator->OpenNextEntry(&entry, cb.callback()); |
| 291 cachetool_io->ReturnSuccess(); | |
| 49 while (cb.GetResult(rv) == net::OK) { | 292 while (cb.GetResult(rv) == net::OK) { |
| 50 std::string url = entry->GetKey(); | 293 std::string url = entry->GetKey(); |
| 51 std::cout << url << std::endl; | 294 cachetool_io->ReturnString(url); |
| 52 entry->Close(); | 295 entry->Close(); |
| 53 entry = nullptr; | 296 entry = nullptr; |
| 54 rv = entry_iterator->OpenNextEntry(&entry, cb.callback()); | 297 rv = entry_iterator->OpenNextEntry(&entry, cb.callback()); |
| 55 } | 298 } |
| 299 cachetool_io->ReturnString(""); | |
| 56 return true; | 300 return true; |
| 57 } | 301 } |
| 58 | 302 |
| 59 // Get a key's stream to a buffer. | 303 // Get a key's stream to a buffer. |
| 60 scoped_refptr<net::GrowableIOBuffer> GetStreamForKeyBuffer( | 304 scoped_refptr<net::GrowableIOBuffer> GetStreamForKeyBuffer( |
| 61 Backend* cache_backend, | 305 CachetoolIOBase* cachetool_io, |
| 62 const std::string& key, | 306 const std::string& key, |
| 63 int index) { | 307 int index) { |
| 308 DCHECK(!cachetool_io->has_failed()); | |
| 64 Entry* cache_entry; | 309 Entry* cache_entry; |
| 65 net::TestCompletionCallback cb; | 310 net::TestCompletionCallback cb; |
| 66 int rv = cache_backend->OpenEntry(key, &cache_entry, cb.callback()); | 311 int rv = cachetool_io->cache_backend()->OpenEntry(key, &cache_entry, |
| 312 cb.callback()); | |
| 67 if (cb.GetResult(rv) != net::OK) { | 313 if (cb.GetResult(rv) != net::OK) { |
| 68 std::cerr << "Couldn't find key's entry." << std::endl; | 314 cachetool_io->ReturnFailure("Couldn't find key's entry."); |
| 69 return nullptr; | 315 return nullptr; |
| 70 } | 316 } |
| 71 | 317 |
| 72 const int kInitBufferSize = 8192; | 318 const int kInitBufferSize = 8192; |
| 73 scoped_refptr<net::GrowableIOBuffer> buffer(new net::GrowableIOBuffer()); | 319 scoped_refptr<net::GrowableIOBuffer> buffer(new net::GrowableIOBuffer()); |
| 74 buffer->SetCapacity(kInitBufferSize); | 320 buffer->SetCapacity(kInitBufferSize); |
| 75 while (true) { | 321 while (true) { |
| 76 rv = cache_entry->ReadData(index, buffer->offset(), buffer.get(), | 322 rv = cache_entry->ReadData(index, buffer->offset(), buffer.get(), |
| 77 buffer->capacity() - buffer->offset(), | 323 buffer->capacity() - buffer->offset(), |
| 78 cb.callback()); | 324 cb.callback()); |
| 79 rv = cb.GetResult(rv); | 325 rv = cb.GetResult(rv); |
| 80 if (rv < 0) { | 326 if (rv < 0) { |
| 81 cache_entry->Close(); | 327 cache_entry->Close(); |
| 82 std::cerr << "Stream read error." << std::endl; | 328 cachetool_io->ReturnFailure("Stream read error."); |
| 83 return nullptr; | 329 return nullptr; |
| 84 } | 330 } |
| 85 buffer->set_offset(buffer->offset() + rv); | 331 buffer->set_offset(buffer->offset() + rv); |
| 86 if (rv == 0) | 332 if (rv == 0) |
| 87 break; | 333 break; |
| 88 buffer->SetCapacity(buffer->offset() * 2); | 334 buffer->SetCapacity(buffer->offset() * 2); |
| 89 } | 335 } |
| 90 cache_entry->Close(); | 336 cache_entry->Close(); |
| 91 return buffer; | 337 return buffer; |
| 92 } | 338 } |
| 93 | 339 |
| 94 // Print a key's stream to stdout. | 340 // Print a key's stream to stdout. |
| 95 bool GetStreamForKey(Backend* cache_backend, | 341 void GetStreamForKey(CachetoolIOBase* cachetool_io) { |
| 96 const std::string& key, | 342 std::string key = cachetool_io->ReadString(); |
| 97 int index) { | 343 int index = cachetool_io->ReadInt(); |
| 344 if (cachetool_io->has_failed()) | |
| 345 return; | |
| 98 scoped_refptr<net::GrowableIOBuffer> buffer( | 346 scoped_refptr<net::GrowableIOBuffer> buffer( |
| 99 GetStreamForKeyBuffer(cache_backend, key, index)); | 347 GetStreamForKeyBuffer(cachetool_io, key, index)); |
| 100 if (!buffer) | 348 if (cachetool_io->has_failed()) |
| 101 return false; | 349 return; |
| 102 if (index == kResponseInfoIndex) { | 350 if (index == kResponseInfoIndex) { |
| 103 net::HttpResponseInfo response_info; | 351 net::HttpResponseInfo response_info; |
| 104 bool truncated_response_info = false; | 352 bool truncated_response_info = false; |
| 105 net::HttpCache::ParseResponseInfo(buffer->StartOfBuffer(), buffer->offset(), | 353 net::HttpCache::ParseResponseInfo(buffer->StartOfBuffer(), buffer->offset(), |
| 106 &response_info, &truncated_response_info); | 354 &response_info, &truncated_response_info); |
| 107 if (truncated_response_info) { | 355 if (truncated_response_info) |
| 108 std::cerr << "Truncated HTTP response." << std::endl; | 356 return cachetool_io->ReturnFailure("Truncated HTTP response."); |
| 109 return false; | 357 cachetool_io->ReturnSuccess(); |
| 110 } | 358 cachetool_io->ReturnString(net::HttpUtil::ConvertHeadersBackToHTTPResponse( |
| 111 std::cout << net::HttpUtil::ConvertHeadersBackToHTTPResponse( | 359 response_info.headers->raw_headers())); |
| 112 response_info.headers->raw_headers()); | |
| 113 } else { | 360 } else { |
| 114 std::cout.write(buffer->StartOfBuffer(), buffer->offset()); | 361 cachetool_io->ReturnSuccess(); |
| 362 cachetool_io->ReturnBuffer(buffer.get()); | |
| 115 } | 363 } |
| 116 return true; | |
| 117 } | 364 } |
| 118 | 365 |
| 119 // Set stdin as the key's raw response headers. | 366 // Set stdin as the key's raw response headers. |
| 120 bool UpdateRawResponseHeaders(Backend* cache_backend, const std::string& key) { | 367 void UpdateRawResponseHeaders(CachetoolIOBase* cachetool_io) { |
| 368 std::string key = cachetool_io->ReadString(); | |
| 369 std::string raw_headers = cachetool_io->ReadBufferedString(); | |
| 370 if (cachetool_io->has_failed()) | |
| 371 return; | |
| 121 scoped_refptr<net::GrowableIOBuffer> buffer( | 372 scoped_refptr<net::GrowableIOBuffer> buffer( |
| 122 GetStreamForKeyBuffer(cache_backend, key, kResponseInfoIndex)); | 373 GetStreamForKeyBuffer(cachetool_io, key, kResponseInfoIndex)); |
| 123 if (!buffer) | 374 if (cachetool_io->has_failed()) |
| 124 return false; | 375 return; |
| 125 net::HttpResponseInfo response_info; | 376 net::HttpResponseInfo response_info; |
| 126 bool truncated_response_info = false; | 377 bool truncated_response_info = false; |
| 127 net::HttpCache::ParseResponseInfo(buffer->StartOfBuffer(), buffer->offset(), | 378 net::HttpCache::ParseResponseInfo(buffer->StartOfBuffer(), buffer->offset(), |
| 128 &response_info, &truncated_response_info); | 379 &response_info, &truncated_response_info); |
| 129 if (truncated_response_info) { | 380 if (truncated_response_info) |
| 130 std::cerr << "Truncated HTTP response." << std::endl; | 381 return cachetool_io->ReturnFailure("Truncated HTTP response."); |
| 131 return false; | 382 |
| 132 } | 383 response_info.headers = new net::HttpResponseHeaders(raw_headers); |
| 133 std::ostringstream raw_headers_stream; | |
| 134 for (std::string line; std::getline(std::cin, line);) | |
| 135 raw_headers_stream << line << std::endl; | |
| 136 response_info.headers = | |
| 137 new net::HttpResponseHeaders(raw_headers_stream.str()); | |
| 138 scoped_refptr<net::PickledIOBuffer> data(new net::PickledIOBuffer()); | 384 scoped_refptr<net::PickledIOBuffer> data(new net::PickledIOBuffer()); |
| 139 response_info.Persist(data->pickle(), false, false); | 385 response_info.Persist(data->pickle(), false, false); |
| 140 data->Done(); | 386 data->Done(); |
| 141 Entry* cache_entry; | 387 Entry* cache_entry; |
| 142 net::TestCompletionCallback cb; | 388 net::TestCompletionCallback cb; |
| 143 int rv = cache_backend->OpenEntry(key, &cache_entry, cb.callback()); | 389 int rv = cachetool_io->cache_backend()->OpenEntry(key, &cache_entry, |
| 390 cb.callback()); | |
| 144 CHECK(cb.GetResult(rv) == net::OK); | 391 CHECK(cb.GetResult(rv) == net::OK); |
| 145 int data_len = data->pickle()->size(); | 392 int data_len = data->pickle()->size(); |
| 146 rv = cache_entry->WriteData(kResponseInfoIndex, 0, data.get(), data_len, | 393 rv = cache_entry->WriteData(kResponseInfoIndex, 0, data.get(), data_len, |
| 147 cb.callback(), true); | 394 cb.callback(), true); |
| 148 if (cb.GetResult(rv) != data_len) { | 395 if (cb.GetResult(rv) != data_len) |
| 149 std::cerr << "Couldn't write headers." << std::endl; | 396 return cachetool_io->ReturnFailure("Couldn't write headers."); |
| 150 return false; | 397 cachetool_io->ReturnSuccess(); |
| 151 } | |
| 152 cache_entry->Close(); | 398 cache_entry->Close(); |
| 153 return true; | |
| 154 } | 399 } |
| 155 | 400 |
| 156 // Delete a specified key stream from the cache. | 401 // Delete a specified key stream from the cache. |
| 157 bool DeleteStreamForKey(Backend* cache_backend, | 402 void DeleteStreamForKey(CachetoolIOBase* cachetool_io) { |
| 158 const std::string& key, | 403 std::string key = cachetool_io->ReadString(); |
| 159 int index) { | 404 int index = cachetool_io->ReadInt(); |
| 405 if (cachetool_io->has_failed()) | |
| 406 return; | |
| 160 Entry* cache_entry; | 407 Entry* cache_entry; |
| 161 net::TestCompletionCallback cb; | 408 net::TestCompletionCallback cb; |
| 162 int rv = cache_backend->OpenEntry(key, &cache_entry, cb.callback()); | 409 int rv = cachetool_io->cache_backend()->OpenEntry(key, &cache_entry, |
| 163 if (cb.GetResult(rv) != net::OK) { | 410 cb.callback()); |
| 164 std::cerr << "Couldn't find key's entry." << std::endl; | 411 if (cb.GetResult(rv) != net::OK) |
| 165 return false; | 412 return cachetool_io->ReturnFailure("Couldn't find key's entry."); |
| 166 } | |
| 167 | 413 |
| 168 scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer("")); | 414 scoped_refptr<net::StringIOBuffer> buffer(new net::StringIOBuffer("")); |
| 169 rv = cache_entry->WriteData(index, 0, buffer.get(), 0, cb.callback(), true); | 415 rv = cache_entry->WriteData(index, 0, buffer.get(), 0, cb.callback(), true); |
| 170 if (cb.GetResult(rv) != 0) { | 416 if (cb.GetResult(rv) != net::OK) |
| 171 std::cerr << "Couldn't delete key stream." << std::endl; | 417 return cachetool_io->ReturnFailure("Couldn't delete key stream."); |
| 172 return false; | 418 cachetool_io->ReturnSuccess(); |
| 173 } | |
| 174 cache_entry->Close(); | 419 cache_entry->Close(); |
| 175 return true; | |
| 176 } | 420 } |
| 177 | 421 |
| 178 // Delete a specified key from the cache. | 422 // Delete a specified key from the cache. |
| 179 bool DeleteKey(Backend* cache_backend, const std::string& key) { | 423 void DeleteKey(CachetoolIOBase* cachetool_io) { |
| 424 std::string key = cachetool_io->ReadString(); | |
| 425 if (cachetool_io->has_failed()) | |
| 426 return; | |
| 180 net::TestCompletionCallback cb; | 427 net::TestCompletionCallback cb; |
| 181 int rv = cache_backend->DoomEntry(key, cb.callback()); | 428 int rv = cachetool_io->cache_backend()->DoomEntry(key, cb.callback()); |
| 182 if (cb.GetResult(rv) != net::OK) { | 429 if (cb.GetResult(rv) != net::OK) |
| 183 std::cerr << "Couldn't delete key." << std::endl; | 430 cachetool_io->ReturnFailure("Couldn't delete key."); |
| 184 return false; | 431 else |
| 185 } | 432 cachetool_io->ReturnSuccess(); |
| 186 return true; | |
| 187 } | 433 } |
| 188 | 434 |
| 189 // Parse stream index from command line argument string. | 435 // Execute all command from the |common_input|. |
|
pasko
2016/07/05 15:13:30
what is |common_input|?
gabadie
2016/07/06 09:25:53
Oups, variable renaming artifact.
| |
| 190 int ParseStreamIndex(const std::string& index_arg) { | 436 bool ExecuteCommands(CachetoolIOBase* cachetool_io) { |
| 191 int index = -1; | 437 while (!cachetool_io->has_failed()) { |
| 192 if (!base::StringToInt(index_arg, &index)) { | 438 std::string subcommand(cachetool_io->ReadCommandName()); |
| 193 std::cerr << "<index> must be an integer." << std::endl; | 439 if (cachetool_io->has_failed()) |
| 194 return -1; | 440 break; |
| 195 } else if (index < 0 || index > 2) { | 441 if (subcommand == "stop") { |
| 196 std::cerr << "Invalid stream index." << std::endl; | 442 cachetool_io->ReturnSuccess(); |
| 197 return -1; | 443 return true; |
| 444 } else if (subcommand == "online") { | |
| 445 OnlineCommandIO online_command_io(cachetool_io->cache_backend()); | |
| 446 return ExecuteCommands(&online_command_io); | |
| 447 } else if (subcommand == "delete_key") { | |
| 448 DeleteKey(cachetool_io); | |
| 449 } else if (subcommand == "delete_stream") { | |
| 450 DeleteStreamForKey(cachetool_io); | |
| 451 } else if (subcommand == "get_size") { | |
| 452 GetSize(cachetool_io); | |
| 453 } else if (subcommand == "get_stream") { | |
| 454 GetStreamForKey(cachetool_io); | |
| 455 } else if (subcommand == "list_keys") { | |
| 456 ListKeys(cachetool_io); | |
| 457 } else if (subcommand == "update_raw_headers") { | |
| 458 UpdateRawResponseHeaders(cachetool_io); | |
| 459 } else { | |
| 460 // The wrong subcommand is originated from the command line. | |
| 461 cachetool_io->ReturnFailure("Unknown command."); | |
| 462 PrintHelp(); | |
| 463 } | |
| 198 } | 464 } |
| 199 return index; | 465 return false; |
| 200 } | |
| 201 | |
| 202 // Print the command line help. | |
| 203 void PrintHelp() { | |
| 204 std::cout << "cachetool <cache_path> <cache_backend_type> <subcommand> ..." | |
| 205 << std::endl | |
| 206 << std::endl; | |
| 207 std::cout << "Available cache backend types: simple, blockfile" << std::endl; | |
| 208 std::cout << "Available subcommands:" << std::endl; | |
| 209 std::cout << " delete_key <key>: Delete key from cache." << std::endl; | |
| 210 std::cout << " delete_stream <key> <index>: Delete a particular stream of a" | |
| 211 << " given key." << std::endl; | |
| 212 std::cout << " get_size: Calculate the total size of the cache in bytes." | |
| 213 << std::endl; | |
| 214 std::cout << " get_stream <key> <index>: Print a particular stream for a" | |
| 215 << " given key." << std::endl; | |
| 216 std::cout << " list_keys: List all keys in the cache." << std::endl; | |
| 217 std::cout << " update_raw_headers <key>: Update stdin as the key's raw " | |
| 218 << "response headers." << std::endl; | |
| 219 std::cout << " validate: Verify that the cache can be opened and return, " | |
| 220 << "confirming the cache exists and is of the right type." | |
| 221 << std::endl; | |
| 222 std::cout << "Expected values of <index> are:" << std::endl; | |
| 223 std::cout << " 0 (HTTP response headers)" << std::endl; | |
| 224 std::cout << " 1 (transport encoded content)" << std::endl; | |
| 225 std::cout << " 2 (compiled content)" << std::endl; | |
| 226 } | 466 } |
| 227 | 467 |
| 228 } // namespace | 468 } // namespace |
| 229 | 469 |
| 230 int main(int argc, char* argv[]) { | 470 int main(int argc, char* argv[]) { |
| 231 base::AtExitManager at_exit_manager; | 471 base::AtExitManager at_exit_manager; |
| 232 base::MessageLoopForIO message_loop; | 472 base::MessageLoopForIO message_loop; |
| 233 base::CommandLine::Init(argc, argv); | 473 base::CommandLine::Init(argc, argv); |
| 234 const base::CommandLine& command_line = | 474 const base::CommandLine& command_line = |
| 235 *base::CommandLine::ForCurrentProcess(); | 475 *base::CommandLine::ForCurrentProcess(); |
| 236 | 476 |
| 237 base::CommandLine::StringVector args = command_line.GetArgs(); | 477 base::CommandLine::StringVector args = command_line.GetArgs(); |
| 238 if (args.size() < 3U) { | 478 if (args.size() < 3U) { |
| 239 PrintHelp(); | 479 PrintHelp(); |
| 240 return 1; | 480 return 1; |
| 241 } | 481 } |
| 242 | 482 |
| 243 base::FilePath cache_path(args[0]); | 483 base::FilePath cache_path(args[0]); |
| 244 std::string cache_backend_type(args[1]); | 484 std::string cache_backend_type(args[1]); |
| 245 std::string subcommand(args[2]); | |
| 246 | 485 |
| 247 net::BackendType backend_type; | 486 net::BackendType backend_type; |
| 248 if (cache_backend_type == "simple") { | 487 if (cache_backend_type == "simple") { |
| 249 backend_type = net::CACHE_BACKEND_SIMPLE; | 488 backend_type = net::CACHE_BACKEND_SIMPLE; |
| 250 } else if (cache_backend_type == "blockfile") { | 489 } else if (cache_backend_type == "blockfile") { |
| 251 backend_type = net::CACHE_BACKEND_BLOCKFILE; | 490 backend_type = net::CACHE_BACKEND_BLOCKFILE; |
| 252 } else { | 491 } else { |
| 253 std::cerr << "Unknown cache type." << std::endl; | 492 std::cerr << "Unknown cache type." << std::endl; |
| 254 PrintHelp(); | 493 PrintHelp(); |
| 255 return 1; | 494 return 1; |
| 256 } | 495 } |
| 257 | 496 |
| 258 std::unique_ptr<Backend> cache_backend; | 497 std::unique_ptr<Backend> cache_backend; |
| 259 net::TestCompletionCallback cb; | 498 net::TestCompletionCallback cb; |
| 260 int rv = disk_cache::CreateCacheBackend( | 499 int rv = disk_cache::CreateCacheBackend( |
| 261 net::DISK_CACHE, backend_type, cache_path, INT_MAX, false, | 500 net::DISK_CACHE, backend_type, cache_path, INT_MAX, false, |
| 262 message_loop.task_runner(), nullptr, &cache_backend, cb.callback()); | 501 message_loop.task_runner(), nullptr, &cache_backend, cb.callback()); |
| 263 if (cb.GetResult(rv) != net::OK) { | 502 if (cb.GetResult(rv) != net::OK) { |
| 264 std::cerr << "Invalid cache." << std::endl; | 503 std::cerr << "Invalid cache." << std::endl; |
| 265 return 1; | 504 return 1; |
| 266 } | 505 } |
| 267 | 506 |
| 268 bool successful_command; | 507 CommandLineIO command_line_io( |
| 269 if (subcommand == "delete_key" && args.size() == 4) { | 508 cache_backend.get(), |
| 270 successful_command = DeleteKey(cache_backend.get(), args[3]); | 509 base::CommandLine::StringVector(args.begin() + 2, args.end())); |
| 271 } else if (subcommand == "delete_stream" && args.size() == 5) { | 510 bool successful_commands = ExecuteCommands(&command_line_io); |
| 272 int index = ParseStreamIndex(args[4]); | 511 |
| 273 if (index < 0) | |
| 274 return 1; | |
| 275 successful_command = | |
| 276 DeleteStreamForKey(cache_backend.get(), args[3], index); | |
| 277 } else if (subcommand == "get_size" && args.size() == 3) { | |
| 278 successful_command = GetSize(cache_backend.get()); | |
| 279 } else if (subcommand == "get_stream" && args.size() == 5) { | |
| 280 int index = ParseStreamIndex(args[4]); | |
| 281 if (index < 0) | |
| 282 return 1; | |
| 283 successful_command = GetStreamForKey(cache_backend.get(), args[3], index); | |
| 284 } else if (subcommand == "list_keys" && args.size() == 3) { | |
| 285 successful_command = ListKeys(cache_backend.get()); | |
| 286 } else if (subcommand == "update_raw_headers" && args.size() == 4) { | |
| 287 successful_command = UpdateRawResponseHeaders(cache_backend.get(), args[3]); | |
| 288 } else if (subcommand == "validate" && args.size() == 3) { | |
| 289 successful_command = true; | |
| 290 } else { | |
| 291 successful_command = false; | |
| 292 PrintHelp(); | |
| 293 } | |
| 294 base::RunLoop().RunUntilIdle(); | 512 base::RunLoop().RunUntilIdle(); |
| 295 cache_backend = nullptr; | 513 cache_backend = nullptr; |
| 296 base::RunLoop().RunUntilIdle(); | 514 base::RunLoop().RunUntilIdle(); |
| 297 return !successful_command; | 515 return !successful_commands; |
| 298 } | 516 } |
| OLD | NEW |