closes #743, Support non-EZproxy proxies
closes #831, transparent EZProxy support adds a proxy pane to the preferences asks before saving proxies to the DB (to avoid the potential phishing risk #831 would otherwise pose)
This commit is contained in:
parent
30e4ae859d
commit
09e8249db8
16 changed files with 893 additions and 195 deletions
|
@ -103,7 +103,7 @@ var Zotero_Browser = new function() {
|
||||||
|
|
||||||
Zotero_Browser.browserData = new Object();
|
Zotero_Browser.browserData = new Object();
|
||||||
Zotero_Browser._scrapePopupShowing = false;
|
Zotero_Browser._scrapePopupShowing = false;
|
||||||
Zotero.Ingester.ProxyMonitor.init();
|
Zotero.Proxies.init();
|
||||||
Zotero.Ingester.MIMEHandler.init();
|
Zotero.Ingester.MIMEHandler.init();
|
||||||
Zotero.Cite.MIMEHandler.init();
|
Zotero.Cite.MIMEHandler.init();
|
||||||
Zotero.Translate.init();
|
Zotero.Translate.init();
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
|
|
||||||
var openURLServerField;
|
var openURLServerField;
|
||||||
var openURLVersionMenu;
|
var openURLVersionMenu;
|
||||||
|
var proxies;
|
||||||
|
|
||||||
function init()
|
function init()
|
||||||
{
|
{
|
||||||
|
@ -32,6 +33,7 @@ function init()
|
||||||
}
|
}
|
||||||
|
|
||||||
refreshStylesList();
|
refreshStylesList();
|
||||||
|
refreshProxyList();
|
||||||
populateQuickCopyList();
|
populateQuickCopyList();
|
||||||
updateQuickCopyInstructions();
|
updateQuickCopyInstructions();
|
||||||
initSearchPane();
|
initSearchPane();
|
||||||
|
@ -930,8 +932,6 @@ function refreshStylesList(cslID) {
|
||||||
var styleData = Zotero.DB.query(sql);
|
var styleData = Zotero.DB.query(sql);
|
||||||
if (!styleData) return;
|
if (!styleData) return;
|
||||||
|
|
||||||
Zotero.debug("ASKED FOR "+cslID);
|
|
||||||
|
|
||||||
var selectIndex = false;
|
var selectIndex = false;
|
||||||
for (var i=0; i<styleData.length; i++) {
|
for (var i=0; i<styleData.length; i++) {
|
||||||
var treeitem = document.createElement('treeitem');
|
var treeitem = document.createElement('treeitem');
|
||||||
|
@ -949,7 +949,6 @@ function refreshStylesList(cslID) {
|
||||||
if(styleData[i].cslID.length < Zotero.ENConverter.uriPrefix.length ||
|
if(styleData[i].cslID.length < Zotero.ENConverter.uriPrefix.length ||
|
||||||
styleData[i].cslID.substr(0, Zotero.ENConverter.uriPrefix.length) != Zotero.ENConverter.uriPrefix) {
|
styleData[i].cslID.substr(0, Zotero.ENConverter.uriPrefix.length) != Zotero.ENConverter.uriPrefix) {
|
||||||
cslCell.setAttribute('src', 'chrome://zotero/skin/tick.png');
|
cslCell.setAttribute('src', 'chrome://zotero/skin/tick.png');
|
||||||
Zotero.debug("ISCSL");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
treerow.appendChild(titleCell);
|
treerow.appendChild(titleCell);
|
||||||
|
@ -1029,12 +1028,13 @@ function addStyle() {
|
||||||
**/
|
**/
|
||||||
function deleteStyle() {
|
function deleteStyle() {
|
||||||
var tree = document.getElementById('styleManager');
|
var tree = document.getElementById('styleManager');
|
||||||
|
if(tree.currentIndex == -1) return;
|
||||||
var treeitem = tree.lastChild.childNodes[tree.currentIndex];
|
var treeitem = tree.lastChild.childNodes[tree.currentIndex];
|
||||||
Zotero.debug(treeitem.getAttribute('id'));
|
|
||||||
var cslID = treeitem.getAttribute('id').substr(11);
|
var cslID = treeitem.getAttribute('id').substr(11);
|
||||||
|
|
||||||
Zotero.Cite.deleteStyle(cslID);
|
Zotero.Cite.deleteStyle(cslID);
|
||||||
this.refreshStylesList();
|
this.refreshStylesList();
|
||||||
|
document.getElementById('styleManager-delete').disabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1042,4 +1042,80 @@ function deleteStyle() {
|
||||||
**/
|
**/
|
||||||
function styleImportError() {
|
function styleImportError() {
|
||||||
alert(Zotero.getString('styles.installError', "This"));
|
alert(Zotero.getString('styles.installError', "This"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a proxy to the proxy pane
|
||||||
|
*/
|
||||||
|
function showProxyEditor(index) {
|
||||||
|
if(index == -1) return;
|
||||||
|
window.openDialog('chrome://zotero/content/preferences/proxyEditor.xul',
|
||||||
|
"zotero-preferences-proxyEditor", "chrome, modal", index !== undefined ? proxies[index] : null);
|
||||||
|
refreshProxyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes the currently selected proxy
|
||||||
|
*/
|
||||||
|
function deleteProxy() {
|
||||||
|
if(document.getElementById('proxyTree').currentIndex == -1) return;
|
||||||
|
proxies[document.getElementById('proxyTree').currentIndex].erase();
|
||||||
|
refreshProxyList();
|
||||||
|
document.getElementById('proxyTree-delete').disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes the proxy pane
|
||||||
|
*/
|
||||||
|
function refreshProxyList() {
|
||||||
|
// get and sort proxies
|
||||||
|
proxies = Zotero.Proxies.get();
|
||||||
|
proxies = proxies.sort(function(a, b) {
|
||||||
|
if(a.multiHost) {
|
||||||
|
if(b.multiHost) {
|
||||||
|
if(a.hosts[0] < b.hosts[0]) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} else if(b.multiHost) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(a.scheme < b.scheme) {
|
||||||
|
return -1;
|
||||||
|
} else if(b.scheme > a.scheme) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
// erase old children
|
||||||
|
var treechildren = document.getElementById('proxyTree-rows');
|
||||||
|
while (treechildren.hasChildNodes()) {
|
||||||
|
treechildren.removeChild(treechildren.firstChild);
|
||||||
|
}
|
||||||
|
|
||||||
|
// add proxies to list
|
||||||
|
for (var i=0; i<proxies.length; i++) {
|
||||||
|
var treeitem = document.createElement('treeitem');
|
||||||
|
var treerow = document.createElement('treerow');
|
||||||
|
var hostnameCell = document.createElement('treecell');
|
||||||
|
var schemeCell = document.createElement('treecell');
|
||||||
|
|
||||||
|
hostnameCell.setAttribute('label', proxies[i].multiHost ? Zotero.getString("proxies.multiSite") : proxies[i].hosts[0]);
|
||||||
|
schemeCell.setAttribute('label', proxies[i].scheme);
|
||||||
|
|
||||||
|
treerow.appendChild(hostnameCell);
|
||||||
|
treerow.appendChild(schemeCell);
|
||||||
|
treeitem.appendChild(treerow);
|
||||||
|
treechildren.appendChild(treeitem);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('proxyTree').currentIndex = -1;
|
||||||
|
document.getElementById('proxyTree-delete').disabled = true;
|
||||||
}
|
}
|
|
@ -334,6 +334,7 @@ To add a new preference:
|
||||||
<caption label="&zotero.preferences.styles.styleManager;"/>
|
<caption label="&zotero.preferences.styles.styleManager;"/>
|
||||||
|
|
||||||
<tree flex="1" id="styleManager" hidecolumnpicker="true" rows="6"
|
<tree flex="1" id="styleManager" hidecolumnpicker="true" rows="6"
|
||||||
|
onselect="document.getElementById('styleManager-delete').disabled = undefined"
|
||||||
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { deleteSelectedStyle(); }">
|
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { deleteSelectedStyle(); }">
|
||||||
<treecols>
|
<treecols>
|
||||||
<treecol id="styleManager-title" label="&zotero.preferences.styles.styleManager.title;" flex="3"/>
|
<treecol id="styleManager-title" label="&zotero.preferences.styles.styleManager.title;" flex="3"/>
|
||||||
|
@ -344,7 +345,7 @@ To add a new preference:
|
||||||
</tree>
|
</tree>
|
||||||
<separator class="thin"/>
|
<separator class="thin"/>
|
||||||
<hbox pack="end">
|
<hbox pack="end">
|
||||||
<button label="-" onclick="deleteStyle()"/>
|
<button disabled="true" id="styleManager-delete" label="-" onclick="deleteStyle()"/>
|
||||||
<button label="+" onclick="addStyle()"/>
|
<button label="+" onclick="addStyle()"/>
|
||||||
</hbox>
|
</hbox>
|
||||||
<separator/>
|
<separator/>
|
||||||
|
@ -353,6 +354,44 @@ To add a new preference:
|
||||||
</prefpane>
|
</prefpane>
|
||||||
|
|
||||||
|
|
||||||
|
<prefpane id="zotero-prefpane-proxies"
|
||||||
|
label="&zotero.preferences.prefpane.proxies;"
|
||||||
|
image="chrome://zotero/skin/prefs-proxies.png">
|
||||||
|
<preferences>
|
||||||
|
<preference id="pref-proxies-autoRecognize" name="extensions.zotero.proxies.autoRecognize" type="bool"/>
|
||||||
|
<preference id="pref-proxies-transparent" name="extensions.zotero.proxies.transparent" type="bool"/>
|
||||||
|
</preferences>
|
||||||
|
|
||||||
|
<groupbox>
|
||||||
|
<caption label="&zotero.preferences.proxies.proxyOptions;"/>
|
||||||
|
|
||||||
|
<checkbox id="zotero-proxies-autoRecognize" label="&zotero.preferences.proxies.autoRecognize;"
|
||||||
|
preference="pref-proxies-autoRecognize" oncommand="Zotero.Proxies.init()"/>
|
||||||
|
<checkbox id="zotero-proxies-transparent" label="&zotero.preferences.proxies.transparent;"
|
||||||
|
preference="pref-proxies-transparent" oncommand="Zotero.Proxies.init()"/>
|
||||||
|
</groupbox>
|
||||||
|
|
||||||
|
<groupbox flex="1">
|
||||||
|
<caption label="&zotero.preferences.proxies.configured;"/>
|
||||||
|
|
||||||
|
<tree flex="1" id="proxyTree" hidecolumnpicker="true" rows="6" seltype="single"
|
||||||
|
ondblclick="showProxyEditor(this.currentIndex)" onselect="document.getElementById('proxyTree-delete').disabled = undefined"
|
||||||
|
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { deleteProxy(); }">
|
||||||
|
<treecols>
|
||||||
|
<treecol id="proxyTree-hostname" label="&zotero.preferences.proxies.hostname;" flex="1"/>
|
||||||
|
<treecol id="proxyTree-scheme" label="&zotero.preferences.proxies.scheme;" flex="3"/>
|
||||||
|
</treecols>
|
||||||
|
<treechildren id="proxyTree-rows"/>
|
||||||
|
</tree>
|
||||||
|
<separator class="thin"/>
|
||||||
|
<hbox pack="end">
|
||||||
|
<button disabled="true" id="proxyTree-delete" label="-" onclick="deleteProxy()"/>
|
||||||
|
<button label="+" onclick="showProxyEditor()"/>
|
||||||
|
</hbox>
|
||||||
|
</groupbox>
|
||||||
|
</prefpane>
|
||||||
|
|
||||||
|
|
||||||
<prefpane id="zotero-prefpane-keys"
|
<prefpane id="zotero-prefpane-keys"
|
||||||
label="&zotero.preferences.prefpane.keys;"
|
label="&zotero.preferences.prefpane.keys;"
|
||||||
image="chrome://zotero/skin/prefs-keys.png">
|
image="chrome://zotero/skin/prefs-keys.png">
|
||||||
|
|
137
chrome/content/zotero/preferences/proxyEditor.js
Normal file
137
chrome/content/zotero/preferences/proxyEditor.js
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
/*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (c) 2006 Center for History and New Media
|
||||||
|
George Mason University, Fairfax, Virginia, USA
|
||||||
|
http://chnm.gmu.edu
|
||||||
|
|
||||||
|
Licensed under the Educational Community License, Version 1.0 (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.opensource.org/licenses/ecl1.php
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
Zotero_ProxyEditor = new function() {
|
||||||
|
var treechildren;
|
||||||
|
var tree;
|
||||||
|
var treecol;
|
||||||
|
var multiSite;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when this window is first opened. Sets values if necessary
|
||||||
|
*/
|
||||||
|
this.load = function() {
|
||||||
|
treechildren = document.getElementById("zotero-proxies-hostname-multiSite-tree-children");
|
||||||
|
tree = document.getElementById("zotero-proxies-hostname-multiSite-tree");
|
||||||
|
multiSite = document.getElementById("zotero-proxies-multiSite");
|
||||||
|
|
||||||
|
if(window.arguments && window.arguments[0]) {
|
||||||
|
var proxy = window.arguments[0];
|
||||||
|
document.getElementById("zotero-proxies-scheme").value = proxy.scheme;
|
||||||
|
document.getElementById("zotero-proxies-multiSite").checked = !!proxy.multiHost;
|
||||||
|
if(proxy.hosts) {
|
||||||
|
if(proxy.multiHost) {
|
||||||
|
this.multiSiteChanged();
|
||||||
|
for (var i=0; i<proxy.hosts.length; i++) {
|
||||||
|
_addTreeElement(proxy.hosts[i]);
|
||||||
|
}
|
||||||
|
document.getElementById("zotero-proxies-autoAssociate").checked = proxy.autoAssociate;
|
||||||
|
} else {
|
||||||
|
document.getElementById("zotero-proxies-hostname-text").value = proxy.hosts[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.sizeToContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a user checks/unchecks the Multi-Site checkbox. Shows or hides multi-site
|
||||||
|
* hostname specification box as necessary.
|
||||||
|
*/
|
||||||
|
this.multiSiteChanged = function() {
|
||||||
|
document.getElementById("zotero-proxies-hostname-multiSite").hidden = !multiSite.checked;
|
||||||
|
document.getElementById("zotero-proxies-hostname-multiSite-description").hidden = !multiSite.checked;
|
||||||
|
document.getElementById("zotero-proxies-hostname").hidden = multiSite.checked;
|
||||||
|
window.sizeToContent();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a row is selected
|
||||||
|
*/
|
||||||
|
this.select = function() {
|
||||||
|
document.getElementById("zotero-proxies-delete").disabled = tree.selectedIndex == -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a host when in multi-host mode
|
||||||
|
*/
|
||||||
|
this.addHost = function() {
|
||||||
|
_addTreeElement();
|
||||||
|
tree.startEditing(treechildren.childNodes.length-1, tree.columns.getFirstColumn());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a host when in multi-host mode
|
||||||
|
*/
|
||||||
|
this.deleteHost = function() {
|
||||||
|
if(tree.currentIndex == -1) return;
|
||||||
|
treechildren.removeChild(treechildren.childNodes[tree.currentIndex]);
|
||||||
|
document.getElementById("zotero-proxies-delete").disabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when the user clicks "OK." Updates proxy for Zotero.Proxy.
|
||||||
|
*/
|
||||||
|
this.accept = function() {
|
||||||
|
var proxy = window.arguments && window.arguments[0] ? window.arguments[0] : new Zotero.Proxy();
|
||||||
|
|
||||||
|
proxy.scheme = document.getElementById("zotero-proxies-scheme").value;
|
||||||
|
proxy.multiHost = multiSite.checked;
|
||||||
|
if(proxy.multiHost) {
|
||||||
|
proxy.hosts = [];
|
||||||
|
var treecol = tree.columns.getFirstColumn();
|
||||||
|
for(var i=0; i<tree.view.rowCount; i++) {
|
||||||
|
var host = tree.view.getCellText(i, treecol);
|
||||||
|
if(host) proxy.hosts.push(host);
|
||||||
|
}
|
||||||
|
proxy.autoAssociate = document.getElementById("zotero-proxies-autoAssociate").checked;
|
||||||
|
} else {
|
||||||
|
proxy.hosts = [document.getElementById("zotero-proxies-hostname-text").value];
|
||||||
|
}
|
||||||
|
|
||||||
|
var hasErrors = proxy.validate();
|
||||||
|
if(hasErrors) {
|
||||||
|
Components.interfaces.nsIPromptService.getService().alert(window,
|
||||||
|
Zotero.getString("proxies.error"), Zotero.getString("proxies.error."+hasErrors));
|
||||||
|
if(window.arguments && window.arguments[0]) proxy.revert();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
proxy.save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an element to the tree
|
||||||
|
*/
|
||||||
|
function _addTreeElement(label) {
|
||||||
|
var treeitem = document.createElement('treeitem');
|
||||||
|
var treerow = document.createElement('treerow');
|
||||||
|
var treecell = document.createElement('treecell');
|
||||||
|
|
||||||
|
if(label) treecell.setAttribute('label', label);
|
||||||
|
|
||||||
|
treerow.appendChild(treecell);
|
||||||
|
treeitem.appendChild(treerow);
|
||||||
|
treechildren.appendChild(treeitem);
|
||||||
|
}
|
||||||
|
}
|
46
chrome/content/zotero/preferences/proxyEditor.xul
Normal file
46
chrome/content/zotero/preferences/proxyEditor.xul
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||||
|
<?xml-stylesheet href="chrome://zotero/skin/preferences.css"?>
|
||||||
|
|
||||||
|
<!DOCTYPE window SYSTEM "chrome://zotero/locale/preferences.dtd">
|
||||||
|
<dialog xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
title="" buttons="cancel,accept"
|
||||||
|
id="zotero-proxyEditor"
|
||||||
|
onload="Zotero_ProxyEditor.load();"
|
||||||
|
ondialogaccept="return Zotero_ProxyEditor.accept();">
|
||||||
|
|
||||||
|
<script src="chrome://zotero/content/include.js"/>
|
||||||
|
<script src="proxyEditor.js"/>
|
||||||
|
|
||||||
|
<checkbox id="zotero-proxies-multiSite" label="&zotero.preferences.proxies.multiSite;"
|
||||||
|
oncommand="Zotero_ProxyEditor.multiSiteChanged()"/>
|
||||||
|
<separator class="thin"/>
|
||||||
|
<vbox id="zotero-proxies-hostname-multiSite" hidden="true">
|
||||||
|
<checkbox id="zotero-proxies-autoAssociate" label="&zotero.preferences.proxies.autoAssociate;"/>
|
||||||
|
<tree flex="1" id="zotero-proxies-hostname-multiSite-tree" hidecolumnpicker="true" editable="true" rows="6"
|
||||||
|
onkeypress="if (event.keyCode == event.DOM_VK_DELETE) { Zotero_ProxyEditor.remove(); }"
|
||||||
|
onselect="Zotero_ProxyEditor.select();">
|
||||||
|
<treecols>
|
||||||
|
<treecol label="&zotero.preferences.proxies.hostname;" id="zotero-proxies-hostname-multiSite-tree-col" flex="1"/>
|
||||||
|
</treecols>
|
||||||
|
<treechildren id="zotero-proxies-hostname-multiSite-tree-children"/>
|
||||||
|
</tree>
|
||||||
|
<hbox pack="end">
|
||||||
|
<button id="zotero-proxies-delete" label="-" onclick="Zotero_ProxyEditor.deleteHost()" disabled="true"/>
|
||||||
|
<button id="zotero-proxies-add" label="+" onclick="Zotero_ProxyEditor.addHost()"/>
|
||||||
|
</hbox>
|
||||||
|
</vbox>
|
||||||
|
<vbox id="zotero-proxies-hostname">
|
||||||
|
<label value="&zotero.preferences.proxies.hostname;:" control="zotero-proxies-hostname-text"/>
|
||||||
|
<textbox id="zotero-proxies-hostname-text"/>
|
||||||
|
</vbox>
|
||||||
|
<separator class="thin"/>
|
||||||
|
<label value="&zotero.preferences.proxies.scheme;:" control="zotero-proxies-scheme"/>
|
||||||
|
<textbox id="zotero-proxies-scheme"/>
|
||||||
|
<label value="&zotero.preferences.proxies.variables;"/>
|
||||||
|
<label value="&zotero.preferences.proxies.h_variable;" id="zotero-proxies-hostname-multiSite-description" hidden="true"/>
|
||||||
|
<label value="&zotero.preferences.proxies.p_variable;"/>
|
||||||
|
<label value="&zotero.preferences.proxies.d_variable;"/>
|
||||||
|
<label value="&zotero.preferences.proxies.f_variable;"/>
|
||||||
|
<label value="&zotero.preferences.proxies.a_variable;"/>
|
||||||
|
</dialog>
|
|
@ -26,185 +26,6 @@
|
||||||
|
|
||||||
Zotero.Ingester = new Object();
|
Zotero.Ingester = new Object();
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Zotero.Ingester.ProxyMonitor
|
|
||||||
//
|
|
||||||
/////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
// A singleton for recognizing EZProxies and converting URLs such that databases
|
|
||||||
// will work from outside them. Unfortunately, this only works with the ($495)
|
|
||||||
// EZProxy software. If there are open source alternatives, we should support
|
|
||||||
// them too.
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Precompile proxy regexps
|
|
||||||
*/
|
|
||||||
Zotero.Ingester.ProxyMonitor = new function() {
|
|
||||||
var _ezProxyRe = /\?(?:.+&)?(url|qurl)=([^&]+)/i;
|
|
||||||
var _juniperProxyRe = /^(https?:\/\/[^\/:]+(?:\:[0-9]+)?)\/(.*)?,DanaInfo=([^+,]*)([^+]*)(?:\+(.*))?$/;
|
|
||||||
var _pathRe = /([^?]*\/)([^?\/]*)(\?(.*))?$/
|
|
||||||
/*var _hostRe = new RegExp();
|
|
||||||
_hostRe.compile("^https?://(([^/:]+)(?:\:([0-9]+))?)");*/
|
|
||||||
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIIOService);
|
|
||||||
var on = false;
|
|
||||||
var _mapFromEZProxy = null;
|
|
||||||
var _mapToJuniperProxy = null;
|
|
||||||
var _mapToEZProxy = null;
|
|
||||||
|
|
||||||
this.init = init;
|
|
||||||
this.proxyToProper = proxyToProper;
|
|
||||||
this.properToProxy = properToProxy;
|
|
||||||
this.observe = observe;
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
if(!on) {
|
|
||||||
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
|
||||||
.getService(Components.interfaces.nsIObserverService);
|
|
||||||
observerService.addObserver(this, "http-on-examine-response", false);
|
|
||||||
}
|
|
||||||
on = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
function observe(channel) {
|
|
||||||
channel.QueryInterface(Components.interfaces.nsIHttpChannel);
|
|
||||||
try {
|
|
||||||
// remove content-disposition headers for endnote, etc.
|
|
||||||
var contentType = channel.getResponseHeader("Content-Type").toLowerCase();
|
|
||||||
for each(var desiredContentType in Zotero.Ingester.MIMEHandler.URIContentListener.desiredContentTypes) {
|
|
||||||
if(contentType.length < desiredContentType.length) {
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
if(contentType.substr(0, desiredContentType.length) == desiredContentType) {
|
|
||||||
channel.setResponseHeader("Content-Disposition", "", false);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// find ezproxies
|
|
||||||
if(channel.getResponseHeader("Server") == "EZproxy") {
|
|
||||||
// We're connected to an EZproxy
|
|
||||||
if(channel.responseStatus != "302") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should be able to scrape the URL out of this
|
|
||||||
var m = _ezProxyRe.exec(channel.URI.spec);
|
|
||||||
if(!m) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Found URL
|
|
||||||
var variable = m[1];
|
|
||||||
var properURL = m[2];
|
|
||||||
if(variable.toLowerCase() == "qurl") {
|
|
||||||
properURL = unescape(properURL);
|
|
||||||
}
|
|
||||||
var properURI = _parseURL(properURL);
|
|
||||||
if(!properURI) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the new URL
|
|
||||||
var newURL = channel.getResponseHeader("Location");
|
|
||||||
if(!newURL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var newURI = _parseURL(newURL);
|
|
||||||
if(!newURI) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if((channel.URI.host == newURI.host && channel.URI.port != newURI.port) ||
|
|
||||||
(newURI.host != channel.URI.host &&
|
|
||||||
newURI.hostPort.substr(newURI.hostPort.length-channel.URI.hostPort.length) == channel.URI.hostPort)) {
|
|
||||||
// Different ports but the same server means EZproxy active
|
|
||||||
|
|
||||||
Zotero.debug("EZProxy: host "+newURI.hostPort+" is really "+properURI.hostPort);
|
|
||||||
// Initialize variables here so people who never use EZProxies
|
|
||||||
// don't get the (very very minor) speed hit
|
|
||||||
if(!_mapFromEZProxy) {
|
|
||||||
_mapFromEZProxy = new Object();
|
|
||||||
_mapToEZProxy = new Object();
|
|
||||||
}
|
|
||||||
_mapFromEZProxy[newURI.hostPort] = properURI.hostPort;
|
|
||||||
_mapToEZProxy[properURI.hostPort] = newURI.hostPort;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch(e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a page's proper url, adjusting for proxying
|
|
||||||
*/
|
|
||||||
function proxyToProper(url) {
|
|
||||||
var m = _juniperProxyRe.exec(url);
|
|
||||||
if(m) {
|
|
||||||
url = "http://"+m[3]+"/"+m[2]+m[5];
|
|
||||||
|
|
||||||
if(!_mapToJuniperProxy) _mapToJuniperProxy = new Object();
|
|
||||||
_mapToJuniperProxy[m[3]] = {prePath:m[1], additionalInfo:m[4], danaInfoBeforeFile:(m[2].substr(m[2].length-1) == "/")};
|
|
||||||
|
|
||||||
Zotero.debug("Juniper Proxy: proper url is "+url);
|
|
||||||
} else if(_mapFromEZProxy) {
|
|
||||||
// EZProxy detection is active
|
|
||||||
|
|
||||||
var uri = _parseURL(url);
|
|
||||||
if(uri && _mapFromEZProxy[uri.hostPort]) {
|
|
||||||
url = url.replace(uri.hostPort, _mapFromEZProxy[uri.hostPort]);
|
|
||||||
Zotero.debug("EZProxy: proper url is "+url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Returns a page's proxied url from the proper url
|
|
||||||
*/
|
|
||||||
function properToProxy(url) {
|
|
||||||
if(_mapToJuniperProxy || _mapToEZProxy) {
|
|
||||||
// Proxy detection is active
|
|
||||||
var uri = _parseURL(url);
|
|
||||||
|
|
||||||
if(uri) {
|
|
||||||
if(_mapToEZProxy && _mapToEZProxy[uri.hostPort]) {
|
|
||||||
// Actually need to map
|
|
||||||
url = url.replace(uri.hostPort, _mapToEZProxy[uri.hostPort]);
|
|
||||||
Zotero.debug("EZProxy: proxied url is "+url);
|
|
||||||
} else if(_mapToJuniperProxy && _mapToJuniperProxy[uri.hostPort]) {
|
|
||||||
var m = _pathRe.exec(uri.path);
|
|
||||||
|
|
||||||
if(_mapToJuniperProxy[uri.hostPort].danaInfoBeforeFile) {
|
|
||||||
url = _mapToJuniperProxy[uri.hostPort].prePath+m[1]+",DanaInfo="+uri.hostPort+_mapToJuniperProxy[uri.hostPort].additionalInfo+"+";
|
|
||||||
if(m[2]) url += m[2];
|
|
||||||
} else {
|
|
||||||
url = _mapToJuniperProxy[uri.hostPort].prePath+m[1]+m[2]+",DanaInfo="+uri.hostPort+_mapToJuniperProxy[uri.hostPort].additionalInfo+"+";
|
|
||||||
}
|
|
||||||
if(m[3]) url += m[3];
|
|
||||||
Zotero.debug("Juniper Proxy: proxied url is "+url);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Parses a url into components (hostPort, port, host, and spec)
|
|
||||||
*/
|
|
||||||
function _parseURL(url) {
|
|
||||||
// create an nsIURI (not sure if this is faster than the regular
|
|
||||||
// expression, but it's at least more kosher)
|
|
||||||
var uri = ioService.newURI(url, null, null);
|
|
||||||
return uri;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Zotero.OpenURL = new function() {
|
Zotero.OpenURL = new function() {
|
||||||
this.resolve = resolve;
|
this.resolve = resolve;
|
||||||
this.discoverResolvers = discoverResolvers;
|
this.discoverResolvers = discoverResolvers;
|
||||||
|
|
526
chrome/content/zotero/xpcom/proxy.js
Normal file
526
chrome/content/zotero/xpcom/proxy.js
Normal file
|
@ -0,0 +1,526 @@
|
||||||
|
/*
|
||||||
|
***** BEGIN LICENSE BLOCK *****
|
||||||
|
|
||||||
|
Copyright (c) 2006 Center for History and New Media
|
||||||
|
George Mason University, Fairfax, Virginia, USA
|
||||||
|
http://chnm.gmu.edu
|
||||||
|
|
||||||
|
Licensed under the Educational Community License, Version 1.0 (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.opensource.org/licenses/ecl1.php
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
|
Utilities based in part on code taken from Piggy Bank 2.1.1 (BSD-licensed)
|
||||||
|
|
||||||
|
|
||||||
|
***** END LICENSE BLOCK *****
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A singleton to handle URL rewriting proxies
|
||||||
|
*/
|
||||||
|
Zotero.Proxies = new function() {
|
||||||
|
var on = false;
|
||||||
|
var proxies = false;
|
||||||
|
var hosts;
|
||||||
|
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIIOService);
|
||||||
|
var autoRecognize = false;
|
||||||
|
var transparent = false;
|
||||||
|
|
||||||
|
this.init = function() {
|
||||||
|
if(!on) {
|
||||||
|
var observerService = Components.classes["@mozilla.org/observer-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIObserverService);
|
||||||
|
observerService.addObserver(this, "http-on-examine-response", false);
|
||||||
|
this.get();
|
||||||
|
}
|
||||||
|
on = true;
|
||||||
|
|
||||||
|
autoRecognize = Zotero.Prefs.get("proxies.autoRecognize");
|
||||||
|
transparent = Zotero.Prefs.get("proxies.transparent");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Observe method to capture page loads
|
||||||
|
*/
|
||||||
|
this.observe = function(channel) {
|
||||||
|
channel.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||||||
|
try {
|
||||||
|
// remove content-disposition headers for endnote, etc.
|
||||||
|
var contentType = channel.getResponseHeader("Content-Type").toLowerCase();
|
||||||
|
for each(var desiredContentType in Zotero.Ingester.MIMEHandler.URIContentListener.desiredContentTypes) {
|
||||||
|
if(contentType.length < desiredContentType.length) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
if(contentType.substr(0, desiredContentType.length) == desiredContentType) {
|
||||||
|
channel.setResponseHeader("Content-Disposition", "", false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
// try to detect a proxy
|
||||||
|
channel.QueryInterface(Components.interfaces.nsIRequest);
|
||||||
|
if(channel.loadFlags & Components.interfaces.nsIHttpChannel.LOAD_DOCUMENT_URI) {
|
||||||
|
channel.QueryInterface(Components.interfaces.nsIHttpChannel);
|
||||||
|
var url = channel.URI.spec;
|
||||||
|
|
||||||
|
// see if there is a proxy we already know
|
||||||
|
var proxy;
|
||||||
|
for each(proxy in proxies) {
|
||||||
|
if(proxy.regexp && proxy.autoAssociate) {
|
||||||
|
var m = proxy.regexp.exec(url);
|
||||||
|
if(m) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(m) {
|
||||||
|
// add this host if we know a proxy
|
||||||
|
var host = m[proxy.parameters.indexOf("%h")+1];
|
||||||
|
if(proxy.hosts.indexOf(host) == -1) {
|
||||||
|
proxy.hosts.push(host);
|
||||||
|
proxy.save();
|
||||||
|
}
|
||||||
|
} else if(autoRecognize) {
|
||||||
|
// otherwise, try to detect a proxy
|
||||||
|
var proxy = false;
|
||||||
|
for each(var detector in Zotero.Proxies.Detectors) {
|
||||||
|
try {
|
||||||
|
proxy = detector(channel);
|
||||||
|
} catch(e) {
|
||||||
|
Components.utils.reportError(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(proxy) {
|
||||||
|
var checkState = {value:false};
|
||||||
|
var ps = Components.classes["@mozilla.org/embedcomp/prompt-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIPromptService);
|
||||||
|
var window = Components.classes["@mozilla.org/appshell/window-mediator;1"]
|
||||||
|
.getService(Components.interfaces.nsIWindowMediator)
|
||||||
|
.getMostRecentWindow("navigator:browser");
|
||||||
|
|
||||||
|
var button = ps.confirmEx(window,
|
||||||
|
Zotero.getString("proxies.recognized"),
|
||||||
|
Zotero.getString("proxies.recognized.message"),
|
||||||
|
((proxies.length ? 0 : ps.BUTTON_DELAY_ENABLE) + ps.BUTTON_POS_0 * ps.BUTTON_TITLE_OK +
|
||||||
|
ps.BUTTON_POS_1 * ps.BUTTON_TITLE_CANCEL + ps.BUTTON_POS_1_DEFAULT),
|
||||||
|
null, null, null, Zotero.getString("proxies.recognized.disable"), checkState);
|
||||||
|
|
||||||
|
if(button == 0) proxy.save();
|
||||||
|
if(checkState.value) {
|
||||||
|
autoRecognize = false;
|
||||||
|
Zotero.Prefs.set("proxies.autoRecognize", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try to get an applicable proxy
|
||||||
|
if(transparent) {
|
||||||
|
var webNav = null;
|
||||||
|
try {
|
||||||
|
webNav = channel.notificationCallbacks.QueryInterface(Components.interfaces.nsIWebNavigation);
|
||||||
|
} catch(e) {}
|
||||||
|
|
||||||
|
if(webNav) {
|
||||||
|
var proxied = this.properToProxy(url, true);
|
||||||
|
if(proxied) webNav.loadURI(proxied, 0, channel.URI, null, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all proxy objects
|
||||||
|
*/
|
||||||
|
this.get = function() {
|
||||||
|
if(!proxies) {
|
||||||
|
var rows = Zotero.DB.query("SELECT * FROM proxies");
|
||||||
|
proxies = [new Zotero.Proxy(row) for each(row in rows)];
|
||||||
|
this.refreshHostMap();
|
||||||
|
}
|
||||||
|
return proxies;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a proxy object from the list of proxy objects
|
||||||
|
*/
|
||||||
|
this.remove = function(proxy) {
|
||||||
|
var index = proxies.indexOf(proxy);
|
||||||
|
if(index == -1) return false;
|
||||||
|
proxies.splice(index, 1);
|
||||||
|
this.refreshHostMap();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves a proxy object not previously in the proxy list
|
||||||
|
*/
|
||||||
|
this.save = function(proxy) {
|
||||||
|
proxies.push(proxy);
|
||||||
|
for each(var host in proxy.hosts) {
|
||||||
|
if(!hosts[host]) {
|
||||||
|
hosts[host] = proxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Refreshes host map; necessary when proxies are added, changed, or deleted
|
||||||
|
*/
|
||||||
|
this.refreshHostMap = function() {
|
||||||
|
hosts = {};
|
||||||
|
for each(var proxy in proxies) {
|
||||||
|
for each(var host in proxy.hosts) {
|
||||||
|
if(!hosts[host]) {
|
||||||
|
hosts[host] = proxy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a page's proper url, adjusting for proxying
|
||||||
|
*/
|
||||||
|
this.proxyToProper = function(url, onlyReturnIfProxied) {
|
||||||
|
for each(var proxy in proxies) {
|
||||||
|
if(proxy.regexp) {
|
||||||
|
var m = proxy.regexp.exec(url);
|
||||||
|
if(m) {
|
||||||
|
var toProper = proxy.toProper(m);
|
||||||
|
Zotero.debug("Zotero.Proxies.proxyToProper: "+url+" to "+toProper);
|
||||||
|
return toProper;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (onlyReturnIfProxied ? false : url);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a page's proxied url from the proper url
|
||||||
|
*/
|
||||||
|
this.properToProxy = function(url, onlyReturnIfProxied) {
|
||||||
|
var uri = ioService.newURI(url, null, null);
|
||||||
|
if(hosts[uri.hostPort]) {
|
||||||
|
var toProxy = hosts[uri.hostPort].toProxy(uri);
|
||||||
|
Zotero.debug("Zotero.Proxies.properToProxy: "+url+" to "+toProxy);
|
||||||
|
return toProxy;
|
||||||
|
}
|
||||||
|
return (onlyReturnIfProxied ? false : url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class to handle individual proxy servers
|
||||||
|
*
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
Zotero.Proxy = function(row) {
|
||||||
|
if(row) {
|
||||||
|
this._loadFromRow(row);
|
||||||
|
} else {
|
||||||
|
this.hosts = [];
|
||||||
|
this.multiHost = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Zotero_Proxy_schemeParameters = {
|
||||||
|
"%p":"(.*?)", // path
|
||||||
|
"%d":"(.*?)", // directory
|
||||||
|
"%f":"(.*?)", // filename
|
||||||
|
"%a":"(.*?)" // filename
|
||||||
|
};
|
||||||
|
const Zotero_Proxy_schemeParameterRegexps = {
|
||||||
|
"%p":/([^%])%p/,
|
||||||
|
"%d":/([^%])%d/,
|
||||||
|
"%f":/([^%])%f/,
|
||||||
|
"%h":/([^%])%h/,
|
||||||
|
"%a":/([^%])%a/
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Compiles the regular expression against which we match URLs for this proxy
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype.compileRegexp = function() {
|
||||||
|
const metaRe = /[-[\]{}()*+?.\\^$|,#\s]/g;
|
||||||
|
|
||||||
|
// take host only if flagged as multiHost
|
||||||
|
var parametersToCheck = Zotero_Proxy_schemeParameters;
|
||||||
|
if(this.multiHost) parametersToCheck["%h"] = "([a-zA-Z0-9]+\\.[a-zA-Z0-9\.]+)";
|
||||||
|
|
||||||
|
indices = this.indices = {};
|
||||||
|
this.parameters = [];
|
||||||
|
for(var param in parametersToCheck) {
|
||||||
|
var index = this.scheme.indexOf(param);
|
||||||
|
|
||||||
|
// avoid escaped matches
|
||||||
|
while(this.scheme[index-1] == "%") {
|
||||||
|
this.scheme = this.scheme.substr(0, index-1)+this.scheme.substr(index);
|
||||||
|
index = this.scheme.indexOf(param, index+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(index != -1) {
|
||||||
|
this.indices[param] = index;
|
||||||
|
this.parameters.push(param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort params by index
|
||||||
|
this.parameters = this.parameters.sort(function(a, b) {
|
||||||
|
return indices[a]-indices[b];
|
||||||
|
})
|
||||||
|
|
||||||
|
// now replace with regexp fragment in reverse order
|
||||||
|
var re = "^"+this.scheme.replace(metaRe, "\\$&")+"$";
|
||||||
|
for(var i=this.parameters.length-1; i>=0; i--) {
|
||||||
|
var param = this.parameters[i];
|
||||||
|
re = re.replace(Zotero_Proxy_schemeParameterRegexps[param], "$1"+parametersToCheck[param]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.regexp = new RegExp(re);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensures that the proxy scheme and host settings are valid for this proxy type
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype.validate = function() {
|
||||||
|
if(this.scheme.length < 8 || (this.scheme.substr(0, 7) != "http://" && this.scheme.substr(0, 8) != "https://")) {
|
||||||
|
return "scheme.noHTTP";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!this.multiSite && (!this.hosts.length || !this.hosts[0])) {
|
||||||
|
return "host.invalid";
|
||||||
|
} else if(this.multiSite && !Zotero_Proxy_schemeParameterRegexps["%h"].test(this.scheme)) {
|
||||||
|
return "scheme.noHost";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!Zotero_Proxy_schemeParameterRegexps["%p"].test(this.scheme) &&
|
||||||
|
(!Zotero_Proxy_schemeParameterRegexps["%d"].test(this.scheme) ||
|
||||||
|
!Zotero_Proxy_schemeParameterRegexps["%f"].test(this.scheme))) {
|
||||||
|
return "scheme.noPath";
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves any changes to this proxy
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype.save = function() {
|
||||||
|
// ensure this proxy is valid
|
||||||
|
Zotero.debug(this);
|
||||||
|
var hasErrors = this.validate();
|
||||||
|
if(hasErrors) throw "Proxy could not be saved because it is invalid: error "+hasErrors;
|
||||||
|
|
||||||
|
this.autoAssociate = this.multiHost && this.autoAssociate;
|
||||||
|
this.compileRegexp();
|
||||||
|
if(this.proxyID) {
|
||||||
|
Zotero.Proxies.refreshHostMap();
|
||||||
|
} else {
|
||||||
|
Zotero.Proxies.save(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Zotero.DB.beginTransaction();
|
||||||
|
|
||||||
|
if(this.proxyID) {
|
||||||
|
Zotero.DB.query("UPDATE proxies SET multiHost = ?, autoAssociate = ?, scheme = ? WHERE proxyID = ?",
|
||||||
|
[this.multiHost ? 1 : 0, this.autoAssociate ? 1 : 0, this.scheme, this.proxyID]);
|
||||||
|
Zotero.DB.query("DELETE FROM proxyHosts WHERE proxyID = ?", [this.proxyID]);
|
||||||
|
} else {
|
||||||
|
this.proxyID = Zotero.DB.query("INSERT INTO proxies (multiHost, autoAssociate, scheme) VALUES (?, ?, ?)",
|
||||||
|
[this.multiHost ? 1 : 0, this.autoAssociate ? 1 : 0, this.scheme])
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hosts = this.hosts.sort();
|
||||||
|
var host;
|
||||||
|
for(var i in this.hosts) {
|
||||||
|
host = this.hosts[i] = this.hosts[i].toLowerCase();
|
||||||
|
Zotero.DB.query("INSERT INTO proxyHosts (proxyID, hostname) VALUES (?, ?)",
|
||||||
|
[this.proxyID, host]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Zotero.DB.commitTransaction();
|
||||||
|
} catch(e) {
|
||||||
|
Zotero.DB.rollbackTransaction();
|
||||||
|
throw(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverts to the previously saved version of this proxy
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype.revert = function() {
|
||||||
|
if(!this.proxyID) throw "Cannot revert an unsaved proxy";
|
||||||
|
this._loadFromRow(Zotero.DB.rowQuery("SELECT * FROM proxies WHERE proxyID = ?", [this.proxyID]));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes this proxy
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype.erase = function() {
|
||||||
|
if(!this.proxyID) throw "Tried to erase an unsaved proxy";
|
||||||
|
Zotero.Proxies.remove(this);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Zotero.DB.beginTransaction();
|
||||||
|
Zotero.DB.query("DELETE FROM proxies WHERE proxyID = ?", [this.proxyID]);
|
||||||
|
Zotero.DB.query("DELETE FROM proxyHosts WHERE proxyID = ?", [this.proxyID]);
|
||||||
|
Zotero.DB.commitTransaction();
|
||||||
|
} catch(e) {
|
||||||
|
Zotero.DB.rollbackTransaction();
|
||||||
|
throw(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a proxied URL to an unproxied URL using this proxy
|
||||||
|
*
|
||||||
|
* @param m {Array} The match from running this proxy's regexp against a URL spec
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype.toProper = function(m) {
|
||||||
|
if(this.multiHost) {
|
||||||
|
properURL = "http://"+m[this.parameters.indexOf("%h")+1]+"/";
|
||||||
|
} else {
|
||||||
|
properURL = "http://"+this.hosts[0]+"/";
|
||||||
|
}
|
||||||
|
|
||||||
|
if(this.indices["%p"]) {
|
||||||
|
properURL += m[this.parameters.indexOf("%p")+1];
|
||||||
|
} else {
|
||||||
|
var dir = m[this.parameters.indexOf("%d")+1];
|
||||||
|
var file = m[this.parameters.indexOf("%f")+1];
|
||||||
|
if(dir !== "") properURL += dir+"/";
|
||||||
|
properURL += file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return properURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an unproxied URL to a proxied URL using this proxy
|
||||||
|
*
|
||||||
|
* @param {nsIURI} uri The nsIURI corresponding to the unproxied URL
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype.toProxy = function(uri) {
|
||||||
|
proxyURL = this.scheme;
|
||||||
|
|
||||||
|
for(var i=this.parameters.length-1; i>=0; i--) {
|
||||||
|
var param = this.parameters[i];
|
||||||
|
var value = "";
|
||||||
|
if(param == "%h") {
|
||||||
|
value = uri.hostPort;
|
||||||
|
} else if(param == "%p") {
|
||||||
|
value = uri.path.substr(1);
|
||||||
|
} else if(param == "%d") {
|
||||||
|
value = uri.path.substr(0, uri.path.lastIndexOf("/"));
|
||||||
|
} else if(param == "%f") {
|
||||||
|
value = uri.path.substr(uri.path.lastIndexOf("/")+1)
|
||||||
|
}
|
||||||
|
|
||||||
|
proxyURL = proxyURL.substr(0, this.indices[param])+value+proxyURL.substr(this.indices[param]+2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return proxyURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a proxy object from a DB row
|
||||||
|
*/
|
||||||
|
Zotero.Proxy.prototype._loadFromRow = function(row) {
|
||||||
|
this.proxyID = row.proxyID;
|
||||||
|
this.multiHost = !!row.multiHost;
|
||||||
|
this.autoAssociate = !!row.autoAssociate;
|
||||||
|
this.scheme = row.scheme;
|
||||||
|
this.hosts = Zotero.DB.columnQuery("SELECT hostname FROM proxyHosts WHERE proxyID = ? ORDER BY hostname", row.proxyID);
|
||||||
|
this.compileRegexp();
|
||||||
|
}
|
||||||
|
|
||||||
|
Zotero.Proxies.Detectors = new Object();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detector for OCLC EZProxy
|
||||||
|
*/
|
||||||
|
Zotero.Proxies.Detectors.EZProxy = function(channel) {
|
||||||
|
const ezProxyRe = /\?(?:.+&)?(url|qurl)=([^&]+)/i;
|
||||||
|
try {
|
||||||
|
if(channel.getResponseHeader("Server") != "EZproxy" || channel.responseStatus != "302") {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should be able to scrape the URL out of this
|
||||||
|
var m = ezProxyRe.exec(channel.URI.spec);
|
||||||
|
if(!m) return false;
|
||||||
|
|
||||||
|
var ioService = Components.classes["@mozilla.org/network/io-service;1"]
|
||||||
|
.getService(Components.interfaces.nsIIOService);
|
||||||
|
|
||||||
|
// Found URL
|
||||||
|
var properURL = m[2];
|
||||||
|
if(m[1].toLowerCase() == "qurl") properURL = unescape(properURL);
|
||||||
|
var properURI = ioService.newURI(properURL, null, null);
|
||||||
|
if(!properURI) return false;
|
||||||
|
|
||||||
|
// Get the new URL
|
||||||
|
var newURL = channel.getResponseHeader("Location");
|
||||||
|
if(!newURL) return false;
|
||||||
|
|
||||||
|
// Ignore if we already know about it
|
||||||
|
if(Zotero.Proxies.proxyToProper(newURL, true)) return false;
|
||||||
|
|
||||||
|
// parse into nsIURI
|
||||||
|
var newURI = ioService.newURI(newURL, null, null);
|
||||||
|
if(!newURI) return false;
|
||||||
|
|
||||||
|
if(channel.URI.host == newURI.host && channel.URI.port != newURI.port) {
|
||||||
|
// Old style per-port
|
||||||
|
var proxy = new Zotero.Proxy();
|
||||||
|
proxy.multiHost = false;
|
||||||
|
proxy.scheme = newURI.scheme+"://"+newURI.hostPort+"/%p";
|
||||||
|
proxy.hosts = [properURI.hostPort];
|
||||||
|
} else if(newURI.host != channel.URI.host) {
|
||||||
|
// New style rewriting
|
||||||
|
var proxy = new Zotero.Proxy();
|
||||||
|
proxy.multiHost = proxy.autoAssociate = true;
|
||||||
|
proxy.scheme = newURI.scheme+"://"+newURI.hostPort.replace(properURI.host, "%h")+"/%p";
|
||||||
|
proxy.hosts = [properURI.hostPort];
|
||||||
|
}
|
||||||
|
return proxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detector for Juniper Networks WebVPN
|
||||||
|
*/
|
||||||
|
Zotero.Proxies.Detectors.Juniper = function(channel) {
|
||||||
|
const juniperRe = /^(https?:\/\/[^\/:]+(?:\:[0-9]+)?)\/(.*),DanaInfo=([^+,]*)([^+]*)(?:\+(.*))?$/;
|
||||||
|
try {
|
||||||
|
var url = channel.URI.spec;
|
||||||
|
var m = juniperRe.exec(url);
|
||||||
|
} catch(e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!m) return false;
|
||||||
|
|
||||||
|
var proxy = new Zotero.Proxy();
|
||||||
|
proxy.multiHost = true;
|
||||||
|
proxy.scheme = m[1]+"/%d"+",DanaInfo=%h%a+%f";
|
||||||
|
proxy.hosts = [m[3]];
|
||||||
|
return proxy;
|
||||||
|
}
|
|
@ -1665,6 +1665,12 @@ Zotero.Schema = new function(){
|
||||||
Zotero.DB.query("INSERT INTO itemAttachments (itemID, linkMode) VALUES (?, ?)", [id, 3]);
|
Zotero.DB.query("INSERT INTO itemAttachments (itemID, linkMode) VALUES (?, ?)", [id, 3]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (i==39) {
|
||||||
|
Zotero.DB.query("CREATE TABLE proxies (\n proxyID INTEGER PRIMARY KEY,\n multiHost INT,\n autoAssociate INT,\n scheme TEXT\n)");
|
||||||
|
Zotero.DB.query("CREATE TABLE proxyHosts (\n hostID INTEGER PRIMARY KEY,\n proxyID INTEGER,\n hostname TEXT,\n FOREIGN KEY (proxyID) REFERENCES proxies(proxyID)\n)");
|
||||||
|
Zotero.DB.query("CREATE INDEX proxyHosts_proxyID ON proxyHosts(proxyID)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateDBVersion('userdata', toVersion);
|
_updateDBVersion('userdata', toVersion);
|
||||||
|
|
|
@ -271,7 +271,7 @@ Zotero.Translate.prototype.setCollection = function(collection) {
|
||||||
Zotero.Translate.prototype.setLocation = function(location) {
|
Zotero.Translate.prototype.setLocation = function(location) {
|
||||||
if(this.type == "web") {
|
if(this.type == "web") {
|
||||||
// account for proxies
|
// account for proxies
|
||||||
this.location = Zotero.Ingester.ProxyMonitor.proxyToProper(location);
|
this.location = Zotero.Proxies.proxyToProper(location);
|
||||||
if(this.location != location) {
|
if(this.location != location) {
|
||||||
// figure out if this URL is being proxies
|
// figure out if this URL is being proxies
|
||||||
this.locationIsProxied = true;
|
this.locationIsProxied = true;
|
||||||
|
@ -1109,7 +1109,7 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
||||||
// if item was accessed through a proxy, ensure that the proxy
|
// if item was accessed through a proxy, ensure that the proxy
|
||||||
// address remains in the accessed version
|
// address remains in the accessed version
|
||||||
if(this.locationIsProxied && item.url) {
|
if(this.locationIsProxied && item.url) {
|
||||||
item.url = Zotero.Ingester.ProxyMonitor.properToProxy(item.url);
|
item.url = Zotero.Proxies.properToProxy(item.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
// create new item
|
// create new item
|
||||||
|
@ -1383,7 +1383,7 @@ Zotero.Translate.prototype._itemDone = function(item, attachedTo) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.locationIsProxied) {
|
if(this.locationIsProxied) {
|
||||||
attachment.url = Zotero.Ingester.ProxyMonitor.properToProxy(attachment.url);
|
attachment.url = Zotero.Proxies.properToProxy(attachment.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileBaseName = Zotero.Attachments.getFileBaseNameFromItem(myID);
|
var fileBaseName = Zotero.Attachments.getFileBaseNameFromItem(myID);
|
||||||
|
|
|
@ -555,7 +555,7 @@ Zotero.Utilities.Ingester.prototype.processDocuments = function(urls, processor,
|
||||||
if(this.translate.locationIsProxied) {
|
if(this.translate.locationIsProxied) {
|
||||||
for(var i in urls) {
|
for(var i in urls) {
|
||||||
if(this.translate.locationIsProxied) {
|
if(this.translate.locationIsProxied) {
|
||||||
urls[i] = Zotero.Ingester.ProxyMonitor.properToProxy(urls[i]);
|
urls[i] = Zotero.Proxies.properToProxy(urls[i]);
|
||||||
}
|
}
|
||||||
// check for a protocol colon
|
// check for a protocol colon
|
||||||
if(!Zotero.Utilities.Ingester._protocolRe.test(urls[i])) {
|
if(!Zotero.Utilities.Ingester._protocolRe.test(urls[i])) {
|
||||||
|
@ -591,7 +591,7 @@ Zotero.Utilities.Ingester.HTTP.prototype.doGet = function(urls, processor, done,
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.translate.locationIsProxied) {
|
if(this.translate.locationIsProxied) {
|
||||||
url = Zotero.Ingester.ProxyMonitor.properToProxy(url);
|
url = Zotero.Proxies.properToProxy(url);
|
||||||
}
|
}
|
||||||
if(!Zotero.Utilities.Ingester._protocolRe.test(url)) {
|
if(!Zotero.Utilities.Ingester._protocolRe.test(url)) {
|
||||||
throw("invalid URL in processDocuments");
|
throw("invalid URL in processDocuments");
|
||||||
|
@ -620,7 +620,7 @@ Zotero.Utilities.Ingester.HTTP.prototype.doGet = function(urls, processor, done,
|
||||||
|
|
||||||
Zotero.Utilities.Ingester.HTTP.prototype.doPost = function(url, body, onDone, requestContentType, responseCharset) {
|
Zotero.Utilities.Ingester.HTTP.prototype.doPost = function(url, body, onDone, requestContentType, responseCharset) {
|
||||||
if(this.translate.locationIsProxied) {
|
if(this.translate.locationIsProxied) {
|
||||||
url = Zotero.Ingester.ProxyMonitor.properToProxy(url);
|
url = Zotero.Ingester.Proxies.properToProxy(url);
|
||||||
}
|
}
|
||||||
if(!Zotero.Utilities.Ingester._protocolRe.test(url)) {
|
if(!Zotero.Utilities.Ingester._protocolRe.test(url)) {
|
||||||
throw("invalid URL in processDocuments");
|
throw("invalid URL in processDocuments");
|
||||||
|
|
|
@ -61,6 +61,7 @@
|
||||||
<!ENTITY zotero.preferences.quickCopy.siteEditor.outputFormat "Output Format">
|
<!ENTITY zotero.preferences.quickCopy.siteEditor.outputFormat "Output Format">
|
||||||
|
|
||||||
<!ENTITY zotero.preferences.prefpane.styles "Styles">
|
<!ENTITY zotero.preferences.prefpane.styles "Styles">
|
||||||
|
|
||||||
<!ENTITY zotero.preferences.styles.styleManager "Style Manager">
|
<!ENTITY zotero.preferences.styles.styleManager "Style Manager">
|
||||||
<!ENTITY zotero.preferences.styles.styleManager.title "Title">
|
<!ENTITY zotero.preferences.styles.styleManager.title "Title">
|
||||||
<!ENTITY zotero.preferences.styles.styleManager.updated "Updated">
|
<!ENTITY zotero.preferences.styles.styleManager.updated "Updated">
|
||||||
|
@ -81,6 +82,23 @@
|
||||||
<!ENTITY zotero.preferences.keys.overrideGlobal "Try to override conflicting shortcuts">
|
<!ENTITY zotero.preferences.keys.overrideGlobal "Try to override conflicting shortcuts">
|
||||||
<!ENTITY zotero.preferences.keys.changesTakeEffect "Changes take effect in new windows only">
|
<!ENTITY zotero.preferences.keys.changesTakeEffect "Changes take effect in new windows only">
|
||||||
|
|
||||||
|
<!ENTITY zotero.preferences.prefpane.proxies "Proxies">
|
||||||
|
|
||||||
|
<!ENTITY zotero.preferences.proxies.proxyOptions "Proxy Options">
|
||||||
|
<!ENTITY zotero.preferences.proxies.autoRecognize "Automatically recognize common URL-rewriting proxy systems">
|
||||||
|
<!ENTITY zotero.preferences.proxies.transparent "Transparently redirect requests through previously used proxies">
|
||||||
|
<!ENTITY zotero.preferences.proxies.configured "Configured Proxies">
|
||||||
|
<!ENTITY zotero.preferences.proxies.hostname "Hostname">
|
||||||
|
<!ENTITY zotero.preferences.proxies.scheme "Scheme">
|
||||||
|
|
||||||
|
<!ENTITY zotero.preferences.proxies.multiSite "Multi-Site">
|
||||||
|
<!ENTITY zotero.preferences.proxies.autoAssociate "Automatically associate new hosts">
|
||||||
|
<!ENTITY zotero.preferences.proxies.variables "You may use the following variables in your proxy scheme:">
|
||||||
|
<!ENTITY zotero.preferences.proxies.h_variable "%h - The hostname of the proxied site (e.g., www.zotero.org)">
|
||||||
|
<!ENTITY zotero.preferences.proxies.p_variable "%p - The path of the proxied page excluding the leading slash (e.g., about/index.html)">
|
||||||
|
<!ENTITY zotero.preferences.proxies.d_variable "%d - The directory path (e.g., about/)">
|
||||||
|
<!ENTITY zotero.preferences.proxies.f_variable "%f - The filename (e.g., index.html)">
|
||||||
|
<!ENTITY zotero.preferences.proxies.a_variable "%a - Any string">
|
||||||
|
|
||||||
<!ENTITY zotero.preferences.prefpane.advanced "Advanced">
|
<!ENTITY zotero.preferences.prefpane.advanced "Advanced">
|
||||||
|
|
||||||
|
|
|
@ -498,3 +498,13 @@ styles.updateStyle = Update existing style "%1$S" with "%2$S"?
|
||||||
styles.installed = The style "%S" was installed successfully.
|
styles.installed = The style "%S" was installed successfully.
|
||||||
styles.installError = %S does not appear to be a valid CSL file.
|
styles.installError = %S does not appear to be a valid CSL file.
|
||||||
styles.deleteStyle = Are you sure you want to delete the style "%1$S"?
|
styles.deleteStyle = Are you sure you want to delete the style "%1$S"?
|
||||||
|
|
||||||
|
proxies.multiSite = Multi-Site
|
||||||
|
proxies.error = Information Validation Error
|
||||||
|
proxies.error.scheme.noHTTP = Valid proxy schemes must start with "http://" or "https://"
|
||||||
|
proxies.error.host.invalid = You must enter a full hostname for the site served by this proxy (e.g., jstor.org).
|
||||||
|
proxies.error.scheme.noHost = A multi-site proxy scheme must contain the host variable (%h).
|
||||||
|
proxies.error.scheme.noPath = A valid proxy scheme must contain either the path variable (%p) or the directory and filename variables (%d and %f).
|
||||||
|
proxies.recognized = Proxy Recognized
|
||||||
|
proxies.recognized.message = Would you like Zotero to store information about this proxy server to enable saving of references accessed through it?\n\nWARNING: Only click "OK" below if you have accessed this site through your library or another institution you trust.
|
||||||
|
proxies.recognized.disable = Disable automatic recognition of proxy systems
|
BIN
chrome/skin/default/zotero/prefs-proxies.png
Normal file
BIN
chrome/skin/default/zotero/prefs-proxies.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.2 KiB |
|
@ -20,7 +20,7 @@ var xpcomFiles = ['zotero',
|
||||||
'data/collections', 'data/cachedTypes', 'data/creator', 'data/creators',
|
'data/collections', 'data/cachedTypes', 'data/creator', 'data/creators',
|
||||||
'data/itemFields', 'data/notes', 'data/tag', 'data/tags', 'db', 'enstyle',
|
'data/itemFields', 'data/notes', 'data/tag', 'data/tags', 'db', 'enstyle',
|
||||||
'file', 'fulltext', 'id', 'ingester', 'integration', 'itemTreeView', 'mime',
|
'file', 'fulltext', 'id', 'ingester', 'integration', 'itemTreeView', 'mime',
|
||||||
'notifier', 'progressWindow', 'quickCopy', 'report', 'schema', 'search',
|
'notifier', 'progressWindow', 'proxy', 'quickCopy', 'report', 'schema', 'search',
|
||||||
'sync', 'timeline', 'translate', 'utilities', 'zeroconf'];
|
'sync', 'timeline', 'translate', 'utilities', 'zeroconf'];
|
||||||
|
|
||||||
for (var i=0; i<xpcomFiles.length; i++) {
|
for (var i=0; i<xpcomFiles.length; i++) {
|
||||||
|
|
|
@ -79,4 +79,8 @@ pref("extensions.zotero.annotations.warnOnClose", true);
|
||||||
// Server
|
// Server
|
||||||
pref("extensions.zotero.sync.server.autoSync", true);
|
pref("extensions.zotero.sync.server.autoSync", true);
|
||||||
pref("extensions.zotero.sync.server.username", '');
|
pref("extensions.zotero.sync.server.username", '');
|
||||||
pref("extensions.zotero.sync.server.compressData", true);
|
pref("extensions.zotero.sync.server.compressData", true);
|
||||||
|
|
||||||
|
// Proxy
|
||||||
|
pref("extensions.zotero.proxies.autoRecognize", true);
|
||||||
|
pref("extensions.zotero.proxies.transparent", false);
|
19
userdata.sql
19
userdata.sql
|
@ -1,4 +1,4 @@
|
||||||
-- 38
|
-- 39
|
||||||
|
|
||||||
-- This file creates tables containing user-specific data -- any changes made
|
-- This file creates tables containing user-specific data -- any changes made
|
||||||
-- here must be mirrored in transition steps in schema.js::_migrateSchema()
|
-- here must be mirrored in transition steps in schema.js::_migrateSchema()
|
||||||
|
@ -254,4 +254,19 @@ CREATE TABLE highlights (
|
||||||
dateModified DATE,
|
dateModified DATE,
|
||||||
FOREIGN KEY (itemID) REFERENCES itemAttachments(itemID)
|
FOREIGN KEY (itemID) REFERENCES itemAttachments(itemID)
|
||||||
);
|
);
|
||||||
CREATE INDEX highlights_itemID ON highlights(itemID);
|
CREATE INDEX highlights_itemID ON highlights(itemID);
|
||||||
|
|
||||||
|
CREATE TABLE proxies (
|
||||||
|
proxyID INTEGER PRIMARY KEY,
|
||||||
|
multiHost INT,
|
||||||
|
autoAssociate INT,
|
||||||
|
scheme TEXT
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE TABLE proxyHosts (
|
||||||
|
hostID INTEGER PRIMARY KEY,
|
||||||
|
proxyID INTEGER,
|
||||||
|
hostname TEXT
|
||||||
|
FOREIGN KEY (proxyID) REFERENCES proxies(proxyID)
|
||||||
|
);
|
||||||
|
CREATE INDEX proxyHosts_proxyID ON proxyHosts(proxyID);
|
Loading…
Add table
Add a link
Reference in a new issue