openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs

commit 1c81d899acb3148e5365f6112ea328e36b58d2df
parent 5eb41df7cab498ca1373696c0f9f893e55cc291e
Author: dankert <devnull@localhost>
Date:   Mon, 14 Sep 2009 23:36:20 +0200

Client-Bibliotheken für PHP und Java.

Diffstat:
client/java/de/openrat/client/CMSRequest.java | 387+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
client/java/de/openrat/client/test/CMSRequestTest.java | 173+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
client/php/client.php | 147+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 707 insertions(+), 0 deletions(-)

diff --git a/client/java/de/openrat/client/CMSRequest.java b/client/java/de/openrat/client/CMSRequest.java @@ -0,0 +1,387 @@ +/* +OpenRat Java-Client +Copyright (C) 2009 Jan Dankert + +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; if not, write to the +Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +Boston, MA 02110-1301, USA. + + */ +package de.openrat.client; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.StringReader; +import java.io.UnsupportedEncodingException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketAddress; +import java.net.URLEncoder; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; + +import org.w3c.dom.Document; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +/** + * API-Request to the OpenRat Content Management System. <br> + * <br> + * The call to the CMS server is done via a (non-SSL) HTTP connection.<br> + * <br> + * Before a call you are able to set some key/value-pairs as parameters. After calling the CMS a + * DOM-document is returned, which contains the server response.<br> + * Example <br> + * + * <pre> + * CMSRequest request = new CMSRequest(&quot;your.openrat.example.com&quot;); + * //prints tracing information to stdout. + * request.trace = true; + * try { + * request.parameter.put(&quot;action&quot;, &quot;index&quot;); + * request.parameter.put(&quot;subaction&quot;, &quot;showlogin&quot;); // login page + * request.parameter.put(&quot;...&quot;, &quot;...&quot;); + * Document response = request.call(); + * // now traverse through the dom tree and get your information. + * } + * catch (IOException e) { + * // your error handling. + * } + * </pre> + * + * @author Jan Dankert + */ +public class CMSRequest { + + // some constants... + private static final String CHARSET_UTF8 = "UTF-8"; + private static final String HTTP_GET = "GET"; + private static final String HTTP_POST = "POST"; + + /** + * if <code>true</code>, Tracing-Output will be logged to stdout. Default: <code>false</code>. + */ + // this is public, for easier use. + public boolean trace = false; + + /** + * HTTP-method, must be "GET" or "POST", default: "GET". + */ + private String method = HTTP_GET; + + /** + * Parameter map. + */ + private Map<String, String> parameter = new HashMap<String, String>(); + + private String serverPath; + private String serverHost; + private int serverPort; + + private String proxyHostname; + private int proxyPort; + private SocketAddress socketAddress; + + private String cookieName; + private String cookieValue; + + /** + * Setting a HTTP-Cookie. + * + * @param name name + * @param value value + */ + public void setCookie(String name, String value) { + + this.cookieName = this.urlEncode(name); + this.cookieValue = this.urlEncode(value); + } + + /** + * URL-Encoder. + * + * @param value + * @return url-encoded value + */ + private String urlEncode(String value) { + + try { + return URLEncoder.encode(value, CHARSET_UTF8); + } + catch (UnsupportedEncodingException e) { + // maybe... this would be strange + throw new IllegalStateException(CHARSET_UTF8 + " ist not supported by this VM"); + } + } + + /** + * Setting a HTTP-Proxy. + * + * @param host hostname + * @param port port + */ + public void setProxy(String host, int port) { + + this.proxyHostname = host; + this.proxyPort = port; + } + + /** + * Set the HTTP Method. Default is "GET". + * + * @param method HTTP-method + */ + public void setMethod(String method) { + + if (!HTTP_GET.equalsIgnoreCase(method) && !HTTP_POST.equalsIgnoreCase(method)) + throw new IllegalArgumentException("Method must be '" + HTTP_POST + "' or '" + HTTP_GET + + "'."); + + this.method = method.toUpperCase(); + } + + /** + * Clear parameter values. + */ + public void clearParameters() { + + parameter.clear(); + } + + /** + * Setting a parameter value. <strong>DO NOT url-encode your values</strong> as this is done + * automatically inside this method! + * + * @param paramName name + * @param paramValue value + */ + public void setParameter(String paramName, String paramValue) { + + if (paramName == null || paramValue == null || "" == paramName) + throw new IllegalArgumentException("parameter name and value must have values"); + + parameter.put(paramName, paramValue); + } + + /** + * Constructs a CMS-Request to the specified server.<br> + * Server-Path is "/", Server-Port is 80. + * + * @param host hostname + */ + public CMSRequest(String host) { + + super(); + this.serverHost = host; + this.serverPath = "/"; + this.serverPort = 80; + } + + /** + * Constructs a CMS-Request to the specified server/path.<br> + * Server-Port is 80. + * + * @param host hostname + * @param path path + */ + public CMSRequest(String host, String path) { + + super(); + this.serverHost = host; + this.serverPath = path; + this.serverPort = 80; + } + + /** + * Constructs a CMS-Request to the specified server/path/port. + * + * @param host hostname + * @param path path + * @param port port-number + */ + public CMSRequest(String host, String path, int port) { + + super(); + this.serverHost = host; + this.serverPath = path; + this.serverPort = port; + } + + /** + * Sends a request to the openrat-server and parses the response into a DOM tree document. + * + * @return server response as a DOM tree + * @throws IOException if server is unrechable or responds non-wellformed XML + */ + public Document performRequest() throws IOException { + + final Socket socket = new Socket(); + + try { + + final boolean useProxy = this.proxyHostname != null; + final boolean useCookie = this.cookieName != null; + + if (serverPath == null) + this.serverPath = "/"; + if (!serverPath.startsWith("/")) + this.serverPath = "/" + this.serverPath; + + // When a client uses a proxy, it typically sends all requests to that proxy, instead + // of to the servers in the URLs. Requests to a proxy differ from normal requests in one + // way: in the first line, they use the complete URL of the resource being requested, + // instead of just the path. + if (useProxy) { + socketAddress = new InetSocketAddress(this.proxyHostname, this.proxyPort); + } else { + socketAddress = new InetSocketAddress(this.serverHost, serverPort); + } + + socket.setKeepAlive(false); + socket.setReuseAddress(false); + socket.connect(socketAddress, 5000); + + final StringBuffer header = new StringBuffer(); + + final StringBuffer parameterList = new StringBuffer(); + + for (Entry<String, String> entry : this.parameter.entrySet()) { + if (parameterList.length() > 0) + parameterList.append("&"); + parameterList.append(this.urlEncode(entry.getKey())); + parameterList.append("="); + parameterList.append(this.urlEncode(entry.getValue())); + } + + String httpUrl = this.serverPath; + + if (useProxy) + // See RFC 2616 Section 5.1.2 "Request-URI" + // "The absolute URI form is REQUIRED when the request is being made to a proxy" + httpUrl = "http://" + this.serverHost + httpUrl; + + if (HTTP_GET.equals(this.method)) + httpUrl = httpUrl + "?" + parameterList; + + // using HTTP/1.0 as this is supported by all HTTP-servers and proxys. + // We have no need for HTTP/1.1 at the moment. + header.append(this.method + " " + httpUrl + " HTTP/1.0\n"); + + // Setting the HTTP Header + header.append("Host: " + this.serverHost + "\n"); + header.append("User-Agent: Mozilla/5.0; compatible (OpenRat java-client)\n"); + header.append("Accept: application/xml\n"); + header.append("Accept-Language: " + Locale.getDefault().getLanguage() + "\n"); + header.append("Accept-Charset: utf-8\n"); + header.append("Connection: close\n"); + if (useCookie) + header.append("Cookie: " + cookieName + "=" + cookieValue + "\n"); + + if (HTTP_POST.equals(this.method)) { + header.append("Content-Type: application/x-www-form-urlencoded" + "\n"); + header.append("Content-Length: " + parameterList.length() + "\n"); + } + + header.append("\n"); + + if (HTTP_POST.equals(this.method)) + header.append(parameterList); + + if (this.trace) + System.out.println("--- request ---"); + if (this.trace) + System.out.println(header.toString()); + + final PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true); + printWriter.write(header.toString()); + printWriter.flush(); + + final InputStream inputStream = socket.getInputStream(); + final int available = inputStream.available(); + + final BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket + .getInputStream())); + + final String httpResponse = bufferedReader.readLine().trim(); + final String httpRetCode = httpResponse.substring(9, 12); + + if (this.trace) + System.out.println("--- response ---"); + if (this.trace) + System.out.println(httpResponse); + + // Check if we got the status 200=OK. + if (!httpRetCode.equals("200")) { + + // non-200-status seems to be an error. + throw new IOException("No HTTP 200: Status=" + httpRetCode + " (" + httpResponse + + ")"); + } + + while (true) { + + String responseHeader = bufferedReader.readLine().trim(); + + if (responseHeader.equals("")) + break; + + if (this.trace) + System.out.println(responseHeader); + } + + StringBuffer response = new StringBuffer(); + while (bufferedReader.ready()) { + + response.append(bufferedReader.readLine() + "\n"); + } + socket.close(); + + if (this.trace) + System.out.println("--- response body ---"); + if (this.trace) + System.out.println(response + "\n\n\n"); + + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + final DocumentBuilder builder = factory.newDocumentBuilder(); + final Document document = builder.parse(new InputSource(new StringReader(response + .toString()))); + + return document; + + } + catch (ParserConfigurationException e) { + throw new IOException("XML-Parser-Configuration invalid" + e.getMessage()); + } + catch (SAXException e) { + throw new IOException("Server did not return a valid XML-document" + e.getMessage()); + } + finally { + try { + socket.close(); // Clean up the socket. + } + catch (IOException e) { + // We have done our very best. + } + } + } +} diff --git a/client/java/de/openrat/client/test/CMSRequestTest.java b/client/java/de/openrat/client/test/CMSRequestTest.java @@ -0,0 +1,173 @@ +package de.openrat.client.test; + +import java.io.IOException; + +import javax.xml.xpath.XPath; +import javax.xml.xpath.XPathConstants; +import javax.xml.xpath.XPathExpression; +import javax.xml.xpath.XPathExpressionException; +import javax.xml.xpath.XPathFactory; + +import junit.framework.TestCase; + +import org.w3c.dom.Document; +import org.w3c.dom.NodeList; + +import de.openrat.client.CMSRequest; + +/** + * @author Jan Dankert + */ +public class CMSRequestTest extends TestCase { + + /** + */ + public void testRequest() { + + // Call the DEMO-Server of OpenRat. + CMSRequest request = new CMSRequest("demo.openrat.de", "", 80); + + // prints tracing information to stdout. + request.trace = true; + + // setting a HTTP proxy + request.setProxy("proxy.somewhere.example", 8080); + + // Now we do some example requests to the openrat server. + try { + // requesting the login page + request.setParameter("action", "index"); + request.setParameter("subaction", "showlogin"); + Document document = request.performRequest(); + + // Evaluating the session id. + String sessionName = this.getText(document, "/server/session/name"); + String sessionId = this.getText(document, "/server/session/id"); + request.setCookie(sessionName, sessionId); + + // lets try login with a wrong password + request.clearParameters(); + request.setMethod("POST"); + request.setParameter("action", "index"); + request.setParameter("subaction", "login"); + request.setParameter("login_name", "admin"); + request.setParameter("login_password", "wrongpassword"); // forcing an login error + request.setParameter("dbid", "db1"); + + document = request.performRequest(); // will answer with an error element, see stdout. + // we are NOT logged in now. + + // requesting a page which is only available for authenticated users + request.setMethod("get"); + request.clearParameters(); + request.setParameter("action", "index"); + request.setParameter("subaction", "projectmenu"); + + try { + document = request.performRequest(); + fail(); + } + catch (IOException e) { + // should crash with HTTP-status=403, as we are NOT logged in. + } + + // requesting a unknown action, the server should throw an error + request.clearParameters(); + request.setParameter("action", "index"); + request.setParameter("subaction", "didntknow"); + + try { + document = request.performRequest(); + fail(); + } + catch (IOException e) { + // should crash with HTTP-status=501, as the subaction does not exist. + } + + // OK, lets try a real login now. + request.setMethod("POST"); + request.clearParameters(); + request.setParameter("action", "index"); + request.setParameter("subaction", "login"); + request.setParameter("login_name", "admin"); + request.setParameter("login_password", "admin"); + request.setParameter("dbid", "db1"); + + document = request.performRequest(); + + // lets see, what projects are available. + request.setMethod("get"); + request.clearParameters(); + request.setParameter("action", "index"); + request.setParameter("subaction", "projectmenu"); + + document = request.performRequest(); + + // Access the project names via XPath + NodeList nl = this.getNodeSet(document, "/server/projects/entry/name"); + for (int i = 0; i < nl.getLength(); i++) { + System.out.println("Project name: " + nl.item(i).getTextContent()); + } + + // list all users + request.clearParameters(); + request.setParameter("action", "user"); + request.setParameter("subaction", "listing"); + + document = request.performRequest(); + + // lets see the rights of the folder with id 1 + request.clearParameters(); + request.setParameter("action", "folder"); + request.setParameter("subaction", "rights"); + request.setParameter("id", "1"); + + document = request.performRequest(); + + // lets see the contents of the folder with id 1 + request.clearParameters(); + request.setParameter("action", "folder"); + request.setParameter("subaction", "show"); + request.setParameter("id", "1"); + + document = request.performRequest(); + + // Access the object names via XPath + nl = this.getNodeSet(document, "/server/object/entry/name"); + for (int i = 0; i < nl.getLength(); i++) { + System.out.println("Object name: " + nl.item(i).getTextContent()); + } + } + catch (IOException e) { + + e.printStackTrace(); + fail(); + } + } + + private String getText(Document document, String xpath) throws IOException { + + XPath xPath = XPathFactory.newInstance().newXPath(); + + try { + XPathExpression xPathExpression = xPath.compile(xpath); + return (String) xPathExpression.evaluate(document, XPathConstants.STRING); + } + catch (XPathExpressionException e) { + throw new IOException(e.getMessage()); + } + } + + private NodeList getNodeSet(Document document, String xpath) throws IOException { + + XPath xPath = XPathFactory.newInstance().newXPath(); + + try { + XPathExpression xPathExpression = xPath.compile(xpath); + return (NodeList) xPathExpression.evaluate(document, XPathConstants.NODESET); + } + catch (XPathExpressionException e) { + throw new IOException(e.getMessage()); + } + } +} diff --git a/client/php/client.php b/client/php/client.php @@ -0,0 +1,146 @@ +<html> +<head> +<title>OpenRat API-Client</title> +</head> +<body> +<h1>OpenRat API-Client</h1> +<h2>Request</h2> +<form action="<?php echo $_SERVER['SCRIPT_NAME'] ?>"> +<table> +<tr> +<th>Parameter</th><th>Value</th> +</tr> +<?php for( $i=1; $i<=10; $i++ ) { ?> +<tr> +<td><input name="param<?php echo $i ?>" value="<?php echo $_REQUEST['param'.$i] ?>"></td> +<td><input name="value<?php echo $i ?>" value="<?php echo htmlentities($_REQUEST['value'.$i]) ?>" size="50"></td> +<!-- +<td><textarea rows="3" cols="50" name="value<?php echo $i ?>"><?php echo htmlentities($_REQUEST['value'.$i]) ?></textarea></td> + --> +</tr> +<?php } ?> +</table><br> +<select name="type"> +<?php foreach( array('text/html','application/json','application/xml') as $type ) { ?> +<option value="<?php echo $type ?>" <?php echo ($_REQUEST['type']==$type)?'selected':'' ?>><?php echo $type ?></option> +<?php } ?> +</select><input type="submit"> +</form> +<hr> +<h2>Response</h2> +<strong> +<?php if ( !empty($_REQUEST['param1']) ) { + + $error = ''; + $status = ''; + + $errno = 0; + $errstr = ''; + + $host = $_SERVER['SERVER_ADDR']; + $port = $_SERVER['SERVER_PORT']; + $path = substr($_SERVER['SCRIPT_NAME'],0,-15).'/do.php'; + $method = 'GET'; + + // Die Funktion fsockopen() erwartet eine Protokollangabe (bei TCP optional, bei SSL notwendig). + if ( $port == '443' ) + $prx_proto = 'ssl://'; // SSL + else + $prx_proto = 'tcp://'; // Default + + $fp = fsockopen ($prx_proto.$host,$port, $errno, $errstr, 30); + + if ( !$fp || !is_resource($fp) ) + { + echo "Connection refused: '".$prx_proto.$host.':'.$port." - $errstr ($errno)"; + } + else + { + $lb = "\r\n"; + $http_get = $path; + + $parameterString = ''; + + for( $i = 1;$i<=10;$i++) + { + if (!empty($_REQUEST['param'.$i])) + { + if ( strlen($parameterString) > 0) + $parameterString .= '&'; + elseif ( $withPraefixQuestionMark ) + $parameterString .= '?'; + + $parameterString .= urlencode($_REQUEST['param'.$i]) . '=' .urlencode($_REQUEST['value'.$i]); + } + } + + if ( $method == 'GET') + if ( !empty($parameterString) ) + $http_get .= '?'.$parameterString; + + if ( $method == 'POST' ) + { + $header[] = 'Content-Type: application/x-www-form-urlencoded'; + $header[] = 'Content-Length: '.strlen($parameterString); + } + + $header[] = 'Host: '.$host; + $header[] = 'Accept: '.$_REQUEST['type']; + $request_header = array( $method.' '.$http_get.' HTTP/1.0') + $header; + $http_request = implode($lb,$request_header).$lb.$lb; + + if ( $method == 'POST' ) + $http_request .= $parameterString; + + if (!is_resource($fp)) { + $error = 'Connection lost after connect: '.$prx_proto.$host.':'.$port; + return false; + } + fputs($fp, $http_request); // Die HTTP-Anfrage zum Server senden. + + // Jetzt erfolgt das Auslesen der HTTP-Antwort. + $isHeader = true; + + // RFC 1945 (Section 6.1) schreibt als Statuszeile folgendes Format vor + // "HTTP/" 1*DIGIT "." 1*DIGIT SP 3DIGIT SP + if (!is_resource($fp)) { + echo 'Connection lost during transfer: '.$host.':'.$port; + } + elseif (!feof($fp)) { + $line = fgets($fp,1028); + $status = substr($line,9,3); + } + else + { + echo 'Unexpected EOF while reading HTTP-Response'; + } + + while (!feof($fp)) { + $line = fgets($fp,1028); + if ( $isHeader && trim($line)=='' ) // Leerzeile nach Header. + { + $isHeader = false; + } + elseif( $isHeader ) + { + list($headerName,$headerValue) = explode(': ',$line) + array(1=>''); + $responseHeader[$headerName] = trim($headerValue); + } + else + { + $body .= $line; + } + } + fclose($fp); // Verbindung brav schlie�en. + $response = $body; + + // 301 Moved Permanently + // 302 Moved Temporarily + echo '<span style="background-color:'.($status=='200'?'green':'red').'">HTTP-Status '.$status.'</span>'; + } + ?> + </strong> +<pre><?php echo htmlentities($response) ?></pre> +<?php } ?> +</body> +</html>+ \ No newline at end of file