summaryrefslogtreecommitdiff
path: root/content/cgi.md
blob: 5f293e992019de1ccbf2a4e2e9db5a0eda5f7372 (plain)
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
---
title: "Server-Side Scripting with CGI"
date: 2021-07-25
tags: ['server']
---
The basic website tutorial here describes how to set up a static website
--- 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!

But sometimes you genuinely *do* 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.

## CGI

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.

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.).

### Limitations of CGI

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.

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.

## Let\'s write a CGI script!

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.

### The working example

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?

Here\'s how it will work. When in a browser you submit a request to your
website like

```txt
example.com/calculator.html?a=10&b=32
```

you will receive a page with the result of the addition of 10 and 32:
42.

*Unless* you send your request on a weekend. Then the website will
respond with

```txt
I don't get paid to work on weekends! Come back Monday.
```

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:

-   getting inputs from the user;
-   getting external information (here just the system time, but you
    could imagine instead connecting to a database);
-   using the above to create dynamic output.

### The code

Here\'s an implementation of the lazy calculator as a Ruby CGI script:

```ruby
#!/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
```

Let\'s go through what\'s happening here.

### The shebang line

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 `#!` (known as
the shebang; read more about it on
[Wikipedia](https://en.wikipedia.org/wiki/Shebang_(Unix))).

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.

### Query parameters

The next interesting lines of code are where we set the variables `a`
and `b`. Here we are getting user inputs from the request.

In the example request we mentioned above
(`example.com/calculator.html?a=10&b=32`), the part starting from the
question mark, `?a=10&b=32`, is the *query string*. 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.

The query string contains key-value pairs. The Ruby CGI library makes
them available in the `CGI` object it provides. We just need to index it
with the desired key, and we\'ll get the corresponding value.

### Wrapping it up

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.

The Ruby library by default returns an HTML response, so we really
should have wrapped our outputs in some `html`, `body`, etc. tags.
Alternatively, we could have specified that the response is just plain
text with

```txt
cgi.out 'text/plain' do
```

In general, your CGI library will probably have ways of specifying all
sorts of HTTP response headers, like status code, content type, etc.

## Making it work

We have a CGI script, now let\'s point our web server to it.

### Installing FastCGI

If you\'re using Nginx, install `fcgiwrap`:

```sh
apt install fcgiwrap
```

This installs the necessary packages for Nginx to use FastCGI --- 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.

Other web servers will probably have a similarly simple way of enabling
FastCGI, or you can look into other methods for launching CGI scripts.

### Nginx configuration

In the configuration file for your website, add something like the
following:

```nginx
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;
}
```

`fastcgi_param` directives specify various parameters for FastCGI.
`SCRIPT_FILENAME` should point to your executable. For `QUERY_STRING`,
we just copy Nginx\'s `$query_string` variable. You might want to pass
other information to your CGI script as well, see for example [the
Debian wiki](https://wiki.debian.org/nginx/FastCGI) 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.

## Contribution

-   Martin Chrzanowski \-- [website](https://m-chrzan.xyz),
    [donate](https://m-chrzan.xyz/donate.html)