aboutsummaryrefslogtreecommitdiff
path: root/src/fastcgi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/fastcgi.cpp')
-rw-r--r--src/fastcgi.cpp277
1 files changed, 277 insertions, 0 deletions
diff --git a/src/fastcgi.cpp b/src/fastcgi.cpp
new file mode 100644
index 0000000..aba3b71
--- /dev/null
+++ b/src/fastcgi.cpp
@@ -0,0 +1,277 @@
1#include "bu/fastcgi.h"
2
3#include <arpa/inet.h>
4#include <errno.h>
5
6#include "bu/membuf.h"
7
8#include "bu/sio.h"
9using Bu::sio;
10using Bu::Fmt;
11
12Bu::FastCgi::FastCgi() :
13 pSrv( NULL ),
14 bRunning( true )
15{
16 pSrv = new Bu::ServerSocket( STDIN_FILENO, false );
17}
18
19Bu::FastCgi::FastCgi( int iPort ) :
20 pSrv( NULL ),
21 bRunning( true )
22{
23 pSrv = new Bu::ServerSocket( iPort );
24}
25
26Bu::FastCgi::~FastCgi()
27{
28}
29
30bool Bu::FastCgi::isEmbedded()
31{
32 struct sockaddr name;
33 socklen_t namelen = sizeof(name);
34 if( getpeername( STDIN_FILENO, &name, &namelen ) != 0 &&
35 errno == ENOTCONN )
36 {
37 sio << "errno = " << errno << " (" << strerror( errno ) << ")" <<
38 sio.nl;
39 sio << "Socket found" << sio.nl;
40 return true;
41 }
42 else
43 {
44 sio << "errno = " << errno << " (" << strerror( errno ) << ")" <<
45 sio.nl;
46 sio << "No socket detected, running in standalone mode" << sio.nl;
47 return false;
48 }
49}
50
51void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::Record &r )
52{
53 s.read( &r, sizeof(Record) );
54 r.uRequestId = ntohs( r.uRequestId );
55 r.uContentLength = ntohs( r.uContentLength );
56}
57
58void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::Record r )
59{
60 r.uRequestId = htons( r.uRequestId );
61 r.uContentLength = htons( r.uContentLength );
62 s.write( &r, sizeof(Record) );
63}
64
65void Bu::FastCgi::read( Bu::Socket &s, Bu::FastCgi::BeginRequestBody &b )
66{
67 s.read( &b, sizeof(BeginRequestBody) );
68 b.uRole = ntohs( b.uRole );
69}
70
71void Bu::FastCgi::write( Bu::Socket &s, Bu::FastCgi::EndRequestBody b )
72{
73 b.uStatus = htonl( b.uStatus );
74 s.write( &b, sizeof(b) );
75}
76
77uint32_t Bu::FastCgi::readLen( Bu::Socket &s, uint16_t &uRead )
78{
79 uint8_t uByte[4];
80 s.read( uByte, 1 );
81 uRead++;
82 if( uByte[0] >> 7 == 0 )
83 return uByte[0];
84
85 s.read( uByte+1, 3 );
86 uRead += 3;
87 return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]);
88}
89
90void Bu::FastCgi::readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uRead )
91{
92 uint32_t uName = readLen( s, uRead );
93 uint32_t uValue = readLen( s, uRead );
94 uRead += uName + uValue;
95 unsigned char *sName = new unsigned char[uName];
96 s.read( sName, uName );
97 Bu::FString fsName( (char *)sName, uName );
98 delete[] sName;
99
100 if( uValue > 0 )
101 {
102 unsigned char *sValue = new unsigned char[uValue];
103 s.read( sValue, uValue );
104 Bu::FString fsValue( (char *)sValue, uValue );
105 hParams.insert( fsName, fsValue );
106 delete[] sValue;
107 }
108 else
109 {
110 hParams.insert( fsName, "" );
111 }
112}
113
114void Bu::FastCgi::run()
115{
116 bRunning = true;
117 while( bRunning )
118 {
119 int iSock = pSrv->accept( 5 );
120 if( iSock < 0 )
121 continue;
122
123 Bu::Socket s( iSock );
124 s.setBlocking( true );
125 try
126 {
127 for(;;)
128 {
129 Record r;
130 read( s, r );
131 while( aChannel.getSize() < r.uRequestId )
132 aChannel.append( NULL );
133 Channel *pChan = NULL;
134 if( r.uRequestId > 0 )
135 pChan = aChannel[r.uRequestId-1];
136
137 sio << "Record (id=" << r.uRequestId << ", len=" <<
138 r.uContentLength << ", pad=" <<
139 (int)r.uPaddingLength << "): ";
140 fflush( stdout );
141
142 switch( (RequestType)r.uType )
143 {
144 case typeBeginRequest:
145 sio << "Begin Request.";
146 {
147 BeginRequestBody b;
148 read( s, b );
149 if( pChan != NULL )
150 {
151 sio << "Error!!!" << sio.nl;
152 return;
153 }
154 pChan = aChannel[r.uRequestId-1] = new Channel();
155 }
156 break;
157
158 case typeParams:
159 sio << "Params.";
160 if( r.uContentLength == 0 )
161 {
162 pChan->uFlags |= chflgParamsDone;
163 }
164 else
165 {
166 uint16_t uUsed = 0;
167 while( uUsed < r.uContentLength )
168 {
169 readPair( s, pChan->hParams, uUsed );
170 }
171 }
172 break;
173
174 case typeStdIn:
175 sio << "StdIn.";
176 if( r.uContentLength == 0 )
177 {
178 pChan->uFlags |= chflgStdInDone;
179 }
180 else
181 {
182 char *buf = new char[r.uContentLength];
183 sio << " (read " << s.read( buf, r.uContentLength )
184 << ")";
185 pChan->sStdIn.append( buf, r.uContentLength );
186 delete[] buf;
187 }
188 break;
189
190 case typeData:
191 sio << "Data.";
192 if( r.uContentLength == 0 )
193 {
194 pChan->uFlags |= chflgDataDone;
195 }
196 else
197 {
198 char *buf = new char[r.uContentLength];
199 s.read( buf, r.uContentLength );
200 pChan->sData.append( buf, r.uContentLength );
201 delete[] buf;
202 }
203 break;
204
205 case typeStdOut:
206 case typeStdErr:
207 case typeEndRequest:
208 case typeAbortRequest:
209 case typeGetValuesResult:
210 sio << "Scary.";
211 // ??? we shouldn't get these.
212 break;
213
214 }
215
216 sio << sio.nl;
217
218 if( pChan )
219 {
220 if( pChan->uFlags == chflgAllDone )
221 {
222 Bu::MemBuf mStdOut, mStdErr;
223 int iRet = request(
224 pChan->hParams, pChan->sStdIn,
225 mStdOut, mStdErr
226 );
227
228 Bu::FString &sStdOut = mStdOut.getString();
229 Bu::FString &sStdErr = mStdErr.getString();
230
231 Record rOut;
232 rOut.uVersion = 1;
233 rOut.uRequestId = r.uRequestId;
234 rOut.uPaddingLength = 0;
235 if( sStdOut.getSize() > 0 )
236 {
237 rOut.uType = typeStdOut;
238 rOut.uContentLength = sStdOut.getSize();
239 write( s, rOut );
240 s.write( sStdOut );
241 }
242 rOut.uType = typeStdOut;
243 rOut.uContentLength = 0;
244 write( s, rOut );
245 if( sStdErr.getSize() > 0 )
246 {
247 rOut.uType = typeStdErr;
248 rOut.uContentLength = sStdErr.getSize();
249 write( s, rOut );
250 s.write( sStdOut );
251 }
252 rOut.uType = typeStdErr;
253 rOut.uContentLength = 0;
254 write( s, rOut );
255
256 rOut.uType = typeEndRequest;
257 rOut.uContentLength = 8;
258 write( s, rOut );
259
260 EndRequestBody b;
261 memset( &b, 0, sizeof(b) );
262 b.uStatus = iRet;
263 write( s, b );
264
265 delete pChan;
266 aChannel[r.uRequestId-1] = NULL;
267 }
268 }
269 }
270 }
271 catch( Bu::SocketException &e )
272 {
273 //sio << "Bu::SocketException: " << e.what() << sio.nl;
274 }
275 }
276}
277