Fix Apache mod_jk or mod_proxy serving stale content

If your web app starts serving stale cached content when run behind mod_jk or mod_proxy with apache, it may be due to apache inserting a default expiration header.

You can confirm this by comparing the headers returned from apache and directly from your web app.  curl -i will show response headers:

curl -i http://example.com | head -20

To disable apache’s content expirations, add the following to your virtual host:

ExpiresActive Off

Here is the official Apache Documentation.

MIME type issue with Apache mod_jk and mod_proxy serving plain text

Some apps do not properly set mime types of content they serve, but still may work properly when served standalone because client applications like browsers are able to interpret the type of the content.  But when served behind Apache, these apps will not behave correctly because Apache will provide a default type of text/plain.

The solution is to add a DefaultType None line to your apache virtual host for these web apps:

DefaultType None

Here are the docs

Snow Leopard Apache Web Server SSL Pass phrase Error

If you are getting errors “Pass phrase incorrect” in your apache logs on Snow Leopard server, it is because the key is protected by a password.  I found the answer here.

The password for the key is stored in the System Keychain.  It is a password entry called “Mac OS X Server certificate management”.  You can open the entry and select “Show Password”.  You may also use the security command line tool to dump the password.

security find-generic-password -l "Mac OS X Server certificate management" -g

or

security dump-keychain -d # look in data for password which will look like a GUID

Once you have the password, you can create a copy of the key without the password using openssl:

openssl rsa -in /etc/certificates/server.domain.com.uniqueid.key.pem \
 -out /etc/certificates/server.domain.com.uniqueid.passwordlesskey.pem

You can then replace the password protected key with the passwordless key or point apache to the passwordless key in your /etc/apache2/sites/sitename.conf file.

Tips for writing command line tools in ruby

  1. Option parsing: Read this article by Allen Wei on RubyLearning Blog for a great overview.  I recommend sticking with the built-in OptionParser if you want to reduce dependencies.
  2. If you want your code to be loadable so you can access functions and classes in the irb console for testing, use the following pattern:
    def main
     #option parsing and execution code here
    end
    if __FILE__ == $0
     main()
    end

    This way the main function will only be automatically called if the script is being executed on the command line.
    And in irb, you can call your functions and classes as you see fit for testing without triggering your whole script to run.

    Note that this is similar to the python __main__ test if you are coming from a python background.

  3. Naming without ruby’s.rb extension: You can name your executable without the rb extension if you wish, just be sure to include your shebang (#!)

    To use the user’s default ruby, use:
    #!/usr/bin/env ruby
    But in some cases you may want the specify the path to ruby so you can use macruby or rubycocoa if you are need those frameworks to be available
    #!/usr/bin/ruby

    When testing in irb,
    require 'script-name'
    won’t work without the rb extension, but
    load 'script-name'
    does work.
  4. Use exit codes. When your script fails or needs to communicate status at exit, use standard exit status codes.
    Exit zero for default success status
    exit 0
    Exit any other number for a failure or warning status. You choose the exit codes for your tool, but be sure to document them if they require more explanation than simple success or failure.
    exit 27
  5. Output to stderr using:
    $stderr.puts "error: problem ...."

Parsing Mac OS X System Profiler

It is pretty cool how Apple System Profiler has a command line equivalent (system_profiler). And it is pretty cool how system_profiler has a -xml option to allow for easier parsing. You might use this info for extracting asset information into a database or for puppet facter facts.

However if you’ve ever looked at that xml, you know that it is a tree full of unpredictable semi-structured data that was designed specifically for the GUI app. So even though you can parse it with your favorite plist parser, there is still a lot more work to do to get to the data you care about.

The tree structure is nice for a browsing through on a single machine, but not so good for reporting across many machines.

Apple stores most of the same data as key value pairs in its database for ARD reporting, but they do a lot of massaging of the data to get it that way.

It is possible to get at this data in an ARD database if you have an ARD collection server, but an ARD collection server isn’t for everyone and doesn’t serve every use case.

You can still get at the nicely formatted ARD information. ARD client includes a tool that outputs most, if not all of the asset information you care about in a much nicer structured format for reporting.

The tool is called sysinfocachegen and you use it like this:

sudo /System/Library/CoreServices/RemoteManagement/ARDAgent.app/Contents/Support/sysinfocachegen -p /tmp/com.yourorganization.systeminfo.plist

Just use your favorite language’s plist parser to read the plist.

Read and Write to a Process using Ruby IO popen without blocking

Once in a while you need to control an interactive command line tool. I kept getting a block when trying to read from a ruby IO popen pipe that was waiting for input. Here is my simple solution/workaround:

sh_process = IO.popen('sh > out.log', 'w')
f = File.open("out.log", "r")
sh_process.puts("ls")
f.read
sh_process.puts("uptime")
f.read
...
f.close

Basically, just create a temp file and read from that. A little hackish, but it works.

Customizing the Cisco or IPSec VPN client in Snow Leopard

The Snow Leopard VPN is not very configurable from the GUI, but behind the scenes it is using a racoon configuration.

To grab the configuration it is generating, configure the VPN in the System Preferences GUI, then rename /usr/sbin/racoon and try connecting. The config file will be written in /var/run/racoon/. Grap a copy of that file and customize it to your needs. Once you have the config file, rename racoon back to its original name.

Then to make the GUI use your custom config file instead of the one it generates, edit /etc/racoon/racoon.conf to include your custom config file and comment out the line:
include "/var/run/racoon/*.conf" ;

By making a few changes I was able to get a successful connection to our Cisco VPN Concentrators.

I’m hoping there is a less hacky way to accomplish this. If you know of one, let me know. Otherwise file a bug with Apple.

Posting form params with httperf or using netcat for troubleshooting

Web apps including rails won’t parse parameters POSTed in an http request unless a specific header is present.
A curl command automatically adds this header for you, but other tools including httperf might not.

To ensure the header gets sent with httperf, add the following command line option:
--add-header 'Content-Type: application/x-www-form-urlencoded\n'

Note, I discovered the answer because curl worked, though httperf did not. So I ran the curl command against a simple netcat (nc) server and noticed the extra http header being received. Netcat was really handy for this. To run a netcat server simply enter nc -l 1234, where 1234 is the port you want to listen on. Then run your client app pointing to your netcat server ip and port. The netcat server will output the raw TCP it receives.