Parcourir la source

URIHandler: file,http

Ranides Atterwim il y a 10 ans
Parent
commit
766d2c6922

+ 26 - 0
assira/src/main/java/net/ranides/assira/functional/CharPredicate.java

@@ -0,0 +1,26 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.functional;
+
+import java.util.function.Predicate;
+
+/**
+ *
+ * @author msieron
+ */
+
+
+public interface CharPredicate extends Predicate<Character> {
+
+    public boolean test(char c);
+    
+    @Override
+    public default boolean test(Character c) {
+        return c!=null && test(c.charValue());
+    }
+    
+}

+ 2 - 3
assira/src/main/java/net/ranides/assira/io/uri/URIResolver.java

@@ -10,7 +10,6 @@ import java.io.File;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.nio.charset.Charset;
 import java.util.Map;
 import java.util.ServiceLoader;
 import net.ranides.assira.collection.maps.HashMap;
@@ -19,7 +18,7 @@ import net.ranides.assira.collection.maps.HashMap;
  *
  * @author Ranides Atterwim <ranides@gmail.com>
  */
-public class URIResolver {
+public final class URIResolver {
     
     public static final URIResolver DEFAULT = new URIResolver(ServiceLoader.load(URIHandler.class));
     
@@ -32,7 +31,7 @@ public class URIResolver {
     public URIResolver(Iterable<URIHandler> handlers) {
         this.handlers = new HashMap<>();
         for(URIHandler handler : handlers) {
-            DEFAULT.register(handler);
+            this.register(handler);
         }
         
     }

+ 14 - 2
assira/src/main/java/net/ranides/assira/io/uri/URIUtils.java

@@ -19,6 +19,7 @@ import net.ranides.assira.collection.maps.MapCollectors;
 import net.ranides.assira.collection.maps.MultiMap;
 import net.ranides.assira.text.Charsets;
 import net.ranides.assira.text.StringTraits;
+import net.ranides.assira.text.StringUtils;
 
 /**
  *
@@ -59,8 +60,19 @@ public final class URIUtils {
     public static File getFile(URI uri) {
         String p = uri.getSchemeSpecificPart();
         String q = uri.getQuery();
-        int qs = (null==q ? 0 : q.length()+1);
-        return new File(p.substring(2, p.length() - qs));
+        int qe = (null==q ? 0 : q.length()+1);
+        
+        // strip repeated "/"
+        int n = p.length();
+        int offset = 0;
+        while( offset<n && '/'==p.charAt(offset) ) { 
+			offset++; 
+		}
+        if(offset>0) {
+            offset--;
+        }
+        
+        return new File(p.substring(offset, p.length() - qe));
     }
     
     public static MultiMap<String,String> getParams(URI uri) {

+ 0 - 7
assira/src/main/java/net/ranides/assira/io/uri/impl/CHandler.java

@@ -14,17 +14,11 @@ import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Reader;
 import java.io.Writer;
-import java.net.HttpURLConnection;
-import java.net.MalformedURLException;
 import java.net.URI;
-import java.net.URL;
 import java.nio.charset.Charset;
 import java.nio.file.Path;
 import java.time.Instant;
-import java.util.Date;
 import java.util.Set;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.io.IOStreams;
 import net.ranides.assira.io.uri.URITime;
@@ -32,7 +26,6 @@ import net.ranides.assira.io.uri.URIFlags;
 import net.ranides.assira.io.uri.URIHandle;
 import net.ranides.assira.io.uri.URIHandler;
 import net.ranides.assira.text.Charsets;
-import net.ranides.assira.text.StringTraits;
 
 /**
  *

+ 8 - 14
assira/src/main/java/net/ranides/assira/io/uri/impl/CHttpHandler.java

@@ -29,6 +29,8 @@ import net.ranides.assira.io.uri.URIFlags;
 import net.ranides.assira.io.uri.URIHandle;
 import net.ranides.assira.text.Charsets;
 import net.ranides.assira.text.StringTraits;
+import net.ranides.assira.trace.LoggerUtils;
+import org.slf4j.Logger;
 
 /**
  *
@@ -36,11 +38,11 @@ import net.ranides.assira.text.StringTraits;
  */
 public class CHttpHandler extends CHandler {
     
+    private static final Logger LOGGER = LoggerUtils.getLogger();
+    
     static final CHttpHandler THAT = new CHttpHandler();
     
     private static final Pattern RE_CHARSET = Pattern.compile(";[ ]*charset=([^; ]+)");
-    
-    private static final String HTTP_NS = "HTTP: unsupported";
 
     @Override
     public URIHandle resolve(URI uri) throws IOException {
@@ -51,7 +53,7 @@ public class CHttpHandler extends CHandler {
     public String scheme() {
         return "http";
     }
-
+    
     @Override
     public URI uri(URIHandle ustream) throws IOException {
         return ((CHttpHandle)ustream).uri;
@@ -68,10 +70,11 @@ public class CHttpHandler extends CHandler {
         Set<URIFlags> re = URIFlags.collect(URIFlags.FILE);
         try {
             HttpURLConnection c = connect(ustream, "HEAD");
-            re.add(URIFlags.READABLE);
             if(2 == (c.getResponseCode() / 100)) {
                 re.add(URIFlags.EXISTS);
+                re.add(URIFlags.READABLE);
             }
+            
             if(StringTraits.starts(c.getContentType(), "text/")) {
                 re.add(URIFlags.TEXT);
             } else {
@@ -84,7 +87,7 @@ public class CHttpHandler extends CHandler {
                 re.add(URIFlags.SEEK);
             }
         } catch(IOException cause) {
-            // do nothing
+            LOGGER.warn("URI.flags: HTTP error", cause);
         }
         return re;
     }
@@ -161,15 +164,6 @@ public class CHttpHandler extends CHandler {
         return new OutputStreamWriter(c.getOutputStream(), getContentCharset(c.getContentType()));
     }
 
-    @Override
-    public void copy(URIHandle ustream, URIHandle location) throws IOException {
-        try(InputStream istream = ustream.istream()) {
-            try(OutputStream ostream = location.ostream()) {
-                IOStreams.copy(istream, ostream);
-            }
-        } 
-    }
-    
     private HttpURLConnection connect(URIHandle ustream, String method) throws IOException {
         HttpURLConnection c = (HttpURLConnection)((CHttpHandle)ustream).uri.toURL().openConnection();
         c.setRequestMethod(method);

+ 22 - 4
assira/src/main/java/net/ranides/assira/text/StringUtils.java

@@ -18,6 +18,7 @@ import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import net.ranides.assira.collection.query.CQuery;
 import net.ranides.assira.collection.query.CQueryBuilder;
+import net.ranides.assira.functional.CharPredicate;
 import net.ranides.assira.lexer.CharStreamer;
 import net.ranides.assira.math.MathUtils;
 import net.ranides.assira.reflection.util.ReflectUtils;
@@ -399,17 +400,33 @@ public final class StringUtils {
     }
 	
     public static String ltrim(String text) {
+        return ltrim(text, Character::isWhitespace);
+    }
+    
+    public static String ltrim(String text, char ch) {
+        return ltrim(text, c -> ch==c);
+    }
+    
+    public static String ltrim(String text, CharPredicate cp) {
         if(null == text) {
             return "";
         }
         int n = text.length(), offset = 0;
-        while( offset<n && Character.isWhitespace(text.charAt(offset)) ) { 
+        while( offset<n && cp.test(text.charAt(offset)) ) { 
 			offset++; 
 		}
         return text.substring(offset);
     }
-
+    
     public static String rtrim(String text) {
+        return rtrim(text, Character::isWhitespace);
+    }
+    
+    public static String rtrim(String text, char ch) {
+        return rtrim(text, c -> c==ch);
+    }
+
+    public static String rtrim(String text, CharPredicate cp) {
         if(null == text) {
             return "";
         }
@@ -807,7 +824,7 @@ public final class StringUtils {
     public static int length(String value) {
 		return null == value ? 0 : value.length();
 	}
-    
+        
     public static int indexOf(CharSequence text, CharSequence pattern) {
         return indexOf(text, pattern, 0);
     }
@@ -816,6 +833,7 @@ public final class StringUtils {
      * We use Knuth–Morris–Pratt algorithm. Complexity: Θ(n)
      * @param text
      * @param pattern
+     * @param offset
      * @return 
      */
 	public static int indexOf(CharSequence text, CharSequence pattern, int offset) {
@@ -1028,5 +1046,5 @@ public final class StringUtils {
         }
         
     }
-	
+    
 }

+ 115 - 103
assira/src/test/java/net/ranides/assira/text/URIUtilsTest.java

@@ -1,103 +1,115 @@
-/*
- * @author Ranides Atterwim <ranides@gmail.com>
- * @copyright Ranides Atterwim
- * @license WTFPL
- * @url http://ranides.net/projects/assira
- */
-package net.ranides.assira.text;
-
-import net.ranides.assira.io.uri.URIUtils;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import net.ranides.assira.collection.maps.HashMultiMap;
-import org.junit.Test;
-import static net.ranides.assira.junit.NewAssert.*;
-
-/**
- *
- * @author Ranides Atterwim <ranides@gmail.com>
- */
-public class URIUtilsTest {
-    
-    @Test
-    public void testEncodeURL() {
-        assertEquals("hello%3Aworld%3Fparam%3D5", URIUtils.encodeURL("hello:world?param=5"));
-        
-        assertEquals("hello%3Aworld%3Fparam%3D5", URIUtils.encodeURL("hello:world?param=5", new FCharset("UTF-8")));
-        
-        assertThrows(AssertionError.class, ()->{
-            URIUtils.encodeURL("hello:world?param=5", new FCharset("UFC888"));
-        });
-        
-    }
-    
-    @Test
-    public void testDecodeURL() {
-        assertEquals("hello:world?param=5", URIUtils.decodeURL("hello%3Aworld%3Fparam%3D5"));
-        
-        assertEquals("hello:world?param=5", URIUtils.decodeURL("hello%3Aworld%3Fparam%3D5", new FCharset("UTF-8")));
-        
-        assertThrows(AssertionError.class, ()->{
-            URIUtils.decodeURL("hello%3Aworld%3Fparam%3D5", new FCharset("UFC888"));
-        });
-    }
-    
-    @Test
-    public void testGetQueryParams() throws URISyntaxException {
-        URI u1 = new URI("file://root?charset=UTF-8&endl=unix&follow&fs=ntfs&a=1&a=2");
-        URI u2 = new URI("file://root?charset=UTF-8");
-        URI u3 = new URI("file://root?charset");
-        URI u4 = new URI("file://root?");
-        URI u5 = new URI("file://root");
-        
-        Map<String,String> exp1 = new HashMultiMap<>();
-        exp1.put("endl", "unix");
-        exp1.put("charset", "UTF-8");
-        exp1.put("follow", "");
-        exp1.put("fs", "ntfs");
-        exp1.put("a", "2");
-        exp1.put("a", "1");
-        assertEquivalent(exp1, URIUtils.getParams(u1));
-        
-        Map<String,String> exp2 = new HashMap<>();
-        exp2.put("charset", "UTF-8");
-        assertEquivalent(exp2, URIUtils.getParams(u2));
-        
-        Map<String,String> exp3 = new HashMap<>();
-        exp3.put("charset", "");
-        assertEquivalent(exp3, URIUtils.getParams(u3));
-        
-        assertEquivalent(Collections.emptyMap(), URIUtils.getParams(u4));
-        assertEquivalent(Collections.emptyMap(), URIUtils.getParams(u5));
-    }
-    
-    private static final class FCharset extends Charset {
-
-        public FCharset(String name) {
-            super(name, new String[0]);
-        }
-
-        @Override
-        public boolean contains(Charset cs) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public CharsetDecoder newDecoder() {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public CharsetEncoder newEncoder() {
-            throw new UnsupportedOperationException();
-        }
-        
-    }
-	
-}
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.io.uri;
+
+import net.ranides.assira.io.uri.URIUtils;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import net.ranides.assira.collection.maps.HashMultiMap;
+import org.junit.Test;
+import static net.ranides.assira.junit.NewAssert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class URIUtilsTest {
+    
+    @Test
+    public void testEncodeURL() {
+        assertEquals("hello%3Aworld%3Fparam%3D5", URIUtils.encodeURL("hello:world?param=5"));
+        
+        assertEquals("hello%3Aworld%3Fparam%3D5", URIUtils.encodeURL("hello:world?param=5", new FCharset("UTF-8")));
+        
+        assertThrows(AssertionError.class, ()->{
+            URIUtils.encodeURL("hello:world?param=5", new FCharset("UFC888"));
+        });
+        
+    }
+    
+    @Test
+    public void testDecodeURL() {
+        assertEquals("hello:world?param=5", URIUtils.decodeURL("hello%3Aworld%3Fparam%3D5"));
+        
+        assertEquals("hello:world?param=5", URIUtils.decodeURL("hello%3Aworld%3Fparam%3D5", new FCharset("UTF-8")));
+        
+        assertThrows(AssertionError.class, ()->{
+            URIUtils.decodeURL("hello%3Aworld%3Fparam%3D5", new FCharset("UFC888"));
+        });
+    }
+    
+    @Test
+    public void testGetQueryParams() throws URISyntaxException {
+        URI u1 = new URI("file://root?charset=UTF-8&endl=unix&follow&fs=ntfs&a=1&a=2");
+        URI u2 = new URI("file://root?charset=UTF-8");
+        URI u3 = new URI("file://root?charset");
+        URI u4 = new URI("file://root?");
+        URI u5 = new URI("file://root");
+        
+        Map<String,String> exp1 = new HashMultiMap<>();
+        exp1.put("endl", "unix");
+        exp1.put("charset", "UTF-8");
+        exp1.put("follow", "");
+        exp1.put("fs", "ntfs");
+        exp1.put("a", "2");
+        exp1.put("a", "1");
+        assertEquivalent(exp1, URIUtils.getParams(u1));
+        
+        Map<String,String> exp2 = new HashMap<>();
+        exp2.put("charset", "UTF-8");
+        assertEquivalent(exp2, URIUtils.getParams(u2));
+        
+        Map<String,String> exp3 = new HashMap<>();
+        exp3.put("charset", "");
+        assertEquivalent(exp3, URIUtils.getParams(u3));
+        
+        assertEquivalent(Collections.emptyMap(), URIUtils.getParams(u4));
+        assertEquivalent(Collections.emptyMap(), URIUtils.getParams(u5));
+    }
+    
+    private static final class FCharset extends Charset {
+
+        public FCharset(String name) {
+            super(name, new String[0]);
+        }
+
+        @Override
+        public boolean contains(Charset cs) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CharsetDecoder newDecoder() {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public CharsetEncoder newEncoder() {
+            throw new UnsupportedOperationException();
+        }
+        
+    }
+    
+    @Test
+    public void testGetFile() throws URISyntaxException {
+        assertEquals("/home/data/file", URIUtils.getFile(new URI("file:/home/data/file")).toString());
+        assertEquals("/home/data/file", URIUtils.getFile(new URI("file://home/data/file")).toString());
+        assertEquals("/home/data/file", URIUtils.getFile(new URI("file:///home/data/file")).toString());
+         
+        assertEquals("/domain.net/path/to/file", URIUtils.getFile(new URI("http:///domain.net/path/to/file")).toString());
+        assertEquals("/domain.net/path/to/file", URIUtils.getFile(new URI("http://domain.net/path/to/file")).toString());
+        assertEquals("/domain.net/path/to/file", URIUtils.getFile(new URI("http:/domain.net/path/to/file")).toString());
+        assertEquals("domain.net/path/to/file", URIUtils.getFile(new URI("http:domain.net/path/to/file")).toString());
+    }
+	
+}

+ 39 - 2
assira/src/test/java/net/ranides/assira/io/uri/impl/CHttpHandlerTest.java

@@ -6,15 +6,18 @@
  */
 package net.ranides.assira.io.uri.impl;
 
+import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.net.URI;
 import java.net.URISyntaxException;
 import java.time.Duration;
 import java.time.Instant;
+import java.util.Arrays;
 import net.ranides.assira.io.uri.URIFlags;
 import static net.ranides.assira.io.uri.URIFlags.*;
 import net.ranides.assira.io.uri.URIHandle;
+import net.ranides.assira.io.uri.URIResolver;
 import net.ranides.assira.io.uri.URITime;
 import static net.ranides.assira.junit.NewAssert.*;
 import net.ranides.assira.text.Charsets;
@@ -28,7 +31,7 @@ import org.junit.Test;
 public class CHttpHandlerTest {
 
     @Test
-    public void testDynamicText() throws IOException, URISyntaxException {
+    public void testDynamicList() throws IOException, URISyntaxException {
         
         URI uri = new URI("http://maven.ranides.net/net/ranides/assira/0.58/");
         URIHandle handle = CHttpHandler.THAT.resolve(uri);
@@ -56,6 +59,9 @@ public class CHttpHandlerTest {
         assertEquals("mlns=\"", IOStrings.read(handle.istream(10,15), handle.charset()));
         assertEquals(6964, IOStrings.read(handle.reader()).length());
         assertEquals(Instant.parse("2013-03-08T01:58:31Z"), handle.time(URITime.MODIFIED));
+        assertThrows(IOException.class, ()->{
+            handle.time(URITime.ACCESSED);
+        });
         assertEquals(6964, handle.size());
     }
     
@@ -67,7 +73,7 @@ public class CHttpHandlerTest {
         assertEquals(uri, handle.uri());
         assertEquals(Charsets.UTF8, handle.charset());
         assertEquals(false, handle.exists());
-        assertEquals(URIFlags.constant(READABLE, FILE, TEXT, SIZE), handle.flags());
+        assertEquals(URIFlags.constant(FILE, TEXT, SIZE), handle.flags());
         assertEquals(Instant.now(), handle.time(URITime.MODIFIED), Duration.ofMinutes(60));
         
         assertThrows(IOException.class, ()->{
@@ -83,6 +89,16 @@ public class CHttpHandlerTest {
         });
     }
     
+    @Test
+    public void testDynamicPage() throws IOException, URISyntaxException {
+        URI uri = new URI("http://info.ranides.net/");
+        URIHandle handle = CHttpHandler.THAT.resolve(uri);
+        assertEquals(URIFlags.constant(READABLE, EXISTS, FILE, TEXT), handle.flags());
+        assertEquals("/DTD XHTML 1.0 Trans", IOStrings.read(handle.istream(30, 50), Charsets.UTF8));
+        assertEquals(-1, handle.size());
+        assertTrue(IOStrings.read(handle.reader()).contains("This program is free software;"));
+        assertTrue(IOStrings.read(handle.reader(Charsets.UTF8)).contains("This program is free software;"));
+    }
     
     @Test
     public void testBinary() throws IOException, URISyntaxException {   
@@ -101,8 +117,29 @@ public class CHttpHandlerTest {
         assertEquals(Instant.parse("2013-03-08T01:58:30Z"), handle.time(URITime.MODIFIED));
         assertEquals(40, handle.size());
         
+        assertEquals("61b37c0973bc00bd33606a2f5050e64baec3a7df", IOStrings.read(handle.istream(), Charsets.US_ASCII));
+        assertEquals("61b37c0973bc00bd33606a2f5050e64baec3a7df", IOStrings.read(handle.reader(Charsets.US_ASCII)));
     }
     
+    @Test
+    public void testError() throws IOException, URISyntaxException { 
+        URIHandle handle1 = CHttpHandler.THAT.resolve(new URI("http://m.maven.ranides.net/"));
+        assertEquals(URIFlags.constant(FILE), handle1.flags());
+        
+        URIHandle handle2 = CHttpHandler.THAT.resolve(new URI("http://no.domain/"));
+        assertEquals(URIFlags.constant(FILE), handle2.flags());
+    }
     
+    @Test
+    public void testCopy() throws IOException, URISyntaxException {
+        URI uri = new URI("http://maven.ranides.net/net/ranides/assira/0.58/assira-0.58.jar.sha1");
+        URIHandle input = CHttpHandler.THAT.resolve(uri);
+        File file = File.createTempFile("CHttpHandler", ".test");
+        file.deleteOnExit();
+        URIHandle target = new URIResolver(Arrays.asList(CFileHandler.THAT)).resolve(file);
+        
+        input.copy(target);
+        assertEquals("61b37c0973bc00bd33606a2f5050e64baec3a7df",IOStrings.read(file, Charsets.UTF8));
+    }
     
 }