Netzprogrammierung: URL-Schemata Robert Tolksdorf und Peter Löhr Überblick 1. Vereinheitlichte Dienstnutzung in Java 2. Eigene URL-Schemata 3. Push- und Pull-Interaktion Robert Tolksdorf und Peter Löhr 3 24 28 2 Vereinheitlichte Dienstnutzung in Java Robert Tolksdorf und Peter Löhr URI, URL, URN • Uniform Resource Identifier - URI: „ ..... is a compact string of characters for identifying an abstract or physical resource“ [RFC 2396] • Syntax: • absoluteURI = scheme ":" ..... • relativeURI = ..... • ..... • Beispiele: • • • • • • • ftp://ftp.is.co.za/rfc/rfc1808.txt gopher://spinaltap.micro.umn.edu/00/Weather/Los%20Angeles http://www.math.uio.no/faq/compression-faq/part1.html mailto:[email protected] news:comp.infosystems.www.servers.unix file:/users/lohr/tmp/abc urn:isbn:n-nn-nnnnnn-n • URI-Schema (scheme) typisiert URIs (ftp, gopher, fax, file,…) Robert Tolksdorf und Peter Löhr 4 URI, URL, URN • Uniform Resource Locator - URL: „ ... is a compact string representation for a resource available via the Internet.“ [RFC 1738] • URL ist ein URI, dessen Schema auf die Zugreifbarkeit der Ressource im Netz hinweist, • z.B. ftp://ftp.is.co.za/rfc/rfc1808.txt • Uniform Resource Name - URN: „ ... are intended to serve as persistent, location-independent, resource identifiers and are designed to make it easy to map other namespaces into URN-space“ [RFC 2141] • • • • Syntax: URN = "urn:" nameSpaceIdentifier ":" string z.B. urn:isbn:n-nn-nnnnnn-n Ist eher URI, der Eigenschaft der Resource beschreibt URN-Namensraum strukturiert URNs (isbn, issn, ...) Robert Tolksdorf und Peter Löhr 5 URL • URL-Schemata sind für Internet-Dienste definiert und vereinheitlichen damit deren Nutzung syntaktisch: • http://grunge.cs.tu-berlin.de:8000/ • ftp://ftp.cs.tu-berlin.de/pub/net/www • mailto:[email protected] • Form: http://grunge.cs.tu-berlin.de:8000/res/data.html#top Protokoll Rechnername Portnummer Pfad Stelle Ressource • Für URLs ist nur die Syntax definiert; die Semantik hängt vom Schema ab (das durch ein Protokoll umgesetzt wird). Robert Tolksdorf und Peter Löhr 6 java.net.URL • URLs als Objekte der Java-klasse java.net.URL • Konstruktoren: • Aus Zeichenkette: • URL(String spec) • Aus Komponenten: • URL(String protocol, String host, String file) • URL(String protocol, String host, int port, String file) • Relativ zu anderer URL • URL(URL context, String spec) • Mit eigenem Protokollobjekt • URL(String protocol, String host, int port, String file, URLStreamHandler handler) • URL(URL context, String spec, URLStreamHandler handler) Robert Tolksdorf und Peter Löhr 7 java.net.URL • Bestandteile erfragen: • • • • • • • • • String String String String int String String String String getAuthority() getFile() getHost() getPath() getPort() getProtocol() getQuery() getRef() getUserInfo() • Vergleichen: • boolean equals(Object obj) • boolean sameFile(URL other) • Darstellung als Zeichenkette • String toString() Robert Tolksdorf und Peter Löhr 8 ... und zur Abwechslung mal Perl $ cat uri #!/usr/bin/perl use URI; $url = URI->new($ARGV[0]); print "Scheme: ", $url->scheme( ), "\n"; print "Userinfo: ", $url->userinfo( ), "\n"; print "Hostname: ", $url->host( ), "\n"; print "Port: ", $url->port( ), "\n"; print "Path: ", $url->path( ), "\n"; print "Query: ", $url->query( ), "\n"; $ uri http://www.cnn.com:[email protected]:80/research.php Scheme: http Userinfo: www.cnn.com:mainpage Nicht Bestandteil der HTTP_ Hostname: 129.170.213.101 Spezifikation, aber von vielen Port: 80 Browsern akzeptiert (und meist Path: /research.php ignoriert) (Sicherheitsrisiko!) Query: $ Robert Tolksdorf und Peter Löhr 9 URLConnection • Man kann sich über eine „Verbindung“ zu einer durch eine URL bezeichnete Ressource „verbinden“: • URLConnection openConnection() • Das für das Schema zuständige Protokoll muss implementiert sein; Prüfung (Unix): currentjdk/classes $ jar tf classes.jar | grep URLConnection.class sun/net/www/protocol/ftp/FtpURLConnection.class sun/net/www/protocol/gopher/GopherURLConnection.class sun/net/www/protocol/http/HttpURLConnection.class sun/net/www/protocol/mailto/MailToURLConnection.class java/net/HttpURLConnection.class sun/net/www/protocol/jar/JarURLConnection.class java/net/JarURLConnection.class sun/net/www/protocol/file/FileURLConnection.class sun/net/www/URLConnection.class java/net/URLConnection.class currentjdk/classes $ Robert Tolksdorf und Peter Löhr 10 Beispiel: Dateien lesen ... import java.net.*; import java.io.*; public class GetFile { public static void main(String[] argv) throws IOException { URL url = new URL(argv[0]); URLConnection connection = url.openConnection(); BufferedReader in = new BufferedReader(new InputStreamReader( connection.getInputStream())); String line; while ((line = in.readLine()) != null) System.out.println(line); in.close(); } } Robert Tolksdorf und Peter Löhr 11 ... mit Schema http: $ java GetFile http://www.mi.fu-berlin.de/~lohr/advent.txt Es treibt der Wind im Winterwalde die Flockenherde wie ein Hirt, und manche Tanne ahnt, wie balde sie fromm und lichterheilig wird, und lauscht hinaus. Den wei?en Wegen streckt sie die Zweige hin ? bereit, und wehrt dem Wind und w?chst entgegen der einen Nacht der Herrlichkeit. (Rilke) $ Robert Tolksdorf und Peter Löhr 12 ... mit Schema ftp: $ java GetFile drwxrwxr-x drwsr-xr-x drwx-----drwxrws--drwxrws--drwxr-xr-x drwxrwxr-t ftp://ftp.inf.fu-berlin.de 4 ftp ftp 4096 Oct 26 04:05 2 ftp ftp 4096 Feb 8 2008 2 ftp ftp 4096 Oct 27 2005 2 ftp ftp 4096 Oct 20 21:16 2 ftp ftp 4096 May 30 2008 2 ftp ftp 4096 Aug 2 2007 50 ftp ftp 4096 Oct 7 14:47 incoming log lost+found mathfilm2008 mevis msgs pub $ java GetFile ftp://ftp.inf.fu-berlin.de/pub/readme This is only a local File-Hierarchy of 'math.fu-berlin.de' ! ==== For public-domain Software and other unspecific Information use server 'ftp.fu-berlin.de' (do anonymous ftp at ftp.fu-berlin.de. ........... ........................... $ Robert Tolksdorf und Peter Löhr 13 ... mit Schema file: Der Effekt von cat uri wird auch erzielt mit $ java GetFile file:/users/lohr/tmp/uri #!/usr/bin/perl use URI; $url = URI->new($ARGV[0]); print "Scheme: ", $url->scheme( ), "\n"; print "Userinfo: ", $url->userinfo( ), "\n"; print "Hostname: ", $url->host( ), "\n"; print "Port: ", $url->port( ), "\n"; print "Path: ", $url->path( ), "\n"; print "Query: ", $url->query( ), "\n"; $ (Warum einfach, wenn es auch kompliziert geht! ;-) Robert Tolksdorf und Peter Löhr 14 Datei schreiben mit Schema ftp: import java.net.*; import java.io.*; public class PutFile { public static void main(String[] argv) throws IOException { URL url = new URL("ftp://ftp.inf.fu-berlin.de/incoming/lohrfile"); URLConnection connection = url.openConnection(); PrintWriter out = new PrintWriter(connection.getOutputStream()); out.println("Vom Eise befreit sind Strom und Bäche"); out.close(); } } $ java PutFile $ java GetFile ftp://ftp.inf.fu-berlin.de/incoming/ drwxr-xr-x 2 ftp ftp 4096 Jul 6 03:05 kia -rw-r--r-1 ftp ftp 38 Dec 12 07:56 lohrfile drwxrwx--2 ftp ftp 4096 Sep 29 12:45 tcimage $ Robert Tolksdorf und Peter Löhr 15 java.net.URLConnection • Zustände von URLConnection • nicht verbunden • verbunden • geschlossen • connect() wechselt von nicht verbunden zu verbunden, falls noch nicht verbunden. • Einige Methoden, die eine Verbindung brauchen, wechseln implizit zu verbunden (getInputStream, ... ) Robert Tolksdorf und Peter Löhr 16 java.net.URLConnection • Abfragen der Eigenschaften der Ressource • • • • Object getContent() (z.B. Eingabestrom-Objekt) String getHeaderField(String name) InputStream getInputStream() OutputStream getOutputStream() • Übliche Kopfzeilen-Information • • • • • • getContentEncoding() (Kompression) getContentLength() getContentType() (MIME-Typ und Zeichensatz) getDate() getExpiration() getLastModifed() • ... sind unter Umständen errechnet oder leer Robert Tolksdorf und Peter Löhr 17 Informationen über eine Seite holen import java.net.*; import java.io.*; public class GetInfo { public static void main(String[] argv) throws Exception{ URL page = new URL(argv[0]); URLConnection connection = page.openConnection(); System.out.println("Länge: " +connection.getContentLength()); System.out.println("Typ: " +connection.getContentType()); System.out.println("Klasse:\n"+connection.getContent().getClass()); } } $ java GetInfo http://www.inf.fu-berlin.de L?nge: 23761 Typ: text/html; charset=utf-8 Klasse: class sun.net.www.protocol.http.HttpURLConnection$HttpInputStream $ Robert Tolksdorf und Peter Löhr 18 Informationen über eine Seite holen $ java GetInfo http://www.mi.fu-berlin.de/~lohr/classes/echo/Factory.class L?nge: 227 Typ: application/x-java-vm Klasse: class sun.net.www.protocol.http.HttpURLConnection$HttpInputStream $ java GetInfo http://www.inf.fu-berlin.de/styles/inst-title-600x400.jpg L?nge: 11947 Typ: image/jpeg Klasse: class sun.awt.image.URLImageSource $ $ java GetInfo ftp://ftp.ietf.org L?nge: -1 Typ: content/unknown Klasse: class sun.net.www.protocol.ftp.FtpURLConnection$FtpInputStream $ Robert Tolksdorf und Peter Löhr 19 java.net.URLConnection • Setzen von Eigenschaften der Anfrage • setAllowUserInteraction(boolean b) Anfrage findet in Interaktion mit dem Benutzer statt • setDoInput(boolean b) Klient will von Verbindung lesen (Voreinstellung: true) • setDoOutput(boolean b) Klient will auf Verbindung schreiben (Voreinstellung: false) • setIfModifiedSince(String s) IfModifiedSince-Kopfzeile setzen • setUseCaches(boolean b) Zwischenspeichern von Daten erlauben (Voreinstellung: true) • setRequestProperty(String key, String value) Kopfzeile setzen Robert Tolksdorf und Peter Löhr 20 Beispiel: Sprache einstellen import java.net.*; import java.io.*; public class GetInfoLang { public static void main(String[] argv) throws Exception{ URL page=new URL(argv[0]); URLConnection connection=page.openConnection(); if (argv.length == 2) connection.setRequestProperty("Accept-Language",argv[1]); System.out.println("Laenge: "+connection.getContentLength()); System.out.println("Typ: "+connection.getContentType()); System.out.println("Klasse:\n"+connection.getContent().getClass()); } } Robert Tolksdorf und Peter Löhr 21 Eine mehrsprachige Website $ java GetInfoLang http://www.cs.tut.fi/~jkorpela/multi Laenge: 1848 Typ: text/html Klasse: class sun.net.www.protocol.http.HttpURLConnection$HttpInputStream $ java GetInfoLang http://www.cs.tut.fi/~jkorpela/multi en Laenge: 1878 Typ: text/html .../index-en.htm ! Klasse: class sun.net.www.protocol.http.HttpURLConnection$HttpInputStream $ java GetInfoLang http://www.cs.tut.fi/~jkorpela/multi de Laenge: 2433 Typ: text/html .../index-de.htm ! Klasse: class sun.net.www.protocol.http.HttpURLConnection$HttpInputStream Robert Tolksdorf und Peter Löhr 22 Eigene URL-Schemata Robert Tolksdorf und Peter Löhr Eigene URL-Schemata • URL-System in Java ist um neue Schemata erweiterbar. Beispiel: daytime (für den Internet-Dienst auf Port 13). • Dazu müssen definiert werden • eine Klasse DaytimeURLConnection extends URLConnection • eine Klasse Handler extends URLStreamHandler • Sie müssen in einem Paket stehen, z.B. in package mypacks.daytime • Durch die Property java.protocol.handler.pkgs muss dem Laufzeitsystem mitgeteilt werden, wo die eigenen Klassen stehen: $ java -Djava.protocol.handler.pkgs=mypacks \ GetInfo daytime://localhost Robert Tolksdorf und Peter Löhr 24 Daytime URLs package mypacks.daytime; import java.net.*; import java.io.*; public class DaytimeURLConnection extends URLConnection { Socket socket; public DaytimeURLConnection(URL url) { super(url); } public void connect() throws IOException { socket = new Socket(url.getHost(), 13); } public Object getContent() throws IOException { connect(); BufferedReader in = new BufferedReader( new InputStreamReader( socket.getInputStream())); return in.readLine(); } } Robert Tolksdorf und Peter Löhr 25 Daytime URLs package mypacks.daytime; import java.net.*; public class Handler extends URLStreamHandler{ protected URLConnection openConnection(URL u) { return new DaytimeURLConnection(u); } } $ java -Djava.protocol.handler.pkgs=mypacks \ GetInfo daytime://localhost 12 DEC 2008 16:15:06 CET $ Robert Tolksdorf und Peter Löhr 26 Push- und Pull-Interaktion Robert Tolksdorf und Peter Löhr Client-Pull und Server-Push • HTTP-Interaktion mit Anfrage und Antwort wird durch Client-Pull und Server-Push erweitert: • Client-Pull • Klient lädt Inhalte in regelmäßigen Abständen nach • Server löst das Verhalten durch zusätzliche Kopfzeile aus • Server-Push • Anbieter schickt mehrere Antworten nacheinander • Klient ersetzt jeweils die Darstellung Robert Tolksdorf und Peter Löhr 28 Client-Pull • Server gibt in der Antwort zusätzliche Kopfzeile an: • Refresh: seconds; ..... • Beispiel: • Refresh: 60; • Korrekter Browser nimmt das zur Kenntnis und lädt regelmäßig die Seite nach. Robert Tolksdorf und Peter Löhr 29 Beispiel: Dynamische Zeitanzeige import java.net.*; import java.io.*; public class TimeServer { public static void main(String[] argv) throws Exception { ServerSocket ss= new ServerSocket(Integer.parseInt(argv[0])); while (true) { Socket socket=ss.accept(); (new BufferedReader( // Kopfzeile lesen - und ignorieren new InputStreamReader( socket.getInputStream()))).readLine(); PrintWriter out = new PrintWriter(socket.getOutputStream()); out.println("HTTP/1.1 200 Ok\n"+ "Content-type: text/html\n"+ "Refresh: 1;\n\n"+ "<html><head><title>Date</title></head>\n"+ "<body><p>Es ist hier gerade "+ new java.util.Date()+ "</body></html>\n"); out.flush(); socket.close(); } }} Testen mit Browser! Robert Tolksdorf und Peter Löhr 30 Server-Push • Anbieter liefert eine Antwort vom Medientyp multipart/mixed an den • • • Klienten Markierung trennt mehrere vollständigen Antwortteile Klient ersetzt Darstellung durch jeweils neuen Antwortteil Server verzögert Auslieferung von jedem Antwortteil: HTTP/1.1 200 Ok Content-type: multipart/mixed;boundary=meinSeitenwechsel --meinSeitenwechsel Content-type: text/html <html><head><title>Ping</title></head><body> <h2>PING!</h2></body></html> (Pause) --meinSeitenwechsel Content-type: text/html <html><head><title>Pong</title></head><body> <h2>PONG!</h2></body></html> Robert Tolksdorf und Peter Löhr 31 Server-Push import java.net.*; import java.io.*; import java.util.*; public class ServerPush { public static void main(String[] argv) throws Exception { int port = Integer.parseInt(argv[0]); int pause = 1000 * (argv.length<2 ? 1 : Integer.parseInt(argv[1])); ServerSocket s = new ServerSocket(port); while (true) { Socket socket = s.accept(); //nix lesen! PrintWriter out = new PrintWriter(socket.getOutputStream()); out.println( "HTTP/1.1 200 Ok\n“ + "Content-type: multipart/mixed; boundary=Seite\n"); ..... Robert Tolksdorf und Peter Löhr 32 Server-Push } } ..... while (!out.checkError()) { out.println("--Seite\nContent-type: text/html\n"); out.println( "<html><head>" + "<title>Date</title></head>\n" + "<body><p><br>" + "Es ist hier gerade " + new Date() + "</body></html>\n"); out.flush(); Thread.sleep(pause); } out.println("\n--Seite--\n"); socket.close(); } Testen z.B. mit Firefox (nicht Safari!) Robert Tolksdorf und Peter Löhr 33 Literatur • www.ietf.org • T. Berners-Lee, R. Fielding, L. Masinter. Uniform Resource • • • • • Identifiers (URI): Generic Syntax. RFC 2396. 1998 Berners-Lee, T., Masinter, L., and M. McCahill, Editors. Uniform Resource Locators (URL), RFC 1738, December 1994. Moats, R. URN Syntax, RFC 2141, May 1997. Joint W3C/IETF URI Planning Interest Group. URIs, URLs, and URNs: Clarifications and Recommendations 1.0. W3C Note. 2001. http://www.w3.org/TR/uri-clarification. Auch RFC 3305. The Official IANA Registry of URI Schemes. http://www.iana.org/assignments/uri-schemes The Official IANA Registry of URN Namespaces. http://www.iana.org/assignments/urn-namespaces Robert Tolksdorf und Peter Löhr 34