42-webserv / SpaceX

Non-blocking I/O HTTP WEB Server
2 stars 1 forks source link

[⚙] CGI #29

Closed codeyoma closed 1 year ago

codeyoma commented 1 year ago

내용

http://www.csce.uark.edu/~sgauch/cgicode/ https://www.tutorialspoint.com/python/python_cgi_programming.htm https://docs.python.org/3/library/cgi.html https://www.ibm.com/docs/en/netcoolomnibus/8.1?topic=scripts-environment-variables-in-cgi-script



태스크

codeyoma commented 1 year ago

CGI wiki example

Server specific variables:

SERVER_SOFTWARE: name/version of HTTP server.

SERVER_NAME: host name of the server, may be dot-decimal IP address.

GATEWAY_INTERFACE: CGI/version.

Request specific variables:

SERVER_PROTOCOL: HTTP/version.

SERVER_PORT: TCP port (decimal).

REQUEST_METHOD: name of HTTP method (see above).

PATH_INFO: path suffix, if appended to URL after program name and a slash.

PATH_TRANSLATED: corresponding full path as supposed by server, if PATH_INFO is present.

SCRIPT_NAME: relative path to the program, like /cgi-bin/script.cgi.

QUERY_STRING: the part of URL after ? character. The query string may be composed of *name=value pairs separated with ampersands (such as var1=val1&var2=val2...) when used to submit form data transferred via GET method as defined by HTML application/x-www-form-urlencoded.

REMOTE_HOST: host name of the client, unset if server did not perform such lookup.

REMOTE_ADDR: IP address of the client (dot-decimal).

AUTH_TYPE: identification type, if applicable.

REMOTE_USER used for certain AUTH_TYPEs.

REMOTE_IDENT: see ident, only if server performed such lookup.

CONTENT_TYPE: Internet media type of input data if PUT or POST method are used, as provided via HTTP header.

CONTENTLENGTH: similarly, size of input data (decimal, in [octets](https://www.wikiwand.com/en/Octet(computing))) if provided via HTTP header.

Variables passed by user agent (HTTP_ACCEPT, HTTP_ACCEPT_LANGUAGE, HTTP_USER_AGENT, HTTP_COOKIE and possibly others) contain values of corresponding HTTP headers and therefore have the same sense.

codeyoma commented 1 year ago

The following Perl program shows all the environment variables passed by the Web server:

#!/usr/bin/env perl

=head1 DESCRIPTION

printenv — a CGI program that just prints its environment

=cut
print "Content-Type: text/plain\n\n";

foreach ( sort keys %ENV ) {
    print "$_=\"$ENV{$_}\"\n";
}
codeyoma commented 1 year ago

Here is a simple CGI program written in Python 3 along with the HTML that handles a simple addition problem.

add.html:

<!DOCTYPE html>
<html>
 <body>
  <form action="add.cgi" method="POST">
   <fieldset>
     <legend>Enter two numbers to add</legend>
     <label>First Number: <input type="number" name="num1"></label><br/>
     <label>Second Number: <input type="number" name="num2"></label><br/>
   </fieldset>
   <button>Add</button>
  </form>
 </body>
</html>

add.cgi:

#!/usr/bin/env python3

import cgi, cgitb
cgitb.enable()

input_data = cgi.FieldStorage()

print('Content-Type: text/html') # HTML is following
print('')                         # Leave a blank line
print('<h1>Addition Results</h1>')
try:
    num1 = int(input_data["num1"].value)
    num2 = int(input_data["num2"].value)
except:
    print('<output>Sorry, the script cannot turn your inputs into numbers (integers).</output>')
    raise SystemExit(1)
print('<output>{0} + {1} = {2}</output>'.format(num1, num2, num1 + num2))

This Python 3 CGI program gets the inputs from the HTML and adds the two numbers together.

perl script

#!/usr/bin/perl

use CGI;

# Create a new CGI object
my $cgi = CGI->new;

# Get the values of the two numbers to add from the query string
# if query string case
# print $ENV{QUERY_STRING};

# else if post put case
my $num1 = $cgi->param('num1');
my $num2 = $cgi->param('num2');

# print "num1 : $num1 \n";
# print "num2 : $num2 \n";
# Convert the numbers to integers

if ($num1 eq "" || $num2 eq "") {
    if (exists $ENV{QUERY_STRING}) {

        $query = $ENV{'QUERY_STRING'};
        @list = split( /\&/, $query);
        foreach (@list) {
            ($var, $val) = split(/=/);
            $val =~ s/\'//g;
            $val =~ s/\+/ /g;
            $val =~ s/%(\w\w)/sprintf("%c", hex($1))/ge;
            if ($var eq "num1") {
                if ($val ne ""){
                    $num1 = int($val);
                }
            } elsif ($var eq "num2") {
                if ($val ne ""){
                    $num2 = int($val);
                }
            }
        }
        if ($num1 eq "" || $num2 eq "") {
            print $cgi->header,
              $cgi->start_html("Addition Result"),
              $cgi->center($cgi->h1("Addition Result"), $cgi->p("num1 or num2 does not exist.")),
              $cgi->end_html;
            exit;
        }else {
            my $sum = $num1 + $num2;

            print $cgi->header,
            $cgi->start_html("Addition Result"),
            $cgi->center($cgi->h1("Addition Result"), $cgi->p("The sum of $num1 and $num2 is $sum.")),
            $cgi->end_html;
            exit;
        }
    }else{
        print $cgi->header,
          $cgi->start_html("Addition Result"),
          $cgi->center($cgi->h1("Addition Result"), $cgi->p("num1 and num2 does not exist.")),
          $cgi->end_html;
        exit;
    }
}else{
    $num1 = int($num1);
    $num2 = int($num2);
    # Add the numbers
    my $sum = $num1 + $num2;

    # Print the HTML response
    print $cgi->header,
        $cgi->start_html("Addition Result"),
        $cgi->center($cgi->h1("Addition Result"), $cgi->p("The sum of $num1 and $num2 is $sum.")),
        $cgi->end_html;
}
codeyoma commented 1 year ago

SERVER_SOFTWARE argv[0]/version 1.0

SERVER_NAME 127.0.0.1

GATEWAY_INTERFACE CGI/1.1

SERVER_PROTOCOL HTTP/1.1

SERVER_PORT PORT_NUMBER which request arrived

REQUEST_METHOD METHOD(upper case) which request arrived

PATH_INFO URI which request arrived? or substitution path

PATH_TRANSLATED PWD/PATH_INFO

SCRIPT_NAME CGI_PASS ( like /cgi-bin/script.cgi )

QUERY_STRING (ex: var1=value1&var2=with%20percent%20encoding )

REMOTE_HOST host ( host name of the client, unset if server did not perform such lookup. )

REMOTE_ADDR IP address of the client (dot-decimal) (ex: "127.0.0.1" )

CONTENT_TYPE Internet media type of input data if PUT or POST method are used, as provided via HTTP header.

CONTENT_LENGTH similarly, size of input data (decimal, in octets) if provided via HTTP header.

??

AUTH_TYPE identification type, if applicable. 'auth-scheme' token in the request Authorization header field. 서블릿을 보호하는 데 사용되는 인증 스키마의 이름입니다. 예를 들면 BASIC, SSL 또는 서블릿이 보호되지 않는 경우 null입니다.

REMOTE_USER used for certain AUTH_TYPEs.

REMOTE_IDENT see ident, only if server performed such lookup.

codeyoma commented 1 year ago
codeyoma commented 1 year ago
#!/usr/bin/python
import cgi, os
import cgitb; cgitb.enable()
# import cgitb; cgitb.enable(display=0, logdir="./log")

save_path = os.getenv("SAVED_PATH")

if save_path is None:
    save_path = "./tmp/"
else:
    save_path += "/"

if not os.path.exists(save_path):
    os.mkdir(save_path)

print("Content-Type: text/html")
# Parse the form data
form = cgi.FieldStorage()
# Extract the uploaded files
files = {}
for field in form.keys():
    # Check if the field is a file field
    if isinstance(form[field], cgi.FieldStorage) and form[field].filename:
        # Save the file to the specified location
        with open(save_path + form[field].filename, 'wb') as f:
            f.write(form[field].file.read())
        files[field] = form[field].filename

if len(files) > 0:
    message = "file uploaded success"
else:
    message = "file uploaded failed"

# Print the uploaded files
response = "<html><body><center>"
response += "<h1>{}<h1>".format(message)
for field, filename in files.items():
    response += "<p>{}: {}</p>\n".format(field, filename)
response += "</center></body></html>"

print("Content-Length: {}".format(len(response)))
print()
print(response)