CGI High Score Program

davecom
Unregistered
 
Post: #1
Hi,
I'm trying to write a CGI program that will receive a score and name, compare it to the list of names already in a text file, and then ouput the name and score combination to the text file if it is high enough.

I've been working with the C standard libraries. I have the whole getting the information down pat, but my C input output skills are not anymore up to par. Anybody have some good resources/tips?
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2004.10
Post: #2
Having written a bunch of CGIs myself, I'd recommend that you REALLY DON'T use C -- rather C++ or (PREFERABLY) PERL.

Here is a simple example in C++ that does what you want:

Code:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>

#define kNumScores (10)

using namespace std;

struct score_t
{
    string name;
    unsigned long score;
    bool operator<(const score_t &inVal) const
        { return score > inVal.score; } // this line is confusing
};

int main()
{
    ifstream inFile("my_scores.dat");
    score_t scores[kNumScores + 1];

    // Read the scores
    for(unsigned i = 0; i < kNumScores; ++i)
    {
        string score;
        getline(inFile, scores[i].name);
        getline(inFile, score);
        scores[i].score = atoi(score.c_str());
    }
    inFile.close();

    // Add the new score
    scores[kNumScores].name = "New Name";
    scores[kNumScores].score = 150;

    // Sort the scores
    sort(scores, scores + kNumScores + 1);

    ofstream outFile("my_scores.dat");
    for(unsigned i = 0; i < kNumScores; ++i)
    {
        outFile << scores[i].name << endl;
        outFile << scores[i].score << endl;
    }
    outFile.close();
    return 0;
}

There are some fun bugs to try and find in the above code that have to do with concurrency (and multiple people entering data at the EXACT same time). This can be fixed with some configuration changes within Apache (causing it to run only a single instantiation of a CGI at a time).

Now, having given you all this, you really don't want to use C/C++, but rather PERL. The reason has to do with the fact that C/C++ can have exploited buffer overflows quite easily, and PERL is much friendlier at ignoring exploit attempts.

(If you choose not to user PERL, use C++ and syntax like the above. [The code presented is actually reasonably good at ignoring buffer overflow problems, etc.])


Good luck with whatever your solution.
Quote this message in a reply
davecom
Unregistered
 
Post: #3
Wow, thanks for all the code. But I can't find anywhere how to access environment variables in C++. Is it necessary to use the C library?
Quote this message in a reply
Luminary
Posts: 5,143
Joined: 2002.04
Post: #4
#include <stdlib.h> and getenv() (C/ObjC/C++); or
#include <cstdlib> and std::getenv() (C++)
Quote this message in a reply
davecom
Unregistered
 
Post: #5
current version just prints out any score sent to it but now I'm getting type 500 errors. Anybody know what causes type 500 errors?

Thanks,
David

ps email notification doesn't appear to be working
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2004.10
Post: #6
Quote:Originally posted by davecom
current version just prints out any score sent to it but now I'm getting type 500 errors. Anybody know what causes type 500 errors?


I dunno, but the code I wrote assumes a file of at least 10 scores.... Maybe this is part of the problem?

Bored
Quote this message in a reply
Oldtimer
Posts: 832
Joined: 2002.09
Post: #7
Isn't 500 access error? I assume you've run chmod on it?
Quote this message in a reply
Member
Posts: 370
Joined: 2002.04
Post: #8
Read the server error log.

Did you ever wonder why we had to run for shelter when the promise of a brave new world unfurled beneath the clear blue sky?
Quote this message in a reply
davecom
Unregistered
 
Post: #9
Thanks for the replies. Where can I find the server error log? Is it the apache one I'm looking for?

Also, I'll have to look into the file errors you referred to jfaller. However I believe it worked on my local machine. Is the problem that I'm attempting to process a get request and then doing file access. Does this REQUIRE a post request?

I did chmod 777 the file it rw to.

Here's the current code - just a few small changes:
Code:
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <cstdlib>

#define kNumScores (10)

using namespace std;

struct score_t
{
        string name;
        unsigned long score;
        bool operator<(const score_t &inVal) const
                { return score > inVal.score; } // this line is confusing
};

int main()
{
        int i,l;
        string d,n;
        ifstream inFile("highscores.txt");
        score_t scores[kNumScores + 1];

        // Read the scores
        for(i = 0; i < kNumScores; ++i)
        {
                string score;
                getline(inFile, scores[i].name);
                getline(inFile, score);
                scores[i].score = atoi(score.c_str());
        }
        inFile.close();

        // Add the new score - maybe?
        char * descr = getenv("QUERY_STRING");
        d = string(descr);
        for(i = 0; i<d.size();i++)
        {
            if(d[i] = ':')
            {
                n = string(d.substr(0,i+1));     //name
                l = atoi((d.substr(i+1,d.size()-i)).c_str());  //level
                break;
            }
        }
        
        
        scores[kNumScores].name = n;
        scores[kNumScores].score = l;

        // Sort the scores
        sort(scores, scores + kNumScores + 1);

        ofstream outFile("highscores.txt");
        for(unsigned i = 0; i < kNumScores; ++i)
        {
                outFile << scores[i].name << endl;
                outFile << scores[i].score << endl;
        }
        outFile.close();
        return 0;
}
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2004.10
Post: #10
Quote:Originally posted by davecom
Thanks for the replies. Where can I find the server error log? Is it the apache one I'm looking for?

Also, I'll have to look into the file errors you referred to jfaller. However I believe it worked on my local machine. Is the problem that I'm attempting to process a get request and then doing file access. Does this REQUIRE a post request?

I did chmod 777 the file it rw to.


I think the apache server error log is located in /var/log/httpd/error_log, and an access log is there abouts too. Something clever is try "tail -f /var/log/httpd/error_log" in Terminal and then try to run the cgi from Safari. That should get it debugged quickly.

Additionally, I think this might have something to do with 500 errors... From locahost

Quote:File permissions


Remember that the server does not run as you. That is, when the server starts up, it is running with the permissions of an unprivileged user - usually ``nobody'', or ``www'' - and so it will need extra permissions to execute files that are owned by you. Usually, the way to give a file sufficient permissions to be executed by ``nobody'' is to give everyone execute permission on the file:

chmod a+x first.pl



Also, if your program reads from, or writes to, any other files, those files will need to have the correct permissions to permit this.


The exception to this is when the server is configured to use suexec. This program allows CGI programs to be run under different user permissions, depending on which virtual host or user home directory they are located in. Suexec has very strict permission checking, and any failure in that checking will result in your CGI programs failing with an "Internal Server Error". In this case, you will need to check the suexec log file to see what specific security check is failing.

As stated above, you will have to adjust the permissions on the high score file accordingly.

If memory serves (and it has been YEARS), the only real differences between a POST and a GET are whether or not the data is visible on the http: request line, and whether apache sends the data to the CGI via stdio or environment variables. You're really probing the old brains cells that cider killed long ago...Rolleyes

The online docs for apache are really quite good. Keep probing there, and if you have questions, post 'em here too.

Good luck
Quote this message in a reply
Oldtimer
Posts: 832
Joined: 2002.09
Post: #11
I will need to look into this post in a few months, so Carlos, if you prune this, I'll prune you. Wink Please respect my obsessive need to control people. Grin
Quote this message in a reply
davecom
Unregistered
 
Post: #12
Okay here's the Apache error. But what does it really mean?

[Fri Nov 28 21:25:50 2003] [error] [client 68.194.30.217] Premature end of script headers: /home/web/david/kopecsoft.com/cgi-bin/a.cgi

Oh and as I said I did chmod the highscores.txt .
Quote this message in a reply
Apprentice
Posts: 19
Joined: 2004.10
Post: #13
Quote:Originally posted by davecom
Okay here's the Apache error. But what does it really mean?

[Fri Nov 28 21:25:50 2003] [error] [client 68.194.30.217] Premature end of script headers: /home/web/david/kopecsoft.com/cgi-bin/a.cgi

Oh and as I said I did chmod the highscores.txt .


Welcome to cgi debugging. Huh

I think this is caused because apache (when it runs your cgi) wants you to send the response headers -- or the HTML responses down the pipe. I think the following should do be put at the end of main(), and you'll be good:

Code:
{
  cout << "HTTP/1.1 200 OK" << endl;
  cout << "Content-Type: text/html\n" << endl;
}

Check that I got the commands right, it has been a while.

Again, I hope this helps.
Quote this message in a reply
davecom
Unregistered
 
Post: #14
Yes, that did help. Using the second line of your header returning code stopped Apache from complaining and everything is working now.

Thanks a lot, everyone!
Quote this message in a reply
Post Reply