Skip to content

Instantly share code, notes, and snippets.

@michaelfm1211
Last active September 5, 2022 02:58
Show Gist options
  • Save michaelfm1211/99b754eaafb494dbceb9928ac67491ba to your computer and use it in GitHub Desktop.
Save michaelfm1211/99b754eaafb494dbceb9928ac67491ba to your computer and use it in GitHub Desktop.
cowsay CGI in C (tested with fastcgi+nginx)
/*
ISC License
Copyright 2022 Michael M.
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#define BUF_SIZ 1024
#define COWSAY_CMD "cowsay"
#define HTTP_400 "400 Bad Request"
#define HTTP_411 "411 Length Required"
// Returns an environment variable if it exists. Otherwise, panic with err.
const char *assert_env(const char *name, const char *err) {
const char *var = getenv(name);
if (!var) {
printf("Status: %s\n\n", err);
exit(1);
}
return var;
}
// Remove all non-alphabetic characters from NULL-terminated string str.
void sanitize(char *str) {
int x = 0;
for (int i = 0; str[i]; i++) {
if (isalpha(str[i]))
str[x++] = str[i];
}
str[x] = '\0';
}
int main() {
const char *req_method = assert_env("REQUEST_METHOD", HTTP_400);
if (strcmp(req_method, "POST")) {
puts("Status: 501 Not Implemented\n");
return 1;
}
int len = atoi(assert_env("CONTENT_LENGTH", HTTP_411)) + 1;
char req_buf[len];
fgets(req_buf, len, stdin);
char *name = "", *line = strtok(req_buf, "\n");
for (; line != NULL; line = strtok(NULL, "\n")) {
char *value;
char *key = strtok_r(line, "=", &value);
if (!strcmp(key, "name")) {
name = value;
break;
}
}
sanitize(name);
char cmd[strlen(name) + sizeof(COWSAY_CMD) + 1];
sprintf(cmd, COWSAY_CMD" Aloha, %s!", name);
FILE *cowsayfd = popen(cmd, "r");
puts("Content-Type: text/html\n");
puts("<link rel=\"stylesheet\" href=\"style.css\">");
puts("<main><h1 style=\"white-space: pre; padding: 20px;"
"overflow: auto; font-family: monospace;\">");
char cowsay_buf[BUF_SIZ];
while (fgets(cowsay_buf, sizeof(cowsay_buf), cowsayfd))
fputs(cowsay_buf, stdout);
puts("\n</h1></main>");
pclose(cowsayfd);
return 0;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="style.css">
<title>Cowsay Aloha</title>
</head>
<body>
<main>
<h1 class="jumo">Aloha, world!</h1>
<p>
Let me say aloha to you too:
</p>
<!-- adjust the path of cowsay.cgi to whatever you need -->
<form action="/cowsay.cgi" method="POST">
<label for="name">Name: </label>
<input type="text" name="name" required>
<input type="submit" value="Aloha!">
</form>
</main>
</body>
</html>
/*
Michael's General Purpose CSS Styles.
This is neither sepcific to nor required by the CGI script, but it's makes
everything look prettier and is nice to have.
*/
/*
ISC License
Copyright 2022 Michael M.
Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
*/
body {
line-height :1.6;
font-family: sans-serif;
color: #444;
}
main {
margin: 40px auto;
max-width: 650px;
font-size: 18px;
padding: 0 10px;
}
h1,h2,h3 {
font-family: monospace;
line-height: 1.2;
background-color: #EEEEEE;
}
.jumbo {
padding: 1em;
overflow: auto;
}
nav {
font-size: 16px;
font-family: monospace;
padding: 5px;
}
nav a {
color: blue;
}
.footnote {
font-size: 15px;
font-style: italic;
}
input[type="text"] {
background: transparent;
border-top: none;
border-left: none;
border-right: none;
outline: none;
color: #111;
padding-left: 3px;
padding-right: 3px;
}
input[type="text"]:hover {
border-color: #333;
}
main input[type="text"] {
font-size: 18px;
}
@media (prefers-color-scheme: dark) {
body {
color: #cfcfcf;
background-color: #1f1f1f;
}
h1,h2,h3 {
background-color: #414141;
}
a,nav a {
color: #56c8ff;
}
input[type="text"] {
color: #EEE;
}
input[type="text"]:hover {
border-color: #CCC;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment