Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 1999,2005 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.greenpepper.shaded.org.apache.xmlrpc;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.UnsupportedEncodingException;
import java.net.BindException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.util.EmptyStackException;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.Vector;
import com.greenpepper.shaded.org.apache.commons.codec.binary.Base64;
/**
* A minimal web server that exclusively handles XML-RPC requests.
*
* @author Hannes Wallnoefer
* @author Jason van Zyl
* @author Daniel L. Rall
*/
public class WebServer implements Runnable
{
protected XmlRpcServer xmlrpc;
protected ServerSocket serverSocket;
protected Thread listener;
protected Vector accept, deny;
protected Stack threadpool;
protected ThreadGroup runners;
// Inputs to setupServerSocket()
private InetAddress address;
private int port;
private boolean paranoid;
protected static final byte[] ctype =
toHTTPBytes("Content-Type: text/xml\r\n");
protected static final byte[] clength =
toHTTPBytes("Content-Length: ");
protected static final byte[] newline = toHTTPBytes("\r\n");
protected static final byte[] doubleNewline = toHTTPBytes("\r\n\r\n");
protected static final byte[] conkeep =
toHTTPBytes("Connection: Keep-Alive\r\n");
protected static final byte[] conclose =
toHTTPBytes("Connection: close\r\n");
protected static final byte[] ok = toHTTPBytes(" 200 OK\r\n");
protected static final byte[] server =
toHTTPBytes("Server: Apache XML-RPC 1.0\r\n");
protected static final byte[] wwwAuthenticate =
toHTTPBytes("WWW-Authenticate: Basic realm=XML-RPC\r\n");
private static final String HTTP_11 = "HTTP/1.1";
private static final String STAR = "*";
/**
* This can be called from command line, but you'll have to edit
* and recompile to change the server port or handler objects. By default,
* it sets up the following responders:
*
*
A java.lang.String object
*
The java.lang.Math class (making its static methods callable via
* XML-RPC)
*
An Echo handler that returns the argument array
*
*
* @see #addDefaultHandlers()
*/
public static void main(String[] argv)
{
int p = determinePort(argv, 8080);
// XmlRpc.setDebug (true);
XmlRpc.setKeepAlive(true);
WebServer webserver = new WebServer(p);
try
{
webserver.addDefaultHandlers();
webserver.start();
}
catch (Exception e)
{
System.err.println("Error running web server");
e.printStackTrace();
System.exit(1);
}
}
/**
* Examines command line arguments from argv. If a
* port may have been provided, parses that port (exiting with
* error status if the port cannot be parsed). If no port is
* specified, defaults to defaultPort.
*
* @param defaultPort The port to use if none was specified.
*/
protected static int determinePort(String[] argv, int defaultPort)
{
int port = defaultPort;
if (argv.length > 0)
{
try
{
port = Integer.parseInt(argv[0]);
}
catch (NumberFormatException nfx)
{
System.err.println("Error parsing port number: " + argv[0]);
System.err.println("Usage: java " + WebServer.class.getName()
+ " [port]");
System.exit(1);
}
}
return port;
}
/**
* Creates a web server at the specified port number.
*/
public WebServer(int port)
{
this(port, null);
}
/**
* Creates a web server at the specified port number and IP address.
*/
public WebServer(int port, InetAddress addr)
{
this(port, addr, new XmlRpcServer());
}
/**
* Creates a web server at the specified port number and IP
* address.
*/
public WebServer(int port, InetAddress addr, XmlRpcServer xmlrpc)
{
this.address = addr;
this.port = port;
this.xmlrpc = xmlrpc;
accept = new Vector();
deny = new Vector();
threadpool = new Stack();
runners = new ThreadGroup("XML-RPC Runner");
}
/**
* Returns the US-ASCII encoded byte representation of text for
* HTTP use (as per section 2.2 of RFC 2068).
*/
protected static final byte[] toHTTPBytes(String text)
{
try
{
return text.getBytes("US-ASCII");
}
catch (UnsupportedEncodingException e)
{
throw new Error(e.getMessage() +
": HTTP requires US-ASCII encoding");
}
}
/**
* Factory method to manufacture the server socket. Useful as a
* hook method for subclasses to override when they desire
* different flavor of socket (i.e. a SSLServerSocket).
*
* @param port
* @param backlog
* @param addr If null, binds to
* INADDR_ANY, meaning that all network interfaces on
* a multi-homed host will be listening.
* @exception Exception Error creating listener socket.
*/
protected ServerSocket createServerSocket(int port, int backlog,
InetAddress addr)
throws Exception
{
return new ServerSocket(port, backlog, addr);
}
/**
* Initializes this server's listener socket with the specified
* attributes, assuring that a socket timeout has been set. The
* {@link #createServerSocket(int, int, InetAddress)} method can
* be overridden to change the flavor of socket used.
*
* @see #createServerSocket(int, int, InetAddress)
*/
private synchronized void setupServerSocket(int backlog)
throws Exception
{
// Since we can't reliably set SO_REUSEADDR until JDK 1.4 is
// the standard, try to (re-)open the server socket several
// times. Some OSes (Linux and Solaris, for example), hold on
// to listener sockets for a brief period of time for security
// reasons before relinquishing their hold.
int attempt = 1;
while (serverSocket == null)
{
try
{
serverSocket = createServerSocket(port, backlog, address);
}
catch (BindException e)
{
if (attempt == 10)
{
throw e;
}
attempt++;
Thread.sleep(1000);
}
}
if (XmlRpc.debug)
{
StringBuffer msg = new StringBuffer();
msg.append("Opened XML-RPC server socket for ");
msg.append(address != null ? address.getHostName() : "localhost");
msg.append(':').append(port);
if (attempt > 1)
{
msg.append(" after ").append(attempt).append(" tries");
}
System.out.println(msg.toString());
}
// A socket timeout must be set.
if (serverSocket.getSoTimeout() <= 0)
{
serverSocket.setSoTimeout(4096);
}
}
/**
* Spawns a new thread which binds this server to the port it's
* configured to accept connections on.
*
* @see #run()
*/
public void start()
{
try
{
setupServerSocket(50);
}
catch (Exception e)
{
listener = null;
e.printStackTrace();
throw new RuntimeException(e.getMessage());
}
// The listener reference is released upon shutdown().
if (listener == null)
{
listener = new Thread(this, "XML-RPC Weblistener");
// Not marked as daemon thread since run directly via main().
listener.start();
}
}
/**
* Register a handler object with this name. Methods of this objects will be
* callable over XML-RPC as "name.method".
*/
public void addHandler(String name, Object target)
{
xmlrpc.addHandler(name, target);
}
/**
* Adds the bundled handlers to the server. Called by {@link
* #main(String[])}.
*/
protected void addDefaultHandlers()
throws Exception
{
// webserver.setParanoid (true);
// webserver.acceptClient ("192.168.*.*");
addHandler("string", "Welcome to XML-RPC!");
addHandler("math", Math.class);
addHandler("auth", new AuthDemo());
addHandler("$default", new Echo());
// XmlRpcClients can be used as Proxies in XmlRpcServers which is a
// cool feature for applets.
String url = "http://www.mailtothefuture.com:80/RPC2";
addHandler("mttf", new XmlRpcClient(url));
SystemHandler system = new SystemHandler();
system.addDefaultSystemHandlers();
addHandler("system", system);
}
/**
* Remove a handler object that was previously registered with this server.
*/
public void removeHandler(String name)
{
xmlrpc.removeHandler(name);
}
/**
* Switch client filtering on/off.
* @see #acceptClient(java.lang.String)
* @see #denyClient(java.lang.String)
*/
public void setParanoid(boolean p)
{
paranoid = p;
}
/**
* Add an IP address to the list of accepted clients. The parameter can
* contain '*' as wildcard character, e.g. "192.168.*.*". You must call
* setParanoid(true) in order for this to have any effect.
*
* @see #denyClient(java.lang.String)
* @see #setParanoid(boolean)
*/
public void acceptClient(String address) throws IllegalArgumentException
{
try
{
AddressMatcher m = new AddressMatcher(address);
accept.addElement(m);
}
catch (Exception x)
{
throw new IllegalArgumentException("\"" + address
+ "\" does not represent a valid IP address");
}
}
/**
* Add an IP address to the list of denied clients. The parameter can
* contain '*' as wildcard character, e.g. "192.168.*.*". You must call
* setParanoid(true) in order for this to have any effect.
*
* @see #acceptClient(java.lang.String)
* @see #setParanoid(boolean)
*/
public void denyClient(String address) throws IllegalArgumentException
{
try
{
AddressMatcher m = new AddressMatcher(address);
deny.addElement(m);
}
catch (Exception x)
{
throw new IllegalArgumentException("\"" + address
+ "\" does not represent a valid IP address");
}
}
/**
* Checks incoming connections to see if they should be allowed.
* If not in paranoid mode, always returns true.
*
* @param s The socket to inspect.
* @return Whether the connection should be allowed.
*/
protected boolean allowConnection(Socket s)
{
if (!paranoid)
{
return true;
}
int l = deny.size();
byte address[] = s.getInetAddress().getAddress();
for (int i = 0; i < l; i++)
{
AddressMatcher match = (AddressMatcher)deny.elementAt(i);
if (match.matches(address))
{
return false;
}
}
l = accept.size();
for (int i = 0; i < l; i++)
{
AddressMatcher match = (AddressMatcher)accept.elementAt(i);
if (match.matches(address))
{
return true;
}
}
return false;
}
/**
* DEPRECATED: Do not use this method, it will be removed soon.
* Use {@link #allowConnection(Socket)} instead.
*
* @deprecated Use allowConnection(Socket) instead.
* @see #allowConnection(Socket)
*/
protected boolean checkSocket(Socket s)
{
return allowConnection(s);
}
/**
* Listens for client requests until stopped. Call {@link
* #start()} to invoke this method, and {@link #shutdown()} to
* break out of it.
*
* @throws RuntimeException Generally caused by either an
* UnknownHostException or BindException
* with the vanilla web server.
*
* @see #start()
* @see #shutdown()
*/
public void run()
{
try
{
while (listener != null)
{
Socket socket = null;
Runner runner = null;
try
{
socket = serverSocket.accept();
try
{
socket.setTcpNoDelay(true);
}
catch (SocketException socketOptEx)
{
System.err.println(socketOptEx);
}
if (allowConnection(socket))
{
runner = getRunner();
runner.handle(socket);
}
else
{
socket.close();
}
}
catch (InterruptedIOException checkState)
{
// Timeout while waiting for a client (from
// SO_TIMEOUT)...try again if still listening.
}
catch (Exception ex)
{
System.err.println("Exception in XML-RPC listener loop ("
+ ex + ").");
if (XmlRpc.debug)
{
ex.printStackTrace();
}
}
catch (Error err)
{
System.err.println("Error in XML-RPC listener loop ("
+ err + ").");
err.printStackTrace();
}
finally
{
if (runner == null && socket != null)
{
try
{
socket.close();
}
catch (Throwable e)
{
}
}
}
}
}
catch (Exception exception)
{
System.err.println("Error accepting XML-RPC connections ("
+ exception + ").");
if (XmlRpc.debug)
{
exception.printStackTrace();
}
}
finally
{
if (serverSocket != null)
{
try
{
serverSocket.close();
if (XmlRpc.debug)
{
System.out.print("Closed XML-RPC server socket");
}
serverSocket = null;
}
catch (IOException e)
{
e.printStackTrace();
}
}
// Shutdown our Runner-based threads
if (runners != null)
{
ThreadGroup g = runners;
runners = null;
try
{
g.interrupt();
}
catch (Exception e)
{
System.err.println(e);
e.printStackTrace();
}
}
}
}
/**
* Stop listening on the server port. Shutting down our {@link
* #listener} effectively breaks it out of its {@link #run()}
* loop.
*
* @see #run()
*/
public synchronized void shutdown()
{
// Stop accepting client connections
if (listener != null)
{
Thread l = listener;
listener = null;
l.interrupt();
}
}
/**
*
* @return
*/
protected Runner getRunner()
{
try
{
return (Runner)threadpool.pop();
}
catch (EmptyStackException empty)
{
int maxRequests = XmlRpc.getMaxThreads();
if (runners.activeCount() > XmlRpc.getMaxThreads())
{
throw new RuntimeException("System overload: Maximum number " +
"of concurrent requests (" +
maxRequests + ") exceeded");
}
return new Runner();
}
}
/**
* Put runner back into {@link #threadpool}.
*
* @param runner The instance to reclaim.
*/
void repoolRunner(Runner runner)
{
threadpool.push(runner);
}
/**
* Responsible for handling client connections.
*/
class Runner implements Runnable
{
Thread thread;
Connection con;
int count;
/**
* Handles the client connection on socket.
*
* @param socket The source to read the client's request from.
*/
public synchronized void handle(Socket socket) throws IOException
{
con = new Connection(socket);
count = 0;
if (thread == null || !thread.isAlive())
{
thread = new Thread(runners, this);
thread.start();
}
else
{
// Wake the thread waiting in our run() method.
this.notify();
}
}
/**
* Delegates to con.run().
*/
public void run()
{
while (con != null && Thread.currentThread() == thread)
{
con.run();
count++;
con = null;
if (count > 200 || threadpool.size() > 20)
{
// We're old, or the number of threads in the pool
// is large.
return;
}
synchronized(this)
{
repoolRunner(this);
try
{
this.wait();
}
catch (InterruptedException ir)
{
Thread.currentThread().interrupt();
}
}
}
}
}
/**
*
*/
class Connection implements Runnable
{
private Socket socket;
private BufferedInputStream input;
private BufferedOutputStream output;
private String user, password;
byte[] buffer;
/**
*
* @param socket
* @throws IOException
*/
public Connection (Socket socket) throws IOException
{
// set read timeout to 30 seconds
socket.setSoTimeout (30000);
this.socket = socket;
input = new BufferedInputStream(socket.getInputStream());
output = new BufferedOutputStream(socket.getOutputStream());
}
/**
*
*/
public void run()
{
try
{
boolean keepAlive = false;
do
{
// reset user authentication
user = null;
password = null;
String line = readLine();
// Netscape sends an extra \n\r after bodypart, swallow it
if (line != null && line.length() == 0)
{
line = readLine();
}
if (XmlRpc.debug)
{
System.out.println(line);
}
int contentLength = -1;
// tokenize first line of HTTP request
StringTokenizer tokens = new StringTokenizer(line);
String method = tokens.nextToken();
String uri = tokens.nextToken();
String httpVersion = tokens.nextToken();
keepAlive = XmlRpc.getKeepAlive()
&& HTTP_11.equals(httpVersion);
do
{
line = readLine();
if (line != null)
{
if (XmlRpc.debug)
{
System.out.println(line);
}
String lineLower = line.toLowerCase();
if (lineLower.startsWith("content-length:"))
{
contentLength = Integer.parseInt(
line.substring(15).trim());
}
if (lineLower.startsWith("connection:"))
{
keepAlive = XmlRpc.getKeepAlive() &&
lineLower.indexOf("keep-alive") > -1;
}
if (lineLower.startsWith("authorization: basic "))
{
parseAuth (line);
}
}
}
while (line != null && line.length() != 0);
if ("POST".equalsIgnoreCase(method))
{
ServerInputStream sin = new ServerInputStream(input,
contentLength);
try
{
byte[] result = xmlrpc.execute(sin, user, password);
writeResponse(result, httpVersion, keepAlive);
}
catch (AuthenticationFailed unauthorized)
{
keepAlive = false;
writeUnauthorized(httpVersion, method);
}
}
else
{
keepAlive = false;
writeBadRequest(httpVersion, method);
}
output.flush();
}
while (keepAlive);
}
catch (Exception exception)
{
if (XmlRpc.debug)
{
exception.printStackTrace();
}
else
{
System.err.println(exception);
}
}
finally
{
try
{
if (socket != null)
{
socket.close();
}
}
catch (IOException ignore)
{
}
}
}
/**
*
* @return
* @throws IOException
*/
private String readLine() throws IOException
{
if (buffer == null)
{
buffer = new byte[2048];
}
int next;
int count = 0;
for (;;)
{
next = input.read();
if (next < 0 || next == '\n')
{
break;
}
if (next != '\r')
{
buffer[count++] = (byte) next;
}
if (count >= buffer.length)
{
throw new IOException("HTTP Header too long");
}
}
return new String(buffer, 0, count);
}
/**
*
* @param line
*/
private synchronized void parseAuth(String line)
{
try
{
Base64 base64Codec = new Base64();
byte[] c = base64Codec.decode(toHTTPBytes(line.substring(21)));
String str = new String(c);
int col = str.indexOf(':');
user = str.substring(0, col);
password = str.substring(col + 1);
}
catch (Throwable ignore)
{
}
}
private void writeResponse(byte[] payload, String httpVersion,
boolean keepAlive)
throws IOException
{
output.write(toHTTPBytes(httpVersion));
output.write(ok);
output.write(server);
output.write(keepAlive ? conkeep : conclose);
output.write(ctype);
output.write(clength);
output.write(toHTTPBytes(Integer.toString(payload.length)));
output.write(doubleNewline);
output.write(payload);
}
private void writeBadRequest(String httpVersion, String httpMethod)
throws IOException
{
output.write(toHTTPBytes(httpVersion));
output.write(toHTTPBytes(" 400 Bad Request"));
output.write(newline);
output.write(server);
output.write(newline);
output.write(toHTTPBytes("Method " + httpMethod +
" not implemented (try POST)"));
}
private void writeUnauthorized(String httpVersion, String httpMethod)
throws IOException
{
output.write(toHTTPBytes(httpVersion));
output.write(toHTTPBytes(" 401 Unauthorized"));
output.write(newline);
output.write(server);
output.write(wwwAuthenticate);
output.write(newline);
output.write(toHTTPBytes("Method " + httpMethod + " requires a " +
"valid user name and password"));
}
}
/**
*
*/
class AddressMatcher
{
int pattern[];
/**
*
* @param address
* @throws Exception
*/
public AddressMatcher(String address) throws Exception
{
pattern = new int[4];
StringTokenizer st = new StringTokenizer(address, ".");
if (st.countTokens() != 4)
{
throw new Exception("\"" + address
+ "\" does not represent a valid IP address");
}
for (int i = 0; i < 4; i++)
{
String next = st.nextToken();
if (STAR.equals(next))
{
pattern[i] = 256;
}
else
{
pattern[i] = (byte) Integer.parseInt(next);
}
}
}
/**
*
* @param address
* @return
*/
public boolean matches (byte address[])
{
for (int i = 0; i < 4; i++)
{
if (pattern[i] > 255)// wildcard
{
continue;
}
if (pattern[i] != address[i])
{
return false;
}
}
return true;
}
}
}