Home | History | Annotate | Download | only in url_request
      1 // Copyright (c) 2012 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/bind.h"
      8 #include "base/bind_helpers.h"
      9 #include "base/strings/stringprintf.h"
     10 #include "net/base/escape.h"
     11 #include "net/base/io_buffer.h"
     12 #include "net/base/net_errors.h"
     13 #include "net/disk_cache/disk_cache.h"
     14 #include "net/http/http_cache.h"
     15 #include "net/http/http_response_headers.h"
     16 #include "net/http/http_response_info.h"
     17 #include "net/url_request/url_request_context.h"
     18 
     19 #define VIEW_CACHE_HEAD \
     20   "<html><meta charset=\"utf-8\">" \
     21   "<meta http-equiv=\"Content-Security-Policy\" " \
     22   "  content=\"object-src 'none'; script-src 'none' 'unsafe-eval'\">" \
     23   "<body><table>"
     24 
     25 #define VIEW_CACHE_TAIL \
     26   "</table></body></html>"
     27 
     28 namespace net {
     29 
     30 namespace {
     31 
     32 std::string FormatEntryInfo(disk_cache::Entry* entry,
     33                             const std::string& url_prefix) {
     34   std::string key = entry->GetKey();
     35   GURL url = GURL(url_prefix + key);
     36   std::string row =
     37       "<tr><td><a href=\"" + url.spec() + "\">" + EscapeForHTML(key) +
     38       "</a></td></tr>";
     39   return row;
     40 }
     41 
     42 }  // namespace.
     43 
     44 ViewCacheHelper::ViewCacheHelper()
     45     : context_(NULL),
     46       disk_cache_(NULL),
     47       entry_(NULL),
     48       iter_(NULL),
     49       buf_len_(0),
     50       index_(0),
     51       data_(NULL),
     52       next_state_(STATE_NONE),
     53       weak_factory_(this) {
     54 }
     55 
     56 ViewCacheHelper::~ViewCacheHelper() {
     57   if (entry_)
     58     entry_->Close();
     59 }
     60 
     61 int ViewCacheHelper::GetEntryInfoHTML(const std::string& key,
     62                                       const URLRequestContext* context,
     63                                       std::string* out,
     64                                       const CompletionCallback& callback) {
     65   return GetInfoHTML(key, context, std::string(), out, callback);
     66 }
     67 
     68 int ViewCacheHelper::GetContentsHTML(const URLRequestContext* context,
     69                                      const std::string& url_prefix,
     70                                      std::string* out,
     71                                      const CompletionCallback& callback) {
     72   return GetInfoHTML(std::string(), context, url_prefix, out, callback);
     73 }
     74 
     75 // static
     76 void ViewCacheHelper::HexDump(const char *buf, size_t buf_len,
     77                               std::string* result) {
     78   const size_t kMaxRows = 16;
     79   int offset = 0;
     80 
     81   const unsigned char *p;
     82   while (buf_len) {
     83     base::StringAppendF(result, "%08x: ", offset);
     84     offset += kMaxRows;
     85 
     86     p = (const unsigned char *) buf;
     87 
     88     size_t i;
     89     size_t row_max = std::min(kMaxRows, buf_len);
     90 
     91     // print hex codes:
     92     for (i = 0; i < row_max; ++i)
     93       base::StringAppendF(result, "%02x ", *p++);
     94     for (i = row_max; i < kMaxRows; ++i)
     95       result->append("   ");
     96     result->append(" ");
     97 
     98     // print ASCII glyphs if possible:
     99     p = (const unsigned char *) buf;
    100     for (i = 0; i < row_max; ++i, ++p) {
    101       if (*p < 0x7F && *p > 0x1F) {
    102         AppendEscapedCharForHTML(*p, result);
    103       } else {
    104         result->push_back('.');
    105       }
    106     }
    107 
    108     result->push_back('\n');
    109 
    110     buf += row_max;
    111     buf_len -= row_max;
    112   }
    113 }
    114 
    115 //-----------------------------------------------------------------------------
    116 
    117 int ViewCacheHelper::GetInfoHTML(const std::string& key,
    118                                  const URLRequestContext* context,
    119                                  const std::string& url_prefix,
    120                                  std::string* out,
    121                                  const CompletionCallback& callback) {
    122   DCHECK(callback_.is_null());
    123   DCHECK(context);
    124   key_ = key;
    125   context_ = context;
    126   url_prefix_ = url_prefix;
    127   data_ = out;
    128   next_state_ = STATE_GET_BACKEND;
    129   int rv = DoLoop(OK);
    130 
    131   if (rv == ERR_IO_PENDING)
    132     callback_ = callback;
    133 
    134   return rv;
    135 }
    136 
    137 void ViewCacheHelper::DoCallback(int rv) {
    138   DCHECK_NE(ERR_IO_PENDING, rv);
    139   DCHECK(!callback_.is_null());
    140 
    141   callback_.Run(rv);
    142   callback_.Reset();
    143 }
    144 
    145 void ViewCacheHelper::HandleResult(int rv) {
    146   DCHECK_NE(ERR_IO_PENDING, rv);
    147   DCHECK_NE(ERR_FAILED, rv);
    148   context_ = NULL;
    149   if (!callback_.is_null())
    150     DoCallback(rv);
    151 }
    152 
    153 int ViewCacheHelper::DoLoop(int result) {
    154   DCHECK(next_state_ != STATE_NONE);
    155 
    156   int rv = result;
    157   do {
    158     State state = next_state_;
    159     next_state_ = STATE_NONE;
    160     switch (state) {
    161       case STATE_GET_BACKEND:
    162         DCHECK_EQ(OK, rv);
    163         rv = DoGetBackend();
    164         break;
    165       case STATE_GET_BACKEND_COMPLETE:
    166         rv = DoGetBackendComplete(rv);
    167         break;
    168       case STATE_OPEN_NEXT_ENTRY:
    169         DCHECK_EQ(OK, rv);
    170         rv = DoOpenNextEntry();
    171         break;
    172       case STATE_OPEN_NEXT_ENTRY_COMPLETE:
    173         rv = DoOpenNextEntryComplete(rv);
    174         break;
    175       case STATE_OPEN_ENTRY:
    176         DCHECK_EQ(OK, rv);
    177         rv = DoOpenEntry();
    178         break;
    179       case STATE_OPEN_ENTRY_COMPLETE:
    180         rv = DoOpenEntryComplete(rv);
    181         break;
    182       case STATE_READ_RESPONSE:
    183         DCHECK_EQ(OK, rv);
    184         rv = DoReadResponse();
    185         break;
    186       case STATE_READ_RESPONSE_COMPLETE:
    187         rv = DoReadResponseComplete(rv);
    188         break;
    189       case STATE_READ_DATA:
    190         DCHECK_EQ(OK, rv);
    191         rv = DoReadData();
    192         break;
    193       case STATE_READ_DATA_COMPLETE:
    194         rv = DoReadDataComplete(rv);
    195         break;
    196 
    197       default:
    198         NOTREACHED() << "bad state";
    199         rv = ERR_FAILED;
    200         break;
    201     }
    202   } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
    203 
    204   if (rv != ERR_IO_PENDING)
    205     HandleResult(rv);
    206 
    207   return rv;
    208 }
    209 
    210 int ViewCacheHelper::DoGetBackend() {
    211   next_state_ = STATE_GET_BACKEND_COMPLETE;
    212 
    213   if (!context_->http_transaction_factory())
    214     return ERR_FAILED;
    215 
    216   HttpCache* http_cache = context_->http_transaction_factory()->GetCache();
    217   if (!http_cache)
    218     return ERR_FAILED;
    219 
    220   return http_cache->GetBackend(
    221       &disk_cache_, base::Bind(&ViewCacheHelper::OnIOComplete,
    222                                base::Unretained(this)));
    223 }
    224 
    225 int ViewCacheHelper::DoGetBackendComplete(int result) {
    226   if (result == ERR_FAILED) {
    227     data_->append("no disk cache");
    228     return OK;
    229   }
    230 
    231   DCHECK_EQ(OK, result);
    232   if (key_.empty()) {
    233     data_->assign(VIEW_CACHE_HEAD);
    234     DCHECK(!iter_);
    235     next_state_ = STATE_OPEN_NEXT_ENTRY;
    236     return OK;
    237   }
    238 
    239   next_state_ = STATE_OPEN_ENTRY;
    240   return OK;
    241 }
    242 
    243 int ViewCacheHelper::DoOpenNextEntry() {
    244   next_state_ = STATE_OPEN_NEXT_ENTRY_COMPLETE;
    245   return disk_cache_->OpenNextEntry(
    246       &iter_, &entry_,
    247       base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this)));
    248 }
    249 
    250 int ViewCacheHelper::DoOpenNextEntryComplete(int result) {
    251   if (result == ERR_FAILED) {
    252     data_->append(VIEW_CACHE_TAIL);
    253     return OK;
    254   }
    255 
    256   DCHECK_EQ(OK, result);
    257   data_->append(FormatEntryInfo(entry_, url_prefix_));
    258   entry_->Close();
    259   entry_ = NULL;
    260 
    261   next_state_ = STATE_OPEN_NEXT_ENTRY;
    262   return OK;
    263 }
    264 
    265 int ViewCacheHelper::DoOpenEntry() {
    266   next_state_ = STATE_OPEN_ENTRY_COMPLETE;
    267   return disk_cache_->OpenEntry(
    268       key_, &entry_,
    269       base::Bind(&ViewCacheHelper::OnIOComplete, base::Unretained(this)));
    270 }
    271 
    272 int ViewCacheHelper::DoOpenEntryComplete(int result) {
    273   if (result == ERR_FAILED) {
    274     data_->append("no matching cache entry for: " + EscapeForHTML(key_));
    275     return OK;
    276   }
    277 
    278   data_->assign(VIEW_CACHE_HEAD);
    279   data_->append(EscapeForHTML(entry_->GetKey()));
    280   next_state_ = STATE_READ_RESPONSE;
    281   return OK;
    282 }
    283 
    284 int ViewCacheHelper::DoReadResponse() {
    285   next_state_ = STATE_READ_RESPONSE_COMPLETE;
    286   buf_len_ = entry_->GetDataSize(0);
    287   if (!buf_len_)
    288     return buf_len_;
    289 
    290   buf_ = new IOBuffer(buf_len_);
    291   return entry_->ReadData(
    292       0,
    293       0,
    294       buf_.get(),
    295       buf_len_,
    296       base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
    297 }
    298 
    299 int ViewCacheHelper::DoReadResponseComplete(int result) {
    300   if (result && result == buf_len_) {
    301     HttpResponseInfo response;
    302     bool truncated;
    303     if (HttpCache::ParseResponseInfo(
    304             buf_->data(), buf_len_, &response, &truncated) &&
    305         response.headers.get()) {
    306       if (truncated)
    307         data_->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
    308 
    309       data_->append("<hr><pre>");
    310       data_->append(EscapeForHTML(response.headers->GetStatusLine()));
    311       data_->push_back('\n');
    312 
    313       void* iter = NULL;
    314       std::string name, value;
    315       while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
    316         data_->append(EscapeForHTML(name));
    317         data_->append(": ");
    318         data_->append(EscapeForHTML(value));
    319         data_->push_back('\n');
    320       }
    321       data_->append("</pre>");
    322     }
    323   }
    324 
    325   index_ = 0;
    326   next_state_ = STATE_READ_DATA;
    327   return OK;
    328 }
    329 
    330 int ViewCacheHelper::DoReadData() {
    331   data_->append("<hr><pre>");
    332 
    333   next_state_ = STATE_READ_DATA_COMPLETE;
    334   buf_len_ = entry_->GetDataSize(index_);
    335   if (!buf_len_)
    336     return buf_len_;
    337 
    338   buf_ = new IOBuffer(buf_len_);
    339   return entry_->ReadData(
    340       index_,
    341       0,
    342       buf_.get(),
    343       buf_len_,
    344       base::Bind(&ViewCacheHelper::OnIOComplete, weak_factory_.GetWeakPtr()));
    345 }
    346 
    347 int ViewCacheHelper::DoReadDataComplete(int result) {
    348   if (result && result == buf_len_) {
    349     HexDump(buf_->data(), buf_len_, data_);
    350   }
    351   data_->append("</pre>");
    352   index_++;
    353   if (index_ < HttpCache::kNumCacheEntryDataIndices) {
    354     next_state_ = STATE_READ_DATA;
    355   } else {
    356     data_->append(VIEW_CACHE_TAIL);
    357     entry_->Close();
    358     entry_ = NULL;
    359   }
    360   return OK;
    361 }
    362 
    363 void ViewCacheHelper::OnIOComplete(int result) {
    364   DoLoop(result);
    365 }
    366 
    367 }  // namespace net.
    368