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