1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
18 * Netscape Communications Corporation.
19 * Portions created by the Initial Developer are Copyright (C) 2001
20 * the Initial Developer. All Rights Reserved.
23 * Darin Fisher <darin@netscape.com> (original author)
24 * Alexey Chernyak <alexeyc@bigfoot.com> (XHTML 1.1 conversion)
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
42 #include "nsAboutCacheEntry.h"
43 #include "nsICacheService.h"
44 #include "nsICacheEntryDescriptor.h"
45 #include "nsIStorageStream.h"
46 #include "nsNetUtil.h"
47 #include "nsAutoPtr.h"
52 #define HEXDUMP_MAX_ROWS 16
55 HexDump(PRUint32
*state
, const char *buf
, PRInt32 n
, nsCString
&result
)
59 const unsigned char *p
;
61 PR_snprintf(temp
, sizeof(temp
), "%08x: ", *state
);
63 *state
+= HEXDUMP_MAX_ROWS
;
65 p
= (const unsigned char *) buf
;
67 PRInt32 i
, row_max
= PR_MIN(HEXDUMP_MAX_ROWS
, n
);
70 for (i
= 0; i
< row_max
; ++i
) {
71 PR_snprintf(temp
, sizeof(temp
), "%02x ", *p
++);
74 for (i
= row_max
; i
< HEXDUMP_MAX_ROWS
; ++i
) {
75 result
.AppendLiteral(" ");
78 // print ASCII glyphs if possible:
79 p
= (const unsigned char *) buf
;
80 for (i
= 0; i
< row_max
; ++i
, ++p
) {
83 result
.AppendLiteral("<");
86 result
.AppendLiteral(">");
89 result
.AppendLiteral("&");
92 if (*p
< 0x7F && *p
> 0x1F) {
107 //-----------------------------------------------------------------------------
108 // nsAboutCacheEntry::nsISupports
110 NS_IMPL_ISUPPORTS2(nsAboutCacheEntry
,
112 nsICacheMetaDataVisitor
)
114 //-----------------------------------------------------------------------------
115 // nsAboutCacheEntry::nsIAboutModule
118 nsAboutCacheEntry::NewChannel(nsIURI
*uri
, nsIChannel
**result
)
120 NS_ENSURE_ARG_POINTER(uri
);
123 nsCOMPtr
<nsIInputStream
> stream
;
124 rv
= GetContentStream(uri
, getter_AddRefs(stream
));
125 if (NS_FAILED(rv
)) return rv
;
127 return NS_NewInputStreamChannel(result
, uri
, stream
,
128 NS_LITERAL_CSTRING("application/xhtml+xml"),
129 NS_LITERAL_CSTRING("utf-8"));
133 nsAboutCacheEntry::GetURIFlags(nsIURI
*aURI
, PRUint32
*result
)
139 //-----------------------------------------------------------------------------
143 nsAboutCacheEntry::GetContentStream(nsIURI
*uri
, nsIInputStream
**result
)
145 nsCOMPtr
<nsIStorageStream
> storageStream
;
146 nsCOMPtr
<nsIOutputStream
> outputStream
;
151 nsCOMPtr
<nsICacheEntryDescriptor
> descriptor
;
152 OpenCacheEntry(uri
, getter_AddRefs(descriptor
));
154 // Init: (block size, maximum length)
155 rv
= NS_NewStorageStream(256, PRUint32(-1), getter_AddRefs(storageStream
));
156 if (NS_FAILED(rv
)) return rv
;
158 rv
= storageStream
->GetOutputStream(0, getter_AddRefs(outputStream
));
159 if (NS_FAILED(rv
)) return rv
;
161 buffer
.AssignLiteral(
162 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
163 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.1//EN\"\n"
164 " \"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd\">\n"
165 "<html xmlns=\"http://www.w3.org/1999/xhtml\">\n"
166 "<head>\n<title>Cache entry information</title>\n"
167 "<style type=\"text/css\">\npre {\n margin: 0;\n}\n"
168 "td:first-child {\n text-align: right;\n vertical-align: top;\n"
169 " line-height: 0.8em;\n}\n</style>\n</head>\n<body>\n");
170 outputStream
->Write(buffer
.get(), buffer
.Length(), &n
);
173 rv
= WriteCacheEntryDescription(outputStream
, descriptor
);
175 rv
= WriteCacheEntryUnavailable(outputStream
);
176 if (NS_FAILED(rv
)) return rv
;
178 buffer
.AssignLiteral("</body>\n</html>\n");
179 outputStream
->Write(buffer
.get(), buffer
.Length(), &n
);
181 nsCOMPtr
<nsIInputStream
> inStr
;
184 rv
= storageStream
->GetLength(&size
);
185 if (NS_FAILED(rv
)) return rv
;
187 return storageStream
->NewInputStream(0, result
);
191 nsAboutCacheEntry::OpenCacheEntry(nsIURI
*uri
, nsICacheEntryDescriptor
**result
)
194 nsCAutoString clientID
, key
;
195 PRBool streamBased
= PR_TRUE
;
197 rv
= ParseURI(uri
, clientID
, streamBased
, key
);
198 if (NS_FAILED(rv
)) return rv
;
200 nsCOMPtr
<nsICacheService
> serv
=
201 do_GetService(NS_CACHESERVICE_CONTRACTID
, &rv
);
202 if (NS_FAILED(rv
)) return rv
;
204 nsCOMPtr
<nsICacheSession
> session
;
205 rv
= serv
->CreateSession(clientID
.get(),
206 nsICache::STORE_ANYWHERE
,
208 getter_AddRefs(session
));
209 if (NS_FAILED(rv
)) return rv
;
211 rv
= session
->SetDoomEntriesIfExpired(PR_FALSE
);
212 if (NS_FAILED(rv
)) return rv
;
214 rv
= session
->OpenCacheEntry(key
, nsICache::ACCESS_READ
, PR_FALSE
, result
);
219 //-----------------------------------------------------------------------------
221 //-----------------------------------------------------------------------------
223 static PRTime
SecondsToPRTime(PRUint32 t_sec
)
225 PRTime t_usec
, usec_per_sec
;
226 LL_I2L(t_usec
, t_sec
);
227 LL_I2L(usec_per_sec
, PR_USEC_PER_SEC
);
228 LL_MUL(t_usec
, t_usec
, usec_per_sec
);
231 static void PrintTimeString(char *buf
, PRUint32 bufsize
, PRUint32 t_sec
)
234 PRTime t_usec
= SecondsToPRTime(t_sec
);
235 PR_ExplodeTime(t_usec
, PR_LocalTimeParameters
, &et
);
236 PR_FormatTime(buf
, bufsize
, "%Y-%m-%d %H:%M:%S", &et
);
239 #define APPEND_ROW(label, value) \
241 buffer.AppendLiteral("<tr><td><tt><b>"); \
242 buffer.AppendLiteral(label); \
243 buffer.AppendLiteral(":</b></tt></td>\n<td><pre>"); \
244 buffer.Append(value); \
245 buffer.AppendLiteral("</pre></td></tr>\n"); \
249 nsAboutCacheEntry::WriteCacheEntryDescription(nsIOutputStream
*outputStream
,
250 nsICacheEntryDescriptor
*descriptor
)
258 rv
= descriptor
->GetKey(str
);
259 if (NS_FAILED(rv
)) return rv
;
261 buffer
.SetCapacity(4096);
262 buffer
.AssignLiteral("<table>"
263 "<tr><td><tt><b>key:</b></tt></td><td>");
265 // Test if the key is actually a URI
266 nsCOMPtr
<nsIURI
> uri
;
267 PRBool isJS
= PR_FALSE
;
268 PRBool isData
= PR_FALSE
;
270 rv
= NS_NewURI(getter_AddRefs(uri
), str
);
271 // javascript: and data: URLs should not be linkified
272 // since clicking them can cause scripts to run - bug 162584
273 if (NS_SUCCEEDED(rv
)) {
274 uri
->SchemeIs("javascript", &isJS
);
275 uri
->SchemeIs("data", &isData
);
277 char* escapedStr
= nsEscapeHTML(str
.get());
278 if (NS_SUCCEEDED(rv
) && !(isJS
|| isData
)) {
279 buffer
.AppendLiteral("<a href=\"");
280 buffer
.Append(escapedStr
);
281 buffer
.AppendLiteral("\">");
282 buffer
.Append(escapedStr
);
283 buffer
.AppendLiteral("</a>");
287 buffer
.Append(escapedStr
);
288 nsMemory::Free(escapedStr
);
289 buffer
.AppendLiteral("</td></tr>\n");
292 // temp vars for reporting
300 descriptor
->GetFetchCount(&i
);
302 APPEND_ROW("fetch count", s
);
305 descriptor
->GetLastFetched(&u
);
307 PrintTimeString(timeBuf
, sizeof(timeBuf
), u
);
308 APPEND_ROW("last fetched", timeBuf
);
310 APPEND_ROW("last fetched", "No last fetch time");
314 descriptor
->GetLastModified(&u
);
316 PrintTimeString(timeBuf
, sizeof(timeBuf
), u
);
317 APPEND_ROW("last modified", timeBuf
);
319 APPEND_ROW("last modified", "No last modified time");
323 descriptor
->GetExpirationTime(&u
);
324 if (u
< 0xFFFFFFFF) {
325 PrintTimeString(timeBuf
, sizeof(timeBuf
), u
);
326 APPEND_ROW("expires", timeBuf
);
328 APPEND_ROW("expires", "No expiration time");
334 descriptor
->GetDataSize(&dataSize
);
335 s
.AppendInt((PRInt32
)dataSize
); // XXX nsICacheEntryInfo interfaces should be fixed.
336 APPEND_ROW("Data size", s
);
344 nsCOMPtr
<nsIFile
> cacheFile
;
345 rv
= descriptor
->GetFile(getter_AddRefs(cacheFile
));
346 if (NS_SUCCEEDED(rv
)) {
347 nsAutoString filePath
;
348 cacheFile
->GetPath(filePath
);
349 APPEND_ROW("file on disk", NS_ConvertUTF16toUTF8(filePath
));
352 APPEND_ROW("file on disk", "none");
355 nsCOMPtr
<nsISupports
> securityInfo
;
356 descriptor
->GetSecurityInfo(getter_AddRefs(securityInfo
));
358 APPEND_ROW("Security", "This is a secure document.");
360 APPEND_ROW("Security",
361 "This document does not have any security info associated with it.");
364 buffer
.AppendLiteral("</table>\n"
367 // let's just look for some well known (HTTP) meta data tags, for now.
371 descriptor
->GetClientID(getter_Copies(str2
));
372 if (!str2
.IsEmpty()) APPEND_ROW("Client", str2
);
375 mBuffer
= &buffer
; // make it available for VisitMetaDataElement()
376 descriptor
->VisitMetaData(this);
379 buffer
.AppendLiteral("</table>\n"
381 outputStream
->Write(buffer
.get(), buffer
.Length(), &n
);
385 // Provide a hexdump of the data
386 nsCOMPtr
<nsIInputStream
> stream
;
387 descriptor
->OpenInputStream(0, getter_AddRefs(stream
));
389 PRUint32 hexDumpState
= 0;
392 PRUint32 count
= PR_MIN(dataSize
, sizeof(chunk
));
393 if (NS_FAILED(stream
->Read(chunk
, count
, &n
)) || n
== 0)
396 HexDump(&hexDumpState
, chunk
, n
, buffer
);
397 outputStream
->Write(buffer
.get(), buffer
.Length(), &n
);
402 buffer
.AssignLiteral("</pre>");
403 outputStream
->Write(buffer
.get(), buffer
.Length(), &n
);
408 nsAboutCacheEntry::WriteCacheEntryUnavailable(nsIOutputStream
*outputStream
)
411 NS_NAMED_LITERAL_CSTRING(buffer
,
412 "The cache entry you selected is not available.");
413 outputStream
->Write(buffer
.get(), buffer
.Length(), &n
);
418 nsAboutCacheEntry::ParseURI(nsIURI
*uri
, nsCString
&clientID
,
419 PRBool
&streamBased
, nsCString
&key
)
422 // about:cache-entry?client=[string]&sb=[boolean]&key=[string]
427 rv
= uri
->GetPath(path
);
428 if (NS_FAILED(rv
)) return rv
;
430 nsACString::const_iterator i1
, i2
, i3
, end
;
431 path
.BeginReading(i1
);
432 path
.EndReading(end
);
435 if (!FindInReadable(NS_LITERAL_CSTRING("?client="), i1
, i2
))
436 return NS_ERROR_FAILURE
;
437 // i2 points to the start of clientID
441 if (!FindInReadable(NS_LITERAL_CSTRING("&sb="), i1
, i3
))
442 return NS_ERROR_FAILURE
;
443 // i1 points to the end of clientID
444 // i3 points to the start of isStreamBased
446 clientID
.Assign(Substring(i2
, i1
));
450 if (!FindInReadable(NS_LITERAL_CSTRING("&key="), i1
, i2
))
451 return NS_ERROR_FAILURE
;
452 // i1 points to the end of isStreamBased
453 // i2 points to the start of key
455 streamBased
= FindCharInReadable('1', i3
, i1
);
456 key
.Assign(Substring(i2
, end
));
462 //-----------------------------------------------------------------------------
463 // nsICacheMetaDataVisitor implementation
464 //-----------------------------------------------------------------------------
467 nsAboutCacheEntry::VisitMetaDataElement(const char * key
,
471 mBuffer
->AppendLiteral("<tr><td><tt><b>");
472 mBuffer
->Append(key
);
473 mBuffer
->AppendLiteral(":</b></tt></td>\n<td><pre>");
474 char* escapedValue
= nsEscapeHTML(value
);
475 mBuffer
->Append(escapedValue
);
476 nsMemory::Free(escapedValue
);
477 mBuffer
->AppendLiteral("</pre></td></tr>\n");
479 *keepGoing
= PR_TRUE
;