[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[ff-cvs] storm ./Makefile doc/dartboard/pointer_identiti...
From: |
Benja Fallenstein |
Subject: |
[ff-cvs] storm ./Makefile doc/dartboard/pointer_identiti... |
Date: |
Wed, 10 Sep 2003 09:20:28 -0400 |
CVSROOT: /cvsroot/storm
Module name: storm
Branch:
Changes by: Benja Fallenstein <address@hidden> 03/09/10 09:20:28
Modified files:
. : Makefile
doc/dartboard/pointer_identities--benja: idea.rst
org/nongnu/storm/pointers: PointerBlock.java PointerId.java
PointerIndex.java
org/nongnu/storm/util: CopyUtil.java HTTPProxy.java
HtmlLinkIndex.java
Log message:
Implement backlinks and history and automatic compilation of RST
CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/Makefile.diff?tr1=1.23&tr2=1.24&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/doc/dartboard/pointer_identities--benja/idea.rst.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/org/nongnu/storm/pointers/PointerBlock.java.diff?tr1=1.4&tr2=1.5&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/org/nongnu/storm/pointers/PointerId.java.diff?tr1=1.5&tr2=1.6&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/org/nongnu/storm/pointers/PointerIndex.java.diff?tr1=1.7&tr2=1.8&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/org/nongnu/storm/util/CopyUtil.java.diff?tr1=1.3&tr2=1.4&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/org/nongnu/storm/util/HTTPProxy.java.diff?tr1=1.47&tr2=1.48&r1=text&r2=text
http://savannah.gnu.org/cgi-bin/viewcvs/storm/storm/org/nongnu/storm/util/HtmlLinkIndex.java.diff?tr1=1.1&tr2=1.2&r1=text&r2=text
Patches:
Index: storm/Makefile
diff -u storm/Makefile:1.23 storm/Makefile:1.24
--- storm/Makefile:1.23 Mon Jun 23 17:18:31 2003
+++ storm/Makefile Wed Sep 10 09:20:27 2003
@@ -2,14 +2,15 @@
TEST=org/
+NAVIDOC_DEPENDS = ../navidoc-depends
RAWSRC = `find org/ -name "*.java"` `find com/ -name "*.java"`
CLASSDIR=CLASSES/
STORM_DEPENDS=../storm-depends
CLASSPATH=$(CLASSDIR):$(STORM_DEPENDS)/cryptix-jce-provider.jar:$(STORM_DEPENDS)/jython.jar:$(STORM_DEPENDS)/gisp.jar:$(STORM_DEPENDS)/dom4j.jar:$(STORM_DEPENDS)/log4j.jar:$(shell
echo $$CLASSPATH)
-PYTHONPATH=-Dpython.path=.:$(STORM_DEPENDS)/jythonlib.jar:$(STORM_DEPENDS)/pythonlib.jar
+PYTHONPATH=-Dpython.path=.:$(STORM_DEPENDS)/jythonlib.jar:$(STORM_DEPENDS)/pythonlib.jar:../navidoc/:$(NAVIDOC_DEPENDS)/docutils.jar
export CLASSPATH
JAVAC=javac
-JAVA=java
+JAVA=java -Dpython.cachedir=. -Dpython.path=$(PYTHONPATH)
-Dpython.verbose=message
KEYFILE=my.keys
clean:
Index: storm/doc/dartboard/pointer_identities--benja/idea.rst
diff -u storm/doc/dartboard/pointer_identities--benja/idea.rst:1.4
storm/doc/dartboard/pointer_identities--benja/idea.rst:1.5
--- storm/doc/dartboard/pointer_identities--benja/idea.rst:1.4 Wed Jul 9
21:51:14 2003
+++ storm/doc/dartboard/pointer_identities--benja/idea.rst Wed Sep 10
09:20:27 2003
@@ -4,7 +4,7 @@
:Author: Benja Fallenstein <address@hidden>
:Created: 2003-07-10
-:Changed: $Date: 2003/07/10 01:51:14 $
+:Changed: $Date: 2003/09/10 13:20:27 $
.. contents::
@@ -36,64 +36,6 @@
any (cryptographic) thing that you can do.
-What timestamping does
-----------------------
-
-One important technique here is timestamping. When
-signatures aren't timestamped, once the key is
-compromised, no signatures signed by this key
-can be trusted any more: There's no way to verify
-they were created before the key was revoked.
-
-If signatures are timestamped, you can verify
-that a signature was created before the key
-was revoked. So, you cannot create new signatures
-(the problem above isn't completely solved),
-but the old signatures don't become invalid.
-
-Unfortunately, the good methods for timestamping
-have been heavily patented (by `Surety, Inc.`__).
-
-__ http://www.surety.com/
-
-Here's a simple, patentless timestamping
-technology (there was a patent, but it's been
-overturned):
-
- There is a Trusted Third Party (TTP) which is
- trusted by everybody. To obtain a timestamp,
- submit a hash of your document to the TTP.
- The TTP will sign a statement like, "Hash H
- was submitted on 2003-07-10." Showing the
- TTP's signature proves that the document
- really existed on that date.
-
-Of course, the TTP could be fraudulent.
-
-Here's a much better system:
-
- There is a central timestamping service (TS).
- To obtain a timestamp, submit its hash to the TS.
- The TS operates in a sequence of "rounds," say,
- one minute long. It builds a hash tree of all
- documents submitted in one round. Showing the chain
- of hashes required to authenticate your document
- as part of the hash proves that your document
- existed during that timestamping round.
-
- Each round includes the hash of the previous round,
- so each round certifies the previous round. Once
- a week or so, the TS publishes the current round's
- hash in a widely-witnessed manner (e.g., in an
- important newspaper). Thus, even if one doesn't trust
- the TS or anybody on the network at all, the age
- of a document can be proven (well enough that it
- should stand up in court) with a resolution of
- one week (in the example).
-
-Unfortunately, this one's patented.
-
-
Using a public key infrastructure (PKI)?
----------------------------------------
@@ -231,4 +173,98 @@
guarantee that your private key will not be exposed,
you need to give somebody else the right to assign
you a new key; which means you need to trust them
-not to assign your key to someone else.
\ No newline at end of file
+not to assign your key to someone else.
+
+
+Non-repudiability
+=================
+
+Now, an important consideration here is
+*non-repudiability*: the inability to sign a message
+today and say tomorrow, "No, it wasn't me!"
+
+Repudiability is a problem in public-key cryptography
+when keys expire oor are revoked. If anybody could
+have a copy of the corresponding private key,
+a signature given with it isn't worth anything-- even
+if it was given *before* the key expired, because
+we cannot prove that.
+
+In our context, repudiability results in two problems:
+
+- Web page authors can claim they never published
+ a version of their page which they really *did*
+ publish.
+- Parent authorities deny the history of their
+ child authorities. I.e., a parent authority changes
+ the child authority's key to one that the parent
+ authority controls; it doesn't sign the blocks
+ that the child authority had signed, so all the
+ blocks signed by the child authority are invalidated
+ and all history of the data is lost.
+
+Normally, timestamping is used to proof the validity
+of signatures after the key was revoked.
+
+
+How timestamping works
+----------------------
+
+The trick with timestamping is,
+if signatures are timestamped, you can verify
+that a signature was created *before* the key
+was revoked.
+
+Unfortunately, the good methods for timestamping
+have been heavily patented (by `Surety, Inc.`__).
+
+__ http://www.surety.com/
+
+Here's a simple, patentless timestamping
+technology (there was a patent, but it's been
+overturned):
+
+ There is a Trusted Third Party (TTP) which is
+ trusted by everybody. To obtain a timestamp,
+ submit a hash of your document to the TTP.
+ The TTP will sign a statement like, "Hash H
+ was submitted on 2003-07-10." Showing the
+ TTP's signature proves that the document
+ really existed on that date.
+
+Of course, the TTP could be fraudulent.
+
+Here's a much better system:
+
+ There is a central timestamping service (TS).
+ To obtain a timestamp, submit its hash to the TS.
+ The TS operates in a sequence of "rounds," say,
+ one minute long. It builds a hash tree of all
+ documents submitted in one round. Showing the chain
+ of hashes required to authenticate your document
+ as part of the hash proves that your document
+ existed during that timestamping round.
+
+ Each round includes the hash of the previous round,
+ so each round certifies the previous round. Once
+ a week or so, the TS publishes the current round's
+ hash in a widely-witnessed manner (e.g., in an
+ important newspaper). Thus, even if one doesn't trust
+ the TS or anybody on the network at all, the age
+ of a document can be proven (well enough that it
+ should stand up in court) with a resolution of
+ one week (in the example).
+
+Unfortunately, this one's patented.
+
+
+So what can we do?
+------------------
+
+Well, first of all, we need some way to keep signatures
+valid even after the key that originally signed them
+has expired (or been revoked) and been replaced by
+a new key, without having to take every signature given
+with the old key and giving it again with the new key.
+
+The key, here, is to
\ No newline at end of file
Index: storm/org/nongnu/storm/pointers/PointerBlock.java
diff -u storm/org/nongnu/storm/pointers/PointerBlock.java:1.4
storm/org/nongnu/storm/pointers/PointerBlock.java:1.5
--- storm/org/nongnu/storm/pointers/PointerBlock.java:1.4 Thu May 22
18:03:52 2003
+++ storm/org/nongnu/storm/pointers/PointerBlock.java Wed Sep 10 09:20:27 2003
@@ -110,4 +110,9 @@
if(!s.verify(signature))
throw new IOException("Wrong signature in block: "+block.getId());
}
+
+ public boolean equals(Object o) {
+ if(!(o instanceof PointerBlock)) return false;
+ return ((PointerBlock)o).blockId.equals(blockId);
+ }
}
Index: storm/org/nongnu/storm/pointers/PointerId.java
diff -u storm/org/nongnu/storm/pointers/PointerId.java:1.5
storm/org/nongnu/storm/pointers/PointerId.java:1.6
--- storm/org/nongnu/storm/pointers/PointerId.java:1.5 Tue May 13 10:40:28 2003
+++ storm/org/nongnu/storm/pointers/PointerId.java Wed Sep 10 09:20:27 2003
@@ -50,6 +50,8 @@
}
private static SecureRandom random = new SecureRandom();
+
+
private String uri;
private byte[] bytes;
private String randomPart;
@@ -58,7 +60,7 @@
uri = uri.toLowerCase().intern();
this.uri = uri;
- int colon = uri.lastIndexOf(':');
+ int colon = uri.indexOf(':', PREFIX_LEN+1);
if(!uri.startsWith(PREFIX))
throw new IllegalArgumentException("Storm URN must start "+PREFIX+"
[[ was "+uri+" ]]");
Index: storm/org/nongnu/storm/pointers/PointerIndex.java
diff -u storm/org/nongnu/storm/pointers/PointerIndex.java:1.7
storm/org/nongnu/storm/pointers/PointerIndex.java:1.8
--- storm/org/nongnu/storm/pointers/PointerIndex.java:1.7 Thu May 22
18:03:52 2003
+++ storm/org/nongnu/storm/pointers/PointerIndex.java Wed Sep 10 09:20:27 2003
@@ -75,6 +75,57 @@
return b.getName();
}
+ /** Get a list of past pointer blocks of a pointer (newest first) */
+ public SortedSet getHistory(PointerId id) throws IOException {
+ SortedSet s = new TreeSet(new Comparator() {
+ public int compare(Object o1, Object o2) {
+ PointerBlock p1 = (PointerBlock)o1;
+ PointerBlock p2 = (PointerBlock)o2;
+ if(p1.getTimestamp() == p2.getTimestamp())
+ return 0;
+ else if(p1.getTimestamp() < p2.getTimestamp())
+ return +1;
+ else
+ return -1;
+ }
+ });
+
+ Collector c = db.get(id.toString()).block();
+ for(Iterator i=c.iterator(); i.hasNext();) {
+ IndexedPool.Mapping m = (IndexedPool.Mapping)i.next();
+ if(dbg) p("Process: "+m.block+" "+m.value);
+
+ long timestamp;
+ try {
+ timestamp = Long.parseLong(m.value);
+ } catch(NumberFormatException _) {
+ // malformed entry
+ continue;
+ }
+ PointerBlock p;
+ try {
+ p = new PointerBlock(pool.get(m.block));
+ } catch(Throwable _) {
+ System.out.println("Couldn't use '"+m.block+"' because: "+_);
+ continue;
+ }
+
+ if(p.getPointer().equals(id) &&
+ p.getTimestamp() == timestamp) {
+ s.add(p);
+ }
+ }
+
+ return s;
+ }
+
+ /** Return whether a particular pointer block is the
+ * newest one for its pointer.
+ */
+ public boolean isCurrent(PointerBlock pb) throws IOException,
GeneralSecurityException {
+ return pb.equals(getPointerBlock(pb.getPointer()));
+ }
+
public PointerBlock getPointerBlock(PointerId id)
throws IOException, GeneralSecurityException {
if(dbg) p("Get: "+id);
Index: storm/org/nongnu/storm/util/CopyUtil.java
diff -u storm/org/nongnu/storm/util/CopyUtil.java:1.3
storm/org/nongnu/storm/util/CopyUtil.java:1.4
--- storm/org/nongnu/storm/util/CopyUtil.java:1.3 Sat Apr 19 08:20:32 2003
+++ storm/org/nongnu/storm/util/CopyUtil.java Wed Sep 10 09:20:27 2003
@@ -90,9 +90,13 @@
}
/** Read data from an input stream into a String.
- * Most useful for debug output. Encoding is US-ASCII.
+ * Most useful for debug output. Default encoding is US-ASCII.
*/
+ static public String readString(InputStream in, String encoding) throws
IOException {
+ return new String(readBytes(in), encoding);
+ }
+
static public String readString(InputStream in) throws IOException {
- return new String(readBytes(in), "US-ASCII");
+ return readString(in, "US-ASCII");
}
}
Index: storm/org/nongnu/storm/util/HTTPProxy.java
diff -u storm/org/nongnu/storm/util/HTTPProxy.java:1.47
storm/org/nongnu/storm/util/HTTPProxy.java:1.48
--- storm/org/nongnu/storm/util/HTTPProxy.java:1.47 Mon Jun 23 17:18:31 2003
+++ storm/org/nongnu/storm/util/HTTPProxy.java Wed Sep 10 09:20:27 2003
@@ -36,6 +36,7 @@
import java.net.*;
import java.util.*;
import java.security.*;
+import org.python.util.PythonInterpreter;
/** An HTTP server serving blocks from a Storm pool. When started from command
* line, it servers the directory given as first argument.
@@ -52,9 +53,11 @@
protected String URNPAC;
protected String BACKLINKS;
protected String QUERY = "search?q=";
+ protected String HISTORY = "history?doc=";
protected HTTPServer server;
protected boolean acceptPut = false;
+ protected boolean showBlocks = false;
protected KeyPair keyPair;
public HTTPProxy(IndexedPool pool, int port) throws IOException {
@@ -103,9 +106,12 @@
boolean rewrite = false, backlinks = false;
String uri = req.getRequestURI();
if(HTTPProxy.dbg) p("<"+port+"> GET: "+uri + " (" +
this.getRemoteIPAddress() + ")");
-
- /* URN proxy requests don't start with slash */
- if(!uri.startsWith("/"))
+
+ if(uri.startsWith("x-storm:"))
+ /* Work around Amaya bug */
+ uri = REWRITE + "/urn:" + uri;
+ else if(!uri.startsWith("/"))
+ /* URN proxy requests don't start with slash */
return serveBlock(uri, resf);
else
uri = uri.substring(1);
@@ -113,10 +119,14 @@
if(uri.equals(URNPAC))
return makePAC(req, resf);
if(uri.startsWith(QUERY))
- return query(req, resf, uri);
+ return query(req, resf, uri, false);
+ if(uri.startsWith("rewrite/" + QUERY))
+ return query(req, resf, uri.substring("rewrite/".length()),
true);
+ if(uri.startsWith(HISTORY))
+ return history(req, resf, uri);
String element;
- while(!uri.startsWith("urn:")) {
+ while(!uri.startsWith("urn")) {
int slash = uri.indexOf('/');
if(slash != -1) {
element = uri.substring(0, slash);
@@ -131,6 +141,8 @@
backlinks = true;
else if(element.equals(""))
return serveHomePage(rewrite, backlinks, resf);
+ else if(element.equals("pointers"))
+ return servePointerList(resf);
else
throw new FileNotFoundException("Unknown: "+uri);
}
@@ -141,7 +153,7 @@
BlockId id = getBlockId(uri);
if((!rewrite && !backlinks) ||
- !id.getContentType().equals("text/html"))
+ !id.getContentType().startsWith("text/html"))
return serveBlock(uri, resf);
@@ -152,7 +164,7 @@
HTTPResponse resp = resf.makeResponse(200, "Ok");
resp.setField("Content-Type", id.getContentType());
- String s = CopyUtil.readString(block.getInputStream());
+ String s = CopyUtil.readString(block.getInputStream(), "UTF-8");
String prefix = "";
if(rewrite) {
@@ -164,9 +176,9 @@
s = rewriteURIs(s, prefix);
if(backlinks)
- s = insertBacklinks(s, prefix, id);
+ s = insertBacklinks(s, prefix, uri);
- byte[] bytes = s.getBytes("US-ASCII");
+ byte[] bytes = s.getBytes("UTF-8");
resp.getOutputStream().write(bytes);
resp.close();
return resp;
@@ -227,14 +239,19 @@
writeRewriteLinks(w, rewrite);
+ w.write("<form action=\""+(rewrite ? "/rewrite" : "")+"/search\"
method=\"get\">Find pointer: <input type=\"text\" name=\"q\"><input
type=\"submit\" value=\"Find\"></form>");
+
if(acceptPut) {
w.write("<h2>New pointer</h2>\n\n");
- w.write("<FORM action=\"/new-pointer\" method=\"post\">\n");
+ w.write("<FORM action=\""+(rewrite ? "/rewrite" :
"")+"/new-pointer\" method=\"post\">\n");
w.write("<P>\n");
w.write("Title: <INPUT type=\"text\" name=\"title\">");
w.write("<SELECT name=\"target\">\n");
- w.write("<OPTION selected
value=\"urn:x-storm:1.0:text/plain,3i42h3s6nnfq2msvx7xzkyayscx5qbyj.lwpnacqdbzryxw3vhjvcj64qbznghohhhzwclnq\">Text
file</OPTION>\n");
+ w.write("<OPTION selected
value=\"urn:x-storm:1.0:text/prs.fallenstein.rst,3i42h3s6nnfq2msvx7xzkyayscx5qbyj.lwpnacqdbzryxw3vhjvcj64qbznghohhhzwclnq\">ReStructuredText
file</OPTION>\n");
+ w.write("<OPTION
value=\"urn:x-storm:1.0:text/plain,3i42h3s6nnfq2msvx7xzkyayscx5qbyj.lwpnacqdbzryxw3vhjvcj64qbznghohhhzwclnq\">Text
file</OPTION>\n");
+ w.write("<OPTION
value=\"urn:x-storm:1.0:text/html,3i42h3s6nnfq2msvx7xzkyayscx5qbyj.lwpnacqdbzryxw3vhjvcj64qbznghohhhzwclnq\">HTML
page</OPTION>\n");
+ w.write("<OPTION
value=\"urn:x-storm:1.0:application/vnd.sun.xml.writer,b3xaowxhn3gg2hmz4e7rofjgfuesytja.jjdrwdheghbhr5qzc5we2giul22s6ljipavhj3q\">OpenOffice.org
Writer document</OPTION>\n");
w.write("<OPTION
value=\"urn:x-storm:1.0:application/vnd.kde.kword,ly3m5evqznmuxnuxyduv43ikvor2dkze.gxeygfionykrrizvwkoyevkdysdnrksw4t5i2yi\">KWord
file</OPTION>\n");
w.write("</SELECT>\n");
w.write("<INPUT type=\"submit\" value=\"Create\">\n");
@@ -275,17 +292,20 @@
}
}
- w.write("<h2>Blocks</h2>\n\n");
+ if(showBlocks) {
+ w.write("<h2>Blocks</h2>\n\n");
- synchronized(ids) {
- for(Iterator i=ids.iterator(); i.hasNext();) {
- BlockId id = (BlockId)i.next();
- String s = id.getURI();
- if(rewrite)
- s = base + s;
- w.write("<a href=\""+s+"\">"+id+"</a><br>\n");
+ synchronized(ids) {
+ for(Iterator i=ids.iterator(); i.hasNext();) {
+ BlockId id = (BlockId)i.next();
+ String s = id.getURI();
+ if(rewrite)
+ s = base + s;
+ w.write("<a href=\""+s+"\">"+id+"</a><br>\n");
+ }
}
}
+
w.write("</body></html>\n");
w.close();
return resp;
@@ -305,6 +325,43 @@
return resp;
}
+ protected HTTPResponse servePointerList(HTTPResponse.Factory resf)
+ throws IOException {
+
+ HTTPResponse resp = resf.makeResponse(200, "Ok");
+ resp.setField("Content-Type", "text/plain");
+ Writer w = new OutputStreamWriter(resp.getOutputStream(),
"US-ASCII");
+ PointerIndex pIndex =
+ (PointerIndex)pool.getIndex(PointerIndex.uri);
+
+ Collector pIds = pIndex.getIds();
+
+ /*
+ try {
+ // wait for DHT to receive information from network
+ Thread.sleep(2000);
+ } catch(InterruptedException _) {}
+ */
+
+ synchronized(pIds) {
+ for(Iterator i=pIds.iterator(); i.hasNext();) {
+ PointerId id = (PointerId)i.next();
+ try {
+ PointerBlock pb = pIndex.getPointerBlock(id);
+ String n = pb.getName();
+ String s = id.getURI();
+ w.write(id.getURI()); w.write('\n');
+ w.write(pb.getName()); w.write('\n');
+ w.write('\n');
+ }
+ catch(GeneralSecurityException _) { _.printStackTrace(); }
+ }
+ }
+
+ w.close();
+ return resp;
+ }
+
protected String rewriteURIs(String s, String prefix) {
// Block urns can be in upper or lower or mixed case;
// matching on the lower-case version makes
@@ -335,8 +392,8 @@
return s;
}
- protected String insertBacklinks(String s, String prefix, BlockId id)
- throws IOException {
+ protected String insertBacklinks(String s, String prefix, String uri)
+ throws IOException, GeneralSecurityException {
if(HTTPProxy.dbg) p("Getting HtmlLinkIndex.");
HtmlLinkIndex idx = null;
@@ -344,15 +401,18 @@
idx = (HtmlLinkIndex)pool.getIndex(HtmlLinkIndex.uri);
} catch(NoSuchElementException _) {}
+ PointerIndex pIndex =
+ (PointerIndex)pool.getIndex(PointerIndex.uri);
+
if(HTTPProxy.dbg) p("HtmlLinkIndex = "+idx);
if(idx != null) {
if(HTTPProxy.dbg) p("Looking for links");
- Collector links = idx.getLinksTo(id);
+ Collector links = idx.getLinksTo(uri);
try {
// XXX Are we trying to wait for indexing?
- Thread.sleep(2000);
+ Thread.sleep(500);
} catch(InterruptedException _) {}
if(HTTPProxy.dbg) p("Iter thru links");
@@ -360,31 +420,42 @@
synchronized(links) {
for(Iterator iter=links.iterator();
iter.hasNext();) {
- HtmlLinkIndex.Link link =
- (HtmlLinkIndex.Link)iter.next();
- if(HTTPProxy.dbg) p("Link: "+link.linkText);
- t += "[<a href=\""+prefix+link.linkFrom.getURI()+
- "\">"+link.linkText+"</a>]<br>";
+ PointerBlock pb = (PointerBlock)iter.next();
+ if(HTTPProxy.dbg) p("Linking pointer block: "+pb);
+ if(pIndex.isCurrent(pb)) {
+ String name = pb.getName();
+ if(name.endsWith(" (HTML)"))
+ name = name.substring(0, name.length()-7);
+ t += "[<a href=\""+prefix+pb.getPointer()+
+ "\">"+name+"</a>]<br>";
+ }
}
}
- if(!t.equals("")) {
- int i = s.indexOf("<body");
- i = s.indexOf(">", i);
- if(i < 0) i = 0;
- else i++;
- s = s.substring(0, i)
- + "\n<p><small>This page is referred to as:<br>"
+ if(!t.equals(""))
+ t = "\n<p align=\"right\"><small>This page is linked
from:<br>"
+ t
- + "</small></p>\n"
- + s.substring(i);
- }
+ + "</small></p>\n";
+
+ String history = "";
+ p("Backlinks URI: "+uri);
+ if(uri.toLowerCase().startsWith("urn:x-storm:pointer-0.1:"))
+ history = "\n<p align=\"right\"><small><a
href=\""+ROOTURL+HISTORY+uri+"\">History</a></p></center>";
+
+ int i = s.indexOf("<body");
+ i = s.indexOf(">", i);
+ if(i < 0) i = 0;
+ else i++;
+ s = s.substring(0, i)
+ + history
+ + t
+ + s.substring(i);
}
return s;
}
protected HTTPResponse query(HTTPRequest req,
HTTPResponse.Factory resf,
- String uri) throws IOException {
+ String uri, boolean rewrite) throws
IOException {
String query =
java.net.URLDecoder.decode(uri.substring(QUERY.length()));
@@ -405,7 +476,7 @@
for(Iterator i=pBlocks.iterator(); i.hasNext();) {
PointerBlock p = (PointerBlock)i.next();
- w.write("<p><b><a href=\""+p.getPointer().getURI()+"\">");
+ w.write("<p><b><a href=\""+(rewrite ? ROOTURL+REWRITE+"/" :
"")+p.getPointer().getURI()+"\">");
w.write(p.getName()+"</a></b><br />\n");
w.write("<small>"+p.getPointer().getURI()+"</small></p>\n\n");
}
@@ -415,6 +486,41 @@
return resp;
}
+
+ protected HTTPResponse history(HTTPRequest req,
+ HTTPResponse.Factory resf,
+ String uri) throws IOException,
GeneralSecurityException {
+ PointerId ptr = new PointerId(uri.substring(HISTORY.length()));
+ PointerIndex pIndex =
+ (PointerIndex)pool.getIndex(PointerIndex.uri);
+ SortedSet history = pIndex.getHistory(ptr);
+
+ HTTPResponse resp = resf.makeResponse(200, "Ok");
+ resp.setField("Content-Type", "text/html;charset=UTF-8");
+
+ Writer w = new OutputStreamWriter(resp.getOutputStream(),
+ "UTF-8");
+ String title = "History of \""+pIndex.getTitle(ptr)+"\"";
+ w.write("<html><head><title>"+title+"</title></head><body>\n");
+ w.write("<h1>"+title+"</h1>\n");
+ w.write("<p><a href=\""+ptr+"\">"+ptr+"</a></p>\n\n");
+
+ if(history.isEmpty()) w.write("<p>No versions available.</p>\n\n");
+
+ for(Iterator i=history.iterator(); i.hasNext();) {
+ PointerBlock p = (PointerBlock)i.next();
+ w.write("<p><b><a href=\""+p.getTarget()+"\">");
+ w.write(new Date(p.getTimestamp()).toLocaleString());
+ w.write("</a></b><br />\n");
+ w.write("<small>"+p.getTarget()+"</small></p>\n\n");
+ }
+
+ w.write("</body></html>\n");
+ w.close();
+ return resp;
+ }
+
+
protected HTTPResponse makePAC(HTTPRequest req,
HTTPResponse.Factory resf)
throws IOException {
@@ -439,7 +545,7 @@
protected HTTPResponse doPut(HTTPRequest req, HTTPResponse.Factory
resf)
throws IOException {
- String uri = req.getRequestURI();
+ String uri = URLDecoder.decode(req.getRequestURI());
System.out.println("PUT: "+uri);
if(!acceptPut)
@@ -447,46 +553,82 @@
if(uri.startsWith("/"))
uri = uri.substring(1);
+ else if(uri.startsWith("x-storm:"))
+ /* Work around Amaya bug */
+ uri = REWRITE + "/urn:" + uri;
boolean rewrite = false;
if(uri.startsWith(REWRITE+"/")) {
uri = uri.substring(REWRITE.length()+1);
rewrite = true;
}
+ if(uri.startsWith(BACKLINKS+"/")) {
+ uri = uri.substring(BACKLINKS.length()+1);
+ }
if(dbg) p("PUT accepted");
PointerId id = new PointerId(uri);
PointerIndex idx =
(PointerIndex)pool.getIndex(PointerIndex.uri);
- BlockId current;
+ String contentType, title;
try {
- current = idx.get(id);
+ // because we don't get a content-type
+ // assume it's the same as before
+ contentType = idx.get(id).getContentType();
+ title = idx.getPointerBlock(id).getName();
} catch(Exception _) {
_.printStackTrace();
- throw new Error("Exception while getting key XXX");
+ if(uri.endsWith(":stylesheet")) {
+ // guess
+ contentType = "text/css";
+ title = "CSS stylesheet";
+ } else
+ throw new Error("Exception while getting key XXX");
}
if(dbg) p("Got old pointer value");
- // because we don't get a content-type
- // assume it's the same as before
BlockOutputStream bos =
- pool.getBlockOutputStream(current.getContentType());
+ pool.getBlockOutputStream(contentType);
- if(!rewrite || !current.getContentType().equals("text/html")) {
+ if(!rewrite || !contentType.equals("text/html")) {
CopyUtil.copy(req.getInputStream(), bos);
} else {
String s = CopyUtil.readString(req.getInputStream());
String prefix = ROOTURL+REWRITE+"/";
s = unrewriteURIs(s, prefix);
bos.write(s.getBytes("US-ASCII"));
+ bos.close();
}
if(dbg) p("Created new block: "+bos.getBlockId());
+
+ // If it may be an RST file, try to compile it.
+ p("showct");
+ p("CT: <"+contentType+">");
+ if(contentType.startsWith("text/plain")) {
+ // Try to extract title
+ String charset = "iso-8859-1";
+ String prefix = "text/plain;charset=";
+ if(contentType.startsWith(prefix))
+ charset = contentType.substring(prefix.length());
+ BufferedReader r = new BufferedReader(new
InputStreamReader(bos.getBlock().getInputStream(), charset));
+ String l = r.readLine();
+ // XXX recognizes only titles of the style I use myself ;-)
+ if(l != null && l.startsWith("===")) {
+ String l2 = r.readLine();
+ if(l2 != null && !l2.equals(""))
+ title = l2.trim();
+ }
+
+ new Thread(new CompileRST(id, bos.getBlock(), title)).start();
+ p("Other thread continues");
+ }
+ // Now set RST pointer.
try {
- idx.set(id, bos.getBlockId(), keyPair);
+ idx.set(id, bos.getBlockId(), keyPair, title);
} catch(Exception _) {
_.printStackTrace();
throw new Error("Exception while getting key XXX");
@@ -522,7 +664,8 @@
return doUnknown(req, resf);
if(!uri.equals("/new-pointer") &&
- !uri.equals("/new-pointer-plain"))
+ !uri.equals("/new-pointer-plain") &&
+ !uri.equals("/rewrite/new-pointer"))
return resf.makeError(404, "Not found");
String formdata =
@@ -568,12 +711,13 @@
w.write(id.getURI());
w.close();
} else {
+ boolean rewrite = uri.equals("/rewrite/new-pointer");
resp.setField("Content-Type", "text/html");
Writer w = new OutputStreamWriter(resp.getOutputStream(),
"US-ASCII");
w.write("<html><head><title>Created</title></head><body>");
w.write("New pointer created at: \n");
- w.write("<a href=\""+id.getURI()+"\">"+id.getURI()+"</a>\n");
+ w.write("<a href=\""+(rewrite ? REWRITE :
"")+id.getURI()+"\">"+id.getURI()+"</a>\n");
w.write("<p><a href=\"/\">Back to the home page.</a>\n");
w.write("</body></html>");
w.close();
@@ -644,7 +788,7 @@
return idx.get(new PointerId(uri));
} catch(Exception _) {
_.printStackTrace();
- throw new Error("Exception while getting key XXX");
+ throw new Error("Exception while getting key XXX: "+_);
}
} else {
throw new Error("Malformed Storm URN: "+uri);
@@ -655,6 +799,62 @@
public HTTPConnection newConnection(Socket s) throws IOException {
return new StormConnection(s);
}
+ }
+
+ static PythonInterpreter interp;
+ protected class CompileRST implements Runnable {
+ PointerId rst, html;
+ Block src;
+ String title, stylesheet;
+
+ protected CompileRST(PointerId rst, Block src, String title) {
+ this.rst = rst;
+ this.html = new PointerId(rst.getURI() + ":html");
+ this.src = src;
+ this.title = title;
+
+ String s = rst.getURI();
+ stylesheet = s.substring(0, s.lastIndexOf(':')) + ":stylesheet";
+ p("Stylesheet URI: "+stylesheet);
+ }
+
+ public void run() {
+ p("Start compiling RST...");
+ if(interp == null) {
+ interp = new PythonInterpreter();
+ interp.exec("import docutils");
+ }
+
+ try {
+ String file = "/tmp/"+rst;
+ CopyUtil.copy(src.getInputStream(),
+ new FileOutputStream(file));
+
+ p("Start docutils.");
+ interp.exec("docutils.core.publish_cmdline(writer_name='html',
argv=['"+file+"', '"+file+".gen.html', '--input-encoding=iso-8859-1',
'--output-encoding=utf-8', '--generator', '--source-link',
'--stylesheet="+stylesheet+"'])");
+ p("Docutils finished.");
+
+ BlockOutputStream bos =
+ pool.getBlockOutputStream("text/html;charset=utf-8");
+ CopyUtil.copy(new FileInputStream(file + ".gen.html"), bos);
+
+ p("HTML block created: "+bos.getBlockId());
+
+ try {
+ PointerIndex idx =
+ (PointerIndex)pool.getIndex(PointerIndex.uri);
+ idx.set(html, bos.getBlockId(), keyPair, title + " (HTML)");
+ } catch(Exception _) {
+ _.printStackTrace();
+ throw new Error("Exception while putting key XXX");
+ }
+
+ p("Pointer set: "+html.getURI());
+ } catch(IOException _) {
+ throw new Error("Error while compiling RST: "+_);
+ }
+ p("RST compiled.");
+ }
}
public static void main(String[] args) throws Exception {
Index: storm/org/nongnu/storm/util/HtmlLinkIndex.java
diff -u storm/org/nongnu/storm/util/HtmlLinkIndex.java:1.1
storm/org/nongnu/storm/util/HtmlLinkIndex.java:1.2
--- storm/org/nongnu/storm/util/HtmlLinkIndex.java:1.1 Sat May 3 15:45:26 2003
+++ storm/org/nongnu/storm/util/HtmlLinkIndex.java Wed Sep 10 09:20:28 2003
@@ -27,6 +27,7 @@
*/
package org.nongnu.storm.util;
import org.nongnu.storm.*;
+import org.nongnu.storm.pointers.*;
import org.nongnu.storm.impl.AsyncSetCollector;
import java.io.*;
import java.util.*;
@@ -37,29 +38,32 @@
*/
public class HtmlLinkIndex {
public static final String uri =
- "urn:urn-5:T7uu149pw0Z0ANuQPwkw1oRVfZVn";
+ "urn:urn-5:tYgOeOBalVf5iRPrIuSZl81OJGS3";
public static final IndexType type = new IndexType();
- public static class Link {
- public final BlockId linkFrom;
- public final String linkText;
- protected Link(BlockId f, String t) { linkFrom=f; linkText=t; }
- }
-
protected IndexedPool pool;
protected IndexedPool.DB db;
protected static class IndexType implements IndexedPool.IndexType {
public Set getMappings(Block block) throws IOException {
- if(!block.getId().getContentType().equals("text/html"))
+ PointerBlock pb;
+ try {
+ pb = new PointerBlock(block);
+ } catch(Throwable _) {
+ return Collections.EMPTY_SET;
+ }
+
+ if(!pb.getTarget().getContentType().startsWith("text/html"))
return Collections.EMPTY_SET;
+ Block target = block.getPool().get(pb.getTarget());
+
Set mappings = new HashSet();
- String s = CopyUtil.readString(block.getInputStream());
+ String s = CopyUtil.readString(target.getInputStream());
int i = 0;
while(true) {
- i = s.indexOf("href=\"urn:x-storm:1.0:", i);
+ i = s.indexOf("href=\"urn:x-storm:", i);
if(i < 0) break;
i += "href=\"".length();
int j = s.indexOf('"', i);
@@ -69,15 +73,8 @@
int k = urn.indexOf('#');
if(k > 0) urn = urn.substring(0, k);
- j = s.indexOf('>', j);
- if(j < 0) break;
- k = s.indexOf("</a>", j);
- if(k < 0) break;
-
- String link = s.substring(j+1, k);
-
mappings.add(new IndexedPool.Mapping(block.getId(),
- urn, link));
+ urn, ""));
}
return mappings;
@@ -102,13 +99,20 @@
this.db = db;
}
- public SetCollector getLinksTo(BlockId id) throws IOException {
- Collector c = db.get(id.getURI());
+ /** Return a set of PointerBlocks linking to this target.
+ */
+ public SetCollector getLinksTo(String uri) throws IOException {
+ Collector c = db.get(uri);
final AsyncSetCollector result = new AsyncSetCollector();
c.addCollectionListener(new CollectionListener() {
public boolean item(Object item) {
- IndexedPool.Mapping m = (IndexedPool.Mapping)item;
- result.receive(new Link(m.block, m.value));
+ try {
+ IndexedPool.Mapping m = (IndexedPool.Mapping)item;
+ result.receive(new PointerBlock(pool.get(m.block)));
+ } catch(Exception _) {
+ _.printStackTrace();
+ throw new Error(""+_); // XXX
+ }
return true;
}
public void finish(boolean timeout) {
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [ff-cvs] storm ./Makefile doc/dartboard/pointer_identiti...,
Benja Fallenstein <=