mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
working on internal web server for html help
This commit is contained in:
@@ -861,6 +861,25 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
JMenu menu = new JMenu("Help");
|
||||
JMenuItem item;
|
||||
|
||||
item = new JMenuItem("Web Server Test");
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
//WebServer ws = new WebServer();
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
int port = WebServer.launch("/Users/fry/coconut/processing/build/shared/reference.zip");
|
||||
Base.openURL("http://127.0.0.1:" + port + "/reference/setup_.html");
|
||||
|
||||
} catch (IOException e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
/*
|
||||
item = new JMenuItem("Browser Test");
|
||||
item.addActionListener(new ActionListener() {
|
||||
|
||||
@@ -1,51 +1,34 @@
|
||||
package processing.app;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.zip.*;
|
||||
|
||||
//import javax.swing.SwingUtilities;
|
||||
|
||||
/**
|
||||
* An example of a very simple, multi-threaded HTTP server.
|
||||
* Implementation notes are in WebServer.html, and also
|
||||
* as comments in the source code.
|
||||
* <p>
|
||||
* Taken from <a href="http://java.sun.com/developer/technicalArticles/Networking/Webserver/">this</a> article on java.sun.com.
|
||||
*/
|
||||
class WebServer implements HttpConstants {
|
||||
|
||||
/* static class data/methods */
|
||||
|
||||
/* print to stdout */
|
||||
protected static void p(String s) {
|
||||
System.out.println(s);
|
||||
}
|
||||
|
||||
/* print to the log file */
|
||||
protected static void log(String s) {
|
||||
synchronized (log) {
|
||||
log.println(s);
|
||||
log.flush();
|
||||
}
|
||||
}
|
||||
|
||||
static PrintStream log = null;
|
||||
/* our server's configuration information is stored
|
||||
* in these properties
|
||||
*/
|
||||
protected static Properties props = new Properties();
|
||||
public class WebServer implements HttpConstants {
|
||||
|
||||
/* Where worker threads stand idle */
|
||||
static Vector threads = new Vector();
|
||||
|
||||
/* the web server's virtual root */
|
||||
static File root;
|
||||
//static File root;
|
||||
|
||||
/* timeout on client connections */
|
||||
static int timeout = 0;
|
||||
static int timeout = 10000;
|
||||
|
||||
/* max # worker threads */
|
||||
static int workers = 5;
|
||||
|
||||
// static PrintStream log = System.out;
|
||||
|
||||
/* load www-server.properties from java.home */
|
||||
|
||||
/*
|
||||
static void loadProps() throws IOException {
|
||||
File f = new File
|
||||
(System.getProperty("java.home")+File.separator+
|
||||
@@ -78,7 +61,7 @@ class WebServer implements HttpConstants {
|
||||
}
|
||||
}
|
||||
|
||||
/* if no properties were specified, choose defaults */
|
||||
// if no properties were specified, choose defaults
|
||||
if (root == null) {
|
||||
root = new File(System.getProperty("user.dir"));
|
||||
}
|
||||
@@ -99,58 +82,109 @@ class WebServer implements HttpConstants {
|
||||
p("timeout="+timeout);
|
||||
p("workers="+workers);
|
||||
}
|
||||
*/
|
||||
|
||||
public static void main(String[] a) throws Exception {
|
||||
int port = 8080;
|
||||
if (a.length > 0) {
|
||||
port = Integer.parseInt(a[0]);
|
||||
}
|
||||
loadProps();
|
||||
printProps();
|
||||
/* start worker threads */
|
||||
|
||||
/* print to stdout */
|
||||
// protected static void p(String s) {
|
||||
// System.out.println(s);
|
||||
// }
|
||||
|
||||
/* print to the log file */
|
||||
protected static void log(String s) {
|
||||
if (false) {
|
||||
System.out.println(s);
|
||||
}
|
||||
// synchronized (log) {
|
||||
// log.println(s);
|
||||
// log.flush();
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
//public static void main(String[] a) throws Exception {
|
||||
static public int launch(String zipPath) throws IOException {
|
||||
final ZipFile zip = new ZipFile(zipPath);
|
||||
final HashMap<String, ZipEntry> entries = new HashMap();
|
||||
Enumeration en = zip.entries();
|
||||
while (en.hasMoreElements()) {
|
||||
ZipEntry entry = (ZipEntry) en.nextElement();
|
||||
entries.put(entry.getName(), entry);
|
||||
}
|
||||
|
||||
// if (a.length > 0) {
|
||||
// port = Integer.parseInt(a[0]);
|
||||
// }
|
||||
// loadProps();
|
||||
// printProps();
|
||||
// start worker threads
|
||||
for (int i = 0; i < workers; ++i) {
|
||||
Worker w = new Worker();
|
||||
(new Thread(w, "worker #"+i)).start();
|
||||
WebServerWorker w = new WebServerWorker(zip, entries);
|
||||
Thread t = new Thread(w, "Web Server Worker #" + i);
|
||||
t.start();
|
||||
threads.addElement(w);
|
||||
}
|
||||
|
||||
ServerSocket ss = new ServerSocket(port);
|
||||
while (true) {
|
||||
final int port = 8080;
|
||||
|
||||
Socket s = ss.accept();
|
||||
|
||||
Worker w = null;
|
||||
synchronized (threads) {
|
||||
if (threads.isEmpty()) {
|
||||
Worker ws = new Worker();
|
||||
//SwingUtilities.invokeLater(new Runnable() {
|
||||
Runnable r = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
ServerSocket ss = new ServerSocket(port);
|
||||
while (true) {
|
||||
Socket s = ss.accept();
|
||||
WebServerWorker w = null;
|
||||
synchronized (threads) {
|
||||
if (threads.isEmpty()) {
|
||||
WebServerWorker ws = new WebServerWorker(zip, entries);
|
||||
ws.setSocket(s);
|
||||
(new Thread(ws, "additional worker")).start();
|
||||
} else {
|
||||
w = (Worker) threads.elementAt(0);
|
||||
} else {
|
||||
w = (WebServerWorker) threads.elementAt(0);
|
||||
threads.removeElementAt(0);
|
||||
w.setSocket(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
new Thread(r).start();
|
||||
// });
|
||||
return port;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Worker extends WebServer implements HttpConstants, Runnable {
|
||||
class WebServerWorker /*extends WebServer*/ implements HttpConstants, Runnable {
|
||||
ZipFile zip;
|
||||
HashMap<String, ZipEntry> entries;
|
||||
|
||||
final static int BUF_SIZE = 2048;
|
||||
|
||||
static final byte[] EOL = {(byte)'\r', (byte)'\n' };
|
||||
static final byte[] EOL = { (byte)'\r', (byte)'\n' };
|
||||
|
||||
/* buffer to use for requests */
|
||||
byte[] buf;
|
||||
/* Socket to client we're handling */
|
||||
private Socket s;
|
||||
|
||||
Worker() {
|
||||
buf = new byte[BUF_SIZE];
|
||||
s = null;
|
||||
}
|
||||
WebServerWorker(ZipFile zip, HashMap entries) {
|
||||
this.entries = entries;
|
||||
this.zip = zip;
|
||||
|
||||
buf = new byte[BUF_SIZE];
|
||||
s = null;
|
||||
}
|
||||
|
||||
// Worker() {
|
||||
// buf = new byte[BUF_SIZE];
|
||||
// s = null;
|
||||
// }
|
||||
//
|
||||
synchronized void setSocket(Socket s) {
|
||||
this.s = s;
|
||||
notify();
|
||||
@@ -188,40 +222,35 @@ class Worker extends WebServer implements HttpConstants, Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void handleClient() throws IOException {
|
||||
InputStream is = new BufferedInputStream(s.getInputStream());
|
||||
PrintStream ps = new PrintStream(s.getOutputStream());
|
||||
/* we will only block in read for this many milliseconds
|
||||
* before we fail with java.io.InterruptedIOException,
|
||||
* at which point we will abandon the connection.
|
||||
*/
|
||||
// we will only block in read for this many milliseconds
|
||||
// before we fail with java.io.InterruptedIOException,
|
||||
// at which point we will abandon the connection.
|
||||
s.setSoTimeout(WebServer.timeout);
|
||||
s.setTcpNoDelay(true);
|
||||
/* zero out the buffer from last time */
|
||||
// zero out the buffer from last time
|
||||
for (int i = 0; i < BUF_SIZE; i++) {
|
||||
buf[i] = 0;
|
||||
}
|
||||
try {
|
||||
/* We only support HTTP GET/HEAD, and don't
|
||||
* support any fancy HTTP options,
|
||||
* so we're only interested really in
|
||||
* the first line.
|
||||
*/
|
||||
// We only support HTTP GET/HEAD, and don't support any fancy HTTP
|
||||
// options, so we're only interested really in the first line.
|
||||
int nread = 0, r = 0;
|
||||
|
||||
outerloop:
|
||||
while (nread < BUF_SIZE) {
|
||||
r = is.read(buf, nread, BUF_SIZE - nread);
|
||||
if (r == -1) {
|
||||
/* EOF */
|
||||
return;
|
||||
return; // EOF
|
||||
}
|
||||
int i = nread;
|
||||
nread += r;
|
||||
for (; i < nread; i++) {
|
||||
if (buf[i] == (byte)'\n' || buf[i] == (byte)'\r') {
|
||||
/* read one line */
|
||||
break outerloop;
|
||||
break outerloop; // read one line
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -264,8 +293,23 @@ outerloop:
|
||||
break;
|
||||
}
|
||||
}
|
||||
String fname = (new String(buf, 0, index,
|
||||
i-index)).replace('/', File.separatorChar);
|
||||
|
||||
String fname = new String(buf, index, i-index);
|
||||
// get the zip entry, remove the front slash
|
||||
ZipEntry entry = entries.get(fname.substring(1));
|
||||
//System.out.println(fname + " " + entry);
|
||||
boolean ok = printHeaders(entry, ps);
|
||||
if (entry != null) {
|
||||
InputStream stream = zip.getInputStream(entry);
|
||||
if (doingGet && ok) {
|
||||
sendFile(stream, ps);
|
||||
}
|
||||
} else {
|
||||
send404(ps);
|
||||
}
|
||||
/*
|
||||
String fname =
|
||||
(new String(buf, 0, index, i-index)).replace('/', File.separatorChar);
|
||||
if (fname.startsWith(File.separator)) {
|
||||
fname = fname.substring(1);
|
||||
}
|
||||
@@ -284,17 +328,68 @@ outerloop:
|
||||
send404(targ, ps);
|
||||
}
|
||||
}
|
||||
*/
|
||||
} finally {
|
||||
s.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
boolean printHeaders(ZipEntry targ, PrintStream ps) throws IOException {
|
||||
boolean ret = false;
|
||||
int rCode = 0;
|
||||
if (targ == null) {
|
||||
rCode = HTTP_NOT_FOUND;
|
||||
ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " Not Found");
|
||||
ps.write(EOL);
|
||||
ret = false;
|
||||
} else {
|
||||
rCode = HTTP_OK;
|
||||
ps.print("HTTP/1.0 " + HTTP_OK + " OK");
|
||||
ps.write(EOL);
|
||||
ret = true;
|
||||
}
|
||||
if (targ != null) {
|
||||
WebServer.log("From " +s.getInetAddress().getHostAddress()+": GET " + targ.getName()+" --> "+rCode);
|
||||
}
|
||||
ps.print("Server: Processing Documentation Server");
|
||||
ps.write(EOL);
|
||||
ps.print("Date: " + (new Date()));
|
||||
ps.write(EOL);
|
||||
if (ret) {
|
||||
if (!targ.isDirectory()) {
|
||||
ps.print("Content-length: " + targ.getSize());
|
||||
ps.write(EOL);
|
||||
ps.print("Last Modified: " + new Date(targ.getTime()));
|
||||
ps.write(EOL);
|
||||
String name = targ.getName();
|
||||
int ind = name.lastIndexOf('.');
|
||||
String ct = null;
|
||||
if (ind > 0) {
|
||||
ct = (String) map.get(name.substring(ind));
|
||||
}
|
||||
if (ct == null) {
|
||||
//System.err.println("unknown content type " + name.substring(ind));
|
||||
ct = "application/x-unknown-content-type";
|
||||
}
|
||||
ps.print("Content-type: " + ct);
|
||||
ps.write(EOL);
|
||||
} else {
|
||||
ps.print("Content-type: text/html");
|
||||
ps.write(EOL);
|
||||
}
|
||||
}
|
||||
ps.write(EOL); // adding another newline here [fry]
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
boolean printHeaders(File targ, PrintStream ps) throws IOException {
|
||||
boolean ret = false;
|
||||
int rCode = 0;
|
||||
if (!targ.exists()) {
|
||||
rCode = HTTP_NOT_FOUND;
|
||||
ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " not found");
|
||||
ps.print("HTTP/1.0 " + HTTP_NOT_FOUND + " Not Found");
|
||||
ps.write(EOL);
|
||||
ret = false;
|
||||
} else {
|
||||
@@ -303,18 +398,16 @@ outerloop:
|
||||
ps.write(EOL);
|
||||
ret = true;
|
||||
}
|
||||
log("From " +s.getInetAddress().getHostAddress()+": GET " +
|
||||
targ.getAbsolutePath()+"-->"+rCode);
|
||||
WebServer.log("From " +s.getInetAddress().getHostAddress()+": GET " + targ.getAbsolutePath()+"-->"+rCode);
|
||||
ps.print("Server: Simple java");
|
||||
ps.write(EOL);
|
||||
ps.print("Date: " + (new Date()));
|
||||
ps.write(EOL);
|
||||
if (ret) {
|
||||
if (!targ.isDirectory()) {
|
||||
ps.print("Content-length: "+targ.length());
|
||||
ps.print("Content-length: " + targ.length());
|
||||
ps.write(EOL);
|
||||
ps.print("Last Modified: " + (new
|
||||
Date(targ.lastModified())));
|
||||
ps.print("Last Modified: " + new Date(targ.lastModified()));
|
||||
ps.write(EOL);
|
||||
String name = targ.getName();
|
||||
int ind = name.lastIndexOf('.');
|
||||
@@ -335,13 +428,17 @@ outerloop:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void send404(File targ, PrintStream ps) throws IOException {
|
||||
|
||||
void send404(PrintStream ps) throws IOException {
|
||||
ps.write(EOL);
|
||||
ps.write(EOL);
|
||||
ps.print("<html><body><h1>404 Not Found</h1>"+
|
||||
"The requested resource was not found.</body></html>");
|
||||
ps.write(EOL);
|
||||
ps.write(EOL);
|
||||
ps.println("Not Found\n\n"+
|
||||
"The requested resource was not found.\n");
|
||||
}
|
||||
|
||||
|
||||
void sendFile(File targ, PrintStream ps) throws IOException {
|
||||
InputStream is = null;
|
||||
ps.write(EOL);
|
||||
@@ -351,7 +448,11 @@ outerloop:
|
||||
} else {
|
||||
is = new FileInputStream(targ.getAbsolutePath());
|
||||
}
|
||||
|
||||
sendFile(is, ps);
|
||||
}
|
||||
|
||||
|
||||
void sendFile(InputStream is, PrintStream ps) throws IOException {
|
||||
try {
|
||||
int n;
|
||||
while ((n = is.read(buf)) > 0) {
|
||||
@@ -374,6 +475,7 @@ outerloop:
|
||||
|
||||
static void fillMap() {
|
||||
setSuffix("", "content/unknown");
|
||||
|
||||
setSuffix(".uu", "application/octet-stream");
|
||||
setSuffix(".exe", "application/octet-stream");
|
||||
setSuffix(".ps", "application/postscript");
|
||||
@@ -383,19 +485,24 @@ outerloop:
|
||||
setSuffix(".snd", "audio/basic");
|
||||
setSuffix(".au", "audio/basic");
|
||||
setSuffix(".wav", "audio/x-wav");
|
||||
|
||||
setSuffix(".gif", "image/gif");
|
||||
setSuffix(".jpg", "image/jpeg");
|
||||
setSuffix(".jpeg", "image/jpeg");
|
||||
|
||||
setSuffix(".htm", "text/html");
|
||||
setSuffix(".html", "text/html");
|
||||
setSuffix(".text", "text/plain");
|
||||
setSuffix(".css", "text/css");
|
||||
setSuffix(".java", "text/javascript");
|
||||
|
||||
setSuffix(".txt", "text/plain");
|
||||
setSuffix(".java", "text/plain");
|
||||
|
||||
setSuffix(".c", "text/plain");
|
||||
setSuffix(".cc", "text/plain");
|
||||
setSuffix(".c++", "text/plain");
|
||||
setSuffix(".h", "text/plain");
|
||||
setSuffix(".pl", "text/plain");
|
||||
setSuffix(".txt", "text/plain");
|
||||
setSuffix(".java", "text/plain");
|
||||
}
|
||||
|
||||
void listDirectory(File dir, PrintStream ps) throws IOException {
|
||||
@@ -415,6 +522,7 @@ outerloop:
|
||||
|
||||
}
|
||||
|
||||
|
||||
interface HttpConstants {
|
||||
/** 2XX: generally "OK" */
|
||||
public static final int HTTP_OK = 200;
|
||||
@@ -459,6 +567,3 @@ interface HttpConstants {
|
||||
public static final int HTTP_GATEWAY_TIMEOUT = 504;
|
||||
public static final int HTTP_VERSION = 505;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user