aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2009-04-06 19:13:51 +0000
committerMike Buland <eichlan@xagasoft.com>2009-04-06 19:13:51 +0000
commit514721c24c7212c084ad2530e8239ff121097818 (patch)
treebfe5d346e767df47d10a5631e33a2e0540d72604
parentaaeaa599a14642e916bbd8a32a208ee96a26eaac (diff)
downloadlibbu++-514721c24c7212c084ad2530e8239ff121097818.tar.gz
libbu++-514721c24c7212c084ad2530e8239ff121097818.tar.bz2
libbu++-514721c24c7212c084ad2530e8239ff121097818.tar.xz
libbu++-514721c24c7212c084ad2530e8239ff121097818.zip
Ok, I rearranged some things, we have a tools dir now, those build by default.
Also I added a bunch of classes that I've been tinkering with that are almost ready for use, so I figured I may as well throw them in here.
-rw-r--r--build.conf11
-rw-r--r--src/fastcgi.cpp277
-rw-r--r--src/fastcgi.h120
-rw-r--r--src/tests/fastcgi.cpp81
-rw-r--r--src/tests/url.cpp45
-rw-r--r--src/tools/nidstool.cpp (renamed from src/tests/nidstool.cpp)0
-rw-r--r--src/unit/array.unit4
-rw-r--r--src/urn.cpp0
-rw-r--r--src/urn.h0
9 files changed, 515 insertions, 23 deletions
diff --git a/build.conf b/build.conf
index 769fa31..9094c7a 100644
--- a/build.conf
+++ b/build.conf
@@ -5,7 +5,7 @@
5# This file is part of the libbu++ library and is released under the 5# This file is part of the libbu++ library and is released under the
6# terms of the license contained in the file LICENSE. 6# terms of the license contained in the file LICENSE.
7 7
8default action: check group "lnhdrs", check "libbu++.a" 8default action: check group "lnhdrs", check "libbu++.a", check group "tools"
9"tests" action: check group "lnhdrs", check group "tests" 9"tests" action: check group "lnhdrs", check group "tests"
10"all" action: check group "lnhdrs", check targets() 10"all" action: check group "lnhdrs", check targets()
11 11
@@ -45,6 +45,15 @@ filesIn("src/tests") filter regexp("^src/tests/(.*)\\.cpp$", "tests/{re:1}"):
45 set "LDFLAGS" += "-L. -lbu++", 45 set "LDFLAGS" += "-L. -lbu++",
46 input "src/{target}.cpp" 46 input "src/{target}.cpp"
47 47
48filesIn("src/tools") filter regexp("^src/tools/(.*)\\.cpp$", "{re:1}"):
49 rule "exe",
50 target file,
51 group "tools",
52 requires "libbu++.a",
53 set "CXXFLAGS" += "-I.",
54 set "LDFLAGS" += "-L. -lbu++",
55 input "src/tools/{target}.cpp"
56
48["tests/itoqueue1", "tests/itoqueue2", "tests/socketblock", "tests/itoserver", 57["tests/itoqueue1", "tests/itoqueue2", "tests/socketblock", "tests/itoserver",
49 "tests/itoheap"]: 58 "tests/itoheap"]:
50 set "LDFLAGS" += "-lpthread" 59 set "LDFLAGS" += "-lpthread"
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
diff --git a/src/fastcgi.h b/src/fastcgi.h
new file mode 100644
index 0000000..83e9b83
--- /dev/null
+++ b/src/fastcgi.h
@@ -0,0 +1,120 @@
1#ifndef BU_FAST_CGI_H
2#define BU_FAST_CGI_H
3
4#include "bu/fstring.h"
5#include "bu/hash.h"
6#include "bu/array.h"
7#include "bu/socket.h"
8#include "bu/serversocket.h"
9
10namespace Bu
11{
12 class Stream;
13
14 class FastCgi
15 {
16 public:
17 FastCgi( int iPort );
18 FastCgi();
19 virtual ~FastCgi();
20
21 static bool isEmbedded();
22
23 typedef Bu::Hash<Bu::FString, Bu::FString> StrHash;
24 enum RequestType
25 {
26 typeBeginRequest = 1,
27 typeAbortRequest = 2,
28 typeEndRequest = 3,
29 typeParams = 4,
30 typeStdIn = 5,
31 typeStdOut = 6,
32 typeStdErr = 7,
33 typeData = 8,
34 typeGetValues = 9,
35 typeGetValuesResult = 10
36 };
37
38 enum Role
39 {
40 roleResponder = 1,
41 roleAuthorizer = 2,
42 roleFilter = 3
43 };
44
45 enum Flags
46 {
47 flagsKeepConn = 1
48 };
49
50 enum Status
51 {
52 statusRequestComplete = 0,
53 statusCantMpxConn = 1,
54 statusOverloaded = 2,
55 statusUnknownRole = 3
56 };
57
58 typedef struct {
59 uint8_t uVersion;
60 uint8_t uType;
61 uint16_t uRequestId;
62 uint16_t uContentLength;
63 uint8_t uPaddingLength;
64 uint8_t uReserved;
65 } Record;
66
67 typedef struct {
68 uint16_t uRole;
69 uint8_t uFlags;
70 uint8_t reserved[5];
71 } BeginRequestBody;
72
73 typedef struct {
74 uint32_t uStatus;
75 uint8_t uProtocolStatus;
76 uint8_t reserved[3];
77 } EndRequestBody;
78
79 typedef struct Channel {
80 Channel() : uFlags( 0 ) { }
81 StrHash hParams;
82 Bu::FString sStdIn;
83 Bu::FString sData;
84 uint8_t uFlags;
85 } Channel;
86
87 enum ChannelFlags
88 {
89 chflgParamsDone = 0x01,
90 chflgStdInDone = 0x02,
91 chflgDataDone = 0x04,
92
93 chflgAllDone = 0x03
94 };
95
96 virtual void run();
97
98 virtual void init() { };
99 virtual int request( const StrHash &hParams,
100 const Bu::FString &sStdIn, Bu::Stream &sStdOut,
101 Bu::Stream &sStdErr )=0;
102 virtual void deinit() { };
103
104 private:
105 void read( Bu::Socket &s, Record &r );
106 void read( Bu::Socket &s, BeginRequestBody &b );
107 uint32_t readLen( Bu::Socket &s, uint16_t &uUsed );
108 void readPair( Bu::Socket &s, StrHash &hParams, uint16_t &uUsed );
109
110 void write( Bu::Socket &s, Record r );
111 void write( Bu::Socket &s, EndRequestBody b );
112
113 private:
114 Bu::ServerSocket *pSrv;
115 bool bRunning;
116 Bu::Array<Channel *> aChannel;
117 };
118};
119
120#endif
diff --git a/src/tests/fastcgi.cpp b/src/tests/fastcgi.cpp
new file mode 100644
index 0000000..53dd68a
--- /dev/null
+++ b/src/tests/fastcgi.cpp
@@ -0,0 +1,81 @@
1#include "bu/fastcgi.h"
2
3class Cgi : public Bu::FastCgi
4{
5public:
6 Cgi() :
7 Bu::FastCgi::FastCgi()
8 {
9 }
10
11 Cgi( int iPort ) :
12 Bu::FastCgi::FastCgi( iPort )
13 {
14 }
15
16 virtual ~Cgi()
17 {
18 }
19
20 virtual int request( const StrHash &hParams,
21 const Bu::FString &sStdIn, Bu::Stream &sStdOut,
22 Bu::Stream &sStdErr )
23 {
24 Bu::FString sOut("Content-Type: text/html\r\n\r\n");
25 sOut += "<html><body><h1>Environment:</h1><ul>";
26 for( StrHash::const_iterator i = hParams.begin(); i; i++ )
27 {
28 sOut += "<li>" + i.getKey() + " = " +
29 i.getValue() + "</li>";
30 }
31 sOut += "</ul>";
32 char buf[2048];
33 sOut += "<h1>Cwd:</h1><ul><li>";
34 sOut += getcwd( buf, 2048 );
35 sOut += "</li></ul>";
36 sOut += "<h1>Stdin:</h1>";
37 sOut.formatAppend("%d bytes<pre>", sStdIn.getSize() );
38 Bu::FString sL, sR;
39 for( Bu::FString::const_iterator i = sStdIn.begin();
40 i; i++ )
41 {
42 sL.formatAppend("%02X ",
43 (unsigned int)((unsigned char)*i) );
44 if( *i < 27 )
45 sR += ". ";
46 else
47 sR.formatAppend("&#%d; ",
48 (unsigned int)((unsigned char)*i) );
49 if( sL.getSize()/3 == 8 )
50 {
51 sOut += sL + " | " + sR + "\n";
52 sL = sR = "";
53 }
54 }
55 if( sL != "" )
56 {
57 while( sL.getSize()/3 < 8 )
58 sL += " ";
59 sOut += sL + " | " + sR + "\n";
60 }
61 sOut += "</pre><hr/><pre>";
62 sOut += sStdIn;
63 sOut += "</pre>";
64 sOut += "<form method=\"post\" enctype=\"multipart/form-data\"><textarea name=\"bob\"></textarea><br /><input type=\"file\" name=\"somefile\" /><br /><input type=\"submit\" name=\"yeah\" value=\"try it\" /></form>";
65 sOut += "</body></html>";
66
67 sStdOut.write( sOut );
68
69 return 0;
70 }
71};
72
73int main()
74{
75 Cgi c( 8789 );
76
77 c.run();
78
79 return 0;
80}
81
diff --git a/src/tests/url.cpp b/src/tests/url.cpp
index c9af676..4dc8c46 100644
--- a/src/tests/url.cpp
+++ b/src/tests/url.cpp
@@ -4,28 +4,31 @@
4 4
5int main( int argc, char *argv[] ) 5int main( int argc, char *argv[] )
6{ 6{
7 printf("encodede: %s\n", Bu::Url::encode( argv[1] ).getStr() ); 7 for( argc--, argv++; argc >= 0; argc--, argv++ )
8 printf("decodede: %s\n", Bu::Url::decode( argv[1] ).getStr() );
9 Bu::Url u( argv[1] );
10
11 printf("Protocol: %s\n", u.getProtocol().getStr() );
12 printf("User: %s\n", u.getUser().getStr() );
13 printf("Pass: %s\n", u.getPass().getStr() );
14 printf("Host: %s\n", u.getHost().getStr() );
15 printf("Path: %s\n", u.getPath().getStr() );
16 try
17 {
18 printf("Port: %d\n", u.getPort() );
19 } catch( Bu::ExceptionBase &e )
20 { 8 {
21 printf("Port: not set.\n"); 9 printf("encodede: %s\n", Bu::Url::encode( *argv ).getStr() );
22 } 10 printf("decodede: %s\n", Bu::Url::decode( *argv ).getStr() );
23 printf("Parameters:\n"); 11 Bu::Url u( *argv );
24 for( Bu::Url::ParamList::const_iterator i = u.getParamBegin(); i; i++ ) 12
25 { 13 printf("Protocol: %s\n", u.getProtocol().getStr() );
26 printf(" \"%s\" = \"%s\"\n", 14 printf("User: %s\n", u.getUser().getStr() );
27 (*i).sName.getStr(), (*i).sValue.getStr() 15 printf("Pass: %s\n", u.getPass().getStr() );
28 ); 16 printf("Host: %s\n", u.getHost().getStr() );
17 printf("Path: %s\n", u.getPath().getStr() );
18 try
19 {
20 printf("Port: %d\n", u.getPort() );
21 } catch( Bu::ExceptionBase &e )
22 {
23 printf("Port: not set.\n");
24 }
25 printf("Parameters:\n");
26 for( Bu::Url::ParamList::const_iterator i = u.getParamBegin(); i; i++ )
27 {
28 printf(" \"%s\" = \"%s\"\n",
29 (*i).sName.getStr(), (*i).sValue.getStr()
30 );
31 }
29 } 32 }
30 33
31 return 0; 34 return 0;
diff --git a/src/tests/nidstool.cpp b/src/tools/nidstool.cpp
index d1465ce..d1465ce 100644
--- a/src/tests/nidstool.cpp
+++ b/src/tools/nidstool.cpp
diff --git a/src/unit/array.unit b/src/unit/array.unit
index 3a777d3..b6528eb 100644
--- a/src/unit/array.unit
+++ b/src/unit/array.unit
@@ -36,7 +36,7 @@
36 36
37 const Bu::Array<int> &ci = ai; 37 const Bu::Array<int> &ci = ai;
38 j = 0; 38 j = 0;
39 for( Bu::Array<int>::const_iterator i = ci.begin(); i != ci.end(); i++ ) 39 for( Bu::Array<int>::const_iterator i = ci.begin(); i; i++ )
40 unitTest( (*i) == j++ ); 40 unitTest( (*i) == j++ );
41 unitTest( j == 10 ); 41 unitTest( j == 10 );
42} 42}
@@ -46,6 +46,8 @@
46 Bu::Array<int> ai; 46 Bu::Array<int> ai;
47 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ ) 47 for( Bu::Array<int>::iterator i = ai.begin(); i != ai.end(); i++ )
48 unitFailed("Empty lists shouldn't be iterated through."); 48 unitFailed("Empty lists shouldn't be iterated through.");
49 for( Bu::Array<int>::iterator i = ai.begin(); i; i++ )
50 unitFailed("Empty lists shouldn't be iterated through.");
49} 51}
50 52
51{%copy} 53{%copy}
diff --git a/src/urn.cpp b/src/urn.cpp
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/urn.cpp
diff --git a/src/urn.h b/src/urn.h
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/urn.h