/**
* $Id: $
* $Date: $
*
*/
package org.xmlsh.commands.internal;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamWriter;
import net.sf.saxon.s9api.SaxonApiException;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.xmlsh.core.CoreException;
import org.xmlsh.core.Options;
import org.xmlsh.core.ThrowException;
import org.xmlsh.core.VariableOutputPort;
import org.xmlsh.core.XCommand;
import org.xmlsh.core.XValue;
import org.xmlsh.core.XVariable;
import org.xmlsh.sh.core.Command;
import org.xmlsh.sh.shell.Shell;
import com.sun.net.httpserver.Headers;
import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpHandler;
import com.sun.net.httpserver.HttpServer;
public class httpserver extends XCommand {
static HttpServer mServer = null;
private static Logger mLogger = LogManager.getLogger( httpserver.class);
public class MyHandler implements HttpHandler {
private Shell mShell = null;
private File mInitialCD;
private Command mGet;
private Command mPut;
private Command mPost;
private boolean mChunked = false ;
MyHandler( Shell shell, boolean chunked , String getFunc, String putFunc , String postFunc ) throws CoreException
{
mShell = shell.clone(); // clone shell for execution
mChunked = chunked;
// need to save the CD so we can restore it in the new thread
mInitialCD = mShell.getCurdir();
if( getFunc != null )
mGet = mShell.parseEval(getFunc);
if( putFunc != null )
mPut = mShell.parseEval(putFunc);
if( postFunc != null )
mPost = mShell.parseEval(postFunc);
}
public void handle(HttpExchange http) throws IOException {
try {
XVariable headers = parseHeaders( http );
mShell.setCurdir(mInitialCD);
// System.out.println("Got request in thread: " + Thread.currentThread().getName() );
String method = http.getRequestMethod();
// TBD: Headers headers = http.getRequestHeaders();
Command cmd = null ;
if( method.equals("GET") )
cmd = mGet;
else
if( method.equals("PUT") )
cmd = mPut;
else
if( method.equals("POST") && mPost != null )
cmd = mPost ;
if( cmd == null ){
http.sendResponseHeaders(405, -1);
http.close();
return ;
}
URI uri = http.getRequestURI();
InputStream is = http.getRequestBody();
// If chunked mode we can execute directly to the output
if( mChunked ){
http.sendResponseHeaders(200, 0);
// http.sendResponseHeaders(200, response.length());
OutputStream os = http.getResponseBody();
execute(cmd, uri, is, os, headers );
;
}
// Otherwise must buffer up the response
else {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
execute(cmd, uri, is, bos,headers);
try {
// Eat the data
while( is.read() > 0 )
;
} catch( Exception e )
{
}
http.getResponseHeaders().add("Connection", "close");
http.sendResponseHeaders(200, bos.size() );
// http.sendResponseHeaders(200, response.length());
OutputStream os = http.getResponseBody();
os.write(bos.toByteArray());
os.flush();
os.close();
}
http.close();
} catch( Exception e )
{
mLogger.error("Exception running http handler" , e );
try {
mShell.getEnv().setStdin((InputStream)null);
mShell.getEnv().setStdout((OutputStream)null);
mShell.close();
} catch( Exception e2 )
{}
}
}
private void execute(Command cmd, URI uri, InputStream is, OutputStream os, XVariable headers)
throws CoreException, ThrowException, IOException {
mShell.getEnv().setStdin( is );
mShell.getEnv().setStdout( os );
List<XValue> args = new ArrayList<XValue>();
String query = uri.getQuery();
String path = uri.getPath();
args.add( new XValue(path));
args.add( new XValue(query));
if( headers != null )
mShell.getEnv().setVar(headers,false);
mShell.setArgs(args);
mShell.exec(cmd);
}
/*
* Create a document from a paramater map
* Map is String: String[]
*
* Format is
*
* <headers>
* <header key="key">
* <value>value1</value>
* <value>value2</value>
* ....
* </parameters>
*
*
*/
@SuppressWarnings("unchecked")
private XVariable parseHeaders(HttpExchange request) throws XMLStreamException, CoreException, SaxonApiException {
XVariable var = new XVariable("HTTP_HEADERS",null);
VariableOutputPort port = new VariableOutputPort( var );
XMLStreamWriter writer = port.asXMLStreamWriter(null);
writer.writeStartDocument();
writer.writeStartElement("headers");
Headers headers = request.getRequestHeaders();
Set<String> names = headers.keySet();
for( String name : names ){
List<String> values = headers.get(name);
writer.writeStartElement("header");
writer.writeAttribute("name", name );
for( String value : values ){
writer.writeStartElement("value");
writer.writeCharacters(value);
writer.writeEndElement();
}
writer.writeEndElement();
}
writer.writeEndElement();
writer.writeEndDocument();
writer.close();
port.flush();
return var ;
}
}
@Override
public int run( List<XValue> args )
throws Exception
{
Options opts = new Options( "port:,context:,handler:,get:,put:,post:,chunk" );
opts.parse(args);
if( ! opts.hasRemainingArgs() ){
usage();
return -1;
}
String arg = opts.getRemainingArgs().get(0).toString();
if( arg.equals("stop")){
if( mServer != null )
mServer.stop(0);
mServer = null ;
return 0;
}
else
if( arg.equals("start"))
return start( opts );
else
usage();
return 0;
}
private int start(Options opts) throws IOException, CoreException {
int port = opts.getOptInt("port",80);
String context = opts.getOptString("context", "/");
String get = opts.getOptString("get", null);
String put = opts.getOptString("put", null);
String post = opts.getOptString("post", null);
boolean bChunk = opts.hasOpt("chunk");
if( mServer != null ){
printErr("Server already running");
return 1;
}
mServer = HttpServer.create(new InetSocketAddress(port), 10 );
mServer.createContext(context, new MyHandler(getEnv().getShell(),bChunk, get,put,post));
mServer.setExecutor(null); // creates a default executor
mServer.start();
return 0;
}
}
//
//
//Copyright (C) 2008-2014 David A. Lee.
//
//The contents of this file are subject to the "Simplified BSD License" (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.opensource.org/licenses/bsd-license.php
//
//Software distributed under the License is distributed on an "AS IS" basis,
//WITHOUT WARRANTY OF ANY KIND, either express or implied.
//See the License for the specific language governing rights and limitations under the License.
//
//The Original Code is: all this file.
//
//The Initial Developer of the Original Code is David A. Lee
//
//Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
//
//Contributor(s): none.
//