aboutsummaryrefslogtreecommitdiff
path: root/src/experimental/fastcgi.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/experimental/fastcgi.cpp592
1 files changed, 296 insertions, 296 deletions
diff --git a/src/experimental/fastcgi.cpp b/src/experimental/fastcgi.cpp
index 7068fa8..71426b9 100644
--- a/src/experimental/fastcgi.cpp
+++ b/src/experimental/fastcgi.cpp
@@ -8,7 +8,7 @@
8#include "bu/fastcgi.h" 8#include "bu/fastcgi.h"
9 9
10#ifndef WIN32 10#ifndef WIN32
11 #include <arpa/inet.h> 11 #include <arpa/inet.h>
12#endif 12#endif
13 13
14#include <errno.h> 14#include <errno.h>
@@ -21,17 +21,17 @@ using Bu::sio;
21using Bu::Fmt; 21using Bu::Fmt;
22 22
23Bu::FastCgi::FastCgi() : 23Bu::FastCgi::FastCgi() :
24 pSrv( NULL ), 24 pSrv( NULL ),
25 bRunning( true ) 25 bRunning( true )
26{ 26{
27 pSrv = new Bu::TcpServerSocket( (Bu::TcpServerSocket::socket_t)STDIN_FILENO, false ); 27 pSrv = new Bu::TcpServerSocket( (Bu::TcpServerSocket::socket_t)STDIN_FILENO, false );
28} 28}
29 29
30Bu::FastCgi::FastCgi( int iPort ) : 30Bu::FastCgi::FastCgi( int iPort ) :
31 pSrv( NULL ), 31 pSrv( NULL ),
32 bRunning( true ) 32 bRunning( true )
33{ 33{
34 pSrv = new Bu::TcpServerSocket( iPort ); 34 pSrv = new Bu::TcpServerSocket( iPort );
35} 35}
36 36
37Bu::FastCgi::~FastCgi() 37Bu::FastCgi::~FastCgi()
@@ -41,332 +41,332 @@ Bu::FastCgi::~FastCgi()
41bool Bu::FastCgi::isEmbedded() 41bool Bu::FastCgi::isEmbedded()
42{ 42{
43#ifndef WIN32 43#ifndef WIN32
44 struct sockaddr name; 44 struct sockaddr name;
45 socklen_t namelen = sizeof(name); 45 socklen_t namelen = sizeof(name);
46 if( getpeername( STDIN_FILENO, &name, &namelen ) != 0 && 46 if( getpeername( STDIN_FILENO, &name, &namelen ) != 0 &&
47 errno == ENOTCONN ) 47 errno == ENOTCONN )
48 { 48 {
49 sio << "errno = " << errno << " (" << strerror( errno ) << ")" << 49 sio << "errno = " << errno << " (" << strerror( errno ) << ")" <<
50 sio.nl; 50 sio.nl;
51 sio << "Socket found" << sio.nl; 51 sio << "Socket found" << sio.nl;
52 return true; 52 return true;
53 } 53 }
54 else 54 else
55 { 55 {
56 sio << "errno = " << errno << " (" << strerror( errno ) << ")" << 56 sio << "errno = " << errno << " (" << strerror( errno ) << ")" <<
57 sio.nl; 57 sio.nl;
58 sio << "No socket detected, running in standalone mode" << sio.nl; 58 sio << "No socket detected, running in standalone mode" << sio.nl;
59 return false; 59 return false;
60 } 60 }
61#else 61#else
62 #warning Bu::FastCgi::isEmbedded IS A STUB for WIN32!!!! 62 #warning Bu::FastCgi::isEmbedded IS A STUB for WIN32!!!!
63 return false; 63 return false;
64#endif 64#endif
65} 65}
66 66
67void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::Record &r ) 67void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::Record &r )
68{ 68{
69 int iRead = s.read( &r, sizeof(Record) ); 69 int iRead = s.read( &r, sizeof(Record) );
70 if( iRead != sizeof(Record) ) 70 if( iRead != sizeof(Record) )
71 throw Bu::TcpSocketException("Hey, the size %d is wrong for Record. (%s)", 71 throw Bu::TcpSocketException("Hey, the size %d is wrong for Record. (%s)",
72 iRead, strerror( errno ) ); 72 iRead, strerror( errno ) );
73 r.uRequestId = ntohs( r.uRequestId ); 73 r.uRequestId = ntohs( r.uRequestId );
74 r.uContentLength = ntohs( r.uContentLength ); 74 r.uContentLength = ntohs( r.uContentLength );
75} 75}
76 76
77void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::Record r ) 77void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::Record r )
78{ 78{
79// sio << "Out -> " << r << sio.nl; 79// sio << "Out -> " << r << sio.nl;
80 r.uRequestId = htons( r.uRequestId ); 80 r.uRequestId = htons( r.uRequestId );
81 r.uContentLength = htons( r.uContentLength ); 81 r.uContentLength = htons( r.uContentLength );
82 s.write( &r, sizeof(Record) ); 82 s.write( &r, sizeof(Record) );
83} 83}
84 84
85void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::BeginRequestBody &b ) 85void Bu::FastCgi::read( Bu::TcpSocket &s, Bu::FastCgi::BeginRequestBody &b )
86{ 86{
87 s.read( &b, sizeof(BeginRequestBody) ); 87 s.read( &b, sizeof(BeginRequestBody) );
88 b.uRole = ntohs( b.uRole ); 88 b.uRole = ntohs( b.uRole );
89} 89}
90 90
91void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::EndRequestBody b ) 91void Bu::FastCgi::write( Bu::TcpSocket &s, Bu::FastCgi::EndRequestBody b )
92{ 92{
93 b.uStatus = htonl( b.uStatus ); 93 b.uStatus = htonl( b.uStatus );
94 s.write( &b, sizeof(b) ); 94 s.write( &b, sizeof(b) );
95} 95}
96 96
97uint32_t Bu::FastCgi::readLen( Bu::TcpSocket &s, uint16_t &uRead ) 97uint32_t Bu::FastCgi::readLen( Bu::TcpSocket &s, uint16_t &uRead )
98{ 98{
99 uint8_t uByte[4]; 99 uint8_t uByte[4];
100 s.read( uByte, 1 ); 100 s.read( uByte, 1 );
101 uRead++; 101 uRead++;
102 if( uByte[0] >> 7 == 0 ) 102 if( uByte[0] >> 7 == 0 )
103 return uByte[0]; 103 return uByte[0];
104 104
105 s.read( uByte+1, 3 ); 105 s.read( uByte+1, 3 );
106 uRead += 3; 106 uRead += 3;
107 return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]); 107 return ((uByte[0]&0x7f)<<24)|(uByte[1]<<16)|(uByte[2]<<8)|(uByte[3]);
108} 108}
109 109
110void Bu::FastCgi::readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uRead ) 110void Bu::FastCgi::readPair( Bu::TcpSocket &s, StrHash &hParams, uint16_t &uRead )
111{ 111{
112 uint32_t uName = readLen( s, uRead ); 112 uint32_t uName = readLen( s, uRead );
113 uint32_t uValue = readLen( s, uRead ); 113 uint32_t uValue = readLen( s, uRead );
114 uRead += uName + uValue; 114 uRead += uName + uValue;
115 unsigned char *sName = new unsigned char[uName]; 115 unsigned char *sName = new unsigned char[uName];
116 s.read( sName, uName ); 116 s.read( sName, uName );
117 Bu::String fsName( (char *)sName, uName ); 117 Bu::String fsName( (char *)sName, uName );
118 delete[] sName; 118 delete[] sName;
119 119
120 if( uValue > 0 ) 120 if( uValue > 0 )
121 { 121 {
122 unsigned char *sValue = new unsigned char[uValue]; 122 unsigned char *sValue = new unsigned char[uValue];
123 s.read( sValue, uValue ); 123 s.read( sValue, uValue );
124 Bu::String fsValue( (char *)sValue, uValue ); 124 Bu::String fsValue( (char *)sValue, uValue );
125 hParams.insert( fsName, fsValue ); 125 hParams.insert( fsName, fsValue );
126 delete[] sValue; 126 delete[] sValue;
127 } 127 }
128 else 128 else
129 { 129 {
130 hParams.insert( fsName, "" ); 130 hParams.insert( fsName, "" );
131 } 131 }
132} 132}
133 133
134bool Bu::FastCgi::hasChannel( int iChan ) 134bool Bu::FastCgi::hasChannel( int iChan )
135{ 135{
136 if( aChannel.getSize() < iChan ) 136 if( aChannel.getSize() < iChan )
137 return false; 137 return false;
138 if( aChannel[iChan-1] == NULL ) 138 if( aChannel[iChan-1] == NULL )
139 return false; 139 return false;
140 return true; 140 return true;
141} 141}
142 142
143Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::FastCgi::Record &r ) 143Bu::Formatter &Bu::operator<<( Bu::Formatter &f, const Bu::FastCgi::Record &r )
144{ 144{
145 f << "[Ver=" << (uint32_t)r.uVersion << 145 f << "[Ver=" << (uint32_t)r.uVersion <<
146 ", Type=" << (uint32_t)r.uType << 146 ", Type=" << (uint32_t)r.uType <<
147 ", Req=" << (uint32_t)r.uRequestId << 147 ", Req=" << (uint32_t)r.uRequestId <<
148 ", clen=" << (uint32_t)r.uContentLength << 148 ", clen=" << (uint32_t)r.uContentLength <<
149 ", plen=" << (uint32_t)r.uPaddingLength << 149 ", plen=" << (uint32_t)r.uPaddingLength <<
150 ", resv=" << (uint32_t)r.uReserved << 150 ", resv=" << (uint32_t)r.uReserved <<
151 "]"; 151 "]";
152 return f; 152 return f;
153} 153}
154 154
155void Bu::FastCgi::run() 155void Bu::FastCgi::run()
156{ 156{
157// sio << "sizeof(Bu::FastCgi::Record) = " << sizeof(Record) << sio.nl; 157// sio << "sizeof(Bu::FastCgi::Record) = " << sizeof(Record) << sio.nl;
158 bRunning = true; 158 bRunning = true;
159 while( bRunning ) 159 while( bRunning )
160 { 160 {
161 int iSock = pSrv->accept( 5 ); 161 int iSock = pSrv->accept( 5 );
162 if( iSock < 0 ) 162 if( iSock < 0 )
163 continue; 163 continue;
164 164
165 Bu::TcpSocket s( iSock ); 165 Bu::TcpSocket s( iSock );
166 s.setBlocking( true ); 166 s.setBlocking( true );
167// sio << "Got connection, blocking? " << s.isBlocking() << sio.nl; 167// sio << "Got connection, blocking? " << s.isBlocking() << sio.nl;
168 try 168 try
169 { 169 {
170 for(;;) 170 for(;;)
171 { 171 {
172 Record r; 172 Record r;
173 memset( &r, 0, sizeof(r) ); 173 memset( &r, 0, sizeof(r) );
174// try 174// try
175// { 175// {
176 read( s, r ); 176 read( s, r );
177// } 177// }
178// catch( Bu::ExceptionBase &e ) 178// catch( Bu::ExceptionBase &e )
179// { 179// {
180// sio << "Error: " << e.what() << ", " << s.isOpen() << 180// sio << "Error: " << e.what() << ", " << s.isOpen() <<
181// sio.nl; 181// sio.nl;
182// continue; 182// continue;
183// } 183// }
184 Channel *pChan = NULL; 184 Channel *pChan = NULL;
185 if( r.uRequestId > 0 ) 185 if( r.uRequestId > 0 )
186 { 186 {
187 if( !hasChannel( r.uRequestId ) && 187 if( !hasChannel( r.uRequestId ) &&
188 r.uType != typeBeginRequest ) 188 r.uType != typeBeginRequest )
189 { 189 {
190 sio << "Error, stream data without stream." << sio.nl; 190 sio << "Error, stream data without stream." << sio.nl;
191 sio << r << sio.nl; 191 sio << r << sio.nl;
192 if( r.uContentLength > 0 ) 192 if( r.uContentLength > 0 )
193 { 193 {
194 char *buf = new char[r.uContentLength]; 194 char *buf = new char[r.uContentLength];
195 sio << " (read " << s.read( buf, r.uContentLength ) 195 sio << " (read " << s.read( buf, r.uContentLength )
196 << "/" << r.uContentLength << "):" << sio.nl; 196 << "/" << r.uContentLength << "):" << sio.nl;
197 sio.write( buf, r.uContentLength ); 197 sio.write( buf, r.uContentLength );
198 sio << sio.nl << sio.nl; 198 sio << sio.nl << sio.nl;
199 } 199 }
200 } 200 }
201 while( aChannel.getSize() < r.uRequestId ) 201 while( aChannel.getSize() < r.uRequestId )
202 aChannel.append( NULL ); 202 aChannel.append( NULL );
203 if( r.uRequestId > 0 ) 203 if( r.uRequestId > 0 )
204 pChan = aChannel[r.uRequestId-1]; 204 pChan = aChannel[r.uRequestId-1];
205 } 205 }
206 206
207// sio << "Record (id=" << r.uRequestId << ", len=" << 207// sio << "Record (id=" << r.uRequestId << ", len=" <<
208// r.uContentLength << ", pad=" << 208// r.uContentLength << ", pad=" <<
209// (unsigned int)r.uPaddingLength << "): "; 209// (unsigned int)r.uPaddingLength << "): ";
210// fflush( stdout ); 210// fflush( stdout );
211 211
212 switch( (RequestType)r.uType ) 212 switch( (RequestType)r.uType )
213 { 213 {
214 case typeBeginRequest: 214 case typeBeginRequest:
215// sio << "Begin Request."; 215// sio << "Begin Request.";
216 { 216 {
217 BeginRequestBody b; 217 BeginRequestBody b;
218 read( s, b ); 218 read( s, b );
219 if( pChan != NULL ) 219 if( pChan != NULL )
220 { 220 {
221 sio << "Error!!!" << sio.nl; 221 sio << "Error!!!" << sio.nl;
222 return; 222 return;
223 } 223 }
224 pChan = aChannel[r.uRequestId-1] = new Channel(); 224 pChan = aChannel[r.uRequestId-1] = new Channel();
225 } 225 }
226 break; 226 break;
227 227
228 case typeParams: 228 case typeParams:
229// sio << "Params."; 229// sio << "Params.";
230 if( r.uContentLength == 0 ) 230 if( r.uContentLength == 0 )
231 { 231 {
232 pChan->uFlags |= chflgParamsDone; 232 pChan->uFlags |= chflgParamsDone;
233 } 233 }
234 else 234 else
235 { 235 {
236 uint16_t uUsed = 0; 236 uint16_t uUsed = 0;
237 while( uUsed < r.uContentLength ) 237 while( uUsed < r.uContentLength )
238 { 238 {
239 readPair( s, pChan->hParams, uUsed ); 239 readPair( s, pChan->hParams, uUsed );
240 } 240 }
241 } 241 }
242 break; 242 break;
243 243
244 case typeStdIn: 244 case typeStdIn:
245// sio << "StdIn."; 245// sio << "StdIn.";
246 if( r.uContentLength == 0 ) 246 if( r.uContentLength == 0 )
247 { 247 {
248 pChan->uFlags |= chflgStdInDone; 248 pChan->uFlags |= chflgStdInDone;
249 } 249 }
250 else 250 else
251 { 251 {
252 char *buf = new char[r.uContentLength]; 252 char *buf = new char[r.uContentLength];
253 int iTotal = 0; 253 int iTotal = 0;
254 do 254 do
255 { 255 {
256 size_t iRead = s.read( 256 size_t iRead = s.read(
257 buf, r.uContentLength-iTotal ); 257 buf, r.uContentLength-iTotal );
258 iTotal += iRead; 258 iTotal += iRead;
259// sio << " (read " << iRead << " " << iTotal 259// sio << " (read " << iRead << " " << iTotal
260// << "/" << r.uContentLength << ")"; 260// << "/" << r.uContentLength << ")";
261 pChan->sStdIn.append( buf, iRead ); 261 pChan->sStdIn.append( buf, iRead );
262 } while( iTotal < r.uContentLength ); 262 } while( iTotal < r.uContentLength );
263 delete[] buf; 263 delete[] buf;
264 } 264 }
265 break; 265 break;
266 266
267 case typeData: 267 case typeData:
268// sio << "Data."; 268// sio << "Data.";
269 if( r.uContentLength == 0 ) 269 if( r.uContentLength == 0 )
270 { 270 {
271 pChan->uFlags |= chflgDataDone; 271 pChan->uFlags |= chflgDataDone;
272 } 272 }
273 else 273 else
274 { 274 {
275 char *buf = new char[r.uContentLength]; 275 char *buf = new char[r.uContentLength];
276 s.read( buf, r.uContentLength ); 276 s.read( buf, r.uContentLength );
277 pChan->sData.append( buf, r.uContentLength ); 277 pChan->sData.append( buf, r.uContentLength );
278 delete[] buf; 278 delete[] buf;
279 } 279 }
280 break; 280 break;
281 281
282 case typeStdOut: 282 case typeStdOut:
283 case typeStdErr: 283 case typeStdErr:
284 case typeEndRequest: 284 case typeEndRequest:
285 case typeAbortRequest: 285 case typeAbortRequest:
286 case typeGetValuesResult: 286 case typeGetValuesResult:
287// sio << "Scary."; 287// sio << "Scary.";
288 // ??? we shouldn't get these. 288 // ??? we shouldn't get these.
289 break; 289 break;
290 290
291 case typeGetValues: 291 case typeGetValues:
292 break; 292 break;
293 } 293 }
294 294
295// sio << sio.nl; 295// sio << sio.nl;
296 296
297 if( pChan ) 297 if( pChan )
298 { 298 {
299 if( pChan->uFlags == chflgAllDone ) 299 if( pChan->uFlags == chflgAllDone )
300 { 300 {
301// sio << "All done, generating output." << sio.nl; 301// sio << "All done, generating output." << sio.nl;
302 Bu::MemBuf mStdOut, mStdErr; 302 Bu::MemBuf mStdOut, mStdErr;
303 int iRet = onRequest( 303 int iRet = onRequest(
304 pChan->hParams, pChan->sStdIn, 304 pChan->hParams, pChan->sStdIn,
305 mStdOut, mStdErr 305 mStdOut, mStdErr
306 ); 306 );
307 307
308 Bu::String &sStdOut = mStdOut.getString(); 308 Bu::String &sStdOut = mStdOut.getString();
309 Bu::String &sStdErr = mStdErr.getString(); 309 Bu::String &sStdErr = mStdErr.getString();
310 310
311 Record rOut; 311 Record rOut;
312 memset( &rOut, 0, sizeof(rOut) ); 312 memset( &rOut, 0, sizeof(rOut) );
313 rOut.uVersion = 1; 313 rOut.uVersion = 1;
314 rOut.uRequestId = r.uRequestId; 314 rOut.uRequestId = r.uRequestId;
315 rOut.uPaddingLength = 0; 315 rOut.uPaddingLength = 0;
316 rOut.uType = typeStdOut; 316 rOut.uType = typeStdOut;
317 if( sStdOut.getSize() > 0 ) 317 if( sStdOut.getSize() > 0 )
318 { 318 {
319 for( int iPos = 0; iPos < sStdOut.getSize(); 319 for( int iPos = 0; iPos < sStdOut.getSize();
320 iPos += 65528 ) 320 iPos += 65528 )
321 { 321 {
322 int iSize = sStdOut.getSize()-iPos; 322 int iSize = sStdOut.getSize()-iPos;
323 if( iSize > 65528 ) 323 if( iSize > 65528 )
324 iSize = 65528; 324 iSize = 65528;
325 rOut.uContentLength = iSize; 325 rOut.uContentLength = iSize;
326 write( s, rOut ); 326 write( s, rOut );
327 s.write( sStdOut.getStr()+iPos, iSize ); 327 s.write( sStdOut.getStr()+iPos, iSize );
328 } 328 }
329 } 329 }
330 rOut.uContentLength = 0; 330 rOut.uContentLength = 0;
331 write( s, rOut ); 331 write( s, rOut );
332 332
333 rOut.uType = typeStdErr; 333 rOut.uType = typeStdErr;
334 if( sStdErr.getSize() > 0 ) 334 if( sStdErr.getSize() > 0 )
335 { 335 {
336 for( int iPos = 0; iPos < sStdErr.getSize(); 336 for( int iPos = 0; iPos < sStdErr.getSize();
337 iPos += 65528 ) 337 iPos += 65528 )
338 { 338 {
339 int iSize = sStdErr.getSize()-iPos; 339 int iSize = sStdErr.getSize()-iPos;
340 if( iSize > 65528 ) 340 if( iSize > 65528 )
341 iSize = 65528; 341 iSize = 65528;
342 rOut.uContentLength = iSize; 342 rOut.uContentLength = iSize;
343 write( s, rOut ); 343 write( s, rOut );
344 s.write( sStdErr.getStr()+iPos, iSize ); 344 s.write( sStdErr.getStr()+iPos, iSize );
345 } 345 }
346 } 346 }
347 rOut.uContentLength = 0; 347 rOut.uContentLength = 0;
348 write( s, rOut ); 348 write( s, rOut );
349 349
350 rOut.uType = typeEndRequest; 350 rOut.uType = typeEndRequest;
351 rOut.uContentLength = 8; 351 rOut.uContentLength = 8;
352 write( s, rOut ); 352 write( s, rOut );
353 353
354 EndRequestBody b; 354 EndRequestBody b;
355 memset( &b, 0, sizeof(b) ); 355 memset( &b, 0, sizeof(b) );
356 b.uStatus = iRet; 356 b.uStatus = iRet;
357 write( s, b ); 357 write( s, b );
358 358
359 delete pChan; 359 delete pChan;
360 aChannel[r.uRequestId-1] = NULL; 360 aChannel[r.uRequestId-1] = NULL;
361 } 361 }
362 } 362 }
363 } 363 }
364 } 364 }
365 catch( Bu::TcpSocketException &e ) 365 catch( Bu::TcpSocketException &e )
366 { 366 {
367// sio << "Bu::SocketException: " << e.what() << sio.nl << 367// sio << "Bu::SocketException: " << e.what() << sio.nl <<
368// "\tSocket open: " << s.isOpen() << sio.nl; 368// "\tSocket open: " << s.isOpen() << sio.nl;
369 } 369 }
370 } 370 }
371} 371}
372 372