Commit | Line | Data |
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> |
38 | extern char ** environ; |
39 | #endif |
40 | #include "fcgio.h" |
fae4909b |
41 | #include "fcgi_config.h" // HAVE_IOSTREAM_WITHASSIGN_STREAMBUF |
e9c3e4d1 |
42 | |
18f985c2 |
43 | using namespace std; |
44 | |
e9c3e4d1 |
45 | // Maximum number of bytes allowed to be read from stdin |
46 | static const unsigned long STDIN_MAX = 1000000; |
47 | |
48 | static 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 | |
58 | static 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 | |
99 | int 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 | } |