Andreas Schigold: CGI-Programme in C/C++ erstellen (unter Linux mit Apache)

Hallo liebe Selfforumer,

irgendjemand von Euch weiß doch bestimmt, wie man CGI-Programme in C/C++ schreibt? Es wäre jedenfalls wahnsinnig nett, wenn mir jemand verraten könnte, was ich hier falsch gemacht habe oder was ich noch machen muß, damit es funzt.

folgender simpler Quellcode sollte einfach zu einer entsprechenden Anzeige im WebBrowser führen:

Datei webcgi.c:
  #include <stdio.h>

int main()
  {
          printf("<html>\n\t<head>\n\t\t<title></title>\n\t</head>\n\t<body>\n\t\tHallo Welt!\n\t</body>\n</html>\n");
          return 0;
  }

mit dem gcc kompiliert...:
gcc -o webcgi webcgi.c

... und nach /usr/local/httpd/cgi-bin kopiert:
cp webcgi /usr/local/httpd/cgi-bin

Dann im Webbrowser eingegeben: "http://127.0.0.1/cgi-bin/webcgi"

Leider kam dann nicht das erhoffte "Hallo Welt!", sondern eine Meldung über einen internal Server Error.

Weiß jemand, was ich da falsch gemacht habe? Oder muß ich am Apache noch was konfigurieren? Oder brauche ich ein bestimmtes Modul dazu?

Bin für alle Anregungen dankbar, vor allem auch für Webseiten zu diesem Thema.

gruesse
Andreas Schigold

PS: Ziel ist eine Applikation, die auf ein bereits bestehendes Framework von C++ - Klassen zurückgreift und einen Webbrowser als Oberfläche nutzt, um in einer Applikation die Fähigkeiten lokal und remote anzubieten, wobei lokal ein Linux-Rechner und remote meist ein Windows-Rechner ist.

  1. hi!

    irgendjemand von Euch weiß doch bestimmt, wie man CGI-Programme in
    C/C++ schreibt? Es wäre jedenfalls wahnsinnig nett, wenn mir
    jemand verraten könnte, was ich hier falsch gemacht habe oder was
    ich noch machen muß, damit es funzt.

    Vor allem musst du am Anfang eines CGI-Programms einen passenden
    HTTP-Header ausgeben. Das hast du nicht gemacht. Also sowas wie

    printf("Content-type: text/html\n\n");

    Ist bei Perl-Skripten, die über CGI laufen sollen, genauso, falls
    du sowas schonmal gemacht hast.

    bye, Frank!

    1. Hallo Frank (und alle anderen),

      erstmal vielen vielen Dank für die vielen Infos. Aber das mit dem HTTP-Header und der Minimal-info über den Content-Type war genau das, weshalb es nicht ging.

      Danke nochmal
      Andreas Schigold

      hi!

      irgendjemand von Euch weiß doch bestimmt, wie man CGI-Programme in
      C/C++ schreibt? Es wäre jedenfalls wahnsinnig nett, wenn mir
      jemand verraten könnte, was ich hier falsch gemacht habe oder was
      ich noch machen muß, damit es funzt.

      Vor allem musst du am Anfang eines CGI-Programms einen passenden
      HTTP-Header ausgeben. Das hast du nicht gemacht. Also sowas wie

      printf("Content-type: text/html\n\n");

      Ist bei Perl-Skripten, die über CGI laufen sollen, genauso, falls
      du sowas schonmal gemacht hast.

      bye, Frank!

  2. Hallo,

    irgendjemand von Euch weiß doch bestimmt, wie man CGI-Programme in C/C++ schreibt? Es wäre jedenfalls wahnsinnig nett, wenn mir jemand verraten könnte, was ich hier falsch gemacht habe oder was ich noch machen muß, damit es funzt.

    folgender simpler Quellcode sollte einfach zu einer entsprechenden Anzeige im WebBrowser führen:

    [...]

    mit dem gcc kompiliert...:
    gcc -o webcgi webcgi.c

    Da fehlen noch die Warnungen und Optimieren wäre auch nicht schlecht (Darüber streiten sich die Geister. Diese Geister kommen dann aber meist aus der Asssembler Gruft oder der abusing-C Krypta ;-)

    Mit den o.a. Flags:

    gcc -O2 -W -Wall -pedantic -ansi -o webcgi webcgi.c

    ... und nach /usr/local/httpd/cgi-bin kopiert:
    cp webcgi /usr/local/httpd/cgi-bin

    Evt müssen da noch die Rechte zurechtgestutzt werden.

    Dann im Webbrowser eingegeben: "http://127.0.0.1/cgi-bin/webcgi"

    Leider kam dann nicht das erhoffte "Hallo Welt!", sondern eine Meldung über einen internal Server Error.

    Ja, der Apache (welcher überhaupt?) ist mitunter recht maulfaul ;-)

    Weiß jemand, was ich da falsch gemacht habe? Oder muß ich am Apache noch was konfigurieren? Oder brauche ich ein bestimmtes Modul dazu?

    Nein, normalerweise nichts. Nur das cgi-bin muß eingeschaltet sein (httpd.conf)

    Bin für alle Anregungen dankbar, vor allem auch für Webseiten zu diesem Thema.

    Da gibt es viel zu viele, als das man da eine Empfehlung aussprechen könnte.
    Ein gemütlicher Abend mit Google dürfte da erfolgreich sein.

    PS: Ziel ist eine Applikation, die auf ein bereits bestehendes Framework von C++ - Klassen zurückgreift und einen Webbrowser als Oberfläche nutzt, um in einer Applikation die Fähigkeiten lokal und remote anzubieten,

    Da würde ich dann doch eher ein "richtiges" Modul empfehlen.

    Allerdings ist es im Grunde genommen recht einfach. Statt der normalen Ausgabe ist halt noch der HTTP Header erforderlich, wie Frank schon so trefflich ausführte. Es sollte kein Problem sein, sich ein eigenes webprintf() zu basteln, das das tut.

    BTW: als Zeilenende gilt im HTTP "\r\n". Bitte merken. Den meisten Browsern ist das zwar egal, aber im Header ist es wichtig und wird leicht übersehen. (Passiert mir auch oft genug ;-)

    wobei lokal ein Linux-Rechner und remote meist ein Windows-Rechner ist.

    Das sollte nun gar keine Rolle spielen.
    Zumindest auf der Clientseite nicht.
    SCNR ;-)

    so short

    Christoph Zurnieden

    --
    /*in memoriam*/
    #define goto harmfull

    1. Hi Christoph,

      Leider kam dann nicht das erhoffte "Hallo Welt!", sondern eine
      Meldung über einen internal Server Error.
      Ja, der Apache (welcher überhaupt?) ist mitunter recht maulfaul ;-)

      die Tatsache, daß der Apache nicht jedem Benutzer, sondern nur dem
      Administrator genau sagt, welcher Fehler in _dessen_ Webserver aufge-
      treten ist (durch einen Eintrag im error_log) betrachte ich als
      security feature, nicht als Mundfaulheit.

      Viele Grüße
            Michael

      1. Hallo,

        Leider kam dann nicht das erhoffte "Hallo Welt!", sondern eine
        Meldung über einen internal Server Error.
        Ja, der Apache (welcher überhaupt?) ist mitunter recht maulfaul ;-)

        die Tatsache, daß der Apache nicht jedem Benutzer, sondern nur dem
        Administrator genau sagt, welcher Fehler in _dessen_ Webserver aufge-
        treten ist (durch einen Eintrag im error_log) betrachte ich als
        security feature, nicht als Mundfaulheit.

        Ja, auf den Error-Log hätte ich hinweisen müssen, mein Fehler.

        so short

        Christoph Zurnieden

        --
        /*in memoriam*/
        #define goto harmfull

    2. Hallo Christoph,

      BTW: als Zeilenende gilt im HTTP "\r\n". Bitte merken. Den
      meisten Browsern ist das zwar egal, aber im Header ist es
      wichtig und wird leicht übersehen. (Passiert mir auch oft
      genug ;-)

      Nein, es ist *nicht* "\r\n" :) Bedenke bitte, dass "\r\n"
      plattformabhaengig (lib-abhaengig?) ist. Der OP schreib von
      'meist ein Linux-System', nicht jedoch *immer*. Sinnvoller
      waere "\015\012" (vielleicht als ein

      #define CRLF "\015\012"

      oder so).

      Gruesse,
       CK

      1. Hallo,

        BTW: als Zeilenende gilt im HTTP "\r\n". Bitte merken. Den
        meisten Browsern ist das zwar egal, aber im Header ist es
        wichtig und wird leicht übersehen. (Passiert mir auch oft
        genug ;-)

        Nein, es ist *nicht* "\r\n" :) Bedenke bitte, dass "\r\n"
        plattformabhaengig (lib-abhaengig?) ist.

        Das ist jetzt eine gute Frage. IMHO ist es ISO C, also platformunabhängiger (ja, ich weiß) und internationaler Standard.

        5.2.2 Character display semantics
        [...]
        1 The active position is that location on a display device where the next character output by
        the fputc or fputwc function would appear.The intent of writing a printing character
        (as defined by the isprint or iswprint function) to a display device is to display a
        graphic representation of that character at the active position and then advance the active
        position to the next position on the current line. The direction of writing is locale-
        specific. If the active position is at the final position of a line (if there is one), the
        behavior is unspecified.
        2 Alphabetic escape sequences representing nongraphic characters in the execution
        character set are intended to produce actions on display devices as follows:
        \a (alert)Produces an audible or visible alert. The active position shall not be changed.
        \b (backspace)Movesthe active position to the previous position on the current line. If
        the active position is at the initial position of a line, the behavior is unspecified.
        \f ( form feed)Movesthe active position to the initial position at the start of the next
        logical page.
        \n (newline)Movesthe active position to the initial position of the next line.
        \r (carriage return)Movesthe active position to the initial position of the current line.
        \t (horizontal tab)Movesthe active position to the next horizontal tabulation position
        on the current line. If the active position is at or past the last defined horizontal
        tabulation position, the behavior is unspecified.
        \v (vertical tab)Movesthe active position to the initial position of the next vertical
        tabulation position. If the active position is at or past the last defined vertical
        tabulation position, the behavior is unspecified.
        3 Each of these escape sequences shall produce a unique implementation-defined value
        which can be stored in a single char object. The external representations in a text file
        need not be identical to the internal representations, and are outside the scope of this
        International Standard.

        Mmh... doch nicht?

        RFC 2616
               CR             = <US-ASCII CR, carriage return (13)>
               LF             = <US-ASCII LF, linefeed (10)>
               SP             = <US-ASCII SP, space (32)>
               HT             = <US-ASCII HT, horizontal-tab (9)>
               <">            = <US-ASCII double-quote mark (34)>

        HTTP/1.1 defines the sequence CR LF as the end-of-line marker for all
           protocol elements except the entity-body (see appendix 19.3 for
           tolerant applications). The end-of-line marker within an entity-body
           is defined by its associated media type, as described in section 3.7.

        CRLF           = CR LF

        Aha, dann nicht.

        Warum mußt Du auch immer Recht haben, ha? ;-)))

        Der OP schreib von
        'meist ein Linux-System', nicht jedoch *immer*. Sinnvoller
        waere "\015\012" (vielleicht als ein

        #define CRLF "\015\012"

        oder so).

        Also irgendwie kommt der mir bekannt vor, woher nur? ;-)

        BTW: was ist eigentlich aus der gzip.c Version geworden? (Habe den Direktlink verschlampt und bin jetzt zu faul, mich da wieder durchzuwühlen)
        Außerdem wollte ich aus dem Original ein PE-Datei bauen. Deshalb warte ich ja auch auf Deine neue Version.

        so short

        Christoph Zurnieden

        --
        /*in memoriam*/
        #define goto harmfull

        1. Hallo,

          Das ist jetzt eine gute Frage. IMHO ist es ISO C, also
          platformunabhängiger (ja, ich weiß) und internationaler
          Standard.

          Die Escape-Sequenzen. Ja. Aber nicht der Wert, den sie
          letztenendes verkoerpern.

          [...]
          3 Each of these escape sequences shall produce a unique
          implementation-defined value which can be stored in a
          single char object. The external representations in a text
          file need not be identical to the internal
          representations, and are outside the scope of this
          International Standard.

          Da hast du es doch. Unter Windows nimmt '\n' ausserhalb einer
          Programmumgebung 2 Bytes ein, fuer C ist es als ein Byte
          definiert :) Sonst haette man ja diese bloeden ^M in
          Windows-Textdateien auf Unix-Systemen auch nicht :) Die libc
          wandelt (sofern die Datei im ASCII-Modus geoeffnet wurde)
          die Zeilenenden beim einlesen um in die entsprechende interne
          Repraesentation. Unter UNIX ist das kein Problem, da ist meist
          \n == \n. Unter Windows ist das schon mehr Arbeit :) Und
          aufm Mac ist es ganz verrueckt, da ist \n extern == \r :)

          BTW: was ist eigentlich aus der gzip.c Version geworden?

          Jaaaa... ich weiss. Ich muesste dringend deine und meine
          Aenderungen zusammenbringen. Aber ich arbeite zur Zeit ca.
          10 bis 12h am Tag, weil sich da jemand in der Zeitplanung
          verrechnet hat *grummelgrummel*

          Gruesse,
           CK

          1. Hallo,

            Das ist jetzt eine gute Frage. IMHO ist es ISO C, also
            platformunabhängiger (ja, ich weiß) und internationaler
            Standard.

            Die Escape-Sequenzen. Ja. Aber nicht der Wert, den sie
            letztenendes verkoerpern.

            Hatte ich nicht schon zugegeben, daß Du Recht hast und ich Unrecht? ;-)

            [...]
            3 Each of these escape sequences shall produce a unique
            implementation-defined value which can be stored in a
            single char object. The external representations in a text
            file need not be identical to the internal
            representations, and are outside the scope of this
            International Standard.

            Da hast du es doch. Unter Windows nimmt '\n' ausserhalb einer
            Programmumgebung 2 Bytes ein, fuer C ist es als ein Byte
            definiert :) Sonst haette man ja diese bloeden ^M in
            Windows-Textdateien auf Unix-Systemen auch nicht :)

            Läßt sich abstellen, 'man less' ;-)

            Die libc
            wandelt (sofern die Datei im ASCII-Modus geoeffnet wurde)
            die Zeilenenden beim einlesen um in die entsprechende interne
            Repraesentation. Unter UNIX ist das kein Problem, da ist meist
            \n == \n. Unter Windows ist das schon mehr Arbeit :) Und
            aufm Mac ist es ganz verrueckt, da ist \n extern == \r :)

            Aha, da war ich wohl zu voreilig mit meiner Rechtverteilung.

            Unter Windows ist '\n' auch nur ein Byte, nur das Zeilenende wird dort mit zwei Bytes gesetzt. Ein printf("\n") erzeugt auch unter Windows (mit GCC bzw LCCWin32 als C Compiler mit deren jeweiligen Libcs) nur ein 0x0d, kein 0x0a0d.
            (Das war jetzt nicht nett von Dir, mich zu zwingen heute nochmal Windows zu starten! ;-)

            Auf dem Mac ist es das Gleiche, da sind die Zeilenenden mit 0x0a markiert und ein printf("\n") ergibt trotzdem ein 0x0d. (Wobei ich mich frage, ob sich das jetzt geändert hat, da nun ein BSD unten drunter läuft)
            Letzteres allerdings ohne Gewähr, ich habe schon zu lange auf keinem Mac mehr etwas gebaut.

            BTW: was ist eigentlich aus der gzip.c Version geworden?

            Jaaaa... ich weiss. Ich muesste dringend deine und meine
            Aenderungen zusammenbringen. Aber ich arbeite zur Zeit ca.
            10 bis 12h am Tag, weil sich da jemand in der Zeitplanung
            verrechnet hat *grummelgrummel*

            Ja, bei dem Wort "Deadline" habe ich auch immer einen Strick mit Schlinge vor dem geistigem Auge ;-)
            (Ja, ist ja schon gut, 2 EUR in die Wortwitzkasse)

            so short

            Christoph Zurnieden, der nun seinen Blick gegen die Perseiden richtet, wenn er denn rausgefunden hat, wo die Dinger liegen

            1. Hallo Christoph,

              Hatte ich nicht schon zugegeben, daß Du Recht hast und ich Unrecht? ;-)

              Ja. Aber du bist ja nicht der einzige, der mitliest. Ich wollte es nur noch mal
              etwas naeher erklaeren.

              Läßt sich abstellen, 'man less' ;-)

              Ja, ich weiss :)

              Die libc
              wandelt (sofern die Datei im ASCII-Modus geoeffnet wurde)
              die Zeilenenden beim einlesen um in die entsprechende interne
              Repraesentation. Unter UNIX ist das kein Problem, da ist meist
              \n == \n. Unter Windows ist das schon mehr Arbeit :) Und
              aufm Mac ist es ganz verrueckt, da ist \n extern == \r :)

              Aha, da war ich wohl zu voreilig mit meiner Rechtverteilung.

              Unter Windows ist '\n' auch nur ein Byte, nur das Zeilenende wird dort mit
              zwei Bytes gesetzt.

              Das ist doch das, was ich gesagt habe :) '\n' ist das Zeilenende. Schreibt man
              es in eine Datei, hat die Datei 2 Byte Inhalt.

              Auf dem Mac ist es das Gleiche, da sind die Zeilenenden mit 0x0a markiert
              und ein printf("\n") ergibt trotzdem ein 0x0d.

              Seit MacOS 10, ja :)

              (Wobei ich mich frage, ob sich das jetzt geändert hat, da nun ein BSD unten
              drunter läuft)

              Richtig.

              Gruesse,
               CK

              1. Hallo,

                Die libc
                wandelt (sofern die Datei im ASCII-Modus geoeffnet wurde)
                die Zeilenenden beim einlesen um in die entsprechende interne
                Repraesentation. Unter UNIX ist das kein Problem, da ist meist
                \n == \n. Unter Windows ist das schon mehr Arbeit :) Und
                aufm Mac ist es ganz verrueckt, da ist \n extern == \r :)

                Aha, da war ich wohl zu voreilig mit meiner Rechtverteilung.

                Unter Windows ist '\n' auch nur ein Byte, nur das Zeilenende wird dort mit
                zwei Bytes gesetzt.

                Das ist doch das, was ich gesagt habe :) '\n' ist das Zeilenende. Schreibt man
                es in eine Datei, hat die Datei 2 Byte Inhalt.

                Dann arbeitest Du mit anderen LibCs. Ich habe es hier auf Win98 ausprobiert mit GCC (Cygwin Port) und LCCWin32 und deren LibCs. Beide schmissen nur ein Byte raus und beide Male auch 0x0d.
                Benutzt Du etwa diesen "Visual Crap"? ;-)

                Aber nach Standard wäre es (2 Byte zu setzen) eigentlich sogar korrekt, obwohl ich die Angaben etwas wiedersprüchlich finde:

                \n (newline)Moves the active position to the initial position of the next line.
                \r (carriage return)Moves the active position to the initial position of the current line.

                Auch gibt es dann Schwierigkeiten mit Intergercast Konstrukten, wie '\n', das normalerweise genauso groß wie z.B. '\t' sein muß. Beim Schreiben noch kein Problem, aber beim Lesen.

                Aber Windows war ja schon immer etwas merkwürdig ;-)
                (Die uralte Schreibmschinentechnik für Computer zu benutzen ist ja doch etwas ... äh ..., nun ... ;-)

                (Wobei ich mich frage, ob sich das jetzt geändert hat, da nun ein BSD unten
                drunter läuft)

                Richtig.

                Gab/gibt das keine Schwierigkeiten mit (dem Auswurf von) alten Programmen? Oder greift da die Simulation des alten MacOS?

                so short

                Christoph Zurnieden

                PS:
                Die Perseiden habe ich gefunden, zu sehen war aber nix. Und dafür stehe ich mitten in der Nacht auf! ;-)
                CZ