1 lawrence.luo 1.1.2.1 //%LICENSE////////////////////////////////////////////////////////////////
2 //
3 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
16 //
17 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
19 //
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 lawrence.luo 1.1.2.1 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 //
28 //////////////////////////////////////////////////////////////////////////
29 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <Pegasus/Common/AutoPtr.h>
33 #include <Pegasus/Common/HTTPConnection.h>
34 #include <Pegasus/Common/Logger.h>
35 #include <Pegasus/Common/Tracer.h>
36 #include <Pegasus/Common/XmlWriter.h>
37 #include <Pegasus/Common/FileSystem.h>
38 #include <Pegasus/Common/Constants.h>
39
40 #include <Pegasus/WebServer/WebProcessor.h>
41 #include <Pegasus/WebServer/WebServer.h>
42
43 lawrence.luo 1.1.2.1
44 PEGASUS_USING_STD;
45 PEGASUS_NAMESPACE_BEGIN
46
47
48 const Uint32 WebProcessor::DEFAULT_RESPONSE_BUFFER_SIZE = 8192;// 8 KB
49 const Uint32 WebProcessor::MAX_URI_LENGTH = 256;
50 const String WebProcessor::HTTP_VERSION = "1.1";
51 const String WebProcessor::GZIP = "gzip";
52 const String WebProcessor::DEFLATE = "deflate";
53
54
55
56
57 WebProcessor::WebProcessor(WebServer* const webServer)
|
58 dl.meetei 1.1.2.4 : _webConfig(), _webServer(webServer)
|
59 lawrence.luo 1.1.2.1 {
60 }
61
62 WebProcessor::~WebProcessor()
63 {
64 }
65
66
67 void WebProcessor::handleWebRequest(WebRequest* request)
68 {
|
69 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::handleWebRequest()");
|
70 lawrence.luo 1.1.2.1
71 if (!request)
72 {
73 PEG_METHOD_EXIT();
74 return;
75 }
76
77 Uint32 queueId = request->getQueueId();
|
78 dl.meetei 1.1.2.4
79
|
80 lawrence.luo 1.1.2.1 // check protocol version
81 if (String::equal(request->httpVersion, "")
82 || PEG_NOT_FOUND == request->httpVersion.find("HTTP/"))
83 {// bad request
|
84 dl.meetei 1.1.2.4 _sendError( HTTP_STATUSCODE_BADREQUEST, queueId,
85 "Malformed Http, http version string not found!");
|
86 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
87 return;
88 }
|
89 dl.meetei 1.1.2.4 else if( !String::equal(request->httpVersion, "HTTP/" + HTTP_VERSION))
|
90 lawrence.luo 1.1.2.1 {// protocol-version not supported
91 _sendError(
|
92 dl.meetei 1.1.2.4 HTTP_STATUSCODE_VERSIONNOTSUPPORTED,
93 queueId,
94 "The requested HTTP version '" + request->httpVersion
|
95 lawrence.luo 1.1.2.1 + "' is not supported by this server!");
96 PEG_METHOD_EXIT();
97 return;
98 }
99 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest"
100 "(WebRequest* webRequest) - httpVersion='%s'",
101 (const char*)request->httpVersion.getCString()));
102
103 String* method;
104 // check HTTPmethod
105 if (request->httpMethod == HTTP_METHOD_GET)
106 {
107 method = new String("GET");
108 }
109 else if (request->httpMethod == HTTP_METHOD_HEAD)
110 {
111 method = new String("HEAD");
112 }
113 else
114 {// handle bad request (method not allowed)
115 _sendError(
|
116 dl.meetei 1.1.2.4 HTTP_STATUSCODE_METHODNOTALLOWED,
117 queueId,
118 "The requested HTTP method is not supported by this server,"
|
119 lawrence.luo 1.1.2.1 " 'GET' and 'HEAD' only!",
120 "Allow: HEAD, GET");
121 PEG_METHOD_EXIT();
122 return;
123 }
|
124 dl.meetei 1.1.2.2 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest"
|
125 dl.meetei 1.1.2.4 "(WebRequest* webRequest) - httpMethod='%s'",
126 (const char*)method->getCString()));
|
127 lawrence.luo 1.1.2.1
128 // get absolute filename from URI
129 String fileName;
130 Uint32 statusCode = _getFileNameForURI(request->requestURI, fileName);
131 if (statusCode != HTTP_STATUSCODE_OK)
132 {
133 _sendError(
134 statusCode,
135 queueId,
136 "<p>Request-URI: <b>'" + request->requestURI
137 + "'</b><br/>"
138 + "Current web-root: <b>'" + _webConfig.getWebRoot()
139 + "'</b>"
140 + ((statusCode == HTTP_STATUSCODE_FORBIDDEN)?
141 ("<br/><br/>Reason: It points to a directory or "
142 "the requested file's real path is not located "
143 "in the webRoot!</p>")
144 :("</p>")));
145 PEG_METHOD_EXIT();
146 return;
147 }
148 lawrence.luo 1.1.2.1 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest"
|
149 dl.meetei 1.1.2.4 "(WebRequest* webRequest) - URI maps to valid/allowed " "fileName='%s'",
150 (const char*)fileName.getCString()));
|
151 lawrence.luo 1.1.2.1
152 // get and check contentType for requested file
153 String contentType;
154 /* RFC 2616, section 10.4.7 '406 Not Acceptable'
155 *
156 * Note: HTTP/1.1 servers are allowed to return responses which are
157 * not acceptable according to the accept headers sent in the
158 * request. In some cases, this may even be preferable to sending a
159 * 406 response. User agents are encouraged to inspect the headers of
160 * an incoming response to determine if it is acceptable.
161 *
162 * => So there's no need to check whether the client is willing to accept
163 * the delivered file with a header line in the response including a
164 * mime-type definition it does not know.
165 */
166 if (!_getContentType(fileName, contentType))
167 {
168 // no contentType known for requested file(-extension)
169 _sendError(
|
170 dl.meetei 1.1.2.4 HTTP_STATUSCODE_FORBIDDEN, queueId,
171 "The requested file '" + fileName
|
172 lawrence.luo 1.1.2.1 + "' has an undefined content type. It will not be served!");
173 PEG_METHOD_EXIT();
174 return;
175 }
176 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest"
|
177 dl.meetei 1.1.2.4 "(WebRequest* webRequest) - response contentType='%s'",
178 (const char*)contentType.getCString()));
|
179 lawrence.luo 1.1.2.1
180 /* is it a text based mime-type ?
181 *
182 * Notice:
183 * The mimeTypes-file mapping could be extended to an additional value
184 * indicating whether the file is to treat as binary or text.
185 * There are text based mime-types which do not start with 'text/'.
186 */
187 Boolean isBinFile = String::compare(contentType.subString(0, 4), "text");
|
188 dl.meetei 1.1.2.4
|
189 lawrence.luo 1.1.2.1 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest"
|
190 dl.meetei 1.1.2.4 "(WebRequest* webRequest) - contentType is binary='%s'",
191 (isBinFile ? "true" : "false" )));
|
192 lawrence.luo 1.1.2.1
193 /*
194 * check requested encodings
195 * (for ex. 'gzip, defalte')
196 */
197 String enc;// determined encoding to use
198 statusCode = _getRequestHeaderValue(
199 request->encodings,
200 const_cast<String&>(GZIP),
201 enc);
|
202 dl.meetei 1.1.2.4
|
203 lawrence.luo 1.1.2.1 if (statusCode != HTTP_STATUSCODE_OK)
204 {
|
205 dl.meetei 1.1.2.4 statusCode = _getRequestHeaderValue( request->encodings,
206 const_cast<String&>(DEFLATE),
207 enc);
208
|
209 lawrence.luo 1.1.2.1 if (statusCode == HTTP_STATUSCODE_BADREQUEST)
210 {
211 _sendError(
|
212 dl.meetei 1.1.2.4 statusCode,
213 queueId,
214 "Bad Syntax in header-parameter 'Accept-Encoding' !");
215
|
216 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
217 return;
218 }
219 }
220 //compress files bigger than 10KB, only
221 Boolean compressionFlag = String::equal(GZIP, enc)
|
222 dl.meetei 1.1.2.4 || String::equal(DEFLATE, enc);
|
223 lawrence.luo 1.1.2.1
|
224 dl.meetei 1.1.2.4 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest"
225 "(WebRequest* webRequest) - response encoding='%s', "
226 "compressionFlag='%s'",
227 (const char*)enc.getCString(),
228 (compressionFlag) ? "true" : "false"));
229
230 PEG_TRACE_CSTRING(TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest"
231 "(WebRequest* webRequest) - All Headers have been parsed and "
232 "successfully validated.");
|
233 lawrence.luo 1.1.2.1
234
235 /*
236 * check access to file/if exists
237 */
238 if (!FileSystem::canRead(fileName))
239 {// file not accessible
240 _sendError(
241 HTTP_STATUSCODE_FORBIDDEN,
242 queueId,
243 "The requested file '" + fileName + "' is not accessible!");
244 PEG_METHOD_EXIT();
245 return;
246 }
247
248 PEG_TRACE((TRC_WEBSERVER, Tracer::LEVEL4,
|
249 dl.meetei 1.1.2.4 "WebServer::handleWebRequest(WebRequest* webRequest) - "
250 "File accessible, creating response. HTTP-statusCode: %d ",
251 statusCode));
|
252 lawrence.luo 1.1.2.1
253 // initialize response-buffer
254 Buffer tmp = Buffer(DEFAULT_RESPONSE_BUFFER_SIZE);
255 Buffer& _message = tmp;
256
257 /*
258 * create response
259 */
260 _message << "HTTP/" << HTTP_VERSION << " " << statusCode << " "
261 << _getStatusMessage(statusCode).getCString() << "\r\n";
262 // response Date
263 _message << "Date: " << _getCurrentDate() << "\r\n";
264 _message << "Last-Modified: " << _getDateOfLastMod(fileName) << "\r\n";
265
266 if (isBinFile)// || compressionFlag) TODO: enable for compression
267 {
268 _message << "Accept-Ranges: bytes\r\n";
269 }
270 else
271 {
272 _message << "Accept-Ranges: text/plain\r\n";
273 lawrence.luo 1.1.2.1 }
274
275 // set content-type of file to deliver
276 _message << "Content-Type: " << contentType.getCString();
277 if (!isBinFile && !compressionFlag)
278 {// no charset for bin-files
279 _message << ";charset=utf-8";
280 }
281 _message << "\r\n";
282
283 // compress the file before delivery ?
284 if (compressionFlag)
285 {
286 /*TODO
287 * compress the file and set the new filename
288 * for further processing
289 */
290 // _message << "Content-Encoding: " << enc << "\r\n";
291 }
292
293 Uint32 fileSize;
294 lawrence.luo 1.1.2.1 if (!FileSystem::getFileSize(fileName, fileSize))
295 {
296 _sendError(
297 HTTP_STATUSCODE_INTERNALSERVERERROR,
298 queueId,
299 "The size for requested file '" + fileName
300 + "' could not be determined!");
301 PEG_METHOD_EXIT();
302 return;
303 }
304 // get file's size
305 if (isBinFile)// || compressionFlag) TODO: enable for compression
306 {/*
307 * plain text-files cause trouble due to the "\r\n" which is not counted,
308 * but added for each line
309 */
310 _message << "Content-Length: " << fileSize << "\r\n";
311 }
312 _message << "Connection: keep-alive \r\n";
313 // end of headers
314 _message << "\r\n";
315 lawrence.luo 1.1.2.1
316 PEG_TRACE_CSTRING(TRC_WEBSERVER,Tracer::LEVEL2,"WebServer::handleWebRequest"
317 "(WebRequest* webRequest) - All response headers have been "
318 "written.");
319
320 /*
321 * Write Body
322 */
323 if (request->httpMethod != HTTP_METHOD_HEAD)
324 {
325 if (fileSize != PEG_NOT_FOUND)
326 {
327 _message.reserveCapacity(fileSize);
328 }
329 if (isBinFile)// || compressionFlag) TODO: enable for compression
330 {
331 FileSystem::loadFileToMemory(_message, fileName);
332 }
333 else
334 {
335 _writeTextBody(_message, fileName);
336 lawrence.luo 1.1.2.1 }
337 }
338
339 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest"
340 "(WebRequest* webRequest) - response:\n%s\n",
341 Tracer::getHTTPRequestMessage(_message).get()));
342
343 // create response message
344 HTTPMessage* response = new HTTPMessage(_message, queueId);
345 // set close connection flag
346 response->setCloseConnect(true);
347
348 // request-object is not needed any longer, free memory
349 delete request;
350
351 /*
352 * send response
353 */
354 _sendRepsonse(response);
355 PEG_METHOD_EXIT();
356 }
357 lawrence.luo 1.1.2.1
358 void WebProcessor::_sendError(
|
359 dl.meetei 1.1.2.4 int statusCode,
360 Uint32& queueId,
361 String debugMsg,
362 String additionalHeaderFields)
|
363 lawrence.luo 1.1.2.1 {
|
364 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_sendError()");
|
365 lawrence.luo 1.1.2.1
|
366 dl.meetei 1.1.2.4 Uint32 statusC = Uint32(statusCode);
|
367 lawrence.luo 1.1.2.1 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,"WebServer::_sendError"
|
368 dl.meetei 1.1.2.4 "(Uint32 statusCode, Uint32 queueId, String debugMsg) - "
369 "statusCode: %d, QueueId: %d, debugMsg: %s",
370 statusCode, queueId, (const char*)debugMsg.getCString()));
|
371 lawrence.luo 1.1.2.1
372 // initialize response-buffer
373 Buffer tmp = Buffer(DEFAULT_RESPONSE_BUFFER_SIZE);
374 Buffer& _message = tmp;
375
376 /*
377 * create response
378 */
379 _message << "HTTP/" << HTTP_VERSION << " " << statusC << " "
380 << _getStatusMessage(statusC) << "\r\n";
381 // response Date
382 _message << "Date: " << _getCurrentDate();
383 /*
384 * additional header-fields required for certain errors
385 */
386 if (additionalHeaderFields.size() > Uint32(0))
387 {
388 _message << additionalHeaderFields << "\r\n";
389 }
390 /*
391 * handleError
392 lawrence.luo 1.1.2.1 */
393 _message << "Content-Type: text/html;charset=UTF-8\r\n";//UTF-8 response
394 _message << "\r\n\r\n"; // end of headers
395 _message << getErrorPage(statusC, debugMsg);
396
397 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,"WebServer::_sendError"
398 "(Uint32 statusCode, Uint32 queueId, String debugMsg) - "
399 "response:\n%s\n",
400 Tracer::getHTTPRequestMessage(_message).get()));
401
402 // create response message
403 HTTPMessage* response = new HTTPMessage(_message, queueId);
404
405 // set close connection flag
406 response->setCloseConnect(true);
407 _sendRepsonse(response);
408 PEG_METHOD_EXIT();
409 }
410
411 void WebProcessor::_sendRepsonse(HTTPMessage* response)
412 {
|
413 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_sendRepsonse()");
|
414 lawrence.luo 1.1.2.1 _webServer->handleResponse(response);
415 PEG_METHOD_EXIT();
416 }
417
418 String WebProcessor::getErrorPage(Uint32& statusCode, String& debugMsg)
419 {
|
420 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::getErrorPage()");
|
421 lawrence.luo 1.1.2.1 String page = String("<html><head><title>");
422 page.reserveCapacity(debugMsg.size() + 512);// 512 for the html-strings
423 page.append("Error");
424 page.append("</title></head><body><br/><h1>");
425 page.append(_getStatusMessage(statusCode));
426 page.append("</h1>");
427 #ifdef PEGASUS_DEBUG
428 page.append(debugMsg);
429 #endif /* PEGASUS_DEBUG */
430 page.append("</body></html>\r\n");
|
431 dl.meetei 1.1.2.4
432 PEG_METHOD_EXIT();
|
433 lawrence.luo 1.1.2.1 return page;
434 }
435
436
437 Uint32 WebProcessor::_getFileNameForURI(String& requestURI, String& absPath)
438 {
|
439 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_getFileNameForURI()");
|
440 lawrence.luo 1.1.2.1
441 if (requestURI.size() == Uint32(0))
442 {
443 // bad request, no uri supplied
444 PEG_METHOD_EXIT();
445 return HTTP_STATUSCODE_BADREQUEST;
446 }
447 else if (requestURI.size() > MAX_URI_LENGTH)
448 {
449 // request uri too long
450 PEG_METHOD_EXIT();
451 return HTTP_STATUSCODE_REQUESTURITOOLONG;
452 }
453
454
455 String fileName;
456 Uint32 index = requestURI.find("?");
457 if (index != PEG_NOT_FOUND)
458 {// cut parameters from URL ex: '?id=...&pb=..'
459 fileName = requestURI.subString(0, index);
460 }
461 lawrence.luo 1.1.2.1 else
462 {
463 fileName = requestURI;
464 }
465
466 if (fileName == "/")
467 {// map requests pointing to web-server's document-root to the index file
468 fileName.append(_webConfig.getIndexFile());
469 }
470
471 /*
472 * construct fileName and validate
473 */
474 String webRoot = _webConfig.getWebRoot();
475 String fullPath = (webRoot + fileName);
|
476 lawrence.luo 1.1.2.3 String resolvedPath = FileSystem::getAbsoluteFileName(webRoot,fileName);
|
477 lawrence.luo 1.1.2.1
478 if (FileSystem::isDirectory((const String&)resolvedPath))
479 {// it is not allowed to access directories, error 403
480 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,
|
481 dl.meetei 1.1.2.4 "Directory access to %s is not allowed!",
482 (const char*)resolvedPath.getCString()));
|
483 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
484 return HTTP_STATUSCODE_FORBIDDEN;
485 }
486
487 if (resolvedPath == "")
488 {
489 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,
|
490 dl.meetei 1.1.2.4 "Cannot resolve file path %s",
491 (const char*)fullPath.getCString()));
|
492 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
493 return HTTP_STATUSCODE_NOTFOUND;
494 }
495 /*
496 * further checks can be placed here, for example to
497 * prevent delivery of any config-files in case they are placed
498 * in the webRoot.
499 */
500 // clear first before appending
501 absPath.clear();
502
503 /*
504 * Ensure that the realpath starts with the web-root
505 */
506 if (!resolvedPath.equalNoCase(
507 (resolvedPath.subString(0, webRoot.size())), webRoot))
508 {// directory traversal attack
509 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,
|
510 dl.meetei 1.1.2.4 "Mismatch in resolved path: %s resolves to %s",
511 (const char*)fullPath.getCString(),
512 (const char*)resolvedPath.getCString()));
|
513 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
514 return HTTP_STATUSCODE_FORBIDDEN;
515 }
516
517 // append result
518 absPath.append(resolvedPath);
519
520 PEG_METHOD_EXIT();
521 return HTTP_STATUSCODE_OK;
522 }
523
524 void WebProcessor::_writeTextBody(Buffer& _message, String& fileName)
525 {
|
526 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_writeTextBody()");
|
527 lawrence.luo 1.1.2.1 String line;
528 ifstream infile(fileName.getCString());
529
530 if (!infile)
531 {
532 return;
533 }
534 while (GetLine(infile, line)) {
535 // write UTF-8
536 _message << (const char*)line.getCString() << "\r\n";
537 }
538 infile.close();
|
539 dl.meetei 1.1.2.4 PEG_METHOD_EXIT();
|
540 lawrence.luo 1.1.2.1 }
541
542
543 Boolean WebProcessor::_getContentType(String& fileName, String& contentType)
544 {
|
545 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_getContentType()");
|
546 lawrence.luo 1.1.2.1
547 //find last dot in filename
548 int found = fileName.reverseFind('.');
549 if (found <= 0) {// security
550 //error-case 'hidden file or file with no extension'
551 return false;
552 }
553 String fileExtension = String(fileName.subString(found+1));
554 contentType.clear();
|
555 dl.meetei 1.1.2.4 Boolean rslt = _webConfig.getMimeTypes().lookup(fileExtension, contentType);
|
556 lawrence.luo 1.1.2.1
557 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,
|
558 dl.meetei 1.1.2.4 "File extension is %s, contentType is %s",
559 (const char*)fileExtension.getCString(),
560 (const char*)contentType.getCString()));
|
561 lawrence.luo 1.1.2.1
|
562 dl.meetei 1.1.2.4 PEG_METHOD_EXIT();
563 return rslt;
|
564 lawrence.luo 1.1.2.1 }
565
566
567 char* WebProcessor::_getCurrentDate()
568 {
569 // time_t t;
570 // time(&t);
571 // return asctime(gmtime(&t));
572
573 time_t currentTime;
574 struct tm* gmtTime;
575 char* timeValue = (char*) malloc(30);
576 time(¤tTime);
577 gmtTime = gmtime(¤tTime);
578 strftime(timeValue,30,"%a, %d %b %Y %H:%M:%S GMT",gmtTime);
579 return timeValue;
580 }
581
582
583 char* WebProcessor::_getDateOfLastMod(String& fileName)
584 {
585 lawrence.luo 1.1.2.1 // last modified
586 struct tm* modTime; // create a time structure
587 struct stat attrib; // create a file attribute structure
588 stat(fileName.getCString(), &attrib); // get the attributes
589 modTime = gmtime(&(attrib.st_mtime)); // get the last modified time
590 char* timeValue = (char*) malloc(30);
591 strftime(timeValue,30,"%a, %d %b %Y %H:%M:%S GMT",modTime);
592 return timeValue;//asctime(modTime);
593 }
594
595 String WebProcessor::_getStatusMessage(Uint32& statusCode)
596 {
597 String statusMsg;
598
599 switch(statusCode)
600 {
601
602 /*
603 * 2xx
604 */
605 case HTTP_STATUSCODE_OK:
606 lawrence.luo 1.1.2.1 statusMsg = HTTP_REASONPHRASE_OK;
607 break;
608
609 /*
610 * 4xx
611 */
612 case HTTP_STATUSCODE_BADREQUEST:
613 statusMsg = HTTP_REASONPHRASE_BADREQUEST;
614 break;
615 case HTTP_STATUSCODE_FORBIDDEN:
616 statusMsg = HTTP_REASONPHRASE_FORBIDDEN;
617 break;
618 case HTTP_STATUSCODE_NOTFOUND:
619 statusMsg = HTTP_REASONPHRASE_NOTFOUND;
620 break;
621 case HTTP_STATUSCODE_METHODNOTALLOWED:
622 statusMsg = HTTP_REASONPHRASE_METHODNOTALLOWED;
623 break;
624 case HTTP_STATUSCODE_NOTACCEPTABLE:
625 statusMsg = HTTP_REASONPHRASE_NOTACCEPTABLE;
626 break;
627 lawrence.luo 1.1.2.1 case HTTP_STATUSCODE_REQUESTURITOOLONG:
628 statusMsg = HTTP_REASONPHRASE_REQUESTURITOOLONG;
629 break;
630 /*
631 * 5xx
632 */
633 case HTTP_STATUSCODE_VERSIONNOTSUPPORTED:
634 statusMsg = HTTP_REASONPHRASE_VERSIONNOTSUPPORTED;
635 break;
636 }
637
638 return statusMsg;
639 }
640
641
642
643 Uint32 WebProcessor::_getRequestHeaderValue(
644 String& headerLine, String& prefValue, String& resValue)
645 {
646
647 resValue.clear();
648 lawrence.luo 1.1.2.1 // default
649 resValue.append(prefValue);
650
651 if (headerLine.size() > Uint32(0))
652 {
653
654 Array<String> values = _split(headerLine, ",");
655 Uint32 any = PEG_NOT_FOUND;
656
657 // header line available ?
658 if (values.size() == Uint32(0))
659 {// no, free choice
660 any = 0;
661 }
662 else
663 {
664 // check requested mime types
665 for (int i = 0; Uint32(i) < values.size(); i++)
666 {
667 Array<String> valueDef = _split(values[i], ";");
668 // quality value present ?
669 lawrence.luo 1.1.2.1 if (valueDef.size() > Uint32(1))
670 {// yes, get it
671 String qFactorStr = valueDef[1];
672 // does the length make any sense ? (ex. q=0 & q=0.4)
673 if (qFactorStr.size() > Uint32(2)
674 && qFactorStr.size() < Uint32(5))
675 {// cast the value
676 double qFactor;
677 try
678 {
679 qFactor = atof(// remove 'q='
680 qFactorStr.subString(
681 2,qFactorStr.size()-1).getCString());
682 }
683 catch(...)
684 {
685 return HTTP_STATUSCODE_BADREQUEST;
686 }
687 if (String::equal(valueDef[0], prefValue)
688 && qFactor == 0)
689 {// preferred value is explicitly excluded
690 lawrence.luo 1.1.2.1 /*
691 * TODO figure out if there's one of the other
692 * request values acceptable for processing
693 */
694 return HTTP_STATUSCODE_NOTACCEPTABLE;
695 }
696 }
697 else
698 {// invalid length of quality value
699 return HTTP_STATUSCODE_BADREQUEST;
700 }
701 }
702 else
703 {// no quality value present means it is '1'
704 if (String::equal(prefValue, valueDef[0]))
705 {// the server-side preferred value is acceptable
706 return HTTP_STATUSCODE_OK;
707 }
708 }
709 }
710 }
711 lawrence.luo 1.1.2.1 }
712 return HTTP_STATUSCODE_OK;
713 }
714
715 Array<String> WebProcessor::_split(String& s, const char* delimiter)
716 {
717 Array<String> result;
718 Uint32 delimLength = strlen(delimiter);
719 Boolean run = true;
720
721 while(run)
722 {
723 Uint32 pos = s.find(delimiter);
724 if (pos == PEG_NOT_FOUND)
725 {
726 pos = s.size();
727 run = false;
728 }
729 String res = s.subString(0, pos);
730 result.append(res);
731 s = s.subString(pos + delimLength);
732 lawrence.luo 1.1.2.1 // remove leading whitespace
733 while (s.size() > Uint32(0) && s[0] == " ")
734 {
735 s = s.subString(1);
736 }
737 }
738 return result;
739 }
740 /* END */
741
742 PEGASUS_NAMESPACE_END
|