Saturday, December 19, 2015

Chatting with Binary Web Sockets

This is a follow up article to Chatting with Web Sockets.
Since version 0.97 beta, PAW Server supports binary Web Sockets. Before that only text base Web Sockets were supported.

Binary Web Sockets have the benefit (as the name implies) that binary Blobs (Binary Large Objects) can be exchanged. That offers the possibility to exchange binary data. This blog post shows how to use binary Web Sockets to build a simple (multi-) media chat client by using these new capabilities.

Bellow is a screenshot of the new chat window which also allows to drag and drop (media) files to send them to connected clients. There are two drop areas, the button titled Drop / Select and the message output area. In addition files can be selected by pressing the Drop / Select button.

Chat Window

Supported file types depend on the used browser, but normally audio, video, text and html files should work.

The setup is almost identical to the one described inside the former post Chatting with Web Sockets.
Only the ZIP file including HTML/CSS and JavaScript files are different. You'll find a link to the ZIP file below that post.

So to make sure Web Sockets are setup correctly follow the following steps from the post Chatting with Web Sockets:
  1. Configuring the Web Socket Handler
  2. Web Socket Config File
  3. The BeanShell Script
After the configuration is finished, the only thing left is to extract the ZIP file into a folder (e.g. chat2) of your choice inside the [PAW_HOME]/html folder (usually /sdcard/paw) and to call that page from a browser.

You can now try to connect to the web page (e.g. http://<ip>:8080/chat2/) with multiple browsers and see if the chat is working.

Have fun and merry Xmas :)

Links


Sunday, December 6, 2015

Extending Handlers with BeanShell

This post will show how to extend an existing handler by using BeanShell.
Since PAW 0.96 BeanShell can be used to write handlers (and filters). In earlier versions of PAW handlers and filters had to be provided as Java class file, so a Java development environment was needed. By the use of BeanShell handlers and filters can now be developed directly on an Android device. This is especially handy when developing handler and filters for testing.

PAW Standard Handler Chain

I’ll briefly recap what handlers are good for.
Handlers form the processing chain on HTTP requests. Handler are organized in a list that is processed until a handler processing the request is found. If a handler signals that it can handle the request, the handler will process the request and the list of handlers is no longer processed.

In the example we will extend the BasicAuthHandler which handles the basic authentication to protect a web resource (most often a directory).
The handler will be extended in the way, that it will only request credentials if pages are called from external, localhost request should not need to authenticate.

The standard BasicAuthHandler does not provide this functionality. It always asks for credentials, regardless where the request came from.

Since PAW 0.96 there is a new handler called CallBshHandler which accepts a BeanShell file to act as a handler.

The BeanShell file has the following base structure:

/*
    Variables: server, prefix, handler
*/
init() {

}

/*
    Variables: server, prefix, handler, request
*/
respond() {

}

There are the two methods init() and respond(). Both methods return true on success and false on failure. The init() method receives the server, prefix and handler variables. The server and prefix variables are needed to get configuration parameters specified inside the conf/handler.xml file. The handler variable holds a reference to the calling CallBshHandler  instance. This instance is needed to persist settings (between init() and response()) methods. This is necessary, because init() and response() are not called within the same BeanShell interpreter instance (to make the handler thread safe). To persists objects within the handler, the methods save() and load() are provided. The example will show how these methods are used.

Extending the current BasicAuthHandler will be done in three steps:
  1. Disable the BasicAuthHandler
  2. Create the new handler
  3. Configure the new  handler

Disable the BasicAuthHandler

To disabling the current BasicAuthHandler, find the following handler in the conf/handler.xml file and change the  status property to inactive
<handler status="inactive">
    <name>Basic Auth Handler</name>
   …
</hadler>

Create the New Handler

We will now build a handler that calls the standard BasicAuthHandler only on external requests. Local requests, which have the IP number 127.0.0.1 or ::1 will not be processed and so no credentials will be requested.

To build the new handler, create a directory handler inside the PAW installation folder (paw/handler). Inside that folder create a file called authHandler.bsh with the following content:

import org.paw.handler.BasicAuthHandler;

LOCALHOST = "127.0.0.1";
LOCALHOST_V6 = "::1";

/*
    Variables: server, prefix, handler
*/
init() {
    authHandler = new BasicAuthHandler(); 
    handler.save("authHandler", authHandler);

    return authHandler.init(server, prefix);

}

/*
    Variables: server, prefix, handler, request
*/
respond() {
    ip = request.sock.getInetAddress().getHostAddress();

    if(ip.equals(LOCALHOST) || ip.equals(LOCALHOST_V6)) {
        return false;
    }

    authHandler = handler.load("authHandler");
    return authHandler.respond(request);
}

The code is straightforward. Inside the init() method the BasicAuthHandler is instantiated. That instance is saved within the calling handler by calling handler.save().
The last line of the init() method returns the result of the call to init() of the instantiated BasicAuthHandler class.

If the init() method returns true, the handler will be added to the list of handlers and the respond()method will be called on each request.

When the respond() method is called it first gets the requestor’s IP number and assigns it to the variable ip. If the variable contains a localhost IP (127.0.0.1 or ::1) the method returns false, which indicates that the handler will not handle the request.
In that case no credentials are requested and the handler chain is further processed.

If the request is not initiated by a localhost address, the respond() method of the BasicAuthHandler instance is called and the return value of that method is returned.


Configure the New Handler

To configure the new handler, just place the following handler definition below or above the original BasicAuthHandler definition of the conf/hander.xml file:

<handler status="active">
    <name>BeanShell auth handler</name>
    <description>Auth handler that allows local access</description>
    <removable>true</removable>
    <id>bshAuth</id>
    <files/>
    <params>
      <param name="bshAuth.class" value="org.paw.handler.CallBshHandler" />
      <param name="bshAuth.script" value="[PAW_HOME]/handler/authHandler.bsh" />
      <param name="bshAuth.confdir" value="[PAW_HOME]/webconf/auth" />
    </params>
  </handler>

The parameters describe the class (org.paw.handler.CallBshHandler) and script ([PAW_HOME]/handler/authHandler.bsh) to use. The third parameter called confdir is the standard configuration parameter used by the BasicAuthHandler. The BeanShell handler passes this parameter when calling the BasicAuthHander.init() method from its init() method.

Because the new handler calls the standard handler, the Directory Protection settings from within PAW’s web interface also apply to the new handler.

On next startup of the server the new handler should be active. If the startup fails, increase the log level, restart the server and have a look at the log file.

Testing the Handler

To test the handler, I’ve created a directory test within the html folder (html/test). For the at folder, directory protection has been setup using the Directory Protection page of the web interface.
The localhost connection was tested by using ADB’s TCP forward parameter (adb forward tcp:8080 tcp:8080).

When testing with an IP number, authentication is required:

$ telnet 192.168.178.79 8080
Trying 192.168.178.79...
Connected to 192.168.178.79.
Escape character is '^]'.
GET /test/ HTTP/1.0

HTTP/1.0 401 Unauthorized
WWW-Authenticate: basic realm="Bsh Auth Test"
Date: Sun, 06 Dec 2015 09:05:38 GMT
Server: PAW Server 0.97-android (Brazil/2.0)
Connection: close
Content-Length: 34
Content-Type: text/html

Missing http header: AuthorizationConnection closed by foreign host.

On a localhost request, no authentication is needed and the directory listing is displayed:

$ telnet localhost 8080
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
GET /test/ HTTP/1.0

HTTP/1.0 200 OK
Set-Cookie: cookie=7th5kto9f4nrf1a5r8pdse; PATH=/
Date: Sun, 06 Dec 2015 09:08:32 GMT
Server: PAW Server 0.97-android (Brazil/2.0)
Connection: close
Content-Length: 99
Content-Type: text/html

<title>Directory Listing</title>
<h1>Directory Listing</h1>
<a href=..><b>parent directory</b></a>
Connection closed by foreign host.

Wednesday, November 25, 2015

WSMirror - Web Screen Mirror


WSMirror is a small app that mirrors the device screen and displays it within a web browser.
This can be handy for presentations or talks to present the device screen to a larger audience. The app uses the MediaProjection API available since Android Lollipop (5.x). So the app will only work on Devices running Lollipop or higher.
Due to the use of the MideaProjection API no root is required.



After pressing the start button a URL will be displayed. This URL can be inserted into the address bar of a mordern browser (WebSockets are required). The page will display the mirrored screen. Multiple connections are possible and device rotation is supported.



If the screen refresh is too slow, scaling and quality can be adjusted to make the mirroring more responsive.
To stop WSMirror, just press the stop button.

WSMirror is available on Google Play.


Saturday, October 3, 2015

PAW - New Tags

Since PAW Server 0.96 BeanShell tag handling in XHTML files has been improved. In addition PHP like tags are now supported.
In older PAW versions it was a bit cumbersome to write XHTML pages because BeanSHell and HTML could not be mixed. The following code would not have worked:

<bsh>if(i > 0) {</bsh>
<h3>TEST</h3>
<bsh>}</bsh>

This code now works in the new PAW version, because PAW does no longer execute BeanShell blocks separately but does build  complete BeanShell script representing the page that is executed as a whole.

The old tags <bsh> ... </bsh> still do work, but in addition PHP like <?bsh ... ?> tags are available.
Here is a short example:

<?bsh if(i > 0) { ?>
<h3>TEST</h3>
<?bsh } ?>

To make it easier to output BeanShell variables inside HTML code easier the short print tag <?= ... ?>  is now available:

<?bsh i = 7; { ?>
<b>Value of i = </b> <?=i ?>
<?bsh } ?>

Debugging

Sometimes BeanShell error output in XHTML pages might be hard to read and it sometimes makes development more complicated than it should be.

A BeanShell error output that is visible inside the HTML source looks like this:

<!--
BeanShell Error:

bsh.EvalError: Sourced file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : Attempt to resolve method: getProximity() on undefined variable or class name: sensorListener : at Line: 6 : in file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : sensorListener .getProximity ( ) 

-->

Now that the whole page is executed as one entity there is the possibility to show the generated code inside the HTML page source when an error occurred.
By default this feature is disabled (not everyone should see your code), but while developing it's a good idea to turn it on.

To enable the enhanced debug output, change the the value of the bsh.debug property inside the paw/con/handler.xml from false to true and restart the server.

<param name="bsh.debug" value="true" />

The above sample error message is now enhanced with the generated BeanShell code.

<!--
BeanShell Error:

bsh.EvalError: Sourced file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : Attempt to resolve method: getProximity() on undefined variable or class name: sensorListener : at Line: 6 : in file: inline evaluation of: ``$$.print("<html>\n<body>\n"); import de.fun2code.android.pawserver.AndroidInterf . . . '' : sensorListener .getProximity ( ) 

-->

<!--
Generated BeanShell Code:

  1    $$.print("<html>\n<body>\n");
  2    // Imports
  3    import de.fun2code.android.pawserver.AndroidInterface;
  4    import android.content.Context;
  5    import android.hardware.Sensor;
  6    sensorListener = AndroidInterface.getSensorListener();
* 7    proximity = sensorListene.getProximity();

-->

If possible the erroneous line is marked with an asterisk (*). This should make finding the error much easier.

Tuesday, September 22, 2015

Digest Authentication

Although the PAW Server configuration does not include Digest Authentication by default, this authentication scheme is available and can be configured inside the paw/conf/handler.xml configuration file.

To enable Digest Authentication, add the following lines to  the paw/conf/handler.xml file just after the opening <handlers> tag:

  <handler status="active">
    <name>Digest Handler</name>
    <description>Digest authentication handler.</description>
    <removable>true</removable>
    <id>authDigest</id>
    <files/>
    <params>
      <param name="authDigest.class" value="sunlabs.brazil.handler.DigestAuthHandler" />
      <param name="authDigest.prefix" value="/" />
      <param name="authDigest.realm" value="Protected" />
      <param name="authDigest.credentials" value="[PAW_HOME]/webconf/auth/digest.conf" />
    </params>
  </handler>

This configuration protects the whole web site, if you would only like to protect a single directory, you can change the prefix parameter.

Now create a file called paw/webconf/auth/digest.conf with the following content:

#---------------------------------------------------------
# Digest Authenticatin configuration
#---------------------------------------------------------
# Format:
# username=plain password
#
# Instead of the plain password, HA1 can be used:
# md5(user:realm:pass)
#
# username=HA1
#---------------------------------------------------------
user=test

The sample user is called user, with the password test.
It is recommended to build the HA1 hash for security reasons.

For the changes to take effect, restart the server.

Saturday, August 15, 2015

Advanced PAW Server - Pre-Release 1

PAW's documentation is far from perfect and I often get questions from users how things work. To make life for users and me easier I decided to write an eBook how to use PAW's API to write dynamic web applications.

This is the first pre-release of Advanced PAW Server.




It is not complete and surely contains a lot of bugs and typos.
Nevertheless I hope it is already useful at this point.

Have fun :)

The eBook is available in PDF format.

Here is the download Link:
https://goo.gl/6BDgno