697e529339d1beadd82d780d9d9367336718ce4c
[catagits/fcgi2.git] / examples / echo-cpp.cpp
1 /*
2  *  A simple FastCGI application example in C++.
3  *
4  *  $Id: echo-cpp.cpp,v 1.8 2002/02/01 19:43:27 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 #include "fcgi_config.h"  // HAVE_IOSTREAM_WITHASSIGN_STREAMBUF
42
43 // Maximum number of bytes allowed to be read from stdin
44 static const unsigned long STDIN_MAX = 1000000;
45
46 static void penv(const char * const * envp)
47 {
48     cout << "<PRE>\n";
49     for ( ; *envp; ++envp)
50     {
51         cout << *envp << "\n";
52     }
53     cout << "</PRE>\n";
54 }
55
56 static long gstdin(FCGX_Request * request, char ** content)
57 {
58     char * clenstr = FCGX_GetParam("CONTENT_LENGTH", request->envp);
59     unsigned long clen = STDIN_MAX;
60
61     if (clenstr)
62     {
63         clen = strtol(clenstr, &clenstr, 10);
64         if (*clenstr)
65         {
66             cerr << "can't parse \"CONTENT_LENGTH="
67                  << FCGX_GetParam("CONTENT_LENGTH", request->envp)
68                  << "\"\n";
69             clen = STDIN_MAX;
70         }
71
72         // *always* put a cap on the amount of data that will be read
73         if (clen > STDIN_MAX) clen = STDIN_MAX;
74
75         *content = new char[clen];
76
77         cin.read(*content, clen);
78         clen = cin.gcount();
79     }
80     else
81     {
82         // *never* read stdin when CONTENT_LENGTH is missing or unparsable
83         *content = 0;
84         clen = 0;
85     }
86
87     // Chew up any remaining stdin - this shouldn't be necessary
88     // but is because mod_fastcgi doesn't handle it correctly.
89
90     // ignore() doesn't set the eof bit in some versions of glibc++
91     // so use gcount() instead of eof()...
92     do cin.ignore(1024); while (cin.gcount() == 1024);
93
94     return clen;
95 }
96
97 int main (void)
98 {
99     int count = 0;
100     long pid = getpid();
101
102     streambuf * cin_streambuf  = cin.rdbuf();
103     streambuf * cout_streambuf = cout.rdbuf();
104     streambuf * cerr_streambuf = cerr.rdbuf();
105
106     FCGX_Request request;
107
108     FCGX_Init();
109     FCGX_InitRequest(&request, 0, 0);
110
111     while (FCGX_Accept_r(&request) == 0)
112     {
113         // Note that the default bufsize (0) will cause the use of iostream
114         // methods that require positioning (such as peek(), seek(),
115         // unget() and putback()) to fail (in favour of more efficient IO).
116         fcgi_streambuf cin_fcgi_streambuf(request.in);
117         fcgi_streambuf cout_fcgi_streambuf(request.out);
118         fcgi_streambuf cerr_fcgi_streambuf(request.err);
119
120 #ifdef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF
121         cin  = &cin_fcgi_streambuf;
122         cout = &cout_fcgi_streambuf;
123         cerr = &cerr_fcgi_streambuf;
124 #else
125         cin.rdbuf(&cin_fcgi_streambuf);
126         cout.rdbuf(&cout_fcgi_streambuf);
127         cerr.rdbuf(&cerr_fcgi_streambuf);
128 #endif
129
130         // Although FastCGI supports writing before reading,
131         // many http clients (browsers) don't support it (so
132         // the connection deadlocks until a timeout expires!).
133         char * content;
134         unsigned long clen = gstdin(&request, &content);
135
136         cout << "Content-type: text/html\r\n"
137                 "\r\n"
138                 "<TITLE>echo-cpp</TITLE>\n"
139                 "<H1>echo-cpp</H1>\n"
140                 "<H4>PID: " << pid << "</H4>\n"
141                 "<H4>Request Number: " << ++count << "</H4>\n";
142
143         cout << "<H4>Request Environment</H4>\n";
144         penv(request.envp);
145
146         cout << "<H4>Process/Initial Environment</H4>\n";
147         penv(environ);
148
149         cout << "<H4>Standard Input - " << clen;
150         if (clen == STDIN_MAX) cout << " (STDIN_MAX)";
151         cout << " bytes</H4>\n";
152         if (clen) cout.write(content, clen);
153
154         if (content) delete []content;
155
156         // If the output streambufs had non-zero bufsizes and
157         // were constructed outside of the accept loop (i.e.
158         // their destructor won't be called here), they would
159         // have to be flushed here.
160     }
161
162 #ifdef HAVE_IOSTREAM_WITHASSIGN_STREAMBUF
163     cin  = cin_streambuf;
164     cout = cout_streambuf;
165     cerr = cerr_streambuf;
166 #else
167     cin.rdbuf(cin_streambuf);
168     cout.rdbuf(cout_streambuf);
169     cerr.rdbuf(cerr_streambuf);
170 #endif
171
172     return 0;
173 }