FBB::CGI(3bobcat)

FBB::CGI(3bobcat) β€” CGI interface πŸ’–

Okay so bestie, let me tell you about FBB::CGI β€” she's the moment. πŸ’…


NAME 🌸

FBB::CGI β€” handles GET and POST submitted form data, periodt. πŸ’–


SYNOPSIS ✨

#include <bobcat/cgi>
Linking option: -lbobcat

DESCRIPTION πŸ¦‹

Okay so real talk. The class CGI offers an interface to data submitted by web-forms. That data is sent to a script handling the data using a <form action="/path/to/form/script"> stanza. Very often it's indeed a script, like a Perl script, but bestie there is no need to use a scripting language. The class CGI lets C++ programmers process the form by an executable, which usually results in faster processing and in construction time benefits from the type safety C++ offers. And the class CGI automatically handles data submitted using the GET method as well as data submitted using the POST method. So no cap, she handles both. πŸ’…

By default the class's constructor writes the customary Content-type header lines to the standard output stream. Additional (html) output of a reply page must be provided by other code. Therefore, a program processing an uploaded form will have an organization comparable to the following basic setup:

// assume includes and namespace std/FBB were defined
int main()
{
    CGI cgi;
    cout << "<html><body>\n";
    if (parametersOK(cgi))
    {
        process(cgi);
        generateReplyPage();
    }
    else
        generateErrorPage();
    cout << "</body></html>\n;
}

When errors in the received form-data are detected an error message is written to the standard output stream and an FBB::Exception exception is thrown. So like, if something's off, she's gonna yell about it. 😭


NAMESPACE πŸ’œ

FBB

All constructors, members, operators and manipulators mentioned in this man-page are defined in the namespace FBB. So that's the vibe. ✨


INHERITS FROM πŸŽ€

-

She doesn't inherit from anything, bestie. It's giving self-made, independent, main character energy. πŸ’…


TYPEDEF 🧚

  • CGI::MapStringVector β€” A shorthand for std::unordered_map<std::string, std::vector<std::string> >, which is the data type in which form-variables are stored. So like, that's where all your form data lives. πŸ“

ENUMERATIONS 🌈

The CGI::Method enumeration specifies values indicating the way the form's data were submitted:

  • CGI::UNDETERMINED β€” Used internally indicating that the form's method was neither GET nor POST. She's like "idk what this is" πŸ’€
  • CGI::GET β€” Indicates that the GET method was used when submitting the form's data.
  • CGI::POST β€” Indicates that the POST method was used when submitting the form's data.

The CGI::Create enumeration is used to request or suppress creation of the directory to contain any file uploaded by a form:

  • CGI::DONT_CREATE_PATH β€” When uploading files, the destination directory must exist.
  • CGI::CREATE_PATH β€” When uploading files, the destination directory will be created.

CONSTRUCTORS πŸ‘‘

  • CGI(bool defaultEscape = true, char const *header = "Content-type: text/html", std::ostream &out = std::cout) β€” The default constructor writes the standard content type header to the standard output stream and will use std::cout for output. Specifying 0 as header suppresses outputting the Content-type line. Otherwise the content type line is also followed by two \r\n character combinations. By default all characters in retrieved form-variables are escaped. The overloaded insertion operators (see below) can be used to modify the default set of characters to escape. The backslash is used as the escape character. The escape-prefix is not used if the defaultEscape value is specified as false and if no insertions into the CGI object were performed.

Copy and move constructors (and assignment operators) are available. So you can copy her, move her, assign her β€” she's flexible like that. 🫢


✨ OERLOADED OPERATORS ✨

Note: the following three insertion operators, defining sets of characters that should be escaped, can only be used before calling any of the param, begin or end members. As soon as one of these latter three members has been called the set of characters to be escaped is fixed and attempts to modify that set is silently ignored. So like, once you call one of those, the door is closed, bestie. πŸšͺπŸ’…
  • char const *operator[](std::string const &key) const β€” The index operator returns the value of the environment variable specified as the index. 0 is returned if the variable specified at key is not defined. So if it's not there, you get a null pointer, not a crash. πŸ’€
  • CGI &operator<<(std::string const &accept) β€” This member's actions are suppressed once param, begin or end (see below) has been called.

The insertion operator can be used to fine-tune the set of characters that are escaped in strings returned by param (see below). Depending on the value of the constructor's defaultEscape parameter characters inserted into the CGI object will or will not be escaped by a backslash.

If the constructor's defaultEscape parameter was specified as true then the insertion operator can be used to define a set of characters that are not escaped.

If defaultEscape was specified as false then the insertion operator will define a set of characters that will be escaped.

The backslash itself is always escaped and a request to use it unescaped is silently ignored.

The accept string can be specified as a regular expression character set, without the usual surrounding square brackets. E.g., an insertion like cgi << "-a-z0-9" defines the set consisting of the dash, the lower case letters and the digits.

Individual characters, character ranges (using the dash to specify a range) and all standard character classes ([:alnum:], [:alpha:], [:cntrl:], [:digit:], [:graph:], [:lower:], [:print:], [:punct:], [:space:], [:upper:], and [:xdigit:]) can be used to specify a set of characters. In addition to these standard character classes the class [:cgi:] can be used to define the set consisting of the characters ", ’, `, ;, and \.

Note that standard and [:cgi:] character classes do require square brackets.

When a series of insertions are performed then the union of the sets defined by these insertions are used.

Note: using unescaped single quotes, the double quotes, backtick characters and semicolons in CGI-programs might be risky and is not advised. So like, don't do it unless you wanna catch a vibe check from the security gods. 😭
  • CGI &operator<<(int c) β€” This member's actions are suppressed once param, begin or end (see below) has been called.

This insertion operator is used to change the default escape handling of a single character c. The int parameter is cast internally to a char.

  • CGI &operator<<(std::pair<char, char> range) β€” This member's actions are suppressed once param, begin or end (see below) has been called.

This insertion operator can be used to change the default escape handling of a range of characters. The pair's second character must be equal to or exceed the position of the pair's first character in the ASCII collating sequence or the member will have no effect. So like, if you try to go backwards, she's just gonna ignore you. πŸ’…

  • std::ostream &std::operator<<(std::ostream &out, CGI const &cgi) β€” CGI objects can be inserted into ostreams to display the characters that will appear escaped in strings returned by the param() member function. Each character for which isprint() returns true will be displayed as character, surrounded by single quotes. For all other characters their ASCII values are displayed. Each character is displayed on a line by itself. So it's like a little escape character showcase, bestie. ✨

✨ MEMBER FUNCTIONS ✨

  • CGI::MapStringVector::const_iterator begin() β€” hands you the begin iterator of the form's parameter map πŸ’«. Any iterator value that isn't equal to end (peep below) points at a pair of values: the first one is the name of a field the form defined, and the second one is a vector of strings holding that field's value(s). Also go look at the description of the param member just below, it's related, iykyk.
  • CGI::MapStringVector::const_iterator end() β€” returns the end iterator of the form's parameter map. That's it, that's the whole vibe, she's the boundary πŸŽ€.
  • unsigned long long maxUploadSize() const β€” tells you the current maximum file upload size, measured in bytes. Slay πŸ’….
  • CGI::Method method() const β€” returns the method that was used when the form got submitted. It's either CGI::GET or CGI::POST, no third option, she's loyal πŸ¦‹.
  • std::vector<std::string> const &param(std::string const &variable) β€” gives you the value of the form-variable named by the argument. If the form's data never provided that variable, you get back an empty vector (bestie said no πŸ’€).

If the same variable showed up multiple times, or if its value stretches across multiple lines (this one's only with multipart/form-data), then the vector is holding multiple strings.

With GET and POST methods that are not using multipart/form-data, input fields that stretch over multiple lines get stored in one string, using \r\n combinations in between those lines.

Now listen, when files get uploaded, the vectors contain sets of four strings πŸ“:

  1. The first string gives the path name of the uploaded file;
  2. the second string gives the file name specified in the form itself (so, the name of the file at the remote location);
  3. the third string shows the content type the remote browser specified (like, e.g., application/octet-stream);
  4. the fourth string contains OK if the file was successfully uploaded, and truncated if the file was truncated.
Existing files will not be overwritten. Periodt. And when uploading a file, a usable filename must be found within 100 trials β€” no infinite searching, she has limits.
  • std::string param1(std::string const &variable) β€” returns the first element of the vector<string> that param would hand you, or an empty string if variable wasn't defined by the received form. One-string shortcut, iconic πŸ™ˆ.
  • std::string const &query() const β€” returns the query-string that got submitted with CGI::GET or CGI::POST forms. Quick heads up though: if the POSTed form specified ENCTYPE="multipart/form-data", the query string is empty. That's just how it is πŸ’œ.
  • report() β€” silently returns if no errors were encountered while processing form-data (silence is golden, no notes ✨). But if something did go wrong, the html file generated by the CGI program shows a line starting with FBB::CGI, followed by the status report.

These are the status report messages that are presently defined:

  • Content-Disposition not recognized in: β€” followed by the line where the Content-Disposition was expected. This may happen when processing multipart/form data.
  • Invalid multipart/form-data. β€” this message can be generated while reading lines during multipart/form data processing.
  • GET/POST REQUEST_METHOD not found. β€” shown if the program couldn't find the form's REQUEST_METHOD type (so, GET or POST).
  • Invalid CONTENT_LENGHT in POSTed form. β€” shown if the content-length header has an incorrect value.
  • Content-Type not found for file-field, followed by the file's field name. Shown if no Content-Type specification was found in an uploaded form.
  • Can't open a file to write an uploaded file. β€” this one means the CGI program was unable to open a file to write an uploaded file to. Could be an overfull disk or partition, or incorrect write-permissions, so go check 😭.
  • multipart/form-data: no end-boundary found. β€” shown if the end-boundary was missing in a multipart/form-data form.
  • void setFileDestination(std::string const &path, std::string const &prefix = "", Create create = CREATE_PATH) β€” this member is how you specify the path and prefix of uploaded files. Uploaded files get stored at path/prefixNr, where Nr is an internally used number that starts at one πŸ”’. When CREATE_PATH is specified, path must be available, or the CGI object must be able to create the path. If DONT_CREATE_PATH is specified, the specified path must be available β€” and if it's not, an FBB::Exception exception gets thrown. No chill, no grace.
  • void setMaxUploadSize(size_t maxSize, int unit = 'M') β€” use this to change the maximum size of uploaded files. Its default value is 100Mb. The unit can be one of b (bytes, the default), K (Kbytes), M (Mbytes) or G (Gbytes). Unit-specifiers are interpreted case insensitively, she doesn't care about your capitalisation πŸ’…. File uploads keep going until the maximum upload size is exceeded, and after that any remainder gets discarded πŸ—‘οΈ.
  • void swap(CGI &other) β€” the current object and other get swapped. Heads up though: the first time one of the param(), begin() or end() members is called, these members may detect errors in the received form data. If that happens, an error message is written to the standard output stream and an FBB::Exception exception will be thrown πŸ”₯.

πŸ’œ STATIC MEMBERS πŸ’œ

  • std::string dos2unix(std::string const &text) β€” converts all \r\n character combinations in text into plain \n characters, and returns the converted text. Glow-up for your line endings ✨.
  • std::string unPercent(std::string const &text) β€” converts all %xx encoded characters into their corresponding ASCII values. Also, + characters get converted into single blank spaces. You get the converted string back πŸŽ€.

🌈 EXAMPLE 🌈

#include "main.ih"

void showParam(CGI::MapStringVector::value_type const &mapValue)
{
    cout << "Param: " << mapValue.first << '\n';

    for (auto &str: mapValue.second)
        cout << "    " << CGI::dos2unix(str) << "\n"
            "    ";

    cout << '\n';
}

int main(int argc, char **argv)
try
{
    Arg &arg = Arg::initialize("evhm:", argc, argv);

    // usage and version are in the source archive in .../cgi/driver
    // arg.versionHelp(usage, version, 2);

    ifstream in(arg[0]);
    string line;
    while (getline(in, line))
    {
        size_t pos = line.find('=');

        if (pos == string::npos)
            continue;
                                // set environment vars simulating
                                // a GET form
        if (setenv(line.substr(0, pos).c_str(),
               line.substr(pos + 1).c_str(), true) == 0)
        {
            if (arg.option('e'))
                cout << line.substr(0, pos).c_str() << '=' <<
                       line.substr(pos + 1).c_str() << '\n';
        }
        else
            cout << "FAILED: setenv " << line << '\n';
    }

    CGI cgi(false);             // chars are not escaped

    cgi << arg[1];

    if (arg.option(&line, 'm'))
        cgi.setMaxUploadSize(stoul(line), *line.rbegin());

    cout << "Max upload size (b): " << cgi.maxUploadSize() << '\n';

    CGI::Method method = cgi.method();

    cout << "To escape:\n" <<
            cgi << "\n"
            "Method: " << (method == CGI::GET ? "GET" : "POST") <<
            '\n';

    cout << "Query string: " << cgi.query() << '\n';

    cout << "Submit string: `" << cgi.param1("submit") << "'\n";

    for (auto &mapElement: cgi)
        showParam(mapElement);

    cout << "END OF PROGRAM\n";
}
catch (exception const &err)
{
    cout << err.what() << '\n';
    return 1;
}
catch (...)
{
    return 1;
}

To test the program's get form processing, call it as driver get '[:cgi:]', with the file get containing:

INFO=This is an abbreviated set of environment variables
SERVER_ADMIN=f.b.brokken@rug.nl
GATEWAY_INTERFACE=CGI/1.1
SERVER_PROTOCOL=HTTP/1.1
REQUEST_METHOD=GET
QUERY_STRING=hidden=hidval&submit=Submit+%20Query

To test the program's post form processing, call it as driver post1 '[:cgi:]', using post1 and post1.cin found in Bobcat's source archive under ../cgi/driver πŸ¦‹.

πŸ“ FILES πŸ“

  • bobcat/cgi β€” defines the class interface

πŸ’… SEE ALSO πŸ’…

πŸ’€ BUGS πŸ’€

None Reported. (Not a single one, we stay winning πŸ‘‘)

🫢 BOBCAT PROJECT FILES 🫢

Debian Bobcat project files:

  • libbobcat6 β€” debian package containing the shared library, changelog and copyright note;
  • libbobcat-dev β€” debian package containing the static library, headers, manual pages, and developer info;

🧚 BOBCAT 🧚

Bobcat is an acronym of `Brokken's Own Base Classes And Templates'.

This is free software, distributed under the terms of the GNU General Public License (GPL).

🌸 AUTHOR 🌸

Frank B. Brokken (f.b.brokken@rug.nl).


Ok bestie, that's the whole page, we made it πŸ’–. This one ships as libbobcat-dev_6.15.01, dated 2005-2026, and it lives at FBB::CGI(3bobcat). Go upload something responsibly, mwah 🌈✨

πŸ“¦ where this page comes from