diff options
| author | Mike Buland <eichlan@xagasoft.com> | 2007-10-08 04:11:56 +0000 |
|---|---|---|
| committer | Mike Buland <eichlan@xagasoft.com> | 2007-10-08 04:11:56 +0000 |
| commit | fe1862511da4a6d66e2f11ba633c035c3cf7b14f (patch) | |
| tree | 5b7b4d863c0b26390ae7f786b23485341c0ebd50 /src/protocolhttp.cpp | |
| parent | d8ba63fd2b512297b42b8b7db877205ab287e067 (diff) | |
| download | libbu++-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.
Diffstat (limited to '')
| -rw-r--r-- | src/protocolhttp.cpp | 194 |
1 files changed, 183 insertions, 11 deletions
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 | ||
| 29 | void Bu::ProtocolHttp::onNewData( Bu::Client *pClient ) | 30 | void 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 | ||
| 229 | void Bu::ProtocolHttp::earlyResponse() | ||
| 230 | { | ||
| 231 | if( sMethod == "GET" ) | ||
| 232 | { | ||
| 233 | onRequest( sMethod, sPath ); | ||
| 234 | } | ||
| 235 | else | ||
| 236 | { | ||
| 237 | iState = 20; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | |||
| 241 | void Bu::ProtocolHttp::lateResponse() | ||
| 242 | { | ||
| 243 | onRequest( sMethod, sPath ); | ||
| 244 | } | ||
| 245 | |||
| 246 | void 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 | // | ||
| 274 | Bu::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 | |||
| 322 | Bu::ProtocolHttp::Response::Response( int iCode, const Bu::FString &sReason ) : | ||
| 323 | iCode( iCode ), | ||
| 324 | sReason( sReason ) | ||
| 325 | { | ||
| 326 | } | ||
| 327 | |||
| 328 | Bu::ProtocolHttp::Response::~Response() | ||
| 329 | { | ||
| 330 | } | ||
| 331 | |||
| 332 | void Bu::ProtocolHttp::Response::setHeader( | ||
| 333 | const Bu::FString &sKey, const Bu::FString &sVal ) | ||
| 334 | { | ||
| 335 | hHeaders.insert( sKey, sVal ); | ||
| 336 | } | ||
| 337 | |||
| 338 | void Bu::ProtocolHttp::Response::setContent( const Bu::FString &sCont ) | ||
| 339 | { | ||
| 340 | sContent = sCont; | ||
| 341 | } | ||
| 342 | |||
