(file) Return to WebProcessor.cpp CVS log (file) (dir) Up to [Pegasus] / pegasus / src / Pegasus / WebServer

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

No CVS admin address has been configured
Powered by
ViewCVS 0.9.2