aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2007-10-08 04:11:56 +0000
committerMike Buland <eichlan@xagasoft.com>2007-10-08 04:11:56 +0000
commitfe1862511da4a6d66e2f11ba633c035c3cf7b14f (patch)
tree5b7b4d863c0b26390ae7f786b23485341c0ebd50
parentd8ba63fd2b512297b42b8b7db877205ab287e067 (diff)
downloadlibbu++-fe1862511da4a6d66e2f11ba633c035c3cf7b14f.tar.gz
libbu++-fe1862511da4a6d66e2f11ba633c035c3cf7b14f.tar.bz2
libbu++-fe1862511da4a6d66e2f11ba633c035c3cf7b14f.tar.xz
libbu++-fe1862511da4a6d66e2f11ba633c035c3cf7b14f.zip
Added some helpers and fixes to Bu::Client, also got all the basics of a
general Http handler working, the test for the moment, is Doxysrv, I'll probably write a cute little stand-alone one in libbu++ later as a demo/test.
-rw-r--r--src/client.cpp5
-rw-r--r--src/client.h1
-rw-r--r--src/protocolhttp.cpp194
-rw-r--r--src/protocolhttp.h27
4 files changed, 216 insertions, 11 deletions
diff --git a/src/client.cpp b/src/client.cpp
index 19d2778..ee301e9 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -103,6 +103,11 @@ bool Bu::Client::isOpen()
103 return pSocket->isOpen(); 103 return pSocket->isOpen();
104} 104}
105 105
106void Bu::Client::write( const Bu::FString &sData )
107{
108 sWriteBuf += sData;
109}
110
106void Bu::Client::write( const void *pData, int nBytes ) 111void Bu::Client::write( const void *pData, int nBytes )
107{ 112{
108 sWriteBuf.append( (const char *)pData, nBytes ); 113 sWriteBuf.append( (const char *)pData, nBytes );
diff --git a/src/client.h b/src/client.h
index 0b670e2..517131a 100644
--- a/src/client.h
+++ b/src/client.h
@@ -25,6 +25,7 @@ namespace Bu
25 25
26 Bu::FString &getInput(); 26 Bu::FString &getInput();
27 Bu::FString &getOutput(); 27 Bu::FString &getOutput();
28 void write( const Bu::FString &sData );
28 void write( const void *pData, int nBytes ); 29 void write( const void *pData, int nBytes );
29 void write( int8_t nData ); 30 void write( int8_t nData );
30 void write( int16_t nData ); 31 void write( int16_t nData );
diff --git a/src/protocolhttp.cpp b/src/protocolhttp.cpp
index d18d73d..2f57bdb 100644
--- a/src/protocolhttp.cpp
+++ b/src/protocolhttp.cpp
@@ -1,7 +1,8 @@
1#include <dirent.h> 1#include <dirent.h>
2#include <sys/wait.h> 2#include <sys/wait.h>
3#include <errno.h> 3#include <errno.h>
4#include "protocolhttp.h" 4#include "bu/protocolhttp.h"
5#include "bu/logger.h"
5 6
6#define CRLF "\x0D\x0A" 7#define CRLF "\x0D\x0A"
7#define CR '\x0D' 8#define CR '\x0D'
@@ -28,6 +29,13 @@ void Bu::ProtocolHttp::onNewConnection( Bu::Client *pClient )
28 29
29void Bu::ProtocolHttp::onNewData( Bu::Client *pClient ) 30void Bu::ProtocolHttp::onNewData( Bu::Client *pClient )
30{ 31{
32 logHexDump(
33 1,
34 pClient->getInput().getStr(),
35 pClient->getInput().getSize(),
36 "input"
37 );
38
31 for(;;) 39 for(;;)
32 { 40 {
33 Bu::FString sToken; 41 Bu::FString sToken;
@@ -38,19 +46,19 @@ void Bu::ProtocolHttp::onNewData( Bu::Client *pClient )
38 46
39 switch( iState ) 47 switch( iState )
40 { 48 {
41 case 0: // Initial header 49 case 0: // Start token, should be "method" (get, put, etc)
42 SDB( 0 ); 50 SDB( 0 );
43 sMethod = sToken; 51 sMethod = sToken;
44 iState = 1; 52 iState = 1;
45 break; 53 break;
46 54
47 case 1: // Misc headers 55 case 1: // The path requested
48 SDB( 1 ); 56 SDB( 1 );
49 sPath = sToken; 57 sPath = sToken;
50 iState = 2; 58 iState = 2;
51 break; 59 break;
52 60
53 case 2: // Content 61 case 2: // The protocol name and version
54 SDB( 2 ); 62 SDB( 2 );
55 if( strncmp( sToken.getStr(), "HTTP/", 5 ) ) 63 if( strncmp( sToken.getStr(), "HTTP/", 5 ) )
56 { 64 {
@@ -69,17 +77,62 @@ void Bu::ProtocolHttp::onNewData( Bu::Client *pClient )
69 } 77 }
70 break; 78 break;
71 79
72 case 3: 80 case 3: // End of initial header, now comes mime-style blocks.
73 SDB( 3 ); 81 SDB( 3 );
74 if( iState != ttNewline ) 82 if( tt == ttNewline )
83 {
84 iState = 10;
85 }
86 else if( tt == ttDoubleNewline )
87 {
88 earlyResponse();
89 }
90 else
75 { 91 {
76 pClient->disconnect(); 92 pClient->disconnect();
77 return; 93 return;
78 } 94 }
79 iState = 4;
80 break; 95 break;
81 96
82 case 4: 97 case 10: // HTTP-Message (skipped for now...)
98 SDB( 10 );
99 if( tt == ttString )
100 {
101 iState = 11;
102 }
103 else
104 {
105 pClient->disconnect();
106 }
107 break;
108
109 case 11: // Should be a colon...
110 SDB( 11 );
111 if( tt == ttSeperator && sToken == ":" )
112 {
113 iState = 12;
114 }
115 else
116 {
117 pClient->disconnect();
118 }
119 break;
120
121 case 12:
122 SDB( 12 );
123 if( tt == ttNewline )
124 {
125 iState = 10;
126 }
127 if( tt == ttDoubleNewline )
128 {
129 earlyResponse();
130 }
131 break;
132
133 case 20:
134 SDB( 20 );
135 printf("Content!");
83 break; 136 break;
84 } 137 }
85 } 138 }
@@ -118,11 +171,11 @@ Bu::ProtocolHttp::TokenType Bu::ProtocolHttp::getToken( Bu::FString &line )
118 } 171 }
119 else if( s == CR ) 172 else if( s == CR )
120 { 173 {
121 if( pClient->getInputSize() < 3 ) 174 if( pClient->getInputSize() < 4 )
122 return ttOutOfData; 175 return ttOutOfData;
123 176
124 char ss[2]; 177 char ss[3];
125 pClient->peek( ss, 2, j+1 ); 178 pClient->peek( ss, 3, j+1 );
126 if( ss[0] == LF && ss[1] != ' ' && ss[1] != '\t' ) 179 if( ss[0] == LF && ss[1] != ' ' && ss[1] != '\t' )
127 { 180 {
128 if( bNonWS ) 181 if( bNonWS )
@@ -130,6 +183,11 @@ Bu::ProtocolHttp::TokenType Bu::ProtocolHttp::getToken( Bu::FString &line )
130 pClient->seek( j ); 183 pClient->seek( j );
131 return ttString; 184 return ttString;
132 } 185 }
186 else if( ss[1] == CR && ss[2] == LF )
187 {
188 pClient->seek( 4 );
189 return ttDoubleNewline;
190 }
133 else 191 else
134 { 192 {
135 pClient->seek( 2 ); 193 pClient->seek( 2 );
@@ -168,3 +226,117 @@ bool Bu::ProtocolHttp::isSeperator( char buf )
168 buf == '}' ); 226 buf == '}' );
169} 227}
170 228
229void Bu::ProtocolHttp::earlyResponse()
230{
231 if( sMethod == "GET" )
232 {
233 onRequest( sMethod, sPath );
234 }
235 else
236 {
237 iState = 20;
238 }
239}
240
241void Bu::ProtocolHttp::lateResponse()
242{
243 onRequest( sMethod, sPath );
244}
245
246void Bu::ProtocolHttp::sendResponse( const Response &rRes )
247{
248 char buf[1024];
249 int iSize = sprintf( buf, "HTTP/1.1 %d ", rRes.iCode );
250
251 pClient->write( buf, iSize );
252 pClient->write( rRes.sReason );
253 pClient->write( CRLF, 2 );
254
255 for( Response::StringHash::const_iterator i = rRes.hHeaders.begin();
256 i != rRes.hHeaders.end(); i++ )
257 {
258 pClient->write( i.getKey() );
259 pClient->write(": ", 2 );
260 pClient->write( i.getValue() );
261 pClient->write( CRLF, 2 );
262 }
263
264 iSize = sprintf( buf, "Content-Length: %ld" CRLF, rRes.sContent.getSize() );
265 pClient->write( buf, iSize );
266
267 pClient->write( CRLF, 2 );
268 pClient->write( rRes.sContent );
269}
270
271//
272// Bu::ProtocolHttp::Response
273//
274Bu::ProtocolHttp::Response::Response( int iCode ) :
275 iCode( iCode )
276{
277 switch( iCode )
278 {
279 case 100: sReason = "Continue"; break;
280 case 101: sReason = "Switching Protocols"; break;
281 case 200: sReason = "OK"; break;
282 case 201: sReason = "Created"; break;
283 case 202: sReason = "Accepted"; break;
284 case 203: sReason = "Non-Authoritative Information"; break;
285 case 204: sReason = "No Content"; break;
286 case 205: sReason = "Reset Content"; break;
287 case 206: sReason = "Partial Content"; break;
288 case 300: sReason = "Multiple Choices"; break;
289 case 301: sReason = "Moved Permanently"; break;
290 case 302: sReason = "Found"; break;
291 case 303: sReason = "See Other"; break;
292 case 304: sReason = "Not Modified"; break;
293 case 305: sReason = "Use Proxy"; break;
294 case 307: sReason = "Temporary Redirect"; break;
295 case 400: sReason = "Bad Request"; break;
296 case 401: sReason = "Unauthorized"; break;
297 case 402: sReason = "Payment Required"; break;
298 case 403: sReason = "Forbidden"; break;
299 case 404: sReason = "Not Found"; break;
300 case 405: sReason = "Method Not Allowed"; break;
301 case 406: sReason = "Not Acceptable"; break;
302 case 407: sReason = "Proxy Authentication Required"; break;
303 case 408: sReason = "Request Time-out"; break;
304 case 409: sReason = "Conflict"; break;
305 case 410: sReason = "Gone"; break;
306 case 411: sReason = "Length Required"; break;
307 case 412: sReason = "Precondition Failed"; break;
308 case 413: sReason = "Request Entity Too Large"; break;
309 case 414: sReason = "Request-URI Too Large"; break;
310 case 415: sReason = "Unsupported Media Type"; break;
311 case 416: sReason = "Requested range not satisfiable"; break;
312 case 417: sReason = "Expectation Failed"; break;
313 case 500: sReason = "Internal Server Error"; break;
314 case 501: sReason = "Not Implemented"; break;
315 case 502: sReason = "Bad Gateway"; break;
316 case 503: sReason = "Service Unavailable"; break;
317 case 504: sReason = "Gateway Time-out"; break;
318 case 505: sReason = "HTTP Version not supported"; break;
319 }
320}
321
322Bu::ProtocolHttp::Response::Response( int iCode, const Bu::FString &sReason ) :
323 iCode( iCode ),
324 sReason( sReason )
325{
326}
327
328Bu::ProtocolHttp::Response::~Response()
329{
330}
331
332void Bu::ProtocolHttp::Response::setHeader(
333 const Bu::FString &sKey, const Bu::FString &sVal )
334{
335 hHeaders.insert( sKey, sVal );
336}
337
338void Bu::ProtocolHttp::Response::setContent( const Bu::FString &sCont )
339{
340 sContent = sCont;
341}
342
diff --git a/src/protocolhttp.h b/src/protocolhttp.h
index e10cb23..e2612f5 100644
--- a/src/protocolhttp.h
+++ b/src/protocolhttp.h
@@ -24,6 +24,30 @@ namespace Bu
24 24
25 virtual void onNewConnection( Bu::Client *pClient ); 25 virtual void onNewConnection( Bu::Client *pClient );
26 virtual void onNewData( Bu::Client *pClient ); 26 virtual void onNewData( Bu::Client *pClient );
27
28 virtual void onRequest(
29 const Bu::FString &sMethod, const Bu::FString &sPath )=0;
30
31 class Response
32 {
33 friend class Bu::ProtocolHttp;
34 public:
35 Response( int iCode );
36 Response( int iCode, const Bu::FString &sReason );
37 virtual ~Response();
38
39 void setHeader( const Bu::FString &sKey, const Bu::FString &sVal );
40 void setContent( const Bu::FString &sCont );
41
42 private:
43 int iCode;
44 Bu::FString sReason;
45 typedef Bu::Hash<Bu::FString,Bu::FString> StringHash;
46 StringHash hHeaders;
47 Bu::FString sContent;
48 };
49
50 void sendResponse( const Response &rRes );
27 51
28 private: 52 private:
29 enum TokenType 53 enum TokenType
@@ -47,6 +71,9 @@ namespace Bu
47 bool isWS( char buf ); 71 bool isWS( char buf );
48 bool isSeperator( char buf ); 72 bool isSeperator( char buf );
49 73
74 void earlyResponse();
75 void lateResponse();
76
50 private: /* state */ 77 private: /* state */
51 Bu::Client *pClient; 78 Bu::Client *pClient;
52 TokenList lTokens; 79 TokenList lTokens;