use gcount() instead of eof() because ignore() doesn't set the eof bit in some versio...
[catagits/fcgi2.git] / examples / echo-cpp.cpp
CommitLineData
e9c3e4d1 1/*
2 * A simple FastCGI application example in C++.
3 *
fb0f73bb 4 * $Id: echo-cpp.cpp,v 1.6 2001/11/26 18:08:25 robs Exp $
e9c3e4d1 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>
38extern char ** environ;
39#endif
40#include "fcgio.h"
41
42// Maximum number of bytes allowed to be read from stdin
43static const unsigned long STDIN_MAX = 1000000;
44
45static 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
55static 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
fb0f73bb 83 // Chew up any remaining stdin - this shouldn't be necessary
84 // but is because mod_fastcgi doesn't handle it correctly.
85 //
86 // ignore() doesn't set the eof bit in some versions of glibc++
87 // so use gcount() instead of eof()...
88 do cin.ignore(1024); while (cin.gcount() == 1024);
e9c3e4d1 89
90 return clen;
91}
92
93int main (void)
94{
95 int count = 0;
96 long pid = getpid();
97
98 FCGX_Request request;
99
100 FCGX_Init();
101 FCGX_InitRequest(&request, 0, 0);
102
103 while (FCGX_Accept_r(&request) == 0)
104 {
105 // Note that the default bufsize (0) will cause the use of iostream
106 // methods that require positioning (such as peek(), seek(),
107 // unget() and putback()) to fail (in favour of more efficient IO).
108 fcgi_streambuf fin(request.in);
109 fcgi_streambuf fout(request.out);
110 fcgi_streambuf ferr(request.err);
111
112#ifdef _WIN32
113 cin = &fin;
114 cout = &fout;
115 cerr = &ferr;
116#else
117 cin.rdbuf(&fin);
118 cout.rdbuf(&fout);
119 cerr.rdbuf(&ferr);
120#endif
121
122 // Although FastCGI supports writing before reading,
123 // many http clients (browsers) don't support it (so
124 // the connection deadlocks until a timeout expires!).
125 char * content;
126 unsigned long clen = gstdin(&request, &content);
127
128 cout << "Content-type: text/html\r\n"
129 "\r\n"
130 "<TITLE>echo-cpp</TITLE>\n"
131 "<H1>echo-cpp</H1>\n"
132 "<H4>PID: " << pid << "</H4>\n"
133 "<H4>Request Number: " << ++count << "</H4>\n";
134
135 cout << "<H4>Request Environment</H4>\n";
136 penv(request.envp);
137
138 cout << "<H4>Process/Initial Environment</H4>\n";
139 penv(environ);
140
141 cout << "<H4>Standard Input - " << clen;
142 if (clen == STDIN_MAX) cout << " (STDIN_MAX)";
143 cout << " bytes</H4>\n";
144 if (clen) cout.write(content, clen);
145
146 if (content) delete []content;
147
148 // If the output streambufs had non-zero bufsizes and
149 // were constructed outside of the accept loop (i.e.
150 // their destructor won't be called here), they would
151 // have to be flushed here.
152 }
153
154 return 0;
155}