summaryrefslogtreecommitdiffstats
path: root/khtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'khtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java')
-rw-r--r--khtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java609
1 files changed, 609 insertions, 0 deletions
diff --git a/khtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java b/khtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java
new file mode 100644
index 000000000..58c5ff518
--- /dev/null
+++ b/khtml/java/org/kde/kjas/server/KJASURLStreamHandlerFactory.java
@@ -0,0 +1,609 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (C) 2003 Koos Vriezen <koos ! vriezen () xs4all ! nl>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+package org.kde.kjas.server;
+
+import java.net.*;
+import java.io.*;
+import java.util.*;
+import java.security.*;
+/**
+ *
+ */
+
+class KIOConnection
+{
+ final static int NOT_CONNECTED = 0;
+ final static int CONNECT_WAIT = 1;
+ final static int CONNECTED = 2;
+
+ final static int DATA = 0;
+ final static int FINISHED = 1;
+ final static int ERRORCODE = 2;
+ final static int CONNECT = 6;
+ final static int REQUESTDATA = 7;
+
+ final static int STOP = 0;
+ final static int HOLD = 1;
+ final static int RESUME = 2;
+
+ protected static int id = 0;
+ static Hashtable jobs = new Hashtable(); // should be thread safe
+
+ static void setData(String jobid, int code, byte [] data) {
+ KIOConnection job = (KIOConnection) jobs.get(jobid);
+ if (job == null || !job.setData(code, data))
+ Main.info("KIO KJASHttpURLConnection gone (timedout/closed)");
+ else
+ Thread.yield();
+ }
+
+ private class KJASOutputStream extends OutputStream {
+ KJASOutputStream() {
+ }
+ public void write(int b) throws IOException {
+ byte[] buf = {(byte)b};
+ write(buf);
+ }
+ public synchronized void write(byte b[], int off, int len) throws IOException {
+ byte[] buf = new byte[len];
+ System.arraycopy(b, off, buf, 0, len);
+ sendData(buf, false);
+ }
+ public void write(byte b[]) throws IOException {
+ write(b, 0, b.length);
+ }
+ public void close() throws IOException {
+ disconnect();
+ }
+ public void flush() throws IOException {
+ checkConnected();
+ sendData(null, true);
+ }
+ }
+
+ private class KJASInputStream extends InputStream {
+
+ KJASInputStream() {
+ }
+ public int read() throws IOException {
+ if (getData(true))
+ return 0x00ff & in_buf[in_bufpos++];
+ return -1;
+ }
+ public int read(byte[] b, int off, int len) throws IOException {
+ int total = 0;
+ do {
+ if (!getData(true)) break;
+ int nr = in_buf.length - in_bufpos;
+ if (nr > len)
+ nr = len;
+ System.arraycopy(in_buf, in_bufpos, b, off, nr);
+ len -= nr;
+ total += nr;
+ off += nr;
+ in_bufpos += nr;
+ } while (len > 0);
+ return total > 0 ? total : -1;
+ }
+ public int read(byte[] b) throws IOException {
+ return read(b, 0, b.length);
+ }
+ public int available() throws IOException {
+ return inAvailable();
+ }
+ public boolean markSupported() {
+ return false;
+ }
+ public void close() throws IOException {
+ disconnect();
+ }
+ }
+
+ protected URL url;
+ protected int connect_status = 0;
+ protected String jobid = null; // connection id with KIO
+ protected LinkedList data = new LinkedList(); // not thread safe
+ protected int errorcode = 0;
+ protected boolean finished = false; // all data has arived
+ protected boolean onhold = false; // KIO job is suspended
+ protected boolean request_data = false; // need data for put job
+ private KJASOutputStream out = null;
+ private KJASInputStream in = null;
+ private byte [] in_buf = null; // current input buffer
+ private int in_bufpos = 0; // position in buffer
+ private boolean in_eof = false; // all data is read
+ private final static int LOW_BUFFER_LIMIT = 5; // put onhold off
+ private final static int HIGH_BUFFER_LIMIT = 10; // put onhold on
+
+ protected KIOConnection(URL u) {
+ url = u;
+ }
+ protected void checkConnected() throws IOException {
+ if (connect_status != CONNECTED)
+ throw new IOException("not connected");
+ }
+ protected boolean haveError() {
+ return errorcode != 0;
+ }
+ synchronized protected boolean setData(int code, byte [] d) {
+ // is job still there when entering the monitor
+ if (jobs.get(jobid) == null)
+ return false;
+ if (connect_status == CONNECT_WAIT)
+ connect_status = CONNECTED;
+ switch (code) {
+ case FINISHED:
+ if (d != null && d.length > 0)
+ data.addLast(d);
+ finished = true;
+ onhold = false;
+ jobs.remove(jobid);
+ Main.debug ("KIO FINISHED (" + jobid + ") " + data.size());
+ break;
+ case DATA:
+ if (d.length > 0)
+ data.addLast(d);
+ // Main.debug ("KIO DATA (" + jobid + ") " + data.size());
+ if (!onhold && data.size() > HIGH_BUFFER_LIMIT) {
+ Main.protocol.sendDataCmd(jobid, HOLD);
+ onhold = true;
+ }
+ break;
+ case ERRORCODE:
+ String codestr = new String(d);
+ errorcode = Integer.parseInt(codestr);
+ Main.debug ("KIO ERRORECODE(" + jobid + ") " + errorcode);
+ break;
+ case CONNECT:
+ Main.debug ("KIO CONNECT(" + jobid + ") ");
+ request_data = true;
+ errorcode = 0;
+ break;
+ case REQUESTDATA:
+ Main.debug ("KIO REQUESTDATA(" + jobid + ") ");
+ request_data = true;
+ break;
+ }
+ notifyAll();
+ return true;
+ }
+
+ private synchronized boolean getData(boolean mayblock) throws IOException {
+ if (haveError()) {
+ //disconnect();
+ in_eof = true;
+ //throw new IOException("i/o error " + errorcode);
+ }
+ if (in_eof)
+ return false;
+ checkConnected();
+ if (in_buf != null && in_bufpos < in_buf.length)
+ return true;
+ int datasize = data.size();
+ if (datasize > 0) {
+ in_buf = (byte []) data.removeFirst();
+ in_bufpos = 0;
+ }
+ if (onhold && datasize < LOW_BUFFER_LIMIT) {
+ Main.protocol.sendDataCmd(jobid, RESUME);
+ onhold = false;
+ }
+ if (datasize > 0)
+ return true;
+ if (finished) {
+ in_eof = true;
+ return false;
+ }
+ if (!mayblock)
+ return false;
+ try {
+ wait();
+ } catch (InterruptedException ie) {
+ return false;
+ }
+ return getData(false);
+ }
+ synchronized private int inAvailable() throws IOException {
+ if (in_eof)
+ return 0;
+ checkConnected();
+ if (!getData(false))
+ return 0;
+ int total = in_buf.length - in_bufpos;
+ ListIterator it = data.listIterator(0);
+ while (it.hasNext())
+ total += ((byte []) it.next()).length;
+ return total;
+ }
+ synchronized private void sendData(byte [] d, boolean force) throws IOException {
+ Main.debug ("KIO sendData(" + jobid + ") force:" + force + " request_data:" + request_data);
+ if (d != null)
+ data.addLast(d);
+ if (!request_data && !force) return;
+ if (data.size() == 0) return;
+ if (force && !request_data) {
+ try {
+ wait(10000);
+ } catch (InterruptedException ie) {
+ return;
+ }
+ if (!request_data) {
+ Main.debug ("KIO sendData(" + jobid + ") timeout");
+ data.clear();
+ disconnect();
+ throw new IOException("timeout");
+ }
+ }
+ byte[] buf;
+ int total = 0;
+ ListIterator it = data.listIterator(0);
+ while (it.hasNext())
+ total += ((byte []) it.next()).length;
+ buf = new byte[total];
+ int off = 0;
+ it = data.listIterator(0);
+ while (it.hasNext()) {
+ byte [] b = (byte []) it.next();
+ System.arraycopy(b, 0, buf, off, b.length);
+ off += b.length;
+ }
+ data.clear();
+ request_data = false;
+ Main.protocol.sendPutData(jobid, buf, 0, total);
+ }
+ synchronized void connect(boolean doInput) throws IOException {
+ if (connect_status == CONNECTED)
+ return; // javadocs: call is ignored
+ //(new Exception()).printStackTrace();
+ Main.debug ("KIO connect " + url);
+ errorcode = 0;
+ finished = in_eof = false;
+ jobid = String.valueOf(id++);
+ jobs.put(jobid, this);
+ if (doInput)
+ Main.protocol.sendGetURLDataCmd(jobid, url.toExternalForm());
+ else
+ Main.protocol.sendPutURLDataCmd(jobid, url.toExternalForm());
+ connect_status = CONNECT_WAIT;
+ try {
+ wait(20000);
+ } catch (InterruptedException ie) {
+ errorcode = -1;
+ }
+ boolean isconnected = (connect_status == CONNECTED);
+ if (isconnected && !haveError()) {
+ if (doInput)
+ in = new KJASInputStream();
+ else
+ out = new KJASOutputStream();
+ Main.debug ("KIO connect(" + jobid + ") " + url);
+ return;
+ }
+ connect_status = NOT_CONNECTED;
+ jobs.remove(jobid);
+ if (isconnected) {
+ if (!finished)
+ Main.protocol.sendDataCmd(jobid, STOP);
+ Main.debug ("KIO connect error " + url);
+ throw new ConnectException("connection failed (not found)");
+ }
+ Main.debug ("KIO connect timeout " + url);
+ throw new IOException("connection failed (timeout)");
+ }
+ synchronized void disconnect() {
+ if (connect_status == NOT_CONNECTED)
+ return;
+ Main.debug ("KIO disconnect " + jobid);
+ //(new Exception()).printStackTrace();
+ if (out != null) {
+ try {
+ out.flush();
+ } catch (IOException iox) {}
+ }
+ connect_status = NOT_CONNECTED;
+ out = null;
+ in = null;
+ if (!finished) {
+ Main.protocol.sendDataCmd(jobid, STOP);
+ jobs.remove(jobid);
+ }
+ notifyAll();
+ }
+ InputStream getInputStream() throws IOException {
+ Main.debug ("KIO getInputStream(" + jobid + ") " + url);
+ return in;
+ }
+ OutputStream getOutputStream() throws IOException {
+ Main.debug ("KIO getOutputStream(" + jobid + ") " + url);
+ return out;
+ }
+}
+
+final class KIOHttpConnection extends KIOConnection
+{
+ final static int HEADERS = 3;
+ final static int REDIRECT = 4;
+ final static int MIMETYPE = 5;
+
+ Vector headers = new Vector();
+ Hashtable headersmap = new Hashtable();
+ String responseMessage = null;
+ int responseCode = -1;
+
+ KIOHttpConnection(URL u) {
+ super(u);
+ }
+ protected boolean haveError() {
+ return super.haveError() ||
+ responseCode != 404 && (responseCode < 0 || responseCode >= 400);
+ }
+ protected synchronized boolean setData(int code, byte [] d) {
+ switch (code) {
+ case HEADERS:
+ StringTokenizer tokenizer = new StringTokenizer(new String(d), "\n");
+ while (tokenizer.hasMoreTokens()) {
+ String token = tokenizer.nextToken();
+ int pos = token.indexOf(":");
+ String [] entry = {
+ token.substring(0, pos > -1 ? pos : token.length()).toLowerCase(), token.substring(pos > -1 ? pos+1: token.length()).trim()
+ };
+ headers.add(entry);
+ headersmap.put(entry[0], entry[1]);
+ // Main.debug ("KIO header " + entry[0] + "=" + entry[1]);
+ }
+ responseCode = 0;
+ if (headersmap.size() > 0) {
+ String token = ((String []) headers.get(0))[0];
+ if (!token.startsWith("http/1.")) break;
+ int spos = token.indexOf(' ');
+ if (spos < 0) break;
+ int epos = token.indexOf(' ', spos + 1);
+ if (epos < 0) break;
+ responseCode = Integer.parseInt(token.substring(spos+1, epos));
+ responseMessage = token.substring(epos+1);
+ Main.debug ("KIO responsecode=" + responseCode);
+ }
+ break;
+ }
+ return super.setData(code, d);
+ }
+}
+
+final class KIOSimpleConnection extends KIOConnection
+{
+ KIOSimpleConnection(URL u) {
+ super(u);
+ }
+}
+
+final class KJASHttpURLConnection extends HttpURLConnection
+{
+ private KIOHttpConnection kioconnection;
+
+ KJASHttpURLConnection(URL u) {
+ super(u);
+ kioconnection = new KIOHttpConnection(u);
+ }
+ public Map getHeaderFields() {
+ try {
+ connect();
+ } catch (IOException e) {
+ Main.debug ("Error on implicit connect()");
+ }
+ Main.debug ("KIO getHeaderFields");
+ return kioconnection.headersmap;
+ }
+ public String getHeaderField(String name) {
+ try {
+ connect();
+ } catch (IOException e) {
+ Main.debug ("Error on implicit connect()");
+ }
+ String field = (String) kioconnection.headersmap.get(name);
+ Main.debug ("KIO getHeaderField:" + name + "=" + field);
+ //(new Exception()).printStackTrace();
+ return field;
+ }
+ public String getHeaderField(int n) {
+ try {
+ connect();
+ } catch (IOException e) {
+ Main.debug ("Error on implicit connect()");
+ }
+ Main.debug ("KIO getHeaderField(" + n + ") size=" + kioconnection.headersmap.size());
+ if (n >= kioconnection.headersmap.size())
+ return null;
+ String [] entry = (String []) kioconnection.headers.get(n);
+ String line = entry[0];
+ if (entry[1].length() > 0)
+ line += ":" + entry[1];
+ Main.debug ("KIO getHeaderField(" + n + ")=#" + line + "#");
+ return line;
+ }
+ public String getHeaderFieldKey(int n) {
+ try {
+ connect();
+ } catch (IOException e) {
+ Main.debug ("Error on implicit connect()");
+ }
+ Main.debug ("KIO getHeaderFieldKey " + n);
+ if (n >= kioconnection.headersmap.size())
+ return null;
+ return ((String []) kioconnection.headers.get(n))[0];
+ }
+ public int getResponseCode() throws IOException {
+ Main.debug ("KIO getResponseCode");
+ if (kioconnection.responseCode == -1) {
+ try {
+ connect();
+ } catch (IOException e) {
+ if (kioconnection.responseCode == -1)
+ throw e;
+ }
+ }
+ responseMessage = kioconnection.responseMessage;
+ return kioconnection.responseCode;
+ }
+ public boolean usingProxy() {
+ return false; // FIXME
+ }
+ public void connect() throws IOException {
+ if (connected)
+ return;
+ Main.debug ("KIO KJASHttpURLConnection.connect " + url);
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ security.checkPermission(getPermission());
+ kioconnection.connect(doInput);
+ connected = true;
+ if (kioconnection.responseCode == 404)
+ throw new FileNotFoundException(url.toExternalForm());
+ }
+ public void disconnect() {
+ kioconnection.disconnect();
+ connected = false;
+ }
+ public InputStream getInputStream() throws IOException {
+ doInput = true;
+ doOutput = false;
+ connect();
+ return kioconnection.getInputStream();
+ }
+ public OutputStream getOutputStream() throws IOException {
+ doInput = false;
+ doOutput = true;
+ connect();
+ return kioconnection.getOutputStream();
+ }
+ public InputStream getErrorStream() {
+ Main.debug("KIO KJASHttpURLConnection.getErrorStream" + url);
+ try {
+ if (connected && kioconnection.responseCode == 404)
+ return kioconnection.getInputStream();
+ } catch (Exception ex) {}
+ return null;
+ }
+}
+
+final class KJASSimpleURLConnection extends URLConnection
+{
+ private KIOSimpleConnection kioconnection = null;
+ private int default_port;
+
+ KJASSimpleURLConnection(URL u, int p) {
+ super(u);
+ default_port = p;
+ }
+ public boolean usingProxy() {
+ return false; // FIXME
+ }
+ public Permission getPermission() throws IOException {
+ int p = url.getPort();
+ if (p < 0)
+ p = default_port;
+ return new SocketPermission(url.getHost() + ":" + p, "connect");
+ }
+ public void connect() throws IOException {
+ if (kioconnection != null)
+ return;
+ Main.debug ("KIO KJASSimpleURLConnection.connection " + url);
+ SecurityManager security = System.getSecurityManager();
+ if (security != null)
+ security.checkPermission(getPermission());
+ kioconnection = new KIOSimpleConnection(url);
+ kioconnection.connect(doInput);
+ connected = true;
+ }
+ public void disconnect() {
+ if (kioconnection == null)
+ return;
+ kioconnection.disconnect();
+ kioconnection = null;
+ connected = false;
+ }
+ public InputStream getInputStream() throws IOException {
+ doInput = true;
+ doOutput = false;
+ if (kioconnection == null)
+ connect();
+ return kioconnection.getInputStream();
+ }
+ public OutputStream getOutputStream() throws IOException {
+ doInput = false;
+ doOutput = true;
+ if (kioconnection == null)
+ connect();
+ return kioconnection.getOutputStream();
+ }
+}
+
+
+final class KJASHttpURLStreamHandler extends URLStreamHandler
+{
+ KJASHttpURLStreamHandler(int port) {
+ default_port = port;
+ }
+ protected URLConnection openConnection(URL u) throws IOException {
+ URL url = new URL(u.toExternalForm());
+ return new KJASHttpURLConnection(url);
+ }
+ protected int getDefaultPort() {
+ return default_port;
+ }
+ private int default_port;
+}
+
+final class KJASSimpleURLStreamHandler extends URLStreamHandler
+{
+ KJASSimpleURLStreamHandler(int port) {
+ default_port = port;
+ }
+ protected URLConnection openConnection(URL u) throws IOException {
+ URL url = new URL(u.toExternalForm());
+ return new KJASSimpleURLConnection(url, default_port);
+ }
+ protected int getDefaultPort() {
+ return default_port;
+ }
+ private int default_port;
+}
+
+public final class KJASURLStreamHandlerFactory
+ implements URLStreamHandlerFactory
+{
+ public URLStreamHandler createURLStreamHandler(String protocol) {
+ if (protocol.equals("jar") || protocol.equals("file"))
+ return null;
+ //outputs to early: Main.debug ("createURLStreamHandler " + protocol);
+ Main.debug ("KIO createURLStreamHandler " + protocol);
+ if (protocol.equals("http"))
+ return new KJASHttpURLStreamHandler(80);
+ else if (protocol.equals("https"))
+ return new KJASHttpURLStreamHandler(443);
+ else if (protocol.equals("ftp"))
+ return new KJASSimpleURLStreamHandler(21);
+ else if (protocol.equals("smb"))
+ return new KJASSimpleURLStreamHandler(139);
+ else if (protocol.equals("fish"))
+ return new KJASSimpleURLStreamHandler(22);
+ return null;
+ }
+}