summaryrefslogtreecommitdiff
path: root/src/stable/protocolhttp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/stable/protocolhttp.cpp')
-rw-r--r--src/stable/protocolhttp.cpp353
1 files changed, 353 insertions, 0 deletions
diff --git a/src/stable/protocolhttp.cpp b/src/stable/protocolhttp.cpp
new file mode 100644
index 0000000..eaee9d0
--- /dev/null
+++ b/src/stable/protocolhttp.cpp
@@ -0,0 +1,353 @@
1/*
2 * Copyright (C) 2007-2011 Xagasoft, All rights reserved.
3 *
4 * This file is part of the libbu++ library and is released under the
5 * terms of the license contained in the file LICENSE.
6 */
7
8#include <dirent.h>
9
10#ifndef WIN32
11 #include <sys/wait.h>
12#endif
13
14#include <errno.h>
15#include <stdlib.h>
16#include "bu/protocolhttp.h"
17#include "bu/logger.h"
18
19#define CRLF "\x0D\x0A"
20#define CR '\x0D'
21#define LF '\x0A'
22
23using namespace Bu;
24
25Bu::ProtocolHttp::ProtocolHttp()
26{
27}
28
29Bu::ProtocolHttp::~ProtocolHttp()
30{
31}
32
33void Bu::ProtocolHttp::onNewConnection( Bu::Client *pClient )
34{
35 this->pClient = pClient;
36
37 iState = 0;
38}
39
40#define SDB( i ) (void)0
41//#define SDB( i ) printf("state %d: %d, \"%s\"\n", i, tt, sToken.getStr() )
42
43void Bu::ProtocolHttp::onNewData( Bu::Client *pClient )
44{
45/* logHexDump(
46 1,
47 pClient->getInput().getStr(),
48 pClient->getInput().getSize(),
49 "input"
50 );*/
51
52 for(;;)
53 {
54 Bu::String sToken;
55 TokenType tt = getToken( sToken );
56
57 if( tt == ttOutOfData )
58 return;
59
60 switch( iState )
61 {
62 case 0: // Start token, should be "method" (get, put, etc)
63 SDB( 0 );
64 sMethod = sToken;
65 iState = 1;
66 break;
67
68 case 1: // The path requested
69 SDB( 1 );
70 sPath = sToken;
71 iState = 2;
72 break;
73
74 case 2: // The protocol name and version
75 SDB( 2 );
76 if( strncmp( sToken.getStr(), "HTTP/", 5 ) )
77 {
78 pClient->disconnect();
79 return;
80 }
81 else
82 {
83 char *s, *s2;
84 s = sToken.getStr()+5;
85 iMajor = strtol( s, &s2, 10 );
86 iMinor = strtol( s2+1, NULL, 10 );
87 iState = 3;
88 }
89 break;
90
91 case 3: // End of initial header, now comes mime-style blocks.
92 SDB( 3 );
93 if( tt == ttNewline )
94 {
95 iState = 10;
96 }
97 else if( tt == ttDoubleNewline )
98 {
99 earlyResponse();
100 }
101 else
102 {
103 pClient->disconnect();
104 return;
105 }
106 break;
107
108 case 10: // HTTP-Message (skipped for now...)
109 SDB( 10 );
110 if( tt == ttString )
111 {
112 iState = 11;
113 }
114 else
115 {
116 pClient->disconnect();
117 }
118 break;
119
120 case 11: // Should be a colon...
121 SDB( 11 );
122 if( tt == ttSeperator && sToken == ":" )
123 {
124 iState = 12;
125 }
126 else
127 {
128 pClient->disconnect();
129 }
130 break;
131
132 case 12:
133 SDB( 12 );
134 if( tt == ttNewline )
135 {
136 iState = 10;
137 }
138 if( tt == ttDoubleNewline )
139 {
140 earlyResponse();
141 }
142 break;
143
144 case 20:
145 SDB( 20 );
146 break;
147 }
148 }
149}
150
151Bu::ProtocolHttp::TokenType Bu::ProtocolHttp::getToken( Bu::String &line )
152{
153 char s;
154 int jmax = pClient->getInputSize();
155 bool bNonWS = false;
156
157 for( int j = 0; j < jmax; j++ )
158 {
159 pClient->peek( &s, 1, j );
160 if( iState > 2 && isSeperator( s ) )
161 {
162 if( j == 0 )
163 {
164 line += s;
165 pClient->seek( 1 );
166 return ttSeperator;
167 }
168 else
169 {
170 pClient->seek( j );
171 return ttString;
172 }
173 }
174 else if( isWS( s ) )
175 {
176 if( bNonWS )
177 {
178 pClient->seek( j );
179 return ttString;
180 }
181 }
182 else if( s == CR )
183 {
184 if( pClient->getInputSize() < 4 )
185 return ttOutOfData;
186
187 char ss[3];
188 pClient->peek( ss, 3, j+1 );
189 if( ss[0] == LF && ss[1] != ' ' && ss[1] != '\t' )
190 {
191 if( bNonWS )
192 {
193 pClient->seek( j );
194 return ttString;
195 }
196 else if( ss[1] == CR && ss[2] == LF )
197 {
198 pClient->seek( 4 );
199 return ttDoubleNewline;
200 }
201 else
202 {
203 pClient->seek( 2 );
204 return ttNewline;
205 }
206 }
207
208 j += 2;
209 if( bNonWS )
210 {
211 pClient->seek( j );
212 return ttString;
213 }
214 }
215 else
216 {
217 line += s;
218 bNonWS = true;
219 }
220 }
221
222 return ttOutOfData;
223}
224
225bool Bu::ProtocolHttp::isWS( char buf )
226{
227 return (buf == ' ' || buf == '\t');
228}
229
230bool Bu::ProtocolHttp::isSeperator( char buf )
231{
232 return (buf == '(' || buf == ')' || buf == '<' || buf == '>' ||
233 buf == '@' || buf == ',' || buf == ';' || buf == ':' ||
234 buf == '\\' || buf == '\"' || buf == '/' || buf == '[' ||
235 buf == ']' || buf == '?' || buf == '=' || buf == '{' ||
236 buf == '}' );
237}
238
239void Bu::ProtocolHttp::earlyResponse()
240{
241 if( sMethod == "GET" )
242 {
243 onRequest( sMethod, sPath );
244 iState = 0;
245 }
246 else
247 {
248 iState = 20;
249 }
250}
251
252void Bu::ProtocolHttp::lateResponse()
253{
254 onRequest( sMethod, sPath );
255}
256
257void Bu::ProtocolHttp::sendResponse( const Response &rRes )
258{
259 char buf[1024];
260 int iSize = sprintf( buf, "HTTP/1.1 %d ", rRes.iCode );
261
262 pClient->write( buf, iSize );
263 pClient->write( rRes.sReason );
264 pClient->write( CRLF, 2 );
265
266 for( Response::StringHash::const_iterator i = rRes.hHeaders.begin();
267 i != rRes.hHeaders.end(); i++ )
268 {
269 pClient->write( i.getKey() );
270 pClient->write(": ", 2 );
271 pClient->write( i.getValue() );
272 pClient->write( CRLF, 2 );
273 }
274
275 iSize = sprintf( buf, "Content-Length: %ld" CRLF, rRes.sContent.getSize() );
276 pClient->write( buf, iSize );
277
278 pClient->write( CRLF, 2 );
279 pClient->write( rRes.sContent );
280}
281
282//
283// Bu::ProtocolHttp::Response
284//
285Bu::ProtocolHttp::Response::Response( int iCode ) :
286 iCode( iCode )
287{
288 switch( iCode )
289 {
290 case 100: sReason = "Continue"; break;
291 case 101: sReason = "Switching Protocols"; break;
292 case 200: sReason = "OK"; break;
293 case 201: sReason = "Created"; break;
294 case 202: sReason = "Accepted"; break;
295 case 203: sReason = "Non-Authoritative Information"; break;
296 case 204: sReason = "No Content"; break;
297 case 205: sReason = "Reset Content"; break;
298 case 206: sReason = "Partial Content"; break;
299 case 300: sReason = "Multiple Choices"; break;
300 case 301: sReason = "Moved Permanently"; break;
301 case 302: sReason = "Found"; break;
302 case 303: sReason = "See Other"; break;
303 case 304: sReason = "Not Modified"; break;
304 case 305: sReason = "Use Proxy"; break;
305 case 307: sReason = "Temporary Redirect"; break;
306 case 400: sReason = "Bad Request"; break;
307 case 401: sReason = "Unauthorized"; break;
308 case 402: sReason = "Payment Required"; break;
309 case 403: sReason = "Forbidden"; break;
310 case 404: sReason = "Not Found"; break;
311 case 405: sReason = "Method Not Allowed"; break;
312 case 406: sReason = "Not Acceptable"; break;
313 case 407: sReason = "Proxy Authentication Required"; break;
314 case 408: sReason = "Request Time-out"; break;
315 case 409: sReason = "Conflict"; break;
316 case 410: sReason = "Gone"; break;
317 case 411: sReason = "Length Required"; break;
318 case 412: sReason = "Precondition Failed"; break;
319 case 413: sReason = "Request Entity Too Large"; break;
320 case 414: sReason = "Request-URI Too Large"; break;
321 case 415: sReason = "Unsupported Media Type"; break;
322 case 416: sReason = "Requested range not satisfiable"; break;
323 case 417: sReason = "Expectation Failed"; break;
324 case 500: sReason = "Internal Server Error"; break;
325 case 501: sReason = "Not Implemented"; break;
326 case 502: sReason = "Bad Gateway"; break;
327 case 503: sReason = "Service Unavailable"; break;
328 case 504: sReason = "Gateway Time-out"; break;
329 case 505: sReason = "HTTP Version not supported"; break;
330 }
331}
332
333Bu::ProtocolHttp::Response::Response( int iCode, const Bu::String &sReason ) :
334 iCode( iCode ),
335 sReason( sReason )
336{
337}
338
339Bu::ProtocolHttp::Response::~Response()
340{
341}
342
343void Bu::ProtocolHttp::Response::setHeader(
344 const Bu::String &sKey, const Bu::String &sVal )
345{
346 hHeaders.insert( sKey, sVal );
347}
348
349void Bu::ProtocolHttp::Response::setContent( const Bu::String &sCont )
350{
351 sContent = sCont;
352}
353