CGI programs written in C + +

Source: Internet
Author: User
Tags bool constructor empty inheritance printf strlen hex code

After the previous study, you should be able to use the example of ANSI C for their own server to write CGI programs. ANSI C is chosen because it is almost ubiquitous and is the most popular C language standard. Of course, today's C + + is also very popular, especially in the GNU C + + compiler (g++) in the form of some (annotation ④). g++ can be downloaded free of charge from many places on the Internet, and versions of almost all platforms (usually supplied with operating systems such as Linux and pre-installed) can be selected. As you will see, many of the benefits of object-oriented programming can be obtained from CGI programs.

④:gnu's full name is "Gnu ' not Unix". This was originally a project developed by the Free Software Foundation (FSF) dedicated to replacing the original UNIX operating system with a free version. Linux now seems to be doing things that no predecessors have done. But GNU tools play a crucial role in the development of Linux. In fact, the Linux package comes with a very large number of GNU components.

To avoid presenting too many new concepts for the first time, the program is not intended to be a "pure" C + + program; Some code is written in normal C-although some alternative forms of C + + are also available. But that's not a big problem, because the most important thing that the program uses in C + + is the ability to create classes. When parsing the CGI information, since we are most concerned with the name/value pairs of the field, one class (Pair) is used to represent a single name/value pair, and another class (Cgi_vector) automatically parses the CGI string into the Pair object it will hold (as a vector), This allows you to take each pair out when you are free.
The program is also interesting because it demonstrates many of the pros and cons of C + + java. You'll see something similar, like the class keyword. Access control uses exactly the same keyword public and private, but differs in usage. They control a block, not a single method or field (that is, if you specify private: Each subsequent definition has a private attribute until we specify public: until then). In addition, when you create a class, all definitions automatically default to private.
One reason to use C + + here is to take advantage of the convenience provided by the C + + Standard Template Library (STL). At the very least, the STL contains a vector class. This is a C + + template that can be configured during compilation to accommodate only a specific type of object (here is the pair object). Unlike the vector of Java, if we try to place anything other than the pair object into the vector,c++ vector template, it will cause a compile-time error, while the Java vector will be fully collected. And when you take something out of a vector, it automatically becomes a pair object, without the need for styling. So the check is done at compile time, which makes the program appear more "robust". In addition, the program can run faster because it is not necessary to perform the styling during the run. Vectors also overload operator[], so you can use very handy syntax to extract pair objects. The vector template will be used when the cgi_vector is created; At that time, you can see that such a brief definition contains so much energy.
If you mention a disadvantage, you must not forget the complexity of the pair defined in the following code. Pair's method definition is much more than what we see in Java code. This is because C + + programmers must know ahead of time how to control the replication process with the replica builder, and to complete the assignment with overloaded operator=. As the 12th chapter explains, we sometimes think about the same thing in Java. But in C + +, there is hardly a moment to relax the focus on these issues.
This project first creates a reusable section consisting of pair and cgi_vector in the C + + header file. From a technical standpoint, it's really not a matter of stuffing these things into a header file. But for the present example, this does not cause any damage and is more Java-style, so it is easier to read and understand the code:

: CGITools.h//automatically extracts and decodes data//from CGI GETs and POSTs.
Tested with GNU C + +//(available for most server machines).

#include <string.h> #include <vector>//STL vector using namespace std; A class to hold a single name-value pair/a CGI query.
Cgi_vector holds Pair objects and//returns them from its operator[].
  Class Pair {char* nm;
Char* Val;
  Public:pair () {nm = val = 0;}
    Pair (char* name, char* value) {//creates new memory:nm = decodeurlstring (name);
  val = decodeurlstring (value);
  Const char* Name () const {return nm;}
  Const char* Value () const {return val;} Test for ' emptiness ' bool Empty () const {return (NM = 0) | |
  (val = = 0);
  }//Automatic type conversion for Boolean test:operator bool () const {return (NM!= 0) && (val!= 0);
  }//The following constructors & destructor are//necessary for bookkeeping in C + +. Copy-constructor:pair (const pair& p) {if (p.nm = = 0 | | p.val = = 0) {nm = val = 0;
      else {//Create storage & copy RHS values:nm = new Char[strlen (P.NM) + 1];
      strcpy (nm, P.NM);
      val = new Char[strlen (p.val) + 1];
    strcpy (Val, p.val);
    }//Assignment operator:pair& operator= (const pair& p) {//clean up old lvalues:delete nm;
    Delete Val;
    if (p.nm = = 0 | | p.val = 0) {nm = val = 0;
      else {//Create storage & copy RHS values:nm = new Char[strlen (P.NM) + 1];
      strcpy (nm, P.NM);
      val = new Char[strlen (p.val) + 1];
    strcpy (Val, p.val);
  return *this;
  } ~pair () {//destructor delete nm;//0 value OK Delete val; }//If You use this method outide this class,//You ' re responsible for calling ' delete ' in//the pointer that ' s
    Returned:static char* decodeurlstring (const char* urlstr) {int len = strlen (URLSTR); char* result = new Char[len + 1];
    memset (result, Len + 1, 0);
      for (int i = 0, j = 0; I <= Len i++, J + +) {if (urlstr[i] = = ' + ') result[j] = '; else if (urlstr[i] = = '% ') {result[j] = Translatehex (urlstr[i + 1]) * + Translatehex (urlstr
        [i + 2]); i + 2;
    Move past Hex Code} else//A ordinary character result[j] = Urlstr[i];
  return result; }//Translate a single hex character;  Used by//decodeurlstring (): Static char Translatehex (char hex) {if (hex >= ' A ') return (Hex & 0XDF)
    -' A ' + 10;
  else return hex-' 0 ';

}
}; 
  Parses any CGI query and turns it/in an STL vector of Pair objects:class cgi_vector:public vector<pair> {
  Char* qry; Const char* Start;
  Save starting position//prevent assignment and copy-construction:void operator= (cgi_vector&);
Cgi_vector (cgi_vector&); Public://const fields must is initialized in the C + +//"constructor initIalizer List ": Cgi_vector (char* query): Start (new Char[strlen (query) + 1]) {qry = (char*) start;//Cast to N
    On-const strcpy (qry, query);
    Pair p;
  while ((P = Nextpair ())!= 0) push_back (p); }//destructor: ~cgi_vector () {delete start;} private://produces name-value pairs from the query//string.
    Returns an empty Pair when there ' s//No more query string Left:pair Nextpair () {char* name = Qry; if (name = = 0 | | | *name = = ' ") return Pair ();
    End, return null Pair char* value = STRCHR (name, ' = '); if (value = = 0) return Pair (); Error, return null Pair//null-terminate name, move value to start//of its set of characters: *value = '
    ";
    value++;
    Look for end of value, marked by ' & ': qry = STRCHR (value, ' & '); if (qry = = 0) qry = ""; Last pair found else {*qry = ' * ';//Terminate value string qry++;//move to next pair} RET Urn Pair (name, VAlue); }
}; ///:~


After the #include statement, you can see that one row is:
using namespace Std;
The "namespace" (Namespace) in C + + resolves a problem that is package by Java: Hides the library name. The Std namespace refers to the standard C + + library, and the vector is in this library, so this line is required.
The pair class looks unusually simple, and only accommodates two (private) character pointers-one for the name and the other for the value. The default builder simply sets the two pointers to zero. This is because in C + +, the object's memory does not automatically zero. The second builder invokes the method decodeurlstring () to generate a decoded string in the newly allocated heap memory. This area of memory must be managed and cleared by the object, as seen in the "Wreck". The name () and value () methods generate a read-only pointer for the related fields. Using the Empty () method, we query whether a field of pair object is empty; The result is a basic Boolean data type built into bool--c++. operator BOOL () uses a special form of C + + operator overload. It allows us to control automatic type conversions. If there is a pair object named P, and in an expression that would have been expected to be a Boolean result, such as if (p) {//...), the compiler can tell that it has a pair and that it needs a Boolean value, so it automatically invokes operator bool () for the necessary conversion.
The next three methods are generic encodings that must be used when creating classes in C + +. Based on the so-called "classic form" of the C + + class, we must define the necessary "original" builder, as well as a replica builder and assignment operator--operator= (as well as a break-through to erase memory). The reason for such a definition is that the compiler will "silently" call them. The replica builder needs to be called when an object is passed in or out of a function, and the assignment operator needs to be invoked when the object is allocated. Only if you really understand the workings of the replica builder and assignment operators can you write a truly "robust" class in C + +, but it requires a more laborious process (annotation ⑤).

⑤: My "thinking in C + +" (prentice-hall,1995) used a whole chapter to discuss the subject. If you need more help, be sure to look at that chapter.

The Replica builder Pair (const pair&) is automatically invoked whenever an object is passed in or out of a function by value. That is, we are not going to pass its address in the function framework for the object that is ready to make a full copy of it. This is not an option provided by Java, because we can only pass the handle, so there is no replica builder in Java (if you want to make a local copy, you can "clone" that object-use Clone (), see Chapter 12th). Similarly, if you assign a handle to Java, it simply replicates. But the assignment in C + + means that the entire object is copied. In the replica builder, we create new storage space and copy the original data. But for the assignment operator, we must release the old storage space before allocating the new storage space. What we're going to see may be the most complex of the C + + classes, but that's the strong evidence that Java supporters are proving Java is much simpler than C + +. In Java, we are free to pass the handle, and the cleanup work is handled by the garbage collector, so it can be much easier.
But things are not finished. The pair class uses the char* for NM and Val, and the most complex cases are mostly spread around the pointer. If you replace char* with a more fashionable C + + string class, things will be much simpler (not all compilers provide support for string, of course). So, the first part of pair looks like this:

 class Pair {string nm;
String Val;
    Public:pair () {} Pair (char* name, char* value) {nm = decodeurlstring (name);
  val = decodeurlstring (value);
  Const char* Name () const {return nm.c_str ();} 
  Const char* Value () const {return val.c_str (); //Test for ' emptiness ' bool Empty () const {return (nm.length () = 0) | |
  (val.length () = = 0); }//Automatic type conversion for Boolean test:operator bool () const {return (nm.length ()!= 0) &&am P
  (Val.length ()!= 0); }


(in addition, decodeurlstring () for this class returns a string instead of a char*). We don't have to define replica builder, operator=, or sabotage, because the compiler has done it for us and done it very well. But even if something is done automatically, C + + programmers must understand the details of the replica build and assignment. The remainder of the
pair class is composed of two methods: Decodeurlstring () and a helper method Translatehex ()--will be used by decodeurlstring (). Note that Translatehex () does not protect against malicious input from users, such as "%1h". After allocating enough storage space (which must be released by the decodeurlstring), it iterates through it, converts all "+" to a single space, and converts all hexadecimal code (beginning with a "%") to the corresponding character. The
Cgi_vector is used to parse and hold the entire CGI get command. It is inherited from the STL vector, which is shown to accommodate pair. Inheritance in C + + is represented by a colon, which in Java is extends. In addition, inheritance defaults to the private property, so it's almost certain that you need to use the Public keyword, just as you do. You will also find that Cgi_vector has a replica builder and a operator=, but they are all declared private. This is done to prevent the compiler from synchronizing two functions (they are synchronized if they are not declared by themselves). But it also prohibits the client programmer from passing a cgi_vector by value or by assigning value.
Cgi_vector's job is to get the query_string and parse it into a "name/value" pair, which needs to be done with the help of pair. It first copies the string to the locally allocated memory and uses the constant pointer start to track the starting address (which will later be used to free memory in the debugger). It then parses the string into the original name/value pair with its own Nextpair () method, separating the pairs with a "=" and a "&" symbol. These pairs are passed to the pair builder by Nextpair (), so Nextpair () returns a pair object. The object is then added to the vector with push_back (). Nextpair () returns a value of 0 after traversing the full query_string.
Now that the basic tools are defined, they can be used simply in a CGI program, as follows:

 

: Listmgr2.cpp//CGI version of LISTMGR.C in C + +, which//extracts its input via the Get submission//From the ass Ociated applet.
Also works AS//a ordinary CGI with HTML forms.
#include <stdio.h> #include "CGITools.h" const char* datafile = "List2.txt";
Const char* notify = "Bruce@EckelObjects.com";  #undef DEBUG//Similar code as before, except that it looks//for the email name inside of ' <> ': int inList (file*
  List, const char* emailname) {const int bsize = 255;
  Char Lbuf[bsize];
  Char Emname[bsize]; Put the email name in ' <> ' so there ' s no//possibility of a match within another name:sprintf (Emname, "<
  %s> ", emailname);
  Go to the beginning of the List:fseek (list, 0, seek_set); Read the List:while (fgets (lbuf, bsize, list)) {//Strip off the Newline:char * newline = str
    Chr (lbuf, ' \ n ');
    if (newline!= 0) *newline = ';
  if (Strstr (Lbuf, Emname)!= 0) return 1;
  }return 0; } void Main () {//You must print this out, otherwise the the//server would not send the response:printf ("Content-ty
  Pe:text/plain\n\n ");
  file* list = fopen (datafile, "a+t");
    if (list = = 0) {printf ("Error:could not open database.");
    printf ("Notify%s", Notify);
  Return }//For a CGI ' get, ' the server puts the data//in the environment variable Query_string:cgi_vector QUERY (getenv (
  "Query_string")); #if defined (DEBUG)//Test:dump all names and values for (int i = 0; i < query.size (); i++) {printf ("query[%d]
    . Name () = [%s], ", I, Query[i].name ());
  printf ("query[%d].value () = [%s]\n", I, Query[i].value ());
  #endif (DEBUG) Pair name = Query[0];
  Pair email = query[1];
    if (Name.empty () | | | Email.empty ()) {printf ("Error:null name or email");
  Return
    } if (InList (list, Email.value ())) {printf ("Already in list:%s", Email.value ());
  Return ///It ' s not in the list, add It:fseek (LIST, 0, Seek_end);
  fprintf (list, "%s <%s>;\n", Name.value (), Email.value ());
  Fflush (list);
  Fclose (list);
printf ("%s <%s> added to list\n", Name.value (), Email.value ()); } ///:~


The Alreadyinlist () function is almost identical to the previous version, except that it assumes that all e-mail addresses are in a "<>".
The Web server collects the "?" When you use the Get method (by marking the internal setting in the method of the form Boot command, which is controlled here by the way the data is sent). All the information that follows and puts them into the environment variable query_string (query string). So in order to read that information, you have to get the query_string value, which is done with the standard C library function GETNV (). In main (), notice how easy it is to parse the query_string: just pass it to the builder for the Cgi_vector object (named Query), and all the rest of the work will be done automatically. From this point on, we can take names and values from query and treat them as arrays (this is because operator[] is already overloaded in vectors). In debugging code, you can see how all this works; The debug code is encapsulated between preprocessor boot commands #if defined (debug) and #endif (Debug).
Now, we desperately need to know something about CGI. CGI programs pass their input in one of two ways: passed through query_string during get execution (in this way), or through standard input during post. But the CGI program sends its own output through standard output, which is usually done with the C program's printf () command. So where does this output go? It goes back to the Web server, and the server decides what to do with it. The server makes a decision based on the Content-type (content type) header data. This means that if the Content-type header is not the first thing it sees, it does not know how to handle the data received. So we're going to have to get all the CGI programs out of the Content-type header anyway.
In this case, we want the server to directly feed all the information back to the client (that is, our patches, they are waiting for their reply). The information should be intact, so content-type is set to Text/plain (plain text). Once the server sees this header, all strings are sent directly to the customer. So each string (three for error conditions, one for successful joins) will return to the program slice.
We add the e-mail name (the user's name) with the same code. But in the case of a CGI script, there is no infinite loop-the program simply responds and then interrupts. Each time a CGI request arrives, the program starts, responds to the request, and then shuts itself down. So the CPU can not fall into the awkward situation of empty waiting, only to start the program and open the file only when there is a hidden problem of performance. When a Web server controls a CGI request, its overhead can minimize the risk.
Another benefit of this design is that as pair and cgi_vector are defined, most of the work is done automatically for us, so simply modifying main () makes it easy to create your own CGI program. Although the small Service Program (Servlet) will eventually become more and more popular, in order to create a fast CGI program, C + + is still very convenient.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.