Home | History | Annotate | Download | only in url_request
      1 // Copyright (c) 2011 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/base/net_errors.h"
     11 #include "net/disk_cache/disk_cache.h"
     12 #include "net/http/http_cache.h"
     13 #include "net/http/http_response_headers.h"
     14 #include "net/http/http_response_info.h"
     15 #include "net/url_request/url_request_context.h"
     16 
     17 #define VIEW_CACHE_HEAD \
     18   "<html><body><table>"
     19 
     20 #define VIEW_CACHE_TAIL \
     21   "</table></body></html>"
     22 
     23 namespace net {
     24 
     25 namespace {
     26 
     27 void HexDump(const char *buf, size_t buf_len, std::string* result) {
     28   const size_t kMaxRows = 16;
     29   int offset = 0;
     30 
     31   const unsigned char *p;
     32   while (buf_len) {
     33     base::StringAppendF(result, "%08x:  ", offset);
     34     offset += kMaxRows;
     35 
     36     p = (const unsigned char *) buf;
     37 
     38     size_t i;
     39     size_t row_max = std::min(kMaxRows, buf_len);
     40 
     41     // print hex codes:
     42     for (i = 0; i < row_max; ++i)
     43       base::StringAppendF(result, "%02x  ", *p++);
     44     for (i = row_max; i < kMaxRows; ++i)
     45       result->append("    ");
     46 
     47     // print ASCII glyphs if possible:
     48     p = (const unsigned char *) buf;
     49     for (i = 0; i < row_max; ++i, ++p) {
     50       if (*p < 0x7F && *p > 0x1F) {
     51         AppendEscapedCharForHTML(*p, result);
     52       } else {
     53         result->push_back('.');
     54       }
     55     }
     56 
     57     result->push_back('\n');
     58 
     59     buf += row_max;
     60     buf_len -= row_max;
     61   }
     62 }
     63 
     64 std::string FormatEntryInfo(disk_cache::Entry* entry,
     65                             const std::string& url_prefix) {
     66   std::string key = entry->GetKey();
     67   GURL url = GURL(url_prefix + key);
     68   std::string row =
     69       "<tr><td><a href=\"" + url.spec() + "\">" + EscapeForHTML(key) +
     70       "</a></td></tr>";
     71   return row;
     72 }
     73 
     74 }  // namespace.
     75 
     76 ViewCacheHelper::ViewCacheHelper()
     77     : disk_cache_(NULL),
     78       entry_(NULL),
     79       iter_(NULL),
     80       buf_len_(0),
     81       index_(0),
     82       data_(NULL),
     83       callback_(NULL),
     84       next_state_(STATE_NONE),
     85       ALLOW_THIS_IN_INITIALIZER_LIST(
     86           cache_callback_(this, &ViewCacheHelper::OnIOComplete)),
     87       ALLOW_THIS_IN_INITIALIZER_LIST(
     88           entry_callback_(new CancelableCompletionCallback<ViewCacheHelper>(
     89               this, &ViewCacheHelper::OnIOComplete))) {
     90 }
     91 
     92 ViewCacheHelper::~ViewCacheHelper() {
     93   if (entry_)
     94     entry_->Close();
     95 
     96   // Cancel any pending entry callback.
     97   entry_callback_->Cancel();
     98 }
     99 
    100 int ViewCacheHelper::GetEntryInfoHTML(const std::string& key,
    101                                       URLRequestContext* context,
    102                                       std::string* out,
    103                                       CompletionCallback* callback) {
    104   return GetInfoHTML(key, context, std::string(), out, callback);
    105 }
    106 
    107 int ViewCacheHelper::GetContentsHTML(URLRequestContext* context,
    108                                      const std::string& url_prefix,
    109                                      std::string* out,
    110                                      CompletionCallback* callback) {
    111   return GetInfoHTML(std::string(), context, url_prefix, out, callback);
    112 }
    113 
    114 //-----------------------------------------------------------------------------
    115 
    116 int ViewCacheHelper::GetInfoHTML(const std::string& key,
    117                                  URLRequestContext* context,
    118                                  const std::string& url_prefix,
    119                                  std::string* out,
    120                                  CompletionCallback* callback) {
    121   DCHECK(!callback_);
    122   DCHECK(context);
    123   key_ = key;
    124   context_ = context;
    125   url_prefix_ = url_prefix;
    126   data_ = out;
    127   next_state_ = STATE_GET_BACKEND;
    128   int rv = DoLoop(OK);
    129 
    130   if (rv == ERR_IO_PENDING)
    131     callback_ = callback;
    132 
    133   return rv;
    134 }
    135 
    136 void ViewCacheHelper::DoCallback(int rv) {
    137   DCHECK_NE(ERR_IO_PENDING, rv);
    138   DCHECK(callback_);
    139 
    140   CompletionCallback* c = callback_;
    141   callback_ = NULL;
    142   c->Run(rv);
    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_)
    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(&disk_cache_, &cache_callback_);
    221 }
    222 
    223 int ViewCacheHelper::DoGetBackendComplete(int result) {
    224   if (result == ERR_FAILED) {
    225     data_->append("no disk cache");
    226     return OK;
    227   }
    228 
    229   DCHECK_EQ(OK, result);
    230   if (key_.empty()) {
    231     data_->assign(VIEW_CACHE_HEAD);
    232     DCHECK(!iter_);
    233     next_state_ = STATE_OPEN_NEXT_ENTRY;
    234     return OK;
    235   }
    236 
    237   next_state_ = STATE_OPEN_ENTRY;
    238   return OK;
    239 }
    240 
    241 int ViewCacheHelper::DoOpenNextEntry() {
    242   next_state_ = STATE_OPEN_NEXT_ENTRY_COMPLETE;
    243   return disk_cache_->OpenNextEntry(&iter_, &entry_, &cache_callback_);
    244 }
    245 
    246 int ViewCacheHelper::DoOpenNextEntryComplete(int result) {
    247   if (result == ERR_FAILED) {
    248     data_->append(VIEW_CACHE_TAIL);
    249     return OK;
    250   }
    251 
    252   DCHECK_EQ(OK, result);
    253   data_->append(FormatEntryInfo(entry_, url_prefix_));
    254   entry_->Close();
    255   entry_ = NULL;
    256 
    257   next_state_ = STATE_OPEN_NEXT_ENTRY;
    258   return OK;
    259 }
    260 
    261 int ViewCacheHelper::DoOpenEntry() {
    262   next_state_ = STATE_OPEN_ENTRY_COMPLETE;
    263   return disk_cache_->OpenEntry(key_, &entry_, &cache_callback_);
    264 }
    265 
    266 int ViewCacheHelper::DoOpenEntryComplete(int result) {
    267   if (result == ERR_FAILED) {
    268     data_->append("no matching cache entry for: " + EscapeForHTML(key_));
    269     return OK;
    270   }
    271 
    272   data_->assign(VIEW_CACHE_HEAD);
    273   data_->append(EscapeForHTML(entry_->GetKey()));
    274   next_state_ = STATE_READ_RESPONSE;
    275   return OK;
    276 }
    277 
    278 int ViewCacheHelper::DoReadResponse() {
    279   next_state_ = STATE_READ_RESPONSE_COMPLETE;
    280   buf_len_ = entry_->GetDataSize(0);
    281   entry_callback_->AddRef();
    282   if (!buf_len_)
    283     return buf_len_;
    284 
    285   buf_ = new IOBuffer(buf_len_);
    286   return entry_->ReadData(0, 0, buf_, buf_len_, entry_callback_);
    287 }
    288 
    289 int ViewCacheHelper::DoReadResponseComplete(int result) {
    290   entry_callback_->Release();
    291   if (result && result == buf_len_) {
    292     HttpResponseInfo response;
    293     bool truncated;
    294     if (HttpCache::ParseResponseInfo(buf_->data(), buf_len_, &response,
    295                                           &truncated) &&
    296         response.headers) {
    297       if (truncated)
    298         data_->append("<pre>RESPONSE_INFO_TRUNCATED</pre>");
    299 
    300       data_->append("<hr><pre>");
    301       data_->append(EscapeForHTML(response.headers->GetStatusLine()));
    302       data_->push_back('\n');
    303 
    304       void* iter = NULL;
    305       std::string name, value;
    306       while (response.headers->EnumerateHeaderLines(&iter, &name, &value)) {
    307         data_->append(EscapeForHTML(name));
    308         data_->append(": ");
    309         data_->append(EscapeForHTML(value));
    310         data_->push_back('\n');
    311       }
    312       data_->append("</pre>");
    313     }
    314   }
    315 
    316   index_ = 0;
    317   next_state_ = STATE_READ_DATA;
    318   return OK;
    319 }
    320 
    321 int ViewCacheHelper::DoReadData() {
    322   data_->append("<hr><pre>");
    323 
    324   next_state_ = STATE_READ_DATA_COMPLETE;
    325   buf_len_ = entry_->GetDataSize(index_);
    326   entry_callback_->AddRef();
    327   if (!buf_len_)
    328     return buf_len_;
    329 
    330   buf_ = new IOBuffer(buf_len_);
    331   return entry_->ReadData(index_, 0, buf_, buf_len_, entry_callback_);
    332 }
    333 
    334 int ViewCacheHelper::DoReadDataComplete(int result) {
    335   entry_callback_->Release();
    336   if (result && result == buf_len_) {
    337     HexDump(buf_->data(), buf_len_, data_);
    338   }
    339   data_->append("</pre>");
    340   index_++;
    341   if (index_ < HttpCache::kNumCacheEntryDataIndices) {
    342     next_state_ = STATE_READ_DATA;
    343   } else {
    344     data_->append(VIEW_CACHE_TAIL);
    345     entry_->Close();
    346     entry_ = NULL;
    347   }
    348   return OK;
    349 }
    350 
    351 void ViewCacheHelper::OnIOComplete(int result) {
    352   DoLoop(result);
    353 }
    354 
    355 }  // namespace net.
    356