diyhosting/cgi.html

265 lines
9.3 KiB
HTML

<!DOCTYPE html>
<html lang=en>
<head>
<title>Server-Side Scripting with CGI</title>
<!--# include file=".nav.html" -->
</head>
<body>
<header><h1>Server-Side Scripting with CGI</h1></header>
<nav></nav>
<main>
<p>
The basic website tutorial here describes how to set up a static
website &mdash; one that just serves HTML files saved on your server,
and until you change something manually, the same content will be served
each time a given page is requested. This is perfectly enough for most
personal website needs. This is how blogs should be implemented, instead
of relying on bloatware like WordPress!
</p>
<p>
But sometimes you genuinely <i>do</i> need something more. You need your
website to serve different contents depending on the time, on who the
requester is, on the contents of a database, or maybe process user input
from a form.
</p>
<h2>CGI</h2>
<p>
CGI, or the Common Gateway Interface, is a specification to allow you,
the server owner, to program your web server using pretty much any
programming language you might know. The specification is almost as old
as the Internet itself and for a long time CGI scripting was the primary
method of creating dynamic websites.
</p>
<p>
CGI is a very simple specification indeed. You write a script in your
favorite language, the script receives input about the request in
environment variables, and whatever you print to the standard output
will be the response. Most likely, though, you will want to use a
library for your language of choice that makes a lot of this
request/response handling simpler (e.g. parsing query parameters for
you, setting appropriate headers, etc.).
</p>
<h3>Limitations of CGI</h3>
<p>
While in theory you could implement any sort of functionality with CGI
scripts, it's going to get difficult managing a lot of separate scripts
if they're supposed to be working in tandem to implement a dynamic
website. If you want to build a full out web application, you'd probably
be better off learning a web framework than gluing together Perl
scripts.
</p>
<p>
That said, just as most of the web could be replaced with static
websites, much of the remaining non-static web could be replaced with a
few simple scripts, rather than bloated Ruby on Rails or Django
applications.
</p>
<h2>Let's write a CGI script!</h2>
<p>
We'll implement a simple example CGI script. I'll use Ruby for this
tutorial, but you'll be able to follow along even if you don't know
Ruby, just treat it as pseudocode then find a CGI library for your
language.
</p>
<h3>The working example</h3>
<p>
Our working example will be the Lazy Calculator. Yeah, you're probably
tired of seeing calculator examples in every programming tutorial, but
have you ever implemented one that takes the weekends off?
</p>
<p>
Here's how it will work. When in a browser you submit a request to your
website like
</p>
<pre><code>example.com/calculator.html?a=10&amp;b=32</code></pre>
<p>
you will receive a page with the result of the addition of 10 and 32:
42.
</p>
<p>
<i>Unless</i> you send your request on a weekend. Then the website will
respond with
</p>
<pre><code>I don't get paid to work on weekends! Come back Monday.</code></pre>
<p>
This example will show a few things that CGI scripts can do that you
wouldn't have been able to get using just file hosting in your
web server:
<ul>
<li> getting inputs from the user; </li>
<li>
getting external information (here just the system time, but you
could imagine instead connecting to a database);
</li>
<li> using the above to create dynamic output. </li>
</ul>
<h3>The code</h3>
<p>
Here's an implementation of the lazy calculator as a Ruby CGI script:
</p>
<pre><code>#!/bin/env ruby
require 'cgi'
require 'date'
cgi = CGI.new
today = Date::today
a = cgi["a"].to_i
b = cgi["b"].to_i
if today.saturday? || today.sunday?
cgi.out do
"I don't get paid to work on weekends! Come back Monday."
end
else
cgi.out do
(a + b).to_s
end
end</code></pre>
<p>
Let's go through what's happening here.
</p>
<h3>The shebang line</h3>
<p>
CGI works by pointing your web server to an executable program. A Ruby
or Python script by itself is not immediately executable by a computer.
But on Unix-like systems you can specify the program that will be able
to execute your file in its first line if it starts with <code>#!</code>
(known as the shebang; read more about it on
<a href="https://en.wikipedia.org/wiki/Shebang_(Unix)">Wikipedia</a>).
</p>
<p>
So if you're going to be using a scripting language, you'll probably
need the appropriate shebang line at the top of your script. If you use
a compiled language, you'll just point your web server to the compiled
executable binary.
</p>
<h3>Query parameters</h3>
<p>
The next interesting lines of code are where we set the variables
<code>a</code> and <code>b</code>. Here we are getting user inputs from
the request.
</p>
<p>
In the example request we mentioned above
(<code>example.com/calculator.html?a=10&amp;b=32</code>), the part
starting from the question mark, <code>?a=10&amp;b=32</code>, is the
<i>query string</i>. This is how users can submit parameters with their
web requests. Usually these parameters are set by e.g. a form on your
website, but in our simple example we'll be just manually manipulating
the URL.
</p>
<p>
The query string contains key-value pairs. The Ruby CGI library makes
them available in the <code>CGI</code> object it provides. We just need
to index it with the desired key, and we'll get the corresponding value.
</p>
<h3>Wrapping it up</h3>
<p>
The remaining parts of the code should be pretty self-explanatory. We
get today's date, check if it's a Saturday or a Sunday, and depending on
that, we instruct the CGI library to output either the answer, or a
"come back later" message.
</p>
<p>
The Ruby library by default returns an HTML response, so we really
should have wrapped our outputs in some <code>html</code>,
<code>body</code>, etc. tags. Alternatively, we could have specified
that the response is just plain text with
</p>
<pre><code>cgi.out 'text/plain' do</code></pre>
<p>
In general, your CGI library will probably have ways of specifying all
sorts of HTTP response headers, like status code, content type, etc.
</p>
<h2>Making it work</h2>
<p>
We have a CGI script, now let's point our web server to it.
</p>
<h3>Installing FastCGI</h3>
<p>
If you're using Nginx, install <code>fcgiwrap</code>:
</p>
<pre><code>apt install fcgiwrap</code></pre>
<p>
This installs the necessary packages for Nginx to use FastCGI &mdash; a
layer between your web server and CGI script that allows for faster
handling of scripts than if the web server had to handle it all by
itself.
</p>
<p>
Other web servers will probably have a similarly simple way of enabling
FastCGI, or you can look into other methods for launching CGI scripts.
</p>
<h3>Nginx configuration</h3>
<p>
In the configuration file for your website, add something like the
following:
</p>
<pre><code>location /calculator.html {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME /usr/local/bin/lazy-calculator.rb;
fastcgi_param QUERY_STRING $query_string;
fastcgi_pass unix:/run/fcgiwrap.socket;
}</code></pre>
<p>
<code>fastcgi_param</code> directives specify various parameters for
FastCGI. <code>SCRIPT_FILENAME</code> should point to your executable.
For <code>QUERY_STRING</code>, we just copy Nginx's
<code>$query_string</code> variable. You might want to pass other
information to your CGI script as well, see for example
<a href="https://wiki.debian.org/nginx/FastCGI">the Debian wiki</a> for
a more detailed example, including pointing to an entire directory of
CGI scripts, rather than adding each one by hand to your web server
config.
</p>
<h2>Contribution</h2>
<ul>
<li>Martin Chrzanowski -- <a
href="https://m-chrzan.xyz">website</a>, <a href="https://m-chrzan.xyz/donate.html">donate</a></li>
</ul>
</main>
<!--# include file=".footer.html" -->
</body>
</html>