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