зеркало из https://github.com/mozilla/gecko-dev.git
Bug 542941 - Part4 and 5: fix a sessionID bug, and introduce a new test for redirects, r=dietrich
This commit is contained in:
Родитель
236497986e
Коммит
702b498222
|
@ -2780,13 +2780,17 @@ nsNavHistory::AddVisit(nsIURI* aURI, PRTime aTime, nsIURI* aReferringURI,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
// Get the place id for the referrer, if it exists.
|
||||
// Get the visit id for the referrer, if it exists.
|
||||
PRInt64 referringVisitID = 0;
|
||||
PRInt64 referringSessionID;
|
||||
PRTime referringTime;
|
||||
PRBool referrerIsSame;
|
||||
if (aReferringURI &&
|
||||
NS_SUCCEEDED(aReferringURI->Equals(aURI, &referrerIsSame)) &&
|
||||
!referrerIsSame &&
|
||||
!FindLastVisit(aReferringURI, &referringVisitID, &referringTime, &referringSessionID)) {
|
||||
// Add the referrer
|
||||
// The referrer is not in the database and is not the same as aURI, so it
|
||||
// must be added.
|
||||
rv = AddVisit(aReferringURI, aTime - 1, nsnull, TRANSITION_LINK, PR_FALSE,
|
||||
aSessionID, &referringVisitID);
|
||||
if (NS_FAILED(rv))
|
||||
|
@ -5153,7 +5157,8 @@ nsNavHistory::AddURIInternal(nsIURI* aURI, PRTime aTime, PRBool aRedirect,
|
|||
mozStorageTransaction transaction(mDBConn, PR_FALSE);
|
||||
|
||||
PRInt64 redirectBookmark = 0;
|
||||
PRInt64 visitID, sessionID;
|
||||
PRInt64 visitID = 0;
|
||||
PRInt64 sessionID = 0;
|
||||
nsresult rv = AddVisitChain(aURI, aTime, aToplevel, aRedirect, aReferrer,
|
||||
&visitID, &sessionID, &redirectBookmark);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
@ -5236,6 +5241,12 @@ nsNavHistory::AddVisitChain(nsIURI* aURI,
|
|||
rv = NS_NewURI(getter_AddRefs(redirectSourceURI), redirectSourceUrl);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
// Don't add a new visit if a page redirects to itself.
|
||||
PRBool redirectIsSame;
|
||||
if (NS_SUCCEEDED(aURI->Equals(redirectSourceURI, &redirectIsSame)) &&
|
||||
redirectIsSame)
|
||||
return NS_OK;
|
||||
|
||||
// remember if any redirect sources were bookmarked
|
||||
nsNavBookmarks *bookmarkService = nsNavBookmarks::GetBookmarksService();
|
||||
PRBool isBookmarked;
|
||||
|
@ -5276,12 +5287,31 @@ nsNavHistory::AddVisitChain(nsIURI* aURI,
|
|||
else if (aReferrerURI) {
|
||||
// This page does not come from a redirect and had a referrer.
|
||||
|
||||
// Check if the referrer has a previous visit.
|
||||
PRTime lastVisitTime;
|
||||
PRInt64 referringVisitId;
|
||||
PRBool referrerHasPreviousVisit =
|
||||
FindLastVisit(aReferrerURI, &referringVisitId, &lastVisitTime, aSessionID);
|
||||
|
||||
// Don't add a new visit if the referring site is the same as
|
||||
// the new site. This happens when a page refreshes itself.
|
||||
// Otherwise, if the page has never been added, the visit should be
|
||||
// registered regardless.
|
||||
PRBool referrerIsSame;
|
||||
if (NS_SUCCEEDED(aURI->Equals(aReferrerURI, &referrerIsSame)) &&
|
||||
referrerIsSame)
|
||||
referrerIsSame && referrerHasPreviousVisit) {
|
||||
// Ensure a valid session id to the chain.
|
||||
if (aIsRedirect)
|
||||
*aSessionID = GetNewSessionID();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!referrerHasPreviousVisit ||
|
||||
aTime - lastVisitTime > RECENT_EVENT_THRESHOLD) {
|
||||
// Either the referrer has no visits or the last visit is too
|
||||
// old to be part of this session. Thus start a new session.
|
||||
*aSessionID = GetNewSessionID();
|
||||
}
|
||||
|
||||
// Since referrer is set, this visit comes from an originating page.
|
||||
// For top-level windows, visit is considered user-initiated and it should
|
||||
|
@ -5294,17 +5324,6 @@ nsNavHistory::AddVisitChain(nsIURI* aURI,
|
|||
transitionType = nsINavHistoryService::TRANSITION_FRAMED_LINK;
|
||||
else
|
||||
transitionType = nsINavHistoryService::TRANSITION_LINK;
|
||||
|
||||
// Check if the referrer has a visit,
|
||||
// This also populates the session id.
|
||||
PRTime lastVisitTime;
|
||||
PRInt64 referringVisitId;
|
||||
if (!FindLastVisit(aReferrerURI, &referringVisitId, &lastVisitTime, aSessionID) ||
|
||||
aTime - lastVisitTime > RECENT_EVENT_THRESHOLD) {
|
||||
// Either referrer does not have any visit, or that visit is too
|
||||
// old to be part of this session. Start a new session then.
|
||||
*aSessionID = GetNewSessionID();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// When there is no referrer:
|
||||
|
|
|
@ -53,6 +53,7 @@ XPCSHELL_TESTS = \
|
|||
bookmarks \
|
||||
queries \
|
||||
unit \
|
||||
network \
|
||||
$(NULL)
|
||||
|
||||
# Simple MochiTests
|
||||
|
|
|
@ -0,0 +1,328 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Places.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Google Inc.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2005
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Brian Ryner <bryner@brianryner.com>
|
||||
* Dietrich Ayala <dietrich@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
|
||||
const NS_APP_HISTORY_50_FILE = "UHist";
|
||||
|
||||
// This will also define Cc, Ci.
|
||||
do_load_httpd_js();
|
||||
|
||||
function LOG(aMsg) {
|
||||
aMsg = ("*** PLACES TESTS: " + aMsg);
|
||||
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).
|
||||
logStringMessage(aMsg);
|
||||
print(aMsg);
|
||||
}
|
||||
|
||||
do_get_profile();
|
||||
|
||||
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(Ci.nsIProperties);
|
||||
var provider = {
|
||||
getFile: function(prop, persistent) {
|
||||
persistent.value = true;
|
||||
if (prop == NS_APP_HISTORY_50_FILE) {
|
||||
var histFile = dirSvc.get("ProfD", Ci.nsIFile);
|
||||
histFile.append("history.dat");
|
||||
return histFile;
|
||||
}
|
||||
throw Cr.NS_ERROR_FAILURE;
|
||||
},
|
||||
QueryInterface: function(iid) {
|
||||
if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
|
||||
iid.equals(Ci.nsISupports)) {
|
||||
return this;
|
||||
}
|
||||
throw Cr.NS_ERROR_NO_INTERFACE;
|
||||
}
|
||||
};
|
||||
dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(provider);
|
||||
|
||||
var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
|
||||
function uri(spec) {
|
||||
return iosvc.newURI(spec, null, null);
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads the data from the specified nsIFile, and returns an array of bytes.
|
||||
*/
|
||||
function readFileData(aFile) {
|
||||
var inputStream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
// init the stream as RD_ONLY, -1 == default permissions.
|
||||
inputStream.init(aFile, 0x01, -1, null);
|
||||
var size = inputStream.available();
|
||||
|
||||
// use a binary input stream to grab the bytes.
|
||||
var bis = Cc["@mozilla.org/binaryinputstream;1"].
|
||||
createInstance(Ci.nsIBinaryInputStream);
|
||||
bis.setInputStream(inputStream);
|
||||
|
||||
var bytes = bis.readByteArray(size);
|
||||
|
||||
if (size != bytes.length)
|
||||
throw "Didn't read expected number of bytes";
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compares two arrays, and returns true if they are equal.
|
||||
*/
|
||||
function compareArrays(aArray1, aArray2) {
|
||||
if (aArray1.length != aArray2.length) {
|
||||
print("compareArrays: array lengths differ\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
for (var i = 0; i < aArray1.length; i++) {
|
||||
if (aArray1[i] != aArray2[i]) {
|
||||
print("compareArrays: arrays differ at index " + i + ": " +
|
||||
"(" + aArray1[i] + ") != (" + aArray2[i] +")\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Delete a previously created sqlite file
|
||||
function clearDB() {
|
||||
try {
|
||||
var file = dirSvc.get('ProfD', Ci.nsIFile);
|
||||
file.append("places.sqlite");
|
||||
if (file.exists())
|
||||
file.remove(false);
|
||||
} catch(ex) { dump("Exception: " + ex); }
|
||||
}
|
||||
clearDB();
|
||||
|
||||
/**
|
||||
* Dumps the rows of a table out to the console.
|
||||
*
|
||||
* @param aName
|
||||
* The name of the table or view to output.
|
||||
*/
|
||||
function dump_table(aName)
|
||||
{
|
||||
let db = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsPIPlacesDatabase).
|
||||
DBConnection;
|
||||
let stmt = db.createStatement("SELECT * FROM " + aName);
|
||||
|
||||
dump("\n*** Printing data from " + aName + ":\n");
|
||||
let count = 0;
|
||||
while (stmt.executeStep()) {
|
||||
let columns = stmt.numEntries;
|
||||
|
||||
if (count == 0) {
|
||||
// print the column names
|
||||
for (let i = 0; i < columns; i++)
|
||||
dump(stmt.getColumnName(i) + "\t");
|
||||
dump("\n");
|
||||
}
|
||||
|
||||
// print the row
|
||||
for (let i = 0; i < columns; i++) {
|
||||
switch (stmt.getTypeOfIndex(i)) {
|
||||
case Ci.mozIStorageValueArray.VALUE_TYPE_NULL:
|
||||
dump("NULL\t");
|
||||
break;
|
||||
case Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER:
|
||||
dump(stmt.getInt64(i) + "\t");
|
||||
break;
|
||||
case Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT:
|
||||
dump(stmt.getDouble(i) + "\t");
|
||||
break;
|
||||
case Ci.mozIStorageValueArray.VALUE_TYPE_TEXT:
|
||||
dump(stmt.getString(i) + "\t");
|
||||
break;
|
||||
}
|
||||
}
|
||||
dump("\n");
|
||||
|
||||
count++;
|
||||
}
|
||||
dump("*** There were a total of " + count + " rows of data.\n\n");
|
||||
|
||||
stmt.reset();
|
||||
stmt.finalize();
|
||||
stmt = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes all bookmarks and checks for correct cleanup
|
||||
*/
|
||||
function remove_all_bookmarks() {
|
||||
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
// Clear all bookmarks
|
||||
bs.removeFolderChildren(bs.bookmarksMenuFolder);
|
||||
bs.removeFolderChildren(bs.toolbarFolder);
|
||||
bs.removeFolderChildren(bs.unfiledBookmarksFolder);
|
||||
// Check for correct cleanup
|
||||
check_no_bookmarks()
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks that we don't have any bookmark
|
||||
*/
|
||||
function check_no_bookmarks() {
|
||||
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
|
||||
getService(Ci.nsINavBookmarksService);
|
||||
var query = hs.getNewQuery();
|
||||
query.setFolders([bs.toolbarFolder, bs.bookmarksMenuFolder, bs.unfiledBookmarksFolder], 3);
|
||||
var options = hs.getNewQueryOptions();
|
||||
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
|
||||
var result = hs.executeQuery(query, options);
|
||||
var root = result.root;
|
||||
root.containerOpen = true;
|
||||
do_check_eq(root.childCount, 0);
|
||||
root.containerOpen = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function gets current database connection, if the connection has been closed
|
||||
* it will try to reconnect to the places.sqlite database.
|
||||
*/
|
||||
function DBConn()
|
||||
{
|
||||
let db = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsPIPlacesDatabase).
|
||||
DBConnection;
|
||||
if (db.connectionReady)
|
||||
return db;
|
||||
|
||||
// open a new connection if needed
|
||||
let file = dirSvc.get('ProfD', Ci.nsIFile);
|
||||
file.append("places.sqlite");
|
||||
let storageService = Cc["@mozilla.org/storage/service;1"].
|
||||
getService(Ci.mozIStorageService);
|
||||
try {
|
||||
var dbConn = storageService.openDatabase(file);
|
||||
} catch (ex) {
|
||||
return null;
|
||||
}
|
||||
return dbConn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets title synchronously for a page in moz_places synchronously.
|
||||
* History.SetPageTitle uses LAZY_ADD so we can't rely on it.
|
||||
*
|
||||
* @param aURI
|
||||
* An nsIURI to set the title for.
|
||||
* @param aTitle
|
||||
* The title to set the page to.
|
||||
* @throws if the page is not found in the database.
|
||||
*
|
||||
* @note this function only exists because we have no API to do this. It should
|
||||
* be added in bug 421897.
|
||||
*/
|
||||
function setPageTitle(aURI, aTitle) {
|
||||
let dbConn = DBConn();
|
||||
// Check that the page exists.
|
||||
let stmt = dbConn.createStatement(
|
||||
"SELECT id FROM moz_places_view WHERE url = :url");
|
||||
stmt.params.url = aURI.spec;
|
||||
try {
|
||||
if (!stmt.executeStep()) {
|
||||
do_throw("Unable to find page " + aURIString);
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
// Update the title
|
||||
stmt = dbConn.createStatement(
|
||||
"UPDATE moz_places_view SET title = :title WHERE url = :url");
|
||||
stmt.params.title = aTitle;
|
||||
stmt.params.url = aURI.spec;
|
||||
try {
|
||||
stmt.execute();
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Flushes any events in the event loop of the main thread.
|
||||
*/
|
||||
function flush_main_thread_events()
|
||||
{
|
||||
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
|
||||
while (tm.mainThread.hasPendingEvents())
|
||||
tm.mainThread.processNextEvent(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears history invoking callback when done.
|
||||
*/
|
||||
function waitForClearHistory(aCallback) {
|
||||
const TOPIC_EXPIRATION_FINISHED = "places-expiration-finished";
|
||||
let os = Cc["@mozilla.org/observer-service;1"].
|
||||
getService(Ci.nsIObserverService);
|
||||
let observer = {
|
||||
observe: function(aSubject, aTopic, aData) {
|
||||
os.removeObserver(this, TOPIC_EXPIRATION_FINISHED);
|
||||
aCallback();
|
||||
}
|
||||
};
|
||||
os.addObserver(observer, TOPIC_EXPIRATION_FINISHED, false);
|
||||
|
||||
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
hs.QueryInterface(Ci.nsIBrowserHistory).removeAllPages();
|
||||
}
|
||||
|
||||
// These tests are known to randomly fail due to bug 507790 when database
|
||||
// flushes are active, so we turn off syncing for them.
|
||||
let randomFailingSyncTests = [
|
||||
];
|
||||
let currentTestFilename = do_get_file(_TEST_FILE[0], true).leafName;
|
||||
if (randomFailingSyncTests.indexOf(currentTestFilename) != -1) {
|
||||
print("Test " + currentTestFilename + " is known random due to bug 507790, disabling PlacesDBFlush component.");
|
||||
let sync = Cc["@mozilla.org/places/sync;1"].getService(Ci.nsIObserver);
|
||||
sync.observe(null, "places-debug-stop-sync", null);
|
||||
}
|
|
@ -0,0 +1,235 @@
|
|||
/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et: */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is Places unit test code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Marco Bonardo <mak77@bonardo.net> (Original Author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
/* Tests history redirects handling */
|
||||
|
||||
let hs = Cc["@mozilla.org/browser/nav-history-service;1"].
|
||||
getService(Ci.nsINavHistoryService);
|
||||
let bh = hs.QueryInterface(Ci.nsIBrowserHistory);
|
||||
let ghist3 = hs.QueryInterface(Ci.nsIGlobalHistory3);
|
||||
|
||||
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Components.utils.import("resource://gre/modules/NetUtil.jsm");
|
||||
|
||||
const PERMA_REDIR_PATH = "/permaredir";
|
||||
const TEMP_REDIR_PATH = "/tempredir";
|
||||
const FOUND_PATH = "/found";
|
||||
|
||||
const HTTPSVR = new nsHttpServer();
|
||||
const PORT = 4444;
|
||||
HTTPSVR.registerPathHandler(PERMA_REDIR_PATH, permaRedirHandler);
|
||||
HTTPSVR.registerPathHandler(TEMP_REDIR_PATH, tempRedirHandler);
|
||||
HTTPSVR.registerPathHandler(FOUND_PATH, foundHandler);
|
||||
|
||||
const STATUS = {
|
||||
REDIRECT_PERMANENT: [301, "Moved Permanently"],
|
||||
REDIRECT_TEMPORARY: [302, "Moved"],
|
||||
FOUND: [200, "Found"],
|
||||
}
|
||||
|
||||
const PERMA_REDIR_URL = "http://localhost:" + PORT + PERMA_REDIR_PATH;
|
||||
const TEMP_REDIR_URL = "http://localhost:" + PORT + TEMP_REDIR_PATH;
|
||||
const FOUND_URL = "http://localhost:" + PORT + FOUND_PATH;
|
||||
|
||||
// PERMANENT REDIRECT
|
||||
function permaRedirHandler(aMeta, aResponse) {
|
||||
// Redirect permanently to TEMP_REDIR_URL
|
||||
PathHandler(aMeta, aResponse, "REDIRECT_PERMANENT", TEMP_REDIR_URL);
|
||||
}
|
||||
|
||||
// TEMPORARY REDIRECT
|
||||
function tempRedirHandler(aMeta, aResponse) {
|
||||
// Redirect temporarily to FOUND_URL
|
||||
PathHandler(aMeta, aResponse, "REDIRECT_TEMPORARY", FOUND_URL);
|
||||
}
|
||||
|
||||
// FOUND
|
||||
function foundHandler(aMeta, aResponse) {
|
||||
PathHandler(aMeta, aResponse, "FOUND");
|
||||
}
|
||||
|
||||
function PathHandler(aMeta, aResponse, aChannelEvent, aRedirURL) {
|
||||
aResponse.setStatusLine(aMeta.httpVersion,
|
||||
STATUS[aChannelEvent][0], // Code
|
||||
STATUS[aChannelEvent][1]); // Text
|
||||
if (aRedirURL)
|
||||
aResponse.setHeader("Location", aRedirURL, false);
|
||||
|
||||
//aResponse.setHeader("Content-Type", "text/html", false);
|
||||
let body = STATUS[aChannelEvent][1] + "\r\n";
|
||||
aResponse.bodyOutputStream.write(body, body.length);
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
do_test_pending();
|
||||
|
||||
HTTPSVR.start(PORT);
|
||||
|
||||
var chan = NetUtil.ioService
|
||||
.newChannelFromURI(uri("http://localhost:4444/permaredir"));
|
||||
var listener = new ChannelListener();
|
||||
chan.notificationCallbacks = listener;
|
||||
chan.asyncOpen(listener, null);
|
||||
// The test will continue on onStopRequest.
|
||||
}
|
||||
|
||||
function continue_test() {
|
||||
let dbConn = DBConn();
|
||||
let stmt = dbConn.createStatement(
|
||||
"SELECT v.id, h.url, v.from_visit, v.visit_date, v.visit_type, v.session " +
|
||||
"FROM moz_historyvisits_view v " +
|
||||
"JOIN moz_places_view h on h.id = v.place_id " +
|
||||
"ORDER BY v.id ASC");
|
||||
const EXPECTED = [
|
||||
{ id: 1,
|
||||
url: PERMA_REDIR_URL,
|
||||
from_visit: 0,
|
||||
visit_type: Ci.nsINavHistoryService.TRANSITION_LINK,
|
||||
session: 1 },
|
||||
{ id: 2,
|
||||
url: TEMP_REDIR_URL,
|
||||
from_visit: 1,
|
||||
visit_type: Ci.nsINavHistoryService.TRANSITION_REDIRECT_PERMANENT,
|
||||
session: 1 },
|
||||
{ id: 3,
|
||||
url: FOUND_URL,
|
||||
from_visit: 2,
|
||||
visit_type: Ci.nsINavHistoryService.TRANSITION_REDIRECT_TEMPORARY,
|
||||
session: 1 },
|
||||
];
|
||||
try {
|
||||
while(stmt.executeStep()) {
|
||||
let comparator = EXPECTED.shift();
|
||||
do_check_eq(stmt.row.id, comparator.id);
|
||||
do_check_eq(stmt.row.url, comparator.url);
|
||||
do_check_eq(stmt.row.from_visit, comparator.from_visit);
|
||||
do_check_eq(stmt.row.visit_type, comparator.visit_type);
|
||||
do_check_eq(stmt.row.session, comparator.session);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stmt.finalize();
|
||||
}
|
||||
|
||||
HTTPSVR.stop(do_test_finished);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read count bytes from stream and return as a String object
|
||||
*/
|
||||
function read_stream(stream, count) {
|
||||
/* assume stream has non-ASCII data */
|
||||
var wrapper =
|
||||
Components.classes["@mozilla.org/binaryinputstream;1"]
|
||||
.createInstance(Components.interfaces.nsIBinaryInputStream);
|
||||
wrapper.setInputStream(stream);
|
||||
/* JS methods can be called with a maximum of 65535 arguments, and input
|
||||
streams don't have to return all the data they make .available() when
|
||||
asked to .read() that number of bytes. */
|
||||
var data = [];
|
||||
while (count > 0) {
|
||||
var bytes = wrapper.readByteArray(Math.min(65535, count));
|
||||
data.push(String.fromCharCode.apply(null, bytes));
|
||||
count -= bytes.length;
|
||||
if (bytes.length == 0)
|
||||
do_throw("Nothing read from input stream!");
|
||||
}
|
||||
return data.join('');
|
||||
}
|
||||
|
||||
function ChannelListener() {
|
||||
|
||||
}
|
||||
ChannelListener.prototype = {
|
||||
_buffer: "",
|
||||
_got_onstartrequest: false,
|
||||
_got_onchannelredirect: false,
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIStreamListener,
|
||||
Ci.nsIRequestObserver,
|
||||
Ci.nsIInterfaceRequestor,
|
||||
Ci.nsIChannelEventSink,
|
||||
]),
|
||||
|
||||
// nsIInterfaceRequestor
|
||||
getInterface: function (aIID) {
|
||||
try {
|
||||
return this.QueryInterface(aIID);
|
||||
} catch (e) {
|
||||
throw Components.results.NS_NOINTERFACE;
|
||||
}
|
||||
},
|
||||
|
||||
onStartRequest: function(request, context) {
|
||||
print("onStartRequest");
|
||||
this._got_onstartrequest = true;
|
||||
},
|
||||
|
||||
onDataAvailable: function(request, context, stream, offset, count) {
|
||||
this._buffer = this._buffer.concat(read_stream(stream, count));
|
||||
},
|
||||
|
||||
onStopRequest: function(request, context, status) {
|
||||
print("onStopRequest");
|
||||
this._got_onstoprequest++;
|
||||
let success = Components.isSuccessCode(status);
|
||||
do_check_true(success);
|
||||
do_check_true(this._got_onstartrequest);
|
||||
do_check_true(this._got_onchannelredirect);
|
||||
do_check_true(this._buffer.length > 0);
|
||||
|
||||
// The referrer is wrong since it's the first element in the redirects
|
||||
// chain, but this is good, since it will test a special path.
|
||||
ghist3.addURI(uri(FOUND_URL), false, true, uri(PERMA_REDIR_URL));
|
||||
|
||||
// This forces a CommitLazyMessages, so we don't have to wait for LAZY_ADD.
|
||||
// Actually trying to delete visits in future.
|
||||
hs.removeVisitsByTimeframe((Date.now() * 1000) + 1, (Date.now() * 1000) + 2);
|
||||
|
||||
continue_test();
|
||||
},
|
||||
|
||||
// nsIChannelEventSink
|
||||
onChannelRedirect: function (aOldChannel, aNewChannel, aFlags) {
|
||||
print("onChannelRedirect");
|
||||
this._got_onchannelredirect = true;
|
||||
ghist3.addDocumentRedirect(aOldChannel, aNewChannel, aFlags, true);
|
||||
},
|
||||
};
|
Загрузка…
Ссылка в новой задаче