Reading HTTP POST data using BASH

I recently needed to read the HTTP POST data using a BASH cgi script.

When using BASH this way most of the HTTP variables are set as environment variables, and can be accessed simply. The exception is the HTTP POST data, this goes to the stdin stream.

There were some examples of reading stdin like:

1
POST_DATA=$(</dev/stdin)

and

1
POST_DATA=`cat /dev/stdin`

However I found that these intermittently failed. I believe this is because at the point of execution you can not guarantee that all the data has been sent.

The solution to this is to use the CONTENT_LENGTH environment variable to read the correct number of bytes:

1
2
3
4
5
6
#!/bin/bash
if [ "$REQUEST_METHOD" = "POST" ]; then
    if [ "$CONTENT_LENGTH" -gt 0 ]; then
        read -n $CONTENT_LENGTH POST_DATA <&0
    fi
fi

Outlook / Google Calendar synchronization

I’ve been using Google Calendar Sync for several weeks now and it has removed the headaches of having calendars in two places.

Google Calendar Sync can be configured to do a 2-way synchronization, or a 1-way synchronization (in either direction). It is very quick to setup, and has very few options that need configuring.
Google Calendar Sync
The only improvement I would like is support for multiple calendars. I would like 2-way synchronization for my work calendar, and 1-way synchronization from my other Google Calendars to my Outlook Calendar.

WordTwit WordPress Plugin Installed

I have just installed the WordTwit WordPress Plugin. This post is primarily a test to check that it is all working.

The domain switch

After much procrastination I have finally made the domain switch over to paulturner.me.

All requests to the original domain paul-turner.net are automatically redirected to the correct page on the new domain with a “301 Moved Permanently” HTTP header.

This means that all search engine traffic should be preserved, and the links updated over time.

This was achieved simply with mod_rewrite and a single index.php page:

1
2
3
<?php
header('Location: http://paulturner.me'.$_SERVER['REQUEST_URI'],TRUE,301);
?>

Please update your links.

paulturner.me

A while ago I registered the domain paulturner.me for
a few reasons:

  1. I don’t really like the hyphen in paul-turner.net.
  2. It’s a little more personal.
  3. I currently don’t own paul-turner.net.  (It’s owned by my web hosting company, although I have the option to purchase it)

Currently http://paulturner.me/ redirects back to http://paul-turner.net/ although I have been considering a swap over for some time now.

If I do this my thoughts are to use mod_rewrite with a single PHP program that accepts all the requests from http://paul-turner.net/ and responds with a permanent redirect to the same page on http://paulturner.me/.

Are there any implications in doing this?  I would think that this approach would update all the search engines over time.

What do you think?  Leave me a comment.

Time-lapse tilt-shift photography

Time-lapse photography is a technique where each frame is captured at a much slower rate than it is played back.  When it is replayed everything appears to be moving faster.

Tilt-shift photography is a technique of distorting the plane of focus of an image by tilting the camera lens and distorting the perspective by shifting the lens.  This leads to images which appear to be of miniture worlds.

Combining these two techiniques creates some interesting videos, such as the one below by Keith loutit.


Beached from Keith Loutit on Vimeo.

I found this video here at Web Urbanist.  They have a couple more examples by Keith Loutit, along with several examples of tilt-shit photography.

7 Day Shop

7 Day Shop have always provided good value photographic products, computer & digital accessories (and more as well).

I have used them several times in the past and they have always been reliable and efficient. They have recently announced that they are no longer charging for postage in the UK.

This is great news!

Connect to a Windows remote desktop using Linux

Whilst browsing I found this article of 10 tips when making the switch to Ubuntu Linux.  One of the tips is Remote desktop to a Windows desktop/server.

There is a program called rdesktop that allows you to connect to a windows remote desktop sesson on an IP address (over RDP):

1
rdesktop [server]:[port]

The remote desktop I tried this on was using a VPN tunnel using this command:

1
rdesktop localhost:52893

The article also linked to the Wikipedia rDesktop article which linked to information for other RDP clients.

The only downside I found so far is that the screen resolution was restricted to 800*600 with 16 colours. Not a big problem for occasional use, but I may investigate some of the other solutions.

Does anyone else know of a better alternative?

MySQL slow query log

The MySQL slow query log enables you to log all queries that take longer than a specified number of seconds to execute.  This should help identify any queries that are not performing sufficiently.

All that is required is two additional lines in the MySQL configuration file “my.cnf” in the [mysqld] section.

1
2
3
[mysqld]
log-slow-queries = /var/log/mysql-slow.log
long_query_time = 4

The above configuration will log any queries taking longer than 4 seconds to execute in to the specified log file.

MySQL appears to require that the specified log file exists otherwise the logging is disabled and the error below appears in the MySQL log. (Or it may be that it didn’t have permissions to create the file. I haven’t investigated).

1
081013 14:55:37 [ERROR] Could not use /var/log/mysql-slow.log for logging (error 13). Turning logging off for the whole duration of the MySQL server process. To turn it on again: fix the cause, shutdown the MySQL server and restart it.

To create the log file I did the following:

1
2
3
touch /var/log/mysql-slow.log
chown mysql.mysql /var/log/mysql-slow.log
chmod o-r /var/log/mysql-slow.log

The third command is probably unnecessary, but it meant that the permissions matched the mysqld.log in the same directory.

Once this is done MySQL needs to be restarted to start the query logging:

1
service mysql restart

Visual Basic 6, ActiveX and Unicode

One of the older applications I support uses ActiveX controls embedded inside a web page.  These controls request data from a web server to update the information on the page without requesting the whole page again, much in the same way that AJAX is now commonly used.

This has worked fine for the Latin code pages (ISO8859-1, ISO8859-15), and for the double byte code page (cp950)  that have been tested.  However it did not work when I tried the UTF-8 Unicode code page.

The reason for this is fairly simple:

VB stores strings internally using Unicode, but assumes that the outside world is ANSI.

This means that Visual Basic will convert from ANSI to Unicode (UTF-16) when storing a string, and convert it back again when it is retrieved.

The ActiveX controls use the Microsoft Inet control to request data via HTTP.  This uses the GetChunck() method in the StateChanged event in order to read the data in to a string. This was the first cause of my problems as Visual Basic will automatically convert the data in the string to ANSI, which loses the Unicode characters.

The Inet control GetChunck() method takes two parameters; size and data type. The size parameter tells it how much data to read, and the data type parameter tells it what data type to read it in to. The data was being read in to a string (icString), but to avoid the conversion I had to change this to a byte array (icByteArray) to avoid the automatic conversion process.

So far so good. But now I had a UTF-8 byte array that I needed to convert in to a string without losing data in the conversion process. This was a bit of a sticking point as Visual Basics string conversion function StrConv() can’t cope with UTF-8 and none of the API calls I found to convert the string worked. You can assign a string equal to a byte array and no automatic conversion happens, but as strings are stored internally as UTF-16 this does not work.

I was nearly at the stage where I either needed to write my own conversion process, or re-develop the controls in another language with better UTF-8 support.

Then I found this solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
Public Function ConvertUtf8BytesToString(ByRef data() As Byte) As String
    Dim objStream As ADODB.Stream
    Dim strTmp As String

    ' init stream
    Set objStream = New ADODB.Stream
    objStream.Charset = "utf-8"
    objStream.Mode = adModeReadWrite
    objStream.Type = adTypeBinary
    objStream.Open

    ' write bytes into stream
    objStream.Write data
    objStream.Flush

    ' rewind stream and read text
    objStream.Position = 0
    objStream.Type = adTypeText
    strTmp = objStream.ReadText

    ' close up and return
    objStream.Close
    ConvertUtf8BytesToString = strTmp
End Function

This does not use any APIs but requires the Microsoft ActiveX Data Objects 2.5 Library or later.

Using this solution I was able to assign the original internal string variable to the result of this function and the rest of the code in the controls worked.

1
strWSConnectReturnData = ConvertUtf8BytesToString(bytWSConnectReturnData)

The ActiveX controls also read data values from the webpage and POST them back to the webserver.  The values are read via the DOM. These also need to be converted in the opposite direction, before they can be URL encoded.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Public Function ConvertStringToUtf8Bytes(ByRef strText As String) As Byte()
    Dim objStream As ADODB.Stream
    Dim data() As Byte

    ' init stream
    Set objStream = New ADODB.Stream
    objStream.Charset = "utf-8"
    objStream.Mode = adModeReadWrite
    objStream.Type = adTypeText
    objStream.Open

    ' write bytes into stream
    objStream.WriteText strText
    objStream.Flush

    ' rewind stream and read text
    objStream.Position = 0
    objStream.Type = adTypeBinary
    objStream.Read 3 ' skip first 3 bytes as this is the utf-8 marker
    data = objStream.Read()

    ' close up and return
    objStream.Close
    ConvertStringToUtf8Bytes = data
End Function

This returns a byte array, and I pass it directly in to a function that URL encodes the byte array, returning a sting.

1
String = URLEncodeUTF8ByteArray( ConvertStringToUtf8Bytes( DomValue) )

Many thanks to Tim Hastings for his solution, as this has saved me a lot of pain!