Replace the application/path specific echo.html and echo2.html with the more flexible...
[catagits/fcgi2.git] / examples / echo-cpp.cpp
1 /*
2  *  A simple FastCGI application example in C++.
3  *  
4  *  $Id: echo-cpp.cpp,v 1.5 2001/11/21 21:15:36 robs Exp $
5  *  
6  *  Copyright (c) 2001  Rob Saccoccio and Chelsea Networks
7  *  All rights reserved.
8  *  
9  *  Redistribution and use in source and binary forms, with or without
10  *  modification, are permitted provided that the following conditions
11  *  are met:
12  *  
13  *  1. Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *  2. Redistributions in binary form must reproduce the above copyright
16  *     notice, this list of conditions and the following disclaimer in the
17  *     documentation and/or other materials provided with the distribution.
18  *  3. The name of the author may not be used to endorse or promote products
19  *     derived from this software without specific prior written permission.
20  *  
21  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <stdlib.h>
34 #ifdef _WIN32
35 #include <process.h>
36 #else
37 #include <unistd.h>
38 extern char ** environ;
39 #endif
40 #include "fcgio.h"
41
42 // Maximum number of bytes allowed to be read from stdin
43 static const unsigned long STDIN_MAX = 1000000;
44
45 static void penv(const char * const * envp)
46 {
47     cout << "<PRE>\n";
48     for ( ; *envp; ++envp) 
49     {
50         cout << *envp << "\n";
51     }
52     cout << "</PRE>\n";
53 }
54
55 static long gstdin(FCGX_Request * request, char ** content)
56 {
57     char * clenstr = FCGX_GetParam("CONTENT_LENGTH", request->envp);
58     unsigned long clen = STDIN_MAX;
59
60     if (clenstr)
61     {
62         clen = strtol(clenstr, &clenstr, 10);
63         if (*clenstr)
64         {
65             cerr << "can't parse \"CONTENT_LENGTH=" 
66                  << FCGX_GetParam("CONTENT_LENGTH", request->envp) 
67                  << "\"\n";
68             clen = STDIN_MAX;
69         }
70     }
71
72     // Note that *you* should not read stdin when CONTENT_LENGTH
73     // is missing or unparsable (this is a demo/test program).
74
75     // *always* put a cap on the amount of data that will be read
76     if (clen > STDIN_MAX) clen = STDIN_MAX;
77
78     *content = new char[clen];
79
80     cin.read(*content, clen);
81     clen = cin.gcount();
82
83     // chew up any remaining stdin - this shouldn't be necessary
84     // but is because mod_fastcgi doesn't handle it correctly
85     do cin.ignore(1024); while (! cin.eof());
86
87     return clen;
88 }
89
90 int main (void)
91 {
92     int count = 0;
93     long pid = getpid();
94
95     FCGX_Request request;
96        
97     FCGX_Init();
98     FCGX_InitRequest(&request, 0, 0);
99
100     while (FCGX_Accept_r(&request) == 0) 
101     {
102         // Note that the default bufsize (0) will cause the use of iostream
103         // methods that require positioning (such as peek(), seek(), 
104         // unget() and putback()) to fail (in favour of more efficient IO).
105         fcgi_streambuf fin(request.in);
106         fcgi_streambuf fout(request.out);
107         fcgi_streambuf ferr(request.err);
108
109 #ifdef _WIN32
110         cin = &fin;
111         cout = &fout;
112         cerr = &ferr;
113 #else
114         cin.rdbuf(&fin);
115         cout.rdbuf(&fout);
116         cerr.rdbuf(&ferr);
117 #endif
118
119         // Although FastCGI supports writing before reading,
120         // many http clients (browsers) don't support it (so  
121         // the connection deadlocks until a timeout expires!).
122         char * content;
123         unsigned long clen = gstdin(&request, &content);
124
125         cout << "Content-type: text/html\r\n"
126                 "\r\n"
127                 "<TITLE>echo-cpp</TITLE>\n"
128                 "<H1>echo-cpp</H1>\n"
129                 "<H4>PID: " << pid << "</H4>\n"
130                 "<H4>Request Number: " << ++count << "</H4>\n";
131
132         cout << "<H4>Request Environment</H4>\n";
133         penv(request.envp);
134
135         cout << "<H4>Process/Initial Environment</H4>\n";
136         penv(environ);
137
138         cout << "<H4>Standard Input - " << clen;
139         if (clen == STDIN_MAX) cout << " (STDIN_MAX)";
140         cout << " bytes</H4>\n";
141         if (clen) cout.write(content, clen);
142
143         if (content) delete []content;
144
145         // If the output streambufs had non-zero bufsizes and
146         // were constructed outside of the accept loop (i.e.
147         // their destructor won't be called here), they would
148         // have to be flushed here.
149     }
150
151     return 0;
152 }