Revision: 4902
          http://sourceforge.net/p/vexi/code/4902
Author:   mkpg2
Date:     2016-11-23 20:34:50 +0000 (Wed, 23 Nov 2016)
Log Message:
-----------
Change! and Improvement. Pass listener to pipe method instead of traps on the 
inputstream.
- this will break file uploads in older vexi code.
Improve. Post handling. Previously progress bar useless as data very quickly 
buffered and then slowly uploaded (in real usage).
Removed org.ibex.io project (unused).
Removed old HTTP implementation (unmaintained/obselete).
Improve IOUtil.pipe. Move output.close() outside of synchronization to allow 
recursive call during close (done by http).

Modified Paths:
--------------
    branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Main.java
    branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/PNG.java
    branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Platform.java
    branches/vexi3/org.vexi-library.js/meta/module.xml
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java
    branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java
    branches/vexi3/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp
    branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSTestUtil.java
    branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java
    
branches/vexi3/org.vexi-library.js/src/test/java/org/ibex/js/TestFountain.java
    
branches/vexi3/org.vexi-library.js/src/test/java/test/js/exec/JSTestCase.java
    branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/HTTP.java
    branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/JreHTTP.java
    trunk/org.vexi-build.jpp/src/poke/java/poke/PreprocessHttpFactory.java
    trunk/org.vexi-build.shared/meta/module.revisions
    trunk/org.vexi-library.util/src/main/java/org/ibex/util/Callable.java
    trunk/org.vexi-library.util/src/main/java/org/ibex/util/IOUtil.java

Added Paths:
-----------
    branches/vexi3/org.vexi-library.js/src/poke/java/poke/upload/
    
branches/vexi3/org.vexi-library.js/src/poke/java/poke/upload/PokeDataUpload.java
    trunk/org.vexi-library.util/src/main/java/org/ibex/util/Callback.java

Removed Paths:
-------------
    branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/OrigHTTP.java
    
branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/OrigHTTP_reconnect.java

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Main.java
===================================================================
--- branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Main.java     
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/core/Main.java     
2016-11-23 20:34:50 UTC (rev 4902)
@@ -17,7 +17,6 @@
 import org.ibex.util.Callable;
 import org.ibex.util.Encode;
 import org.ibex.util.Logger;
-import org.vexi.graphics.Picture;
 import org.vexi.plat.Platform;
 import org.vexi.util.Log;
 
@@ -312,10 +311,10 @@
         this.data = data;
         this.name = name;
     }
-    public InputStream _getInputStream(boolean expect) throws IOException {
+    @Override public InputStream getInputStream(boolean expect) throws 
IOException {
         return Encode.JavaSourceCode.decode(data);
     }
-    public String coerceToString() {
+    @Override public String coerceToString() {
         return name!=null?name:super.coerceToString();
     }
 }

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/PNG.java
===================================================================
--- branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/PNG.java  
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/graphics/PNG.java  
2016-11-23 20:34:50 UTC (rev 4902)
@@ -265,11 +265,11 @@
             int upix[] = null;
             int temp[] = new int[rowSize];
             //int nextY = sRow;               // next Y value and number of 
rows to report to sendPixels
-            int rows = 0;
+//            int rows = 0;
             int rowStart = sRow * p.width;
 
             for (int y = sRow; y < p.height; y += rInc, rowStart += sInc) {
-                rows += rInc;
+//                rows += rInc;
                 int rowFilter = dis.read();
                 dis.readFully(inbuf);
                 if (!filterRow(inbuf, pix, upix, rowFilter, filterOffset)) {

Modified: 
branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Platform.java
===================================================================
--- branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Platform.java 
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-core.main/src/main/java/org/vexi/plat/Platform.java 
2016-11-23 20:34:50 UTC (rev 4902)
@@ -6,14 +6,11 @@
 
 import java.awt.Rectangle;
 import java.io.BufferedReader;
-import java.io.File;
-import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 
 import org.ibex.js.JS;
 import org.ibex.js.JSExn;
-import org.ibex.util.Encode;
 import org.ibex.util.Logger;
 import org.vexi.core.Box;
 import org.vexi.core.Constants;

Modified: branches/vexi3/org.vexi-library.js/meta/module.xml
===================================================================
--- branches/vexi3/org.vexi-library.js/meta/module.xml  2016-11-18 12:45:45 UTC 
(rev 4901)
+++ branches/vexi3/org.vexi-library.js/meta/module.xml  2016-11-23 20:34:50 UTC 
(rev 4902)
@@ -6,7 +6,6 @@
        <dependencies>
         <dependency source="local"    name="library.value"/>
                <dependency source="local"    name="library.net"/>
-               <dependency source="local"    name="library.io"/>
         <!-- Test Dependencies -->
            <dependency source="local"    name="library.testing"    
branch="trunk"     scope="test"/>
                <dependency source="ibiblio" org="org.apache.xmlrpc" 
name="xmlrpc-server" tag="3.1.3" scope="test"/>

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java  
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Fountain.java  
2016-11-23 20:34:50 UTC (rev 4902)
@@ -9,7 +9,7 @@
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
-import java.io.FilterInputStream;
+import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
@@ -29,6 +29,7 @@
 import org.ibex.net.HTTPFactory;
 import org.ibex.util.Cache;
 import org.ibex.util.Callable;
+import org.ibex.util.Callback;
 import org.ibex.util.IOUtil;
 import org.ibex.util.Logger;
 
@@ -46,16 +47,27 @@
  */
 public abstract class Fountain extends JS.Obj implements JS.Cloneable, 
Constants {
 
+       public Fountain() {}
        
     // Public Interface 
//////////////////////////////////////////////////////////////////////////////
 
-       static public class NotCacheableException extends Exception { }
+       static public class Info {
+               public String name;
+               public Long length;
+               
+               public JS asJS(){
+                       JS.Obj r = new JS.Obj();
+                       r.putSafe(JSU.S("name"), JSU.S(name));
+                       r.putSafe(JSU.S("length"), JSU.N(length));              
        
+                       return r;
+                       
+               }
+       }
 
     // streams are "sealed" by default to prevent accidental object leakage
     private Cache getCache = new Cache(100);
-    private Scheduler scheduler;
-
-    public final JS get(JS key) throws JSExn {
+    
+    @Override public final JS get(JS key) throws JSExn {
         JS ret = (JS)getCache.get(key);
         if (ret == null) getCache.put(key, ret = _get(key));
         return ret;
@@ -79,85 +91,18 @@
        return r==null?null:r.findWrite();
     }
     
-    final public InputStream getInputStream(boolean expect) throws 
IOException{ return getInputStream(this, expect); }
-    final public InputStream getInputStream(final Fountain principal, boolean 
expect) throws IOException {  
-       try{
-               // HACK - there is some race potential here, but only if 
-               // the programmer decides to try and remove/change these traps 
-               // after accessing the stream.
-               InputStream is = _getInputStream(expect);
-               if(is==null) return is;
-               Trap startTrap = principal.wtrap(SC_start);
-               final Trap progressTrap = principal.wtrap(SC_progress);
-               final Trap finishTrap = principal.wtrap(SC_finish);
-               if(startTrap==null && progressTrap==null && finishTrap==null) 
return is;
-               
-               // HMMM the scheduler stuff is no so clean, perhaps a rethink on
-               // how streams are watched or other change needed.
-               final Scheduler sched = principal.scheduler;
-               
-               JS info = getInfo();
-               //      detirmine the callback rate 
-               int length = JSU.toInt(info.get(SC_length));
-               final int callbackRate = Math.max(8192,length/100);
-               
-               if(startTrap!=null){
-                       sched.scheduleJustTriggerTraps(principal, SC_start, 
info);
-               }
-                       
-               return new FilterInputStream(is) {
-                       private int bytesDownloaded = 0;
-                       private int bytesSinceCallback = 0;
-                       public int read() throws IOException {
-                               int ret = super.read();
-                               if (ret != -1) triggerProgress(1);
-                               else triggerFinish();
-                               return ret;
-                       }
-                       public int read(byte[] b, int off, int len) throws 
IOException {
-                               int ret = super.read(b, off, len);
-                               if (ret != -1) 
-                                       triggerProgress(ret);
-                               else
-                                       triggerFinish();
-                               return ret;
-                       }
-                       private void triggerProgress(int n){
-                               bytesDownloaded += n; bytesSinceCallback += n;
-                               if(bytesSinceCallback>callbackRate){
-                                               
bytesSinceCallback-=callbackRate;
-                                               // FEATURE - if not run yet, 
update previous 
-                                               // scheduled JS arg. 
-                                               if(progressTrap!=null) 
sched.scheduleJustTriggerTraps(principal, SC_progress, JSU.N(bytesDownloaded));
-                                       }
-                       }
-                       
-                       private void triggerFinish(){
-                               if(finishTrap!=null) 
sched.scheduleJustTriggerTraps(principal, SC_finish, JSU.T);
-                       }
-               };
-       }catch(JSExn e){
-                       // only supported by Java 6 (!)
-                       //throw new IOException(e);
-                       throw new IOException(e.getMessage());
-       }
+    public InputStream getInputStream(boolean expect) throws IOException{
+       if(expect)
+               throw new IOException(toString() + " is write only");
+       return null;
     }
-       
-    abstract protected InputStream _getInputStream(boolean expect) throws 
IOException;
     
-    public OutputStream getOutputStream(boolean expect) throws IOException{
+    public OutputStream getOutputStream(boolean expect, Long contentLength) 
throws IOException{
        if(expect)
                throw new IOException(toString() + " is read only");
        return null;
     }
     
-    public void addTrap(JS key, JS f) throws JSExn {
-       super.addTrap(key, f);
-       // used for call backs when input stream is read, we assume
-       // the traps added are callbacks
-       if(scheduler==null) scheduler = Scheduler.expectCurrent();
-    }
-    
     // Perform any caching (Fountain.Multi calls this on its 
     // constituent streams so that it can cache everything up
     // front). REMARK - do we need this? can't we just make sure
@@ -167,15 +112,15 @@
 
     // Info about the stream (lastModified, contentLength, url ...)
     // HACK - optionally takes the stream for HTTP to avoid making two calls
-    public JS getInfo() throws IOException { return new JS.Obj();}
+    public Info getInfo() throws IOException { return new Info(); }
     
-    public JS callMethod(JS this_, JS method, JS[] args) throws JSExn {
+    @Override public JS callMethod(JS this_, JS method, JS[] args) throws 
JSExn {
        if("info".equals(JSU.toString(method))){
                try {
                        final Scheduler sched = Scheduler.expectCurrent();
                        return sched.backgroundCall("get fountain info", new 
Callable<Object, JS>() {
                                public JS run(Object A) throws Exception {
-                                       return getInfo();
+                                       return getInfo().asJS();
                                }
                                });
                } catch (JSExn e) {
@@ -206,36 +151,37 @@
                this.url = url;
         }
         private org.ibex.net.HTTP http() throws IOException{ return 
HTTPFactory.create(logger,url);}
-        public String canonical() { return url; }
+        @Override public String canonical() { return url; }
         
         
-        public JS _get(JS key) throws JSExn { return new HTTP(logger,url + "/" 
+ JSU.toString(key)); }
-        private JS readInfo(HTTPEntityInfo info){
-               JS.Obj r = new JS.Obj();
-               r.putSafe(SC_lastModified, JSU.S(info.lastModified));
-               r.putSafe(SC_length, JSU.N(info.contentLength));
-               r.putSafe(SC_mimetype, JSU.S(info.contentType));
-               r.putSafe(SC_name, JSU.S(url));
-               return r;
+        @Override public JS _get(JS key) throws JSExn { return new 
HTTP(logger,url + "/" + JSU.toString(key)); }
+        private Info readInfo(HTTPEntityInfo info){
+               Info r = new Info();
+               r.name = url;
+               r.length = info.contentLength;
+               return r;
+//             r.putSafe(SC_lastModified, JSU.S(info.lastModified));
+//             r.putSafe(SC_mimetype, JSU.S(info.contentType));
         }
         public HTTPEntityInfo getRawInfo() {
                return responseInfo;
         }
-        public JS getInfo() throws IOException {
+        
+        private void useResponse() throws IOException{
                if(responseInfo==null){
                        HTTPResponse response = http().GET();
                        responseStream = response.body;
                        responseInfo = response.info;;
                }
+        }
+        
+        @Override public Info getInfo() throws IOException {
+               useResponse();
                return readInfo(responseInfo);
         }
         //public String getCacheKey(Vec path) throws NotCacheableException { 
return url; }
-        public InputStream _getInputStream(boolean expect) throws IOException 
{ 
-               if(responseStream==null){
-                       HTTPResponse response = http().GET();
-                       responseStream = response.body;
-                       responseInfo = response.info;
-               }
+        @Override public InputStream getInputStream(boolean expect) throws 
IOException { 
+               useResponse();
                InputStream r = responseStream;
                responseStream = null;
                return r;
@@ -245,21 +191,22 @@
                // if the server doesn't support HTTP/HEAD fallback to get
                catch(HTTPException e){return http.GET(null, null);}
         }*/
-        public OutputStream getOutputStream(boolean expect) { 
-               // ALL WRONG
-               // HACK - we need a way to retrieve the output stream
-               // from the http post
-               ByteArrayOutputStream r = new ByteArrayOutputStream(){
-                       public void close() throws IOException {
-                       HTTPResponse response = http().POST(mimetype, 
toByteArray());
-                       responseStream = response.body;
-                       responseInfo = response.info;
-                       }
-               };
-               return r;
+        @Override public OutputStream getOutputStream(boolean expect, Long 
contentLength) throws IOException { 
+               String contentType = 
"".equals(mimetype)?"application/octet-stream":mimetype;
+               return http().POST2(contentType, contentLength, new Callback() {
+                               public void run(Object arg) {
+                                       if(arg instanceof HTTPResponse){
+                                               HTTPResponse response = 
(HTTPResponse)arg;
+                                               responseStream = response.body;
+                               responseInfo = response.info;
+                                       }else{
+                                               logger.warn(HTTP.class, arg);
+                                       }
+                               }
+                       });
         }
         
-        public JS getResponseInfo(){ return readInfo(responseInfo); }
+        public JS getResponseInfo(){ return readInfo(responseInfo).asJS(); }
         
                public void setRequestInfo(JS info) throws JSExn {
                        Enumeration en = info.keys().iterator();
@@ -276,8 +223,8 @@
     public static class Resource extends Fountain {
         private final URL res;
         public Resource(URL res) { this.res = res; }
-        public InputStream _getInputStream(boolean expect) throws IOException 
{ return res.openStream(); }
-        public String coerceToString(){ return res.toString(); }
+        @Override public InputStream getInputStream(boolean expect) throws 
IOException { return res.openStream(); }
+        @Override public String coerceToString(){ return res.toString(); }
     }        
     
     /** byte arrays */
@@ -288,8 +235,14 @@
         public ByteArray(JS suggested) throws JSExn { 
                this.suggested = suggested==null?8192:JSU.toInt(suggested);
         }
-        public InputStream _getInputStream(boolean expect) throws IOException 
{ return new ByteArrayInputStream(bytes); }
-        public OutputStream getOutputStream(boolean expect) throws IOException 
{
+        @Override public Info getInfo() throws IOException {
+               Info r = new Info();
+               if(bytes!=null) r.length = (long)bytes.length;
+               return r;
+        }
+        
+        @Override public InputStream getInputStream(boolean expect) throws 
IOException { return new ByteArrayInputStream(bytes); }
+        public OutputStream getOutputStream(boolean expect, Integer 
contentLength) throws IOException {
                return new ByteArrayOutputStream(suggested){
                        public void close() throws IOException {
                                super.close();
@@ -325,17 +278,15 @@
                this.writeable = writeable;
                this.checkCase = checkCase;
         }
-        public String canonical() { return "file://"+path; }
-        public JS getInfo() throws IOException {
+        @Override public String canonical() { return "file://"+path; }
+        @Override public Info getInfo() throws IOException {
                java.io.File f = new java.io.File(path);
-               JS.Obj r = new JS.Obj();
-               //r.putSafe(SC_lastModified, JSU.S(f.lastModified()));
-               //r.putSafe(SC_mimetype, JSU.S(info.contentType));
-               r.putSafe(SC_length, JSU.N(f.length()));
-               r.putSafe(SC_name, JSU.S(canonical()));
-               return r;
+               Info r = new Info();
+               r.name = canonical();
+               r.length = f.length();
+               return r;
         }
-        public InputStream _getInputStream(boolean expect) throws IOException 
{ 
+        @Override public InputStream getInputStream(boolean expect) throws 
IOException { 
                try{
                        return new FileInputStream(path);
                }catch(FileNotFoundException e){
@@ -343,21 +294,21 @@
                        return null;
                }
         }
-        public OutputStream getOutputStream(boolean expect) throws IOException 
{
+        @Override public OutputStream getOutputStream(boolean expect, Long 
contentLength) throws IOException {
                if(!writeable) {
                        if(expect) throw new IOException("File readonly: " + 
coerceToString());
                        return null;
                }
                return new FileOutputStream(path);
         }
-        public JS _get(JS key) throws JSExn { return new File(path + 
java.io.File.separatorChar + JSU.toString(key), writeable, checkCase); }
+        @Override public JS _get(JS key) throws JSExn { return new File(path + 
java.io.File.separatorChar + JSU.toString(key), writeable, checkCase); }
         public void remove() throws JSExn {
                if(writeable){
                        new java.io.File(path).delete();
                }else
                        throw new JSExn("not writeable " + writeable);
         }
-        Set _getKeySet() throws IOException {
+        @Override Set _getKeySet() throws IOException {
                Set s = new HashSet();
                java.io.File f = new java.io.File(path);
                if(f.isDirectory()){
@@ -369,9 +320,9 @@
                return s;
         }
         private java.io.File file(){ return new java.io.File(path); } 
-        public long getTimestamp() { return file().lastModified(); }
-        public int hashCode() { return file().hashCode(); }
-        public boolean equals(Object obj) {
+        @Override public long getTimestamp() { return file().lastModified(); }
+        @Override public int hashCode() { return file().hashCode(); }
+        @Override  public boolean equals(Object obj) {
                if(!(obj instanceof File)) return false;
                return file().equals(((File)obj).file());
         }
@@ -408,20 +359,64 @@
                }
        } 
     
-    static final public int[] ARGTYPES_afountain = new int[]{JSU.FOUNTAIN};
     static public String nameOf(JS[] args) throws JSExn{
-       JSU.checkArgs(args, ARGTYPES_afountain);
-       return ((Fountain)args[0]).canonical();
+       Fountain arg = JSU.expectArg_fountain(args, 0);
+       return arg.canonical();
     }
     
-    static final int[] ARGTYPES_2fountains = new 
int[]{JSU.FOUNTAIN,JSU.FOUNTAIN};
     static public void pipe(final JS[] args) throws JSExn{
-       JSU.checkArgs(args, ARGTYPES_2fountains); 
+       final Fountain f0 = JSU.expectArg_fountain(args, 0);
+       final Fountain f1 = JSU.expectArg_fountain(args, 1);
+       final JS listener = JSU.getArg(args, 2);                
                final Scheduler sched = Scheduler.expectCurrent();
+               
                sched.backgroundCall("pipe streams", new Callable<Object, JS>() 
{
                        public JS run(Object A) throws Exception {
                        try {
-                               
IOUtil.pipe(((Fountain)args[0]).getInputStream(true), 
((Fountain)args[1]).getOutputStream(true));
+                               Info info = f0.getInfo();
+                               Long contentLength = info.length;
+                               OutputStream os =f1.getOutputStream(true, 
contentLength);
+                               if(listener!=null){
+                                       
+                               long length = 
contentLength==null?819200:contentLength;
+                               final int callbackRate = 
(int)Math.max(8192,length/100);
+                               
+                               sched.schedulePutAndTriggerTraps(listener, 
SC_start, info.asJS());
+                                       
+                               os = new FilterOutputStream(os) {
+                                       private int bytesDownloaded = 0;
+                                       private int bytesSinceCallback = 0;
+                                       
+                                       public void write(int b) throws 
IOException {
+                                               out.write(b);
+                                               triggerProgress(1);
+                                       }
+                                       public void write(byte[] b, int off, 
int len) throws IOException {
+                                               out.write(b, off, len);
+                                               triggerProgress(len);
+                                       }
+    
+                                       private void triggerProgress(int n) 
throws IOException{
+                                               bytesDownloaded += n; 
bytesSinceCallback += n;
+                                               
if(bytesSinceCallback>callbackRate){
+                                                               
bytesSinceCallback-=callbackRate;
+                                                               // FEATURE - if 
not run yet, update previous 
+                                                               // scheduled JS 
arg.
+                                                                       
sched.schedulePutAndTriggerTraps(listener, SC_progress, JSU.N(bytesDownloaded));
+                                                       }
+                                       }
+                                       
+                                       public void close() throws IOException {
+                                               super.close();
+                                                               
sched.schedulePutAndTriggerTraps(listener, SC_finish, JSU.T);                   
                                        
+                                       }
+                               };                                      
+                               }
+                               
+                               
+                               // REMARK need our own buffer, since pipe can 
be recurvively called with HTTP stuff (reading response
+//                             byte[] buffer = new byte[16*1024];
+                               IOUtil.pipe(f0.getInputStream(true), os);
                                        return null;
                        } catch (IOException e) {
                                throw JSU.handleFountainExn(e);
@@ -480,7 +475,7 @@
         }
         //public String getCacheKey() throws NotCacheableException { return 
parent.getCacheKey() + "!zip:"; }
         public JS _get(JS key) throws JSExn { return new ZipFile(parent, 
path==null?JSU.toString(key):path+'/'+JSU.toString(key)); }
-        public InputStream _getInputStream(boolean expect) throws IOException {
+        public InputStream getInputStream(boolean expect) throws IOException {
                ZipEntry entry = parent.getEntry(path);
                if (entry == null) throw new IOException("requested file (" + 
path + ") not found in archive");
                return parent.getInputStream(entry);
@@ -537,8 +532,8 @@
             this.path = path;
         }
         //public String getCacheKey() throws NotCacheableException { return 
parent.getCacheKey() + "!zip:"; }
-        public JS _get(JS key) throws JSExn { return new ZipStream(parent, 
path==null?JSU.toString(key):path+'/'+JSU.toString(key)); }
-        public InputStream _getInputStream(boolean expect) throws IOException {
+        @Override public JS _get(JS key) throws JSExn { return new 
ZipStream(parent, path==null?JSU.toString(key):path+'/'+JSU.toString(key)); }
+        @Override public InputStream getInputStream(boolean expect) throws 
IOException {
             InputStream pis = parent.getInputStream(expect);
             ZipInputStream zis = new ZipInputStream(pis);
             ZipEntry ze = zis.getNextEntry();
@@ -627,14 +622,14 @@
                                throw new JSExn(e.getMessage());}
                return new Multiple(fountains, key, path); 
         }
-        public InputStream _getInputStream(boolean expect) throws IOException {
+        public InputStream getInputStream(boolean expect) throws IOException {
             InputStream is;
             // FIXME: consider not doing loop when chosen!=null
             for (int i=0; i< fountains.size(); i++) {
               Fountain stream = (Fountain)fountains.get(i);
                 if (stream!=null) {
                     try {
-                        is = stream.getInputStream(this, expect);
+                        is = stream.getInputStream(expect);
                     } 
                     catch (FileNotFoundException e) { is=null; }
                     catch (IOException e) { is=null; }

Modified: branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java       
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/JSU.java       
2016-11-23 20:34:50 UTC (rev 4902)
@@ -4,13 +4,19 @@
 
 package org.ibex.js;
 
-import java.io.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.charset.Charset;
 
 import org.ibex.js.JS.ConstructorList;
-import org.ibex.js.parse.*;
-import org.ibex.net.HTTP.*;
-import org.ibex.util.*;
+import org.ibex.js.parse.ByteCodes;
+import org.ibex.js.parse.Function;
+import org.ibex.js.parse.Lexer;
+import org.ibex.js.parse.Tokens;
+import org.ibex.net.HTTP.HTTPErrorResponse;
+import org.ibex.util.Basket;
+import org.ibex.util.XML;
 import org.vexi.value.Rational;
 
 public class JSU implements Constants{
@@ -71,7 +77,7 @@
     
     static public OutputStream getOutputStream(JS js) throws IOException { 
        Fountain f = getFountain(js);
-       return (f!=null)?f.getOutputStream(false):null;
+       return (f!=null)?f.getOutputStream(false,null):null;
     }
     
     // HACK - this is an unideal way to handle it, as it relies
@@ -365,6 +371,19 @@
        return r;
     }
     
+    static public Fountain getArg_fountain(JS[] args, int index) throws JSExn {
+        JS r = getArg(args, index);
+        if(r==null) return null;
+       Fountain js = getFountain(r);
+        if(js==null) throw new JSExn("Arg "+index+". Expected fountain, got 
"+r);
+        return js;
+    }
+    static public Fountain expectArg_fountain(JS[] args, int index) throws 
JSExn {
+       Fountain r = getArg_fountain(args, index);
+        if(r==null) throw new JSExn("Arg "+index+". Expected fountain, got 
null");
+       return r;
+    }
+    
     /** lets us put multi-level get/put/call keys all in the same method */
     static public class Sub extends JS.Obj {
         final public JS main;

Modified: 
branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java 
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-library.js/src/main/java/org/ibex/js/Scheduler.java 
2016-11-23 20:34:50 UTC (rev 4902)
@@ -485,7 +485,7 @@
        }  
     }
        
-    public void scheduleJustTriggerTraps(final JS.Obj obj, final JS key, final 
JS value) {
+    public void scheduleJustTriggerTraps(final JS obj, final JS key, final JS 
value) {
         add(new Callable() {
             public Object run(Object o) throws Exception {
                 justTriggerTraps(obj, key, value);
@@ -494,6 +494,16 @@
         });
     }
     
+    public void schedulePutAndTriggerTraps(final JS obj, final JS key, final 
JS value) {
+        add(new Callable() {
+            public Object run(Object o) throws Exception {
+                putAndTriggerTraps(obj, key, value);
+                return null;
+            }
+        });
+    }
+    
+    
     public void schedule(final Callable callback, final Object response) {
         add(new Callable() {
             // Optimise this object creation away by adding set

Modified: branches/vexi3/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp
===================================================================
--- branches/vexi3/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp      
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-library.js/src/main/jpp/org/vexi/js/VexiJS.jpp      
2016-11-23 20:34:50 UTC (rev 4902)
@@ -488,7 +488,6 @@
             }
             case 2: {
                  //#switch(JSU.toString(method))
-                case "pipe": Fountain.pipe(args); return null;
                 case "parsexml": 
                     JSU.checkArgs(args, ARGTYPES_parsexml);
                     new XMLHelper(scheduler(),args[1]).doParse(args[0]);
@@ -499,6 +498,7 @@
             //#switch(JSU.toString(method))
             case "buffer": return new 
Fountain.ByteArray(args.length>0?args[0]:null);
             case "multiple": return Fountain.multiple(args);
+            case "pipe": Fountain.pipe(args); return null;
             //#end
             return super.callMethod(this_, method, args);
         }
@@ -698,11 +698,10 @@
     }
     
     static private JS new_utf8writer(JS[] args) throws JSExn {
-        JSU.checkArgs(args, Fountain.ARGTYPES_afountain);
-        Fountain f = (Fountain)args[0];
+        Fountain f = JSU.expectArg_fountain(args, 0);
         final BufferedWriter w;
         try {
-            w = new BufferedWriter(new 
OutputStreamWriter(f.getOutputStream(true), "UTF8"));
+            w = new BufferedWriter(new 
OutputStreamWriter(f.getOutputStream(true, null), "UTF8"));
         } catch (UnsupportedEncodingException e) {
             throw new Error("UF8 not available!");
         } catch (IOException e) {
@@ -924,7 +923,8 @@
     
     
     static public JS new_xmlwriter(JS[] args) throws JSExn {
-        JSU.checkArgs(args, Fountain.ARGTYPES_afountain);
+        
+       JSU.expectArg(args, 0);
         try {
             final BufferedWriter out = new BufferedWriter(new 
OutputStreamWriter(JSU.getOutputStream(args[0])));
             JS writer = new JS.Immutable() {

Modified: 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSTestUtil.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSTestUtil.java    
    2016-11-18 12:45:45 UTC (rev 4901)
+++ 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/JSTestUtil.java    
    2016-11-23 20:34:50 UTC (rev 4902)
@@ -4,17 +4,16 @@
 import java.io.FilenameFilter;
 import java.lang.reflect.Method;
 import java.net.URISyntaxException;
-import java.net.URL;
 import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.Map;
 
-import junit.framework.TestSuite;
-
 import org.ibex.js.JS.Enumeration;
 import org.ibex.js.JS.Keys;
 import org.vexi.testutil.JUnitUtil;
 
+import junit.framework.TestSuite;
+
 public class JSTestUtil {
        static private File guessWorkspaceDirectorForEclEmma(File dir){
                while( !dir.getName().equals(".metadata")){
@@ -119,8 +118,8 @@
                                        try {
                                                Class klass = 
Class.forName(cfullname);
                                                try{
-                                                       Method m = 
(Method)klass.getMethod("suite", null);
-                                                       csuite = 
(TestSuite)m.invoke(null, null);
+                                                       Method m = 
(Method)klass.getMethod("suite");
+                                                       csuite = 
(TestSuite)m.invoke(null);
                                                        break;
                                                }catch(NoSuchMethodException 
e){continue;}
                                                //klass.getSuperclass()

Modified: 
branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java
===================================================================
--- branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java     
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-library.js/src/poke/java/org/ibex/js/RunJS.java     
2016-11-23 20:34:50 UTC (rev 4902)
@@ -159,7 +159,7 @@
        
        static public boolean finishedCleanly() throws Exception{
                for(int i=10; i>0; i--){
-                       if(!SCHEDULER.scheduleWakeUp.isAlive()) return true;
+                       if(!Scheduler.scheduleWakeUp.isAlive()) return true;
                        java.lang.Thread.sleep(100);
                }
                return false;

Added: 
branches/vexi3/org.vexi-library.js/src/poke/java/poke/upload/PokeDataUpload.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/poke/java/poke/upload/PokeDataUpload.java
                            (rev 0)
+++ 
branches/vexi3/org.vexi-library.js/src/poke/java/poke/upload/PokeDataUpload.java
    2016-11-23 20:34:50 UTC (rev 4902)
@@ -0,0 +1,90 @@
+package poke.upload;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.ibex.js.Fountain.HTTP;
+import org.ibex.js.JS;
+import org.ibex.js.JSArray;
+import org.ibex.js.JSExn;
+import org.ibex.js.JSU;
+import org.ibex.js.JSUX;
+import org.ibex.js.XMLRPC;
+import org.ibex.util.DefaultLog;
+import org.ibex.util.IOUtil;
+
+public class PokeDataUpload {
+       static public void main(String[] args) throws JSExn, IOException {
+               String password = args[0];
+               
+               // log in
+               XMLRPC xmlrpc = new XMLRPC(DefaultLog.logger, 
"http://synergetixtest.statii.co.uk/xmlrpc";, "emanate.ApplicationPublic.login");
+               List args1 = new ArrayList();
+               Collections.addAll(args1, new String[]{"%statii/Statii%", null, 
"m...@synergetix.eu", password});
+               JSArray args2 = (JSArray)JSUX.dynamicToJs(args1);
+               JS r = xmlrpc.doCall(args2);
+               String session = ""+r.get(JSU.S("sessionId"));
+               System.err.println("!!"+session);
+               
+               String uploadUrl = 
"http://synergetixtest.statii.co.uk/blob?session="+session+"&name=tttttt";;
+               // 
+               HTTP upload = new HTTP(DefaultLog.logger, uploadUrl);
+               
+               final long contentLength = 1000000; 
+               InputStream is = new InputStream() {
+                       private long count = contentLength;
+                       public int read() throws IOException {
+                               count--;
+                               if(count<0){
+                                       
+                                       return -1;
+                               }
+                               return (int)'t';
+                       }
+               };
+               
+               long t0 = System.currentTimeMillis();
+               final int callbackRate = 8192;
+               OutputStream os = new 
FilterOutputStream(upload.getOutputStream(true, contentLength)){
+                       private int bytesDownloaded = 0;
+                       private int bytesSinceCallback = 0;
+                       
+                       @Override public void write(byte[] b, int off, int len) 
throws IOException {
+                               super.write(b, off, len);
+                               triggerProgress(len);
+                       }
+                       
+                       @Override public void write(int b) throws IOException {
+                               super.write(b);
+                               triggerProgress(1);
+                       }
+                       @Override public void close() throws IOException {
+                               super.close();
+                               triggerFinish();
+                       }
+                       
+                       private void triggerProgress(int n){
+                               bytesDownloaded += n; bytesSinceCallback += n;
+                               if(bytesSinceCallback>callbackRate){
+                                       bytesSinceCallback-=callbackRate;
+                                       // FEATURE - if not run yet, update 
previous 
+                                       // scheduled JS arg. 
+                                       System.err.println("Progress: 
"+bytesDownloaded);
+                               }
+                       }
+                       
+                       private void triggerFinish(){
+                               System.err.println("Finished");
+                       }
+               };
+               IOUtil.pipe(is,  os);
+               
+               long delta = System.currentTimeMillis()-t0;
+               System.err.println("Took "+delta+"ms");
+       }
+}


Property changes on: 
branches/vexi3/org.vexi-library.js/src/poke/java/poke/upload/PokeDataUpload.java
___________________________________________________________________
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
Modified: 
branches/vexi3/org.vexi-library.js/src/test/java/org/ibex/js/TestFountain.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/test/java/org/ibex/js/TestFountain.java  
    2016-11-18 12:45:45 UTC (rev 4901)
+++ 
branches/vexi3/org.vexi-library.js/src/test/java/org/ibex/js/TestFountain.java  
    2016-11-23 20:34:50 UTC (rev 4902)
@@ -3,18 +3,17 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
-import java.util.Map;
 
 import javax.servlet.ServletException;
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 
+import org.ibex.js.Fountain.Info;
+import org.ibex.util.IOUtil;
+
 import junit.framework.Assert;
 import junit.framework.TestCase;
-
-import org.ibex.util.IOUtil;
-
 import test.servlets.SimpleContainer;
 
 public class TestFountain extends TestCase {
@@ -28,16 +27,11 @@
                Fountain a = new Fountain.ByteArray((JS)null);
                Fountain b = new Fountain.ByteArray((JS)null);
                Fountain.writeUTF8(new JS[]{a,JSU.S("sausage")});
-               IOUtil.pipe(a.getInputStream(true), b.getOutputStream(true));
+               IOUtil.pipe(a.getInputStream(true), b.getOutputStream(true, 
null));
                String s = JSU.toString(Fountain.parseUTF8(new JS[]{b}));
                Assert.assertEquals("sausage",s);
        }
-       
 
-       private int expectInt(Object o){
-           return ((Number)o).intValue();
-       }
-
        public void testEvents() throws Exception{
                
 
@@ -47,12 +41,10 @@
                try{
                        Fountain f = new Fountain.HTTP(RunJS.LOG, 
"http://localhost:"+PORT+"/resource";);
                        //InputStream i = f.getInputStream();
-                       JS infoJS = f.getInfo();
-                       Map info = (Map) JSPojoWrapper.jsToDynamic(infoJS);
-                       //String lastModified = (String) 
info.get("lastModified");
-                       System.out.println(JSON.marshal(infoJS));
-                       
assertEquals("http://localhost:9999/resource",info.get("name"));
-                       assertEquals(53, expectInt(info.get("length")));
+                       Fountain.Info info = f.getInfo();
+                       long length = info.length;
+                       
assertEquals("http://localhost:9999/resource",info.name);
+                       assertEquals(53l, length);
                        
                }finally{
                        stopServer();
@@ -61,12 +53,11 @@
                {       
                        Fountain f = new 
Fountain.File(TestFountain.class.getResource("resource.txt").getFile());
                        //InputStream i = a.getInputStream();
-                       JS infoJS = f.getInfo();
-                       Map info = (Map) JSPojoWrapper.jsToDynamic(infoJS);
-                       System.out.println(JSON.marshal(infoJS));
-                       String name = (String) info.get("name");
+                       Info info = f.getInfo();
+                       String name = info.name;
+                       long length = info.length;
                        assertTrue(name.endsWith("resource.txt"));
-            assertEquals(53, expectInt(info.get("length")));
+            assertEquals(53l, length);
                }
        }
        

Modified: 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/exec/JSTestCase.java
===================================================================
--- 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/exec/JSTestCase.java   
    2016-11-18 12:45:45 UTC (rev 4901)
+++ 
branches/vexi3/org.vexi-library.js/src/test/java/test/js/exec/JSTestCase.java   
    2016-11-23 20:34:50 UTC (rev 4902)
@@ -1,13 +1,9 @@
 package test.js.exec;
 
-import java.io.IOException;
 import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.io.Reader;
 
-import junit.framework.AssertionFailedError;
-import junit.framework.TestCase;
-
 import org.ibex.js.DevUtil;
 import org.ibex.js.ExecParser;
 import org.ibex.js.Fountain;
@@ -16,6 +12,9 @@
 import org.ibex.js.RunJS;
 import org.ibex.js.parse.Function;
 
+import junit.framework.AssertionFailedError;
+import junit.framework.TestCase;
+
 /**
  * @author mike
  */

Modified: 
branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/HTTP.java
===================================================================
--- branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/HTTP.java    
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/HTTP.java    
2016-11-23 20:34:50 UTC (rev 4902)
@@ -1,16 +1,19 @@
 package org.ibex.net;
 
-import java.io.*;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
 
-import org.ibex.net.HTTP.HTTPSettings;
+import org.ibex.util.Callback;
 
 public abstract class HTTP {
        
     static public class HTTPEntityInfo {
-       final public int contentLength;       ///< the length of the entire 
content body; -1 if chunked
+       final public long contentLength;       ///< the length of the entire 
content body; -1 if chunked
        final public String contentType;
         final public String lastModified;
-        HTTPEntityInfo(int contentLength, String lastModified, String 
contentType){
+        HTTPEntityInfo(long contentLength, String lastModified, String 
contentType){
                this.contentLength = contentLength;
                this.lastModified = lastModified;
                this.contentType = contentType;
@@ -24,7 +27,7 @@
        final public byte[] bytes;
        final public HTTPEntityInfo info;
        public HTTPErrorResponse(String msg, String code, byte[] bytes, 
HTTPEntityInfo info) { 
-               super("HTTP Error: " + msg); 
+               super("HTTP Error ("+code+"): " + msg); 
                this.code = code;
                this.bytes = bytes;
                this.info = info;
@@ -42,7 +45,7 @@
 
     abstract public HTTPResponse GET() throws IOException;
     abstract public HTTPResponse POST(String mime, byte[] bytes) throws 
IOException;
-       
+    abstract public OutputStream POST2(String contentType, Long contentLength, 
Callback<Object> callback) throws IOException;
 
        static public class HTTPSettings {
                int connectTimeout; // in milliseconds
@@ -72,4 +75,5 @@
                        settings.setConnectTimeout(ms);
                else settings = null;
        }
+
 }

Modified: 
branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/JreHTTP.java
===================================================================
--- branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/JreHTTP.java 
2016-11-18 12:45:45 UTC (rev 4901)
+++ branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/JreHTTP.java 
2016-11-23 20:34:50 UTC (rev 4902)
@@ -1,12 +1,14 @@
 
 package org.ibex.net;
 
+import java.io.FilterOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.net.HttpURLConnection;
 import java.net.URL;
 
+import org.ibex.util.Callback;
 import org.ibex.util.IOUtil;
 import org.ibex.util.Logger;
 
@@ -89,6 +91,52 @@
                }
        }
        
+       public OutputStream POST2(String contentType, Long contentLength, final 
Callback<Object> responseCallback) throws IOException {
+               try {
+                       //Create connection
+                       final HttpURLConnection connection = newConnection();
+                       if(contentLength!=null){
+                               // REMARK cannot do file upload if we do this
+//                             connection.setRequestProperty("Content-Length", 
"" + contentLength);                    
+                               
connection.setFixedLengthStreamingMode(contentLength);  
+                       }else{
+                               connection.setChunkedStreamingMode(128*1024);   
+                       }
+                       
+                                                       
+                       connection.setConnectTimeout(getConnectTimeout());
+                       connection.setRequestMethod("POST");
+                       connection.setRequestProperty("Content-Type", 
+                                       contentType);
+                       connection.setRequestProperty("Content-Language", 
"en-US");  
+
+                       connection.setUseCaches(false);
+                       connection.setDoInput(true);
+                       connection.setDoOutput(true);
+
+                       //Send request
+                       OutputStream wr = new 
FilterOutputStream(connection.getOutputStream()){
+                               @Override public void write(byte[] b, int off, 
int len) throws IOException {
+                                       // nesessary to avoid doing 1 byte at a 
time
+                                       out.write(b, off, len);
+                               }
+                               
+                               @Override public void close() throws 
IOException {
+                                       super.close();
+                                       try{
+                                               HTTPResponse response = 
readResponse(connection);
+                                               responseCallback.run(response);
+                                       }catch(Throwable t){
+                                               responseCallback.run(t);        
                                                        
+                                       }
+                               }
+                       };
+                       return wr;
+               } catch (IOException e) {
+                       throw e;
+               }
+       }
+       
        private HttpURLConnection newConnection() throws IOException{
                URL url = new URL(this.url);
                return (HttpURLConnection)url.openConnection();

Deleted: 
branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/OrigHTTP.java
===================================================================
--- 
branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/OrigHTTP.java    
    2016-11-18 12:45:45 UTC (rev 4901)
+++ 
branches/vexi3/org.vexi-library.net/src/main/java/org/ibex/net/OrigHTTP.java    
    2016-11-23 20:34:50 UTC (rev 4902)
@@ -1,1473 +0,0 @@
-// Copyright 2000-2008 the Contributors, as shown in the revision logs.
-// Licensed under the Apache Software License 2.0 ("the License").
-// You may not use this file except in compliance with the License.
-
-package org.ibex.net;
-
-import java.net.*;
-import java.io.*;
-import java.util.*;
-
-import org.ibex.util.*;
-import org.ibex.crypto.*;
-/**
- *  This object encapsulates a *single* HTTP connection. Multiple requests may 
be pipelined over a connection (thread-safe),
- *  although any IOException encountered in a request will invalidate all 
later requests.
- */
-public class OrigHTTP extends HTTP {
-
-    public static InetAddress originAddr = null;
-    public static String      originHost = null;
-
-    // FIXME: HACK: these shouldn't be set globally
-    public static String userAgent = "Vexi";
-    public static boolean allowRedirects = true;
-    
-    // Cookies 
//////////////////////////////////////////////////////////////////////////////
-
-    public static class Cookie {
-        public final String  name;
-        public final String  value;
-        public final String  domain;
-        public final String  path;
-        public final Date    expires;
-        public final boolean secure;
-        public Cookie(String name, String value, String domain, String path, 
Date expires, boolean secure) {
-            this.name = name;
-            this.value = value;
-            this.domain = domain;
-            this.path = path;
-            this.expires = expires;
-            this.secure = secure;
-        }
-
-        // FIXME: this could be much more efficient
-        // FIXME currently only implements 
http://wp.netscape.com/newsref/std/cookie_spec.html
-        public static class Jar {
-            private Hash h = new Hash();
-            public String getCookieHeader(String domain, String path, boolean 
secure) {
-                StringBuffer ret = new StringBuffer("Cookie: ");
-                Enumeration e = h.keys();
-                while (e.hasMoreElements()) {
-                    Vec v = (Vec)h.get(e.nextElement());
-                    Cookie cookie = null;
-                    for(int i=0; i<v.size(); i++) {
-                        Cookie c = (Cookie)v.elementAt(i);
-                        if (domain.endsWith(c.domain) &&
-                            (c.path == null || path.startsWith(c.path)) &&
-                            (cookie == null || c.domain.length() > 
cookie.domain.length()))
-                            cookie = c;
-                    }
-                    if (cookie != null) {
-                        ret.append(cookie.name);
-                        ret.append("=");
-                        ret.append(cookie.value);
-                        ret.append("; ");
-                    }
-                }
-                //ret.setLength(ret.length() - 2);
-                return ret.toString();
-            }
-            public void setCookie(String header, String defaultDomain) {
-                String  name       = null;
-                String  value      = null;
-                String  domain     = defaultDomain;
-                String  path       = "/";
-                Date    expires    = null;
-                boolean secure     = false;
-                StringTokenizer st = new StringTokenizer(header, ";");
-                while(st.hasMoreTokens()) {
-                    String s = st.nextToken();
-                    if (s.indexOf('=') == -1) {
-                        if (s.equals("secure")) secure = true;
-                        continue;
-                    }
-                    String start = s.substring(0, s.indexOf('='));
-                    String end   = s.substring(s.indexOf('=')+1);
-                    if (name == null) {
-                        name = start;
-                        value = end;
-                        continue;
-                    }
-                    String p = start.toLowerCase(); 
-                    if("domain".equals(p)) domain = end;
-                    else if("path".equals(p)) path = end;
-                    else if("expires".equals(p)) expires = new Date(end);
-                }
-                if (h.get(name) == null) h.put(name, new Vec());
-                ((Vec)h.get(name)).addElement(new Cookie(name, value, domain, 
path, expires, secure));
-            }
-        }
-    }
-
-    // Public Methods 
////////////////////////////////////////////////////////////////////////////////////////
-    public OrigHTTP(Logger logger, String url) { this(logger, url, false); }
-    public OrigHTTP(Logger logger, String url, boolean skipResolveCheck) { 
this.logger = logger; originalUrl = url; this.skipResolveCheck = 
skipResolveCheck; }
-    // HACK
-    public OrigHTTP(OrigHTTP old) { this(old.logger, old.originalUrl, 
old.skipResolveCheck); }
-    
-    
-    /** Performs an HTTP GET request 
-     * @throws IOException */
-    public HTTPResponse GET() throws IOException{
-       return GET(null,null);}
-    public HTTPResponse GET(String referer, Cookie.Jar cookies) throws 
IOException {
-        return makeRequest("GET", null, referer, cookies); }
-    
-    public HTTPResponse HEAD(String referer, Cookie.Jar cookies) throws 
IOException {
-        return makeRequest("HEAD", null, referer, cookies); }
-    
-    /** Performs an HTTP POST request; content is additional headers, blank 
line, and body */
-    public HTTPResponse POST(String contentType, byte[] content) throws 
IOException {
-        return makeRequest(contentType, content, null, null); }
-    public HTTPResponse POST(String contentType, byte[] content, String 
referer, Cookie.Jar cookies) throws IOException {
-        return makeRequest(contentType, content, referer, cookies); }
-
-    public HTTPEntityInfo lastInfo(){ return lastInfo; }
-
-    public static OrigHTTP stdio = new OrigHTTP(DefaultLog.logger,"stdio:");
-
-
-    // Statics 
///////////////////////////////////////////////////////////////////////////////////////////////
-
-    static Hash resolvedHosts = new Hash();            ///< cache for 
resolveAndCheckIfFirewalled()
-    private static Hash authCache = new Hash();        ///< cache of userInfo 
strings, keyed on originalUrl
-
-
-    // Instance Data 
///////////////////////////////////////////////////////////////////////////////////////////////
-    final Logger logger;
-    final String originalUrl;              ///< the URL as passed to the 
original constructor; this is never changed
-    String url = null;                     ///< the URL to connect to; this is 
munged when the url is parsed */
-    String host = null;                    ///< the host to connect to
-    int port = -1;                         ///< the port to connect on
-    boolean ssl = false;                   ///< true if SSL (HTTPS) should be 
used
-    String path = null;                    ///< the path (URI) to retrieve on 
the server
-    Socket sock = null;                    ///< the socket
-    InputStream in = null;                 ///< the socket's inputstream
-    String userInfo = null;                ///< the username and password 
portions of the URL
-    boolean firstRequest = true;           ///< true iff this is the first 
request to be made on this socket
-    boolean skipResolveCheck = false;      ///< allowed to skip the resolve 
check when downloading PAC script
-    boolean proxied = false;               ///< true iff we're using a proxy
-
-    public HTTPEntityInfo lastInfo;
-    
-    /** this is null if the current request is the first request on
-     *  this HTTP connection; otherwise it is a Semaphore which will be
-     *  released once the request ahead of us has received its response
-     */
-    Semaphore okToRecieve = null;
-
-    /**
-     *  This method isn't synchronized; however, only one thread can be in the 
inner synchronized block at a time, and the rest of
-     *  the method is protected by in-order one-at-a-time semaphore lock-steps
-     */
-    private HTTPResponse makeRequest(String contentType, byte[] content, 
String referer, Cookie.Jar cookies) throws IOException {
-
-        // Step 1: send the request and establish a semaphore to stop any 
requests that pipeline after us
-        Semaphore blockOn = null;
-        Semaphore releaseMe = null;
-        synchronized(this) {
-            try {
-                connect();
-                sendRequest(contentType, content, referer, cookies);
-            } catch (IOException e) {
-                reset();
-                throw e;
-            }
-            blockOn = okToRecieve;
-            releaseMe = okToRecieve = new Semaphore();
-        }
-        
-        // Step 2: wait for requests ahead of us to complete, then read the 
reply off the stream
-        boolean doRelease = true;
-        try {
-            if (blockOn != null) blockOn.block();
-            
-            // previous call wrecked the socket connection, but we already 
sent our request, so we can't just retry --
-            // this could cause the server to receive the request twice, which 
could be bad (think of the case where the
-            // server call causes Amazon.com to ship you an item with 
one-click purchasing).
-            if (in == null)
-                throw new HTTPException("a previous pipelined call messed up 
the socket");
-            
-            Hashtable h = in == null ? null : parseHeaders(in, cookies);
-            if (h == null) {
-                if (firstRequest) throw new HTTPException("server closed the 
socket with no response");
-                // sometimes the server chooses to close the stream between 
requests
-                reset();
-                releaseMe.release();
-                return makeRequest(contentType, content, referer, cookies);
-            }
-
-            String reply = h.get("STATUSLINE").toString();
-            
-            if (reply.startsWith("407") || reply.startsWith("401")) {
-                
-                if (reply.startsWith("407")) doProxyAuth(h, content == null ? 
"GET" : "POST");
-                else doWebAuth(h, content == null ? "GET" : "POST");
-                
-                if (h.get("HTTP").equals("1.0") && h.get("content-length") == 
null) {
-                    logger.info(this, "proxy returned an HTTP/1.0 reply with 
no content-length...");
-                    reset();
-                } else {
-                    newHTTPInputStream(in, h, releaseMe).close();
-                }
-                releaseMe.release();
-                return makeRequest(contentType, content, referer, cookies);
-                
-            } else if (reply.startsWith("3") && allowRedirects) {
-                String location = (String)h.get("location");
-                if (location == null) throw new HTTPException("Got HTTP " + 
reply.substring(0, 3) + " but no Location header");
-                logger.info(HTTP.class, "redirecting to " + location);
-                if (content != null)
-                    return new OrigHTTP(logger, location).POST(contentType, 
content, url, cookies);
-                else
-                    return new OrigHTTP(logger, location).GET(url, cookies);
-                
-            } else if (reply.startsWith("2")) {
-                if (h.get("HTTP").equals("1.0") && h.get("content-length") == 
null)
-                    throw new HTTPException("Vexi does not support HTTP/1.0 
servers which fail to return the Content-Length header");
-                HTTPInputStream ret = newHTTPInputStream(in, h, releaseMe);
-                doRelease = false;
-                return new HTTPResponse(ret.info,ret);
-            } else {
-               HTTPInputStream his = newHTTPInputStream(in, h, releaseMe);
-               // read into stream, so that we can release and are not obliged 
to handle
-               // the response (close the inputstream) - mike (assumes this is 
necessary)
-               ByteArrayOutputStream baos  = new 
ByteArrayOutputStream(his.info.contentLength>0?his.info.contentLength:1024);
-               IOUtil.pipe(his, baos);
-               byte[] bytes = baos.toByteArray();
-               //byte[] bytes = "{}".getBytes();
-               his.close();
-               throw new HTTPErrorResponse(reply, reply.substring(0,3), bytes, 
his.info);
-            }
-            
-        } catch (IOException e) { reset(); throw e;
-        } finally { if (doRelease) releaseMe.release();
-        }
-    }
-
-
-    // Safeguarded DNS Resolver 
///////////////////////////////////////////////////////////////////////////
-
-    /**
-     *  resolves the hostname and returns it as a string in the form "x.y.z.w"
-     *  @throws HTTPException if the host falls within a firewalled netblock
-     */
-    private void resolveAndCheckIfFirewalled(String host) throws HTTPException 
{
-
-        // cached
-        if (resolvedHosts.get(host) != null) return;
-
-        // if all scripts are trustworthy (local FS), continue
-        if (originAddr == null) return;
-
-        // resolve using DNS
-        try {
-            InetAddress addr = InetAddress.getByName(host);
-            byte[] quadbyte = addr.getAddress();
-            if ((quadbyte[0] == 10 ||
-                 (quadbyte[0] == 192 && quadbyte[1] == 168) ||
-                 (quadbyte[0] == 172 && (quadbyte[1] & 0xF0) == 16)) && 
!addr.equals(originAddr))
-                throw new HTTPException("security violation: " + host + " [" + 
addr.getHostAddress() +
-                                        "] is in a firewalled netblock");
-            return;
-        } catch (UnknownHostException uhe) { }
-
-        /*
-        if (Platform.detectProxy() == null)
-            throw new HTTPException("could not resolve hostname \"" + host + 
"\" and no proxy configured");
-        */
-    }
-
-
-    // Methods to attempt socket creation 
/////////////////////////////////////////////////////////////////
-
-    private Socket getSocket(String host, int port, boolean ssl, boolean 
negotiate) throws IOException {
-        Socket ret = ssl ? new SSL(logger, host, port, negotiate) : new 
Socket(java.net.InetAddress.getByName(host), port);
-        ret.setTcpNoDelay(true);
-        return ret;
-    }
-
-    /** Attempts a direct connection */
-    private Socket attemptDirect() {
-        try {
-            logger.debug(this, "attempting to create unproxied socket to " +
-                     host + ":" + port + (ssl ? " [ssl]" : ""));
-            return getSocket(host, port, ssl, true);
-        } catch (IOException e) {
-            logger.info(this, "exception in attemptDirect(): " + e);
-            return null;
-        }
-    }
-
-
-    // Everything Else 
////////////////////////////////////////////////////////////////////////////
-
-    private synchronized void connect() throws IOException {
-        if (originalUrl.equals("stdio:")) { in = new 
BufferedInputStream(System.in); return; }
-        if (sock != null) {
-            if (in == null) in = new 
BufferedInputStream(sock.getInputStream());
-            return;
-        }
-        // grab the userinfo; gcj doesn't have java.net.URL.getUserInfo()
-        String url = originalUrl;
-        userInfo = url.substring(url.indexOf("://") + 3);
-        userInfo = userInfo.indexOf('/') == -1 ? userInfo : 
userInfo.substring(0, userInfo.indexOf('/'));
-        if (userInfo.indexOf('@') != -1) {
-            userInfo = userInfo.substring(0, userInfo.indexOf('@'));
-            url = url.substring(0, url.indexOf("://") + 3) + 
url.substring(url.indexOf('@') + 1);
-        } else {
-            userInfo = null;
-        }
-
-        if (url.startsWith("https:")) {
-            ssl = true;
-        } else if (!url.startsWith("http:")) {
-            throw new IOException("HTTP only supports http/https urls");
-        }
-        if (url.indexOf("://") == -1) throw new IOException("URLs must contain 
a ://");
-        String temphost = url.substring(url.indexOf("://") + 3);
-        path = temphost.substring(temphost.indexOf('/'));
-        temphost = temphost.substring(0, temphost.indexOf('/'));
-        if (temphost.indexOf(':') != -1) {
-            port = 
Integer.parseInt(temphost.substring(temphost.indexOf(':')+1));
-            temphost = temphost.substring(0, temphost.indexOf(':'));
-        } else {
-            port = ssl ? 443 : 80;
-        }
-        if (!skipResolveCheck) resolveAndCheckIfFirewalled(temphost);
-        host = temphost;
-        logger.debug(this, "creating HTTP object for connection to " + host + 
":" + port);
-
-        /*
-        Proxy pi = Platform.detectProxy();
-        OUTER: do {
-            if (pi != null) {
-                for(int i=0; i<pi.excluded.length; i++) if 
(host.equals(pi.excluded[i])) break OUTER;
-                if (sock == null && pi.proxyAutoConfigFunction != null) sock = 
attemptPAC(pi.proxyAutoConfigFunction);
-                if (sock == null && ssl && pi.httpsProxyHost != null) sock = 
attemptHttpProxy(pi.httpsProxyHost,pi.httpsProxyPort);
-                if (sock == null && pi.httpProxyHost != null) sock = 
attemptHttpProxy(pi.httpProxyHost, pi.httpProxyPort);
-                if (sock == null && pi.socksProxyHost != null) sock = 
attemptSocksProxy(pi.socksProxyHost, pi.socksProxyPort);
-            }
-        } while (false);
-        */
-        proxied = sock != null;
-        if (sock == null) sock = attemptDirect();
-        if (sock == null) throw new HTTPException("unable to contact host " + 
host);
-        if (in == null) in = new BufferedInputStream(sock.getInputStream());
-    }
-
-    private void sendRequest(String contentType, byte[] content, String 
referer, Cookie.Jar cookies) throws IOException {
-        // REMARK - the BufferedOutputStream is necessary - for the xmlrpc 
tests at least.
-       // Not sure exactly why, but there were communication problems without 
it.
-       PrintStream ps = new PrintStream(new BufferedOutputStream(
-                       originalUrl.equals("stdio:") ?
-                                       System.out : sock.getOutputStream()));
-        if (content != null) {
-               ps.print("POST " + path + " HTTP/1.0\r\n"); // FIXME chunked 
encoding
-            int contentLength = content.length; 
-            ps.print("Content-Length: " + contentLength + "\r\n");
-            if (contentType != null) ps.print("Content-Type: " + contentType + 
"\r\n");
-        } else {
-            ps.print(contentType + " " + path + " HTTP/1.1\r\n");
-        }
-
-        if (cookies != null) ps.print(cookies.getCookieHeader(host, path, 
ssl));
-        ps.print("User-Agent: " + userAgent + "\r\n");
-        ps.print("Accept-encoding: gzip\r\n");
-        ps.print("Host: " + (host + (port == 80 ? "" : (":" + port))) + 
"\r\n");
-        if (proxied) ps.print("X-RequestOrigin: " + originHost + "\r\n");
-
-        if (Proxy.Authorization.authorization != null) 
ps.print("Proxy-Authorization: "+Proxy.Authorization.authorization2+"\r\n");
-        if (authCache.get(originalUrl) != null) ps.print("Authorization: " + 
authCache.get(originalUrl) + "\r\n");
-
-        ps.print("\r\n");
-        if(content!=null){
-               ps.write(content);
-        }
-        ps.print("\r\n");
-        ps.flush();
-    }
-
-    private void doWebAuth(Hashtable h0, String method) throws IOException {
-        if (userInfo == null) throw new HTTPException("web server demanded 
username/password, but none were supplied");
-        Hashtable h = 
parseAuthenticationChallenge(h0.get("www-authenticate").toString());
-        
-        if (h.get("AUTHTYPE").equals("Basic")) {
-            if (authCache.get(originalUrl) != null) throw new 
HTTPException("username/password rejected");
-            authCache.put(originalUrl, "Basic " + new 
String(Encode.toBase64(userInfo.getBytes("UTF8"))));
-            
-        } else if (h.get("AUTHTYPE").equals("Digest")) {
-            if (authCache.get(originalUrl) != null && 
!"true".equals(h.get("stale")))
-                throw new HTTPException("username/password rejected");
-            String path2 = path;
-            if (path2.startsWith("http://";) || path2.startsWith("https://";)) {
-                path2 = path2.substring(path2.indexOf("://") + 3);
-                path2 = path2.substring(path2.indexOf('/'));
-            }
-            String A1 = userInfo.substring(0, userInfo.indexOf(':')) + ":" + 
h.get("realm") + ":" +
-                userInfo.substring(userInfo.indexOf(':') + 1);
-            String A2 = method + ":" + path2;
-            authCache.put(originalUrl,
-                          "Digest " +
-                          "username=\"" + userInfo.substring(0, 
userInfo.indexOf(':')) + "\", " +
-                          "realm=\"" + h.get("realm") + "\", " +
-                          "nonce=\"" + h.get("nonce") + "\", " +
-                          "uri=\"" + path2 + "\", " +
-                          (h.get("opaque") == null ? "" : ("opaque=\"" + 
h.get("opaque") + "\", ")) + 
-                          "response=\"" + H(H(A1) + ":" + h.get("nonce") + ":" 
+ H(A2)) + "\", " +
-                          "algorithm=MD5"
-                          );
-            
-        } else {
-            throw new HTTPException("unknown authentication type: " + 
h.get("AUTHTYPE"));
-        }
-    }
-
-    private void doProxyAuth(Hashtable h0, String method) throws IOException {
-        if (logger.isInfo()) logger.info(this, "Proxy AuthChallenge: " + 
h0.get("proxy-authenticate"));
-        Hashtable h = 
parseAuthenticationChallenge(h0.get("proxy-authenticate").toString());
-        String style = h.get("AUTHTYPE").toString();
-        //String realm = (String)h.get("realm");
-
-        if (style.equals("NTLM") && Proxy.Authorization.authorization2 == 
null) {
-            logger.info(this, "Proxy identified itself as NTLM, sending Type 1 
packet");
-            Proxy.Authorization.authorization2 = "NTLM " + 
Encode.toBase64(Proxy.NTLM.type1);
-            return;
-        }
-        /*
-        if (!realm.equals("Digest") || Proxy.Authorization.authorization2 == 
null || !"true".equals(h.get("stale")))
-            Proxy.Authorization.getPassword(realm, style, 
sock.getInetAddress().getHostAddress(),
-                                            Proxy.Authorization.authorization);
-        */
-        if (style.equals("Basic")) {
-            Proxy.Authorization.authorization2 =
-                "Basic " + new 
String(Encode.toBase64(Proxy.Authorization.authorization.getBytes("UTF8")));
-            
-        } else if (style.equals("Digest")) {
-            String A1 = Proxy.Authorization.authorization.substring(0, 
userInfo.indexOf(':')) + ":" + h.get("realm") + ":" +
-                
Proxy.Authorization.authorization.substring(Proxy.Authorization.authorization.indexOf(':')
 + 1);
-            String A2 = method + ":" + path;
-            Proxy.Authorization.authorization2 = 
-                "Digest " +
-                "username=\"" + Proxy.Authorization.authorization.substring(0, 
Proxy.Authorization.authorization.indexOf(':')) +
-                "\", " +
-                "realm=\"" + h.get("realm") + "\", " +
-                "nonce=\"" + h.get("nonce") + "\", " +
-                "uri=\"" + path + "\", " +
-                (h.get("opaque") == null ? "" : ("opaque=\"" + h.get("opaque") 
+ "\", ")) + 
-                "response=\"" + H(H(A1) + ":" + h.get("nonce") + ":" + H(A2)) 
+ "\", " +
-                "algorithm=MD5";
-
-        } else if (style.equals("NTLM")) {
-               logger.info(this, "Proxy identified itself as NTLM, got Type 2 
packet");
-            byte[] type2 = 
Encode.fromBase64(((String)h0.get("proxy-authenticate")).substring(5).trim());
-            for(int i=0; i<type2.length; i += 4) {
-                String log = "";
-                if (i<type2.length) log += Integer.toString(type2[i] & 0xff, 
16) + " ";
-                if (i+1<type2.length) log += Integer.toString(type2[i+1] & 
0xff, 16) + " ";
-                if (i+2<type2.length) log += Integer.toString(type2[i+2] & 
0xff, 16) + " ";
-                if (i+3<type2.length) log += Integer.toString(type2[i+3] & 
0xff, 16) + " ";
-                logger.info(this, log);
-            }
-            // FEATURE: need to keep the connection open between type1 and 
type3
-            // FEATURE: finish this
-            //byte[] type3 = Proxy.NTLM.getResponse(
-            //Proxy.Authorization.authorization2 = "NTLM " + 
Encode.toBase64(type3));
-        }            
-    }
-
-
-    // HTTPInputStream 
///////////////////////////////////////////////////////////////////////////////////
-
-    
-    /** An input stream that represents a subset of a longer input stream. 
Supports HTTP chunking as well */
-    class HTTPInputStream extends FilterInputStream {
-
-
-               final public HTTPEntityInfo info;
-               
-               private int length = 0;              ///< if chunking, numbytes 
left in this subset; else the remainder of the chunk
-        private Semaphore releaseMe = null;  ///< this semaphore will be 
released when the stream is closed
-        private boolean chunkedDone = false;         ///< indicates that we 
have encountered the zero-length terminator chunk
-        private boolean firstChunk = true;           ///< if we're on the 
first chunk, we don't pre-read a CRLF
-        
-               
-        HTTPInputStream(InputStream in, Semaphore releaseMe, HTTPEntityInfo 
info) throws IOException {
-            super(in);
-            this.info = info;
-            this.releaseMe = releaseMe;
-            this.length = info.contentLength == -1 ? 0 : info.contentLength;
-        }
-        public boolean markSupported() { return false; }
-        public int read(byte[] b) throws IOException { return read(b, 0, 
b.length); }
-        public long skip(long n) throws IOException { return read(null, -1, 
(int)n); }
-        public int available() throws IOException {
-            if (info.contentLength == -1) return 
java.lang.Math.min(super.available(), length);
-            return super.available();
-        }
-        
-        public int read() throws IOException {
-            byte[] b = new byte[1];
-            int ret = read(b, 0, 1);
-            return ret == -1 ? -1 : b[0] & 0xff;
-        }
-
-        private boolean isHexDigit(char c){
-               return ('0' <= c && '9' >= c) ||  
-                       ('a' <= c && 'f' >= c) ||
-                       ('A' <= c && 'F' >= c);
-        }
-        
-        private void readChunk() throws IOException {
-            if (chunkedDone) return;
-            if (!firstChunk) super.skip(2); // CRLF
-            firstChunk = false;
-            String chunkLen = "";
-            while(true) {
-                int i = super.read();
-                if (i == -1) throw new HTTPException("encountered end of 
stream while reading chunk length");
-
-                // FEATURE: handle chunking extensions
-                if (i == '\r') {
-                    super.read();    // LF
-                    break;
-                } else {
-                    chunkLen += (char)i;
-                    if(!isHexDigit((char)i) || chunkLen.length()>10) throw new 
HTTPException("encountered problem while reading chunk length: " + chunkLen);
-                }
-            }
-            length = Integer.parseInt(chunkLen.trim(), 16);
-            if (length == 0) chunkedDone = true;
-        }
-
-        public int read(byte[] b, int off, int len) throws IOException {
-            boolean good = false;
-            try {
-                if (length == 0 && info.contentLength == -1) {
-                    readChunk();
-                    if (chunkedDone) { good = true; return -1; }
-                } else {
-                    if (length == 0) { good = true; return -1; }
-                }
-                if (len > length) len = length;
-                int ret = b == null ? (int)super.skip(len) : super.read(b, 
off, len);
-                if (ret >= 0) {
-                    length -= ret;
-                    good = true;
-                }
-                return ret;
-            } finally {
-                if (!good) logger.warn(HTTP.class,"HTTP content shorter than 
expected\n"+
-                                               "      remaining : 
"+length+"\n"+
-                                               "      chunked   : 
"+(info.contentLength == -1)+"\n");
-                                                                               
               
-                // REMARK - how can we reset, we never set the mark, and what 
-                // good would it do anyway?
-                // if (!good) reset(); 
-            }
-        }
-
-        public void close() throws IOException {
-            if (info.contentLength == -1) {
-                while(!chunkedDone) {
-                    if (length != 0) skip(length);
-                    readChunk();
-                }
-                skip(2);
-            } else {
-                int skip = length;
-                // available might be 0 is this is a HEAD request
-                // skipping was blocking before this check was instated
-                if(available()==0) skip = 0;
-                if (skip != 0) skip(skip);
-            }
-            if (releaseMe != null) releaseMe.release();
-        }
-
-    }
-    
-    private HTTPEntityInfo newEntityInfo(Hashtable h){
-       int cl = h.get("content-length") == null ? -1 : 
Integer.parseInt(h.get("content-length").toString());
-        String timestamp = (String) h.get("last-modified");
-        if(timestamp==null) timestamp="";
-        String contentType = (String) h.get("content-type");
-        if(contentType==null) contentType = "";
-        return new HTTPEntityInfo (cl, timestamp, contentType);
-    }
-    
-    private HTTPInputStream newHTTPInputStream(InputStream in, Hashtable h, 
Semaphore releaseMe) throws IOException{
-       HTTPEntityInfo info = newEntityInfo(h);
-       lastInfo = info;
-        if ("gzip".equals(h.get("content-encoding"))) in = new 
java.util.zip.GZIPInputStream(in);
-        return new HTTPInputStream(in, releaseMe, info);
-    }
-
-    void reset() {
-        firstRequest = true;
-        in = null;
-        sock = null;
-    }
-
-
-    // Misc Helpers 
///////////////////////////////////////////////////////////////////////////////////
-
-    /** reads a set of HTTP headers off of the input stream, returning null if 
the stream is already at its end */
-    private Hashtable parseHeaders(InputStream in, Cookie.Jar cookies) throws 
IOException {
-        Hashtable ret = new Hashtable();
-
-        // we can't use a BufferedReader directly on the input stream, since 
it will buffer past the end of the headers
-        byte[] buf = new byte[4096];
-        int buflen = 0;
-        while(true) {
-            int read = in.read();
-            if (read == -1 && buflen == 0) return null;
-            if (read == -1) throw new HTTPException("stream closed while 
reading headers");
-            buf[buflen++] = (byte)read;
-            if (buflen >= 4 && buf[buflen - 4] == '\r' && buf[buflen - 3] == 
'\n' &&
-                buf[buflen - 2] == '\r' && buf[buflen - 1] == '\n')
-                break;
-            if (buflen >=2 && buf[buflen - 1] == '\n' && buf[buflen - 2] == 
'\n')
-                break;  // nice for people using stdio
-            if (buflen == buf.length) {
-                byte[] newbuf = new byte[buf.length * 2];
-                System.arraycopy(buf, 0, newbuf, 0, buflen);
-                buf = newbuf;
-            }
-        }
-
-        BufferedReader br = new BufferedReader(new InputStreamReader(new 
ByteArrayInputStream(buf, 0, buflen)));
-        String s = br.readLine();
-        if (!s.startsWith("HTTP/")) throw new HTTPException("Expected reply to 
start with \"HTTP/\", got: " + s);
-        ret.put("STATUSLINE", s.substring(s.indexOf(' ') + 1));
-        ret.put("HTTP", s.substring(5, s.indexOf(' ')));
-
-        while((s = br.readLine()) != null && s.length() > 0) {
-            String front = s.substring(0, s.indexOf(':')).toLowerCase();
-            String back = s.substring(s.indexOf(':') + 1).trim();
-            // ugly hack: we never replace a Digest-auth with a Basic-auth 
(proxy + www)
-            if (front.endsWith("-authenticate") && ret.get(front) != null && 
!back.equals("Digest")) continue;
-            if (front.equals("set-cookie")) cookies.setCookie(back, host);
-            ret.put(front, back);
-        }
-        return ret;
-    }
-
-    private Hashtable parseAuthenticationChallenge(String s) {
-        Hashtable ret = new Hashtable();
-
-        s = s.trim();
-        ret.put("AUTHTYPE", s.substring(0, s.indexOf(' ')));
-        s = s.substring(s.indexOf(' ')).trim();
-
-        while (s.length() > 0) {
-            String val = null;
-            String key = s.substring(0, s.indexOf('='));
-            s = s.substring(s.indexOf('=') + 1);
-            if (s.charAt(0) == '\"') {
-                s = s.substring(1);
-                val = s.substring(0, s.indexOf('\"'));
-                s = s.substring(s.indexOf('\"') + 1);
-            } else {
-                val = s.indexOf(',') == -1 ? s : s.substring(0, 
s.indexOf(','));
-                s = s.indexOf(',') == -1 ? "" : s.substring(s.indexOf(',') + 
1);
-            }
-            if (s.length() > 0 && s.charAt(0) == ',') s = s.substring(1);
-            s = s.trim();
-            ret.put(key, val);
-        }
-        return ret;
-    }
-
-    private String H(String s) throws IOException {
-        byte[] b = s.getBytes("UTF8");
-        MD5 md5 = new MD5();
-        md5.update(b, 0, b.length);
-        byte[] out = new byte[md5.getDigestSize()];
-        md5.doFinal(out, 0);
-        String ret = "";
-        for(int i=0; i<out.length; i++) {
-            ret += "0123456789abcdef".charAt((out[i] & 0xf0) >> 4);
-            ret += "0123456789abcdef".charAt(out[i] & 0x0f);
-        }
-        return ret;
-    }
-
-
-    // Proxy ///////////////////////////////////////////////////////////
-
-    /** encapsulates most of the proxy logic; some is shared in HTTP.java */
-    public static class Proxy {
-        
-        public String httpProxyHost = null;                  ///< the HTTP 
Proxy host to use
-        public int httpProxyPort = -1;                       ///< the HTTP 
Proxy port to use
-        public String httpsProxyHost = null;                 ///< seperate 
proxy for HTTPS
-        public int httpsProxyPort = -1;
-        public String socksProxyHost = null;                 ///< the SOCKS 
Proxy Host to use
-        public int socksProxyPort = -1;                      ///< the SOCKS 
Proxy Port to use
-        public String[] excluded = new String[] { };         ///< hosts to be 
excluded from proxy use; wildcards permitted
-
-        // ** temporarily disabled so HTTP does not depend on org.ibex.js **
-        //public JS proxyAutoConfigFunction = null;            ///< the PAC 
script
-        public Object proxyAutoConfigFunction = null;            ///< the PAC 
script
-    
-        public static Proxy detectProxyViaManual() {
-            Proxy ret = new Proxy();
-            /*
-            ret.httpProxyHost = Platform.getEnv("http_proxy");
-            if (ret.httpProxyHost != null) {
-                if (ret.httpProxyHost.startsWith("http://";)) ret.httpProxyHost 
= ret.httpProxyHost.substring(7);
-                if (ret.httpProxyHost.endsWith("/"))
-                    ret.httpProxyHost = ret.httpProxyHost.substring(0, 
ret.httpProxyHost.length() - 1);
-                if (ret.httpProxyHost.indexOf(':') != -1) {
-                    ret.httpProxyPort = 
Integer.parseInt(ret.httpProxyHost.substring(ret.httpProxyHost.indexOf(':') + 
1));
-                    ret.httpProxyHost = ret.httpProxyHost.substring(0, 
ret.httpProxyHost.indexOf(':'));
-                } else {
-                    ret.httpProxyPort = 80;
-                }
-            }
-        
-            ret.httpsProxyHost = Platform.getEnv("https_proxy");
-            if (ret.httpsProxyHost != null) {
-                if (ret.httpsProxyHost.startsWith("https://";)) 
ret.httpsProxyHost = ret.httpsProxyHost.substring(7);
-                if (ret.httpsProxyHost.endsWith("/"))
-                    ret.httpsProxyHost = ret.httpsProxyHost.substring(0, 
ret.httpsProxyHost.length() - 1);
-                if (ret.httpsProxyHost.indexOf(':') != -1) {
-                    ret.httpsProxyPort = 
Integer.parseInt(ret.httpsProxyHost.substring(ret.httpsProxyHost.indexOf(':') + 
1));
-                    ret.httpsProxyHost = ret.httpsProxyHost.substring(0, 
ret.httpsProxyHost.indexOf(':'));
-                } else {
-                    ret.httpsProxyPort = 80;
-                }
-            }
-        
-            ret.socksProxyHost = Platform.getEnv("socks_proxy");
-            if (ret.socksProxyHost != null) {
-                if (ret.socksProxyHost.startsWith("socks://")) 
ret.socksProxyHost = ret.socksProxyHost.substring(7);
-                if (ret.socksProxyHost.endsWith("/"))
-                    ret.socksProxyHost = ret.socksProxyHost.substring(0, 
ret.socksProxyHost.length() - 1);
-                if (ret.socksProxyHost.indexOf(':') != -1) {
-                    ret.socksProxyPort = 
Integer.parseInt(ret.socksProxyHost.substring(ret.socksProxyHost.indexOf(':') + 
1));
-                    ret.socksProxyHost = ret.socksProxyHost.substring(0, 
ret.socksProxyHost.indexOf(':'));
-                } else {
-                    ret.socksProxyPort = 80;
-                }
-            }
-        
-            String noproxy = Platform.getEnv("no_proxy");
-            if (noproxy != null) {
-                StringTokenizer st = new StringTokenizer(noproxy, ",");
-                ret.excluded = new String[st.countTokens()];
-                for(int i=0; st.hasMoreTokens(); i++) ret.excluded[i] = 
st.nextToken();
-            }
-        
-            if (ret.httpProxyHost == null && ret.socksProxyHost == null) 
return null;
-            */
-            return ret;
-        }
-
-        /*
-        public static JSScope proxyAutoConfigRootScope = new 
ProxyAutoConfigRootScope();
-        public static JS getProxyAutoConfigFunction(String url) {
-            try { 
-                BufferedReader br = new BufferedReader(new 
InputStreamReader(new HTTP(url, true).GET()));
-                String s = null;
-                String script = "";
-                while((s = br.readLine()) != null) script += s + "\n";
-                if (Log.on) Log.info(Proxy.class, "successfully retrieved WPAD 
PAC:");
-                if (Log.on) Log.info(Proxy.class, script);
-            
-                // MS CARP hack
-                Vector carpHosts = new Vector();
-                for(int i=0; i<script.length(); i++)
-                    if (script.regionMatches(i, "new Node(", 0, 9)) {
-                        String host = script.substring(i + 10, 
script.indexOf('\"', i + 11));
-                        if (Log.on) Log.info(Proxy.class, "Detected MS Proxy 
Server CARP Script, Host=" + host);
-                        carpHosts.addElement(host);
-                    }
-                if (carpHosts.size() > 0) {
-                    script = "function FindProxyForURL(url, host) {\nreturn 
\"";
-                    for(int i=0; i<carpHosts.size(); i++)
-                        script += "PROXY " + carpHosts.elementAt(i) + "; ";
-                    script += "\";\n}";
-                    if (Log.on) Log.info(Proxy.class, "DeCARPed PAC script:");
-                    if (Log.on) Log.info(Proxy.class, script);
-                }
-
-                JS scr = JS.fromReader("PAC script at " + url, 0, new 
StringReader(script));
-                JS.cloneWithNewParentScope(scr, 
proxyAutoConfigRootScope).call(null, null, null, null, 0);
-                return (JS)proxyAutoConfigRootScope.get("FindProxyForURL");
-            } catch (Exception e) {
-                if (Log.on) {
-                    Log.info(Platform.class, "WPAD detection failed due to:");
-                    if (e instanceof JSExn) {
-                        try {
-                            org.ibex.js.JSArray arr = new 
org.ibex.js.JSArray();
-                            arr.addElement(((JSExn)e).getObject());
-                        } catch (Exception e2) {
-                            Log.info(Platform.class, e);
-                        }
-                    }
-                    else Log.info(Platform.class, e);
-                }
-                return null;
-            }
-        }
-        */
-
-        // Authorization 
///////////////////////////////////////////////////////////////////////////////////
-
-        public static class Authorization {
-
-            static public String authorization = null;
-            static public String authorization2 = null;
-            static public Semaphore waitingForUser = new Semaphore();
-
-            // FIXME: temporarily disabled so we can use HTTP outside the core
-            /*
-            public static synchronized void getPassword(final String realm, 
final String style,
-                                                        final String proxyIP, 
String oldAuth) throws IOException {
-
-                // this handles cases where multiple threads hit the proxy 
auth at the same time -- all but one will block on the
-                // synchronized keyword. If 'authorization' changed while the 
thread was blocked, it means that the user entered
-                // a password, so we should reattempt authorization.
-
-                if (authorization != oldAuth) return;
-                if (Log.on) Log.info(Authorization.class, "displaying proxy 
authorization dialog");
-                Scheduler.add(new Callable() {
-                        public void run() throws IOException, JSExn {
-                            Box b = new Box();
-                            Template t = null;
-                            // FIXME
-                            
//Template.buildTemplate("org/ibex/builtin/proxy_authorization.ibex", 
Stream.getInputStream((JS)Main.builtin.get("org/ibex/builtin/proxy_authorization.ibex")),
 new Ibex(null));
-                            t.apply(b);
-                            b.put("realm", realm);
-                            b.put("proxyIP", proxyIP);
-                        }
-                    });
-
-                waitingForUser.block();
-                if (Log.on) Log.info(Authorization.class, "got proxy 
authorization info; re-attempting connection");
-            }
-            */
-        }
-
-
-        // ProxyAutoConfigRootJSScope 
////////////////////////////////////////////////////////////////////
-        /*
-        public static class ProxyAutoConfigRootScope extends JSScope.Global {
-
-            public ProxyAutoConfigRootScope() { super(); }
-        
-            public Object get(Object name) throws JSExn {
-                // #switch(name)
-                case "isPlainHostName": return METHOD;
-                case "dnsDomainIs": return METHOD;
-                case "localHostOrDomainIs": return METHOD;
-                case "isResolvable": return METHOD;
-                case "isInNet": return METHOD;
-                case "dnsResolve": return METHOD;
-                case "myIpAddress": return METHOD;
-                case "dnsDomainLevels": return METHOD;
-                case "shExpMatch": return METHOD;
-                case "weekdayRange": return METHOD;
-                case "dateRange": return METHOD;
-                case "timeRange": return METHOD;
-                case "ProxyConfig": return ProxyConfig;
-                // #end
-                return super.get(name);
-            }
-        
-            private static final JS proxyConfigBindings = new JS();
-            private static final JS ProxyConfig = new JS() {
-                    public Object get(Object name) {
-                        if (name.equals("bindings")) return 
proxyConfigBindings;
-                        return null;
-                    }
-                };
-
-            public Object callMethod(Object method, Object a0, Object a1, 
Object a2, Object[] rest, int nargs) throws JSExn {
-                // #switch(method)
-                case "isPlainHostName": return (a0.toString().indexOf('.') == 
-1) ? Boolean.TRUE : Boolean.FALSE;
-                case "dnsDomainIs": return 
(a0.toString().endsWith(a1.toString())) ? Boolean.TRUE : Boolean.FALSE;
-                case "localHostOrDomainIs":
-                    return (a0.equals(a1) || (a0.toString().indexOf('.') == -1 
&& a1.toString().startsWith(a0.toString()))) ? T:F;
-                case "isResolvable": try {
-                    return (InetAddress.getByName(a0.toString()) != null) ? 
Boolean.TRUE : Boolean.FALSE;
-                } catch (UnknownHostException e) { return F; }
-                case "isInNet":
-                    if (nargs != 3) return Boolean.FALSE;
-                    try {
-                        byte[] host = 
InetAddress.getByName(a0.toString()).getAddress();
-                        byte[] net = 
InetAddress.getByName(a1.toString()).getAddress();
-                        byte[] mask = 
InetAddress.getByName(a2.toString()).getAddress();
-                        return ((host[0] & mask[0]) == net[0] &&
-                                (host[1] & mask[1]) == net[1] &&
-                                (host[2] & mask[2]) == net[2] &&
-                                (host[3] & mask[3]) == net[3]) ?
-                            Boolean.TRUE : Boolean.FALSE;
-                    } catch (Exception e) {
-                        throw new JSExn("exception in isInNet(): " + e);
-                    }
-                case "dnsResolve":
-                    try {
-                        return 
InetAddress.getByName(a0.toString()).getHostAddress();
-                    } catch (UnknownHostException e) {
-                        return null;
-                    }
-                case "myIpAddress":
-                    try {
-                        return InetAddress.getLocalHost().getHostAddress();
-                    } catch (UnknownHostException e) {
-                        if (Log.on) Log.info(this, "strange... host does not 
know its own address");
-                        return null;
-                    }
-                case "dnsDomainLevels":
-                    String s = a0.toString();
-                    int i = 0;
-                    while((i = s.indexOf('.', i)) != -1) i++;
-                    return new Integer(i);
-                case "shExpMatch":
-                    StringTokenizer st = new StringTokenizer(a1.toString(), 
"*", false);
-                    String[] arr = new String[st.countTokens()];
-                    String s = a0.toString();
-                    for (int i=0; st.hasMoreTokens(); i++) arr[i] = 
st.nextToken();
-                    return match(arr, s, 0) ? Boolean.TRUE : Boolean.FALSE;
-                case "weekdayRange":
-                    TimeZone tz = (nargs < 3 || a2 == null || 
!a2.equals("GMT")) ?
-                        TimeZone.getTimeZone("UTC") : TimeZone.getDefault();
-                    Calendar c = new GregorianCalendar();
-                    c.setTimeZone(tz);
-                    c.setTime(new java.util.Date());
-                    java.util.Date d = c.getTime();
-                    int day = d.getDay();
-                    String d1s = a0.toString().toUpperCase();
-                    int d1 = 0, d2 = 0;
-                    for(int i=0; i<days.length; i++) if (days[i].equals(d1s)) 
d1 = i;
-                    
-                    if (nargs == 1)
-                        return d1 == day ? Boolean.TRUE : Boolean.FALSE;
-                    
-                    String d2s = a1.toString().toUpperCase();
-                    for(int i=0; i<days.length; i++) if (days[i].equals(d2s)) 
d2 = i;
-                    
-                    return ((d1 <= d2 && day >= d1 && day <= d2) || (d1 > d2 
&& (day >= d1 || day <= d2))) ? T : F;
-                    
-                case "dateRange": throw new JSExn("Ibex does not support 
dateRange() in PAC scripts");
-                case "timeRange": throw new JSExn("Ibex does not support 
timeRange() in PAC scripts");
-                // #end
-                return super.callMethod(method, a0, a1, a2, rest, nargs);
-            }       
-            private static boolean match(String[] arr, String s, int index) {
-                if (index >= arr.length) return true;
-                for(int i=0; i<s.length(); i++) {
-                    String s2 = s.substring(i);
-                    if (s2.startsWith(arr[index]) && match(arr, 
s2.substring(arr[index].length()), index + 1)) return true;
-                }
-                return false;
-            }
-            public static String[] days = { "SUN", "MON", "TUE", "WED", "THU", 
"FRI", "SAT" };
-        }
-        */
-
-        /**
-         *  An implementation of Microsoft's proprietary NTLM authentication 
protocol.  This code was derived from Eric
-         *  Glass's work, and is copyright as follows:
-         *
-         *  Copyright (c) 2003 Eric Glass     (eglass1 at comcast.net). 
-         *
-         *  Permission to use, copy, modify, and distribute this document for 
any purpose and without any fee is hereby
-         *  granted, provided that the above copyright notice and this list of 
conditions appear in all copies.
-         *  The most current version of this document may be obtained from 
http://davenport.sourceforge.net/ntlm.html .
-         */ 
-        public static class NTLM {
-            
-            public static final byte[] type1 = new byte[] { 0x4e, 0x54, 0x4c, 
0x4d, 0x53, 0x53, 0x50, 0x00, 0x01,
-                                                            0x00, 0x00, 0x00, 
0x00, 0x02, 0x02, 0x00 };
-            
-            /**
-             * Calculates the NTLM Response for the given challenge, using the
-             * specified password.
-             *
-             * @param password The user's password.
-             * @param challenge The Type 2 challenge from the server.
-             *
-             * @return The NTLM Response.
-             */
-            public static byte[] getNTLMResponse(String password, byte[] 
challenge)
-                throws UnsupportedEncodingException {
-                byte[] ntlmHash = ntlmHash(password);
-                return lmResponse(ntlmHash, challenge);
-            }
-
-            /**
-             * Calculates the LM Response for the given challenge, using the 
specified
-             * password.
-             *
-             * @param password The user's password.
-             * @param challenge The Type 2 challenge from the server.
-             *
-             * @return The LM Response.
-             */
-            public static byte[] getLMResponse(String password, byte[] 
challenge)
-                {
-                byte[] lmHash = lmHash(password);
-                return lmResponse(lmHash, challenge);
-            }
-
-            /**
-             * Calculates the NTLMv2 Response for the given challenge, using 
the
-             * specified authentication target, username, password, target 
information
-             * block, and client challenge.
-             *
-             * @param target The authentication target (i.e., domain).
-             * @param user The username. 
-             * @param password The user's password.
-             * @param targetInformation The target information block from the 
Type 2
-             * message.
-             * @param challenge The Type 2 challenge from the server.
-             * @param clientChallenge The random 8-byte client challenge. 
-             *
-             * @return The NTLMv2 Response.
-             */
-            public static byte[] getNTLMv2Response(String target, String user,
-                                                   String password, byte[] 
targetInformation, byte[] challenge,
-                                                   byte[] clientChallenge) 
throws UnsupportedEncodingException {
-                byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
-                byte[] blob = createBlob(targetInformation, clientChallenge);
-                return lmv2Response(ntlmv2Hash, blob, challenge);
-            }
-
-            /**
-             * Calculates the LMv2 Response for the given challenge, using the
-             * specified authentication target, username, password, and client
-             * challenge.
-             *
-             * @param target The authentication target (i.e., domain).
-             * @param user The username.
-             * @param password The user's password.
-             * @param challenge The Type 2 challenge from the server.
-             * @param clientChallenge The random 8-byte client challenge.
-             *
-             * @return The LMv2 Response. 
-             */
-            public static byte[] getLMv2Response(String target, String user,
-                                                 String password, byte[] 
challenge, byte[] clientChallenge)
-                throws UnsupportedEncodingException {
-                byte[] ntlmv2Hash = ntlmv2Hash(target, user, password);
-                return lmv2Response(ntlmv2Hash, clientChallenge, challenge);
-            }
-
-            /**
-             * Calculates the NTLM2 Session Response for the given challenge, 
using the
-             * specified password and client challenge.
-             *
-             * @param password The user's password.
-             * @param challenge The Type 2 challenge from the server.
-             * @param clientChallenge The random 8-byte client challenge.
-             *
-             * @return The NTLM2 Session Response.  This is placed in the NTLM
-             * response field of the Type 3 message; the LM response field 
contains
-             * the client challenge, null-padded to 24 bytes.
-             */
-            public static byte[] getNTLM2SessionResponse(String password,
-                                                         byte[] challenge, 
byte[] clientChallenge) throws UnsupportedEncodingException {
-                byte[] ntlmHash = ntlmHash(password);
-                MD5 md5 = new MD5();
-                md5.update(challenge, 0, challenge.length);
-                md5.update(clientChallenge, 0, clientChallenge.length);
-                byte[] sessionHash = new byte[8];
-                byte[] md5_out = new byte[md5.getDigestSize()];
-                md5.doFinal(md5_out, 0);
-                System.arraycopy(md5_out, 0, sessionHash, 0, 8);
-                return lmResponse(ntlmHash, sessionHash);
-            }
-
-            /**
-             * Creates the LM Hash of the user's password.
-             *
-             * @param password The password.
-             *
-             * @return The LM Hash of the given password, used in the 
calculation
-             * of the LM Response.
-             */
-            private static byte[] lmHash(String password) {
-                /*
-                byte[] oemPassword = password.toUpperCase().getBytes("UTF8");
-                int length = java.lang.Math.min(oemPassword.length, 14);
-                byte[] keyBytes = new byte[14];
-                System.arraycopy(oemPassword, 0, keyBytes, 0, length);
-                Key lowKey = createDESKey(keyBytes, 0);
-                Key highKey = createDESKey(keyBytes, 7);
-                byte[] magicConstant = "KGS!@#$%".getBytes("UTF8");
-                Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
-                des.init(Cipher.ENCRYPT_MODE, lowKey);
-                byte[] lowHash = des.doFinal(magicConstant);
-                des.init(Cipher.ENCRYPT_MODE, highKey);
-                byte[] highHash = des.doFinal(magicConstant);
-                byte[] lmHash = new byte[16];
-                System.arraycopy(lowHash, 0, lmHash, 0, 8);
-                System.arraycopy(highHash, 0, lmHash, 8, 8);
-                return lmHash;
-                */
-                return null;
-            }
-
-            /**
-             * Creates the NTLM Hash of the user's password.
-             *
-             * @param password The password.
-             *
-             * @return The NTLM Hash of the given password, used in the 
calculation
-             * of the NTLM Response and the NTLMv2 and LMv2 Hashes.
-             */
-            private static byte[] ntlmHash(String password) throws 
UnsupportedEncodingException {
-                // FIXME
-                /*
-                byte[] unicodePassword = 
password.getBytes("UnicodeLittleUnmarked");
-                MD4 md4 = new MD4();
-                md4.update(unicodePassword, 0, unicodePassword.length);
-                byte[] ret = new byte[md4.getDigestSize()];
-                return ret;
-                */
-                return null;
-            }
-
-            /**
-             * Creates the NTLMv2 Hash of the user's password.
-             *
-             * @param target The authentication target (i.e., domain).
-             * @param user The username.
-             * @param password The password.
-             *
-             * @return The NTLMv2 Hash, used in the calculation of the NTLMv2
-             * and LMv2 Responses. 
-             */
-            private static byte[] ntlmv2Hash(String target, String user,
-                                             String password) throws 
UnsupportedEncodingException {
-                byte[] ntlmHash = ntlmHash(password);
-                String identity = user.toUpperCase() + target.toUpperCase();
-                return hmacMD5(identity.getBytes("UnicodeLittleUnmarked"), 
ntlmHash);
-            }
-
-            /**
-             * Creates the LM Response from the given hash and Type 2 
challenge.
-             *
-             * @param hash The LM or NTLM Hash.
-             * @param challenge The server challenge from the Type 2 message.
-             *
-             * @return The response (either LM or NTLM, depending on the 
provided
-             * hash).
-             */
-            private static byte[] lmResponse(byte[] hash, byte[] challenge)
-                {
-                /*
-                byte[] keyBytes = new byte[21];
-                System.arraycopy(hash, 0, keyBytes, 0, 16);
-                Key lowKey = createDESKey(keyBytes, 0);
-                Key middleKey = createDESKey(keyBytes, 7);
-                Key highKey = createDESKey(keyBytes, 14);
-                Cipher des = Cipher.getInstance("DES/ECB/NoPadding");
-                des.init(Cipher.ENCRYPT_MODE, lowKey);
-                byte[] lowResponse = des.doFinal(challenge);
-                des.init(Cipher.ENCRYPT_MODE, middleKey);
-                byte[] middleResponse = des.doFinal(challenge);
-                des.init(Cipher.ENCRYPT_MODE, highKey);
-                byte[] highResponse = des.doFinal(challenge);
-                byte[] lmResponse = new byte[24];
-                System.arraycopy(lowResponse, 0, lmResponse, 0, 8);
-                System.arraycopy(middleResponse, 0, lmResponse, 8, 8);
-                System.arraycopy(highResponse, 0, lmResponse, 16, 8);
-                return lmResponse;
-                */
-                return null;
-            }
-
-            /**
-             * Creates the LMv2 Response from the given hash, client data, and
-             * Type 2 challenge.
-             *
-             * @param hash The NTLMv2 Hash.
-             * @param clientData The client data (blob or client challenge).
-             * @param challenge The server challenge from the Type 2 message.
-             *
-             * @return The response (either NTLMv2 or LMv2, depending on the

@@ Diff output truncated at 100000 characters. @@
This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
_______________________________________________
Vexi-svn mailing list
Vexi-svn@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/vexi-svn

Reply via email to