Changeset 9

Show
Ignore:
Timestamp:
10/07/05 21:33:16 (3 years ago)
Author:
dsandler
Message:

Fix for #3: POST/PUT fails for certain files (incl. WebDAV)

The solution involves removing a bunch of character-oriented code in Poolboy
and replacing it with byte-oriented code. Unfortunately, the StringBuffer? is
a really handy tool, and nothing really replicates its behavior (even
java.nio.ByteBuffer?) for byte[]. Hence the new class, ByteArrayBuffer?, which
supports quick repeated appends with only one bulk copy to flatten the array
before calling toByteArray() to extract the data.

[Note that any POST/PUT must now fit in the heap of the JVM; future refactoring
could attempt to make this a zero (or close to it) copy operation, but this
would require serious retooling of the way the passthrough proxy operates.]

Confirmed that some basic WebDAV store operations function as expected.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • feedtree/trunk/src/net/feedtree/util/ByteArrayBuffer.java

    r8 r9  
    55 
    66public class ByteArrayBuffer implements Cloneable { 
     7    // TODO: add insert/remove/slice methods 
     8 
    79    protected LinkedList list; 
    810    protected int length; 
     
    2729    } 
    2830 
     31    public int length() { 
     32        return this.length; 
     33    } 
     34 
    2935    public byte[] toByteArray() { 
    3036        flatten(); 
     
    4147            byte[] bi = (byte[])(i.next()); 
    4248            System.arraycopy(bi, 0, newBuf, p, bi.length); 
     49            p += bi.length; 
    4350        } 
    4451         
     
    4855    } 
    4956     
    50     public void append(byte[] buf) { 
     57    public void attach(byte[] buf) { 
     58        if (buf.length == 0) return; 
     59         
     60        flat = flat && (length == 0); // it's still flat after the first append() 
     61 
     62        System.out.println("#### attaching: " + new String(buf)); 
     63 
    5164        list.add(buf); 
    5265        length += buf.length; 
    53         flat = flat && (length == 1); 
    5466    } 
    5567 
    5668    public void append(byte[] buf, int bufStart, int bufLen) { 
     69        if (bufLen == 0) return; 
     70 
    5771        byte[] slice = new byte[bufLen]; 
    5872        System.arraycopy(buf, bufStart, slice, 0, bufLen); 
    5973 
    60         append(slice); 
     74        attach(slice); 
     75    } 
     76     
     77    public void append(byte[] buf) { 
     78        append(buf, 0, buf.length); 
     79    } 
     80     
     81    public String toString() { 
     82        String s; 
     83        byte[] buf = toByteArray(); 
     84         
     85        flatten(); 
     86        if (length < 22) s = new String(buf); 
     87        else { 
     88            byte[] prefix = new byte[10]; 
     89            byte[] suffix = new byte[10]; 
     90            System.arraycopy(buf, 0, prefix, 0, 10); 
     91            System.arraycopy(buf, length-11, suffix, 0, 10); 
     92            s = new String(prefix) + ".." + new String(suffix); 
     93        } 
     94         
     95        return "<ByteArrayBuffer [" + s + "] len=" + length + ">"; 
    6196    } 
    6297} 
  • feedtree/trunk/src/net/feedtree/web/Poolboy.java

    r4 r9  
    33package net.feedtree.web; 
    44 
     5import net.feedtree.util.ByteArrayBuffer; 
     6 
    57import java.io.*; 
     8import java.nio.ByteBuffer; 
    69import java.net.*; 
    710import java.text.*; 
     
    6568     
    6669    public static class PostRequest extends Request { 
    67         public String body; 
     70        public ByteArrayBuffer body; 
    6871        public String getMethod() { return "POST"; } 
    69         public PostRequest(String u, Map h, StringBuffer _bodyBuf) { 
     72        public PostRequest(String u, Map h, ByteArrayBuffer _bodyBuf) { 
    7073            super(u,h); 
    7174            setBody(_bodyBuf); 
    7275        } 
    73         public PostRequest(String u, Map h, String _body) { 
     76        public PostRequest(String u, Map h, byte[] _body) { 
    7477            super(u,h); 
    7578            setBody(_body); 
    7679        } 
    77         public void setBody(String _body) { body = _body; } 
    78         public void setBody(StringBuffer _bodyBuf) { body = _bodyBuf.toString(); } 
     80        public void setBody(byte[] _body) { body = new ByteArrayBuffer(_body); } 
     81        public void setBody(ByteArrayBuffer _bodyBuf) { body = _bodyBuf; } 
    7982    } 
    8083    public static class PutRequest extends PostRequest { 
    8184        public String getMethod() { return "PUT"; } 
    82         public PutRequest(String u, Map h, StringBuffer _bodyBuf) { 
     85        public PutRequest(String u, Map h, ByteArrayBuffer _bodyBuf) { 
    8386            super(u,h,_bodyBuf); 
    8487        } 
    85         public PutRequest(String u, Map h, String _body) { 
     88        public PutRequest(String u, Map h, byte[] _body) { 
    8689            super(u,h,_body); 
    8790        } 
     
    98101            public void println() { print("\r\n"); } 
    99102        } 
     103         
     104        protected String readLineFromStream(BufferedInputStream bis)  
     105            throws IOException 
     106        { 
     107            String s = ""; 
     108             
     109            int ch = bis.read(); 
     110            boolean stop = false; 
     111            while(!stop) { 
     112                switch (ch) { 
     113                    case '\r': 
     114                    case '\n': 
     115                    case -1: 
     116                        stop = true; 
     117                        break; 
     118                    default: 
     119                        s += (char)ch; 
     120                        ch = bis.read(); 
     121                        break; 
     122                } 
     123            } 
     124            // possibly eat CRLF newlines 
     125            if (ch == '\r') { 
     126                bis.mark(2); 
     127                int next = bis.read(); 
     128                if (next != '\n') reset(); 
     129            } 
     130             
     131            return s; 
     132        } 
     133 
     134        protected static final int BUFSIZ = 4096; 
    100135 
    101136        protected boolean PRINT_EXCEPTIONS = true; 
    102137         
    103138        protected Socket socket; 
    104         protected BufferedReader input; 
     139        protected BufferedInputStream rawInput; 
     140        //protected BufferedReader input; 
    105141        protected OutputStream rawOutput; 
    106142        protected WebPrintWriter output; 
     
    132168        protected void attach(Socket _socket) throws java.io.IOException { 
    133169            socket = _socket; 
    134             input = new BufferedReader( 
    135                 new InputStreamReader(socket.getInputStream())); 
     170            rawInput = new BufferedInputStream(socket.getInputStream()); 
    136171            rawOutput = socket.getOutputStream(); 
    137172            output = new WebPrintWriter( 
     
    219254            try { 
    220255                String request, uri; 
    221                 request = input.readLine(); 
     256                 
     257                request = readLineFromStream(rawInput); 
    222258                boolean isGet = request.startsWith("GET ") || request.startsWith("HEAD "); 
    223259                boolean isPost = request.startsWith("POST ") || request.startsWith("PUT "); 
     
    225261                    uri = (request.split(" "))[1];                           
    226262                    Map headers = new HashMap(); 
    227                     String headerLine = input.readLine(); 
     263                    String headerLine = readLineFromStream(rawInput); 
    228264                    while (!headerLine.equals("")) { 
    229265                        Matcher m = kHeaderPattern.matcher(headerLine); 
     
    231267                            headers.put(m.group(1), m.group(2)); 
    232268                        } 
    233                         headerLine = input.readLine(); 
     269                        headerLine = readLineFromStream(rawInput); 
    234270                    } 
    235271                     
    236                     StringBuffer postBuf = null; 
     272                    ByteArrayBuffer postBuf = null; 
    237273 
    238274                    Request requestObj; 
    239275 
    240276                    if (isPost) { 
    241                         postBuf = new StringBuffer(); 
    242                         char buf[] = new char[4096]; 
     277                        postBuf = new ByteArrayBuffer(); 
     278                        byte buf[] = new byte[BUFSIZ]; 
    243279                        int len; 
    244280                        int contentLength = -1; 
     
    249285                        System.out.println("[Poolboy.run] POST/PUT content-length = " + contentLength); 
    250286                        if (contentLength > 0) { 
    251                             while (contentLength > 0) { 
    252                                 len = input.read(buf, 0, 4096); 
     287                            int readLength = 0; 
     288                            while (readLength < contentLength) { 
     289                                len = rawInput.read(buf, 0, BUFSIZ); 
     290                                System.out.println("[Poolboy.run] read " 
     291                                    + readLength + "/" + contentLength 
     292                                    + " bytes (" + len + " just now)"); 
    253293                                if (len >= 0) { 
    254294                                    postBuf.append(buf, 0, len); 
     
    258298                                    + " but read() returned " + len  
    259299                                    + " before all content had been read."); 
    260                                     break; 
     300 
     301                                    //System.out.println("[Poolboy.run] What we got was: >>>\n" + postBuf + "\n<<<"); 
     302                                    break; 
    261303                                } 
    262                                 contentLength -= len; 
     304                                readLength += len; 
    263305                            } 
    264306                        } else { 
    265                             while ( (len = input.read(buf, 0, 4096)) >= 0 ) 
     307                            while ( (len = rawInput.read(buf, 0, BUFSIZ)) >= 0 ) 
    266308                                postBuf.append(buf, 0, len); 
    267309                        } 
  • feedtree/trunk/src/net/feedtree/web/WebProxyHandler.java

    r4 r9  
    7575        cx.connect(); 
    7676        if (request instanceof Poolboy.PostRequest) { 
    77             PrintWriter out = new PrintWriter(cx.getOutputStream()); 
    78             out.print(((Poolboy.PostRequest)request).body); 
    79             out.close(); 
     77            cx.getOutputStream().write( 
     78                ((Poolboy.PostRequest)request).body.toByteArray()); 
    8079        } 
    8180    }