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 lawrence.luo 1.1.2.6 #include <time.h>
|
33 lawrence.luo 1.1.2.1 #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
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 lawrence.luo 1.1.2.1
55
56 WebProcessor::WebProcessor(WebServer* const webServer)
|
57 dl.meetei 1.1.2.4 : _webConfig(), _webServer(webServer)
|
58 lawrence.luo 1.1.2.1 {
59 }
60
61 WebProcessor::~WebProcessor()
62 {
63 }
64
65 void WebProcessor::handleWebRequest(WebRequest* request)
66 {
|
67 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::handleWebRequest()");
|
68 lawrence.luo 1.1.2.1
69 if (!request)
70 {
71 PEG_METHOD_EXIT();
72 return;
73 }
74
75 Uint32 queueId = request->getQueueId();
|
76 dl.meetei 1.1.2.4
77
|
78 lawrence.luo 1.1.2.1 // check protocol version
|
79 dl.meetei 1.1.2.5 if( String::equal(request->httpVersion, "") ||
80 PEG_NOT_FOUND == request->httpVersion.find("HTTP/"))
|
81 lawrence.luo 1.1.2.1 {// bad request
|
82 dl.meetei 1.1.2.4 _sendError( HTTP_STATUSCODE_BADREQUEST, queueId,
83 "Malformed Http, http version string not found!");
|
84 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
85 return;
86 }
|
87 dl.meetei 1.1.2.4 else if( !String::equal(request->httpVersion, "HTTP/" + HTTP_VERSION))
|
88 lawrence.luo 1.1.2.1 {// protocol-version not supported
89 _sendError(
|
90 dl.meetei 1.1.2.4 HTTP_STATUSCODE_VERSIONNOTSUPPORTED,
91 queueId,
92 "The requested HTTP version '" + request->httpVersion
|
93 lawrence.luo 1.1.2.1 + "' is not supported by this server!");
94 PEG_METHOD_EXIT();
95 return;
96 }
97 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest"
|
98 dl.meetei 1.1.2.5 "(WebRequest* webRequest) - httpVersion='%s'",
99 (const char*)request->httpVersion.getCString()));
|
100 lawrence.luo 1.1.2.1
|
101 dl.meetei 1.1.2.5 const char* method = NULL;
|
102 lawrence.luo 1.1.2.1 // check HTTPmethod
103 if (request->httpMethod == HTTP_METHOD_GET)
104 {
|
105 dl.meetei 1.1.2.5 method = "GET";
|
106 lawrence.luo 1.1.2.1 }
107 else if (request->httpMethod == HTTP_METHOD_HEAD)
108 {
|
109 dl.meetei 1.1.2.5 method = "HEAD";
|
110 lawrence.luo 1.1.2.1 }
111 else
112 {// handle bad request (method not allowed)
113 _sendError(
|
114 dl.meetei 1.1.2.4 HTTP_STATUSCODE_METHODNOTALLOWED,
115 queueId,
116 "The requested HTTP method is not supported by this server,"
|
117 lawrence.luo 1.1.2.1 " 'GET' and 'HEAD' only!",
118 "Allow: HEAD, GET");
119 PEG_METHOD_EXIT();
120 return;
121 }
|
122 dl.meetei 1.1.2.5 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"Requested httpMethod= %s",method));
|
123 lawrence.luo 1.1.2.1
124 // get absolute filename from URI
125 String fileName;
126 Uint32 statusCode = _getFileNameForURI(request->requestURI, fileName);
127 if (statusCode != HTTP_STATUSCODE_OK)
128 {
129 _sendError(
|
130 dl.meetei 1.1.2.5 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 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
142 return;
143 }
|
144 dl.meetei 1.1.2.5 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,"URI maps to valid/allowed "
145 "fileName='%s'",
146 (const char*)fileName.getCString()));
|
147 lawrence.luo 1.1.2.1
148 // 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 dl.meetei 1.1.2.5 String contentType;
|
162 lawrence.luo 1.1.2.1 if (!_getContentType(fileName, contentType))
163 {
164 // no contentType known for requested file(-extension)
165 _sendError(
|
166 dl.meetei 1.1.2.4 HTTP_STATUSCODE_FORBIDDEN, queueId,
167 "The requested file '" + fileName
|
168 lawrence.luo 1.1.2.1 + "' has an undefined content type. It will not be served!");
169 PEG_METHOD_EXIT();
170 return;
171 }
|
172 dl.meetei 1.1.2.5 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,
173 " Requested response contentType='%s'",
|
174 dl.meetei 1.1.2.4 (const char*)contentType.getCString()));
|
175 lawrence.luo 1.1.2.1
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 dl.meetei 1.1.2.4
|
185 lawrence.luo 1.1.2.1 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL3,"WebServer::handleWebRequest"
|
186 dl.meetei 1.1.2.4 "(WebRequest* webRequest) - contentType is binary='%s'",
|
187 dl.meetei 1.1.2.5 (isBinFile ? "true" : "false" )));
|
188 lawrence.luo 1.1.2.1
189 /*
190 * 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 dl.meetei 1.1.2.4
|
199 lawrence.luo 1.1.2.1 if (statusCode != HTTP_STATUSCODE_OK)
200 {
|
201 dl.meetei 1.1.2.4 statusCode = _getRequestHeaderValue( request->encodings,
202 const_cast<String&>(DEFLATE),
203 enc);
204
|
205 lawrence.luo 1.1.2.1 if (statusCode == HTTP_STATUSCODE_BADREQUEST)
206 {
207 _sendError(
|
208 dl.meetei 1.1.2.4 statusCode,
209 queueId,
210 "Bad Syntax in header-parameter 'Accept-Encoding' !");
211
|
212 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
213 return;
214 }
215 }
216 //compress files bigger than 10KB, only
217 Boolean compressionFlag = String::equal(GZIP, enc)
|
218 dl.meetei 1.1.2.4 || String::equal(DEFLATE, enc);
|
219 lawrence.luo 1.1.2.1
|
220 dl.meetei 1.1.2.4 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 dl.meetei 1.1.2.5 "successfully validated.");
|
229 lawrence.luo 1.1.2.1
230
231 /*
232 * check access to file/if exists
233 */
234 if (!FileSystem::canRead(fileName))
235 {// file not accessible
236 _sendError(
|
237 dl.meetei 1.1.2.5 HTTP_STATUSCODE_FORBIDDEN,
238 queueId,
239 "The requested file '" + fileName + "' is not accessible!");
240
|
241 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
242 return;
243 }
244
245 PEG_TRACE((TRC_WEBSERVER, Tracer::LEVEL4,
|
246 dl.meetei 1.1.2.4 "WebServer::handleWebRequest(WebRequest* webRequest) - "
|
247 dl.meetei 1.1.2.5 "File accessible, creating response. HTTP-statusCode: %d ",
|
248 dl.meetei 1.1.2.4 statusCode));
|
249 lawrence.luo 1.1.2.1
250 // initialize response-buffer
251 Buffer tmp = Buffer(DEFAULT_RESPONSE_BUFFER_SIZE);
252 Buffer& _message = tmp;
253
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 lawrence.luo 1.1.2.1 }
271
272 // set content-type of file to deliver
273 _message << "Content-Type: " << contentType.getCString();
274 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 lawrence.luo 1.1.2.1 if (!FileSystem::getFileSize(fileName, fileSize))
292 {
293 _sendError(
294 HTTP_STATUSCODE_INTERNALSERVERERROR,
295 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 lawrence.luo 1.1.2.1
|
313 dl.meetei 1.1.2.5 PEG_TRACE_CSTRING(TRC_WEBSERVER,Tracer::LEVEL4,"WebServer::handleWebRequest"
314 "(WebRequest* webRequest) - All response headers have been written.");
|
315 lawrence.luo 1.1.2.1
316 /*
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 dl.meetei 1.1.2.5 "(WebRequest* webRequest) - response:\n%s\n",
337 Tracer::getHTTPRequestMessage(_message).get()));
|
338 lawrence.luo 1.1.2.1
339 // create response message
340 HTTPMessage* response = new HTTPMessage(_message, queueId);
|
341 dl.meetei 1.1.2.5
|
342 lawrence.luo 1.1.2.1 // 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 dl.meetei 1.1.2.4 int statusCode,
357 Uint32& queueId,
358 String debugMsg,
359 String additionalHeaderFields)
|
360 lawrence.luo 1.1.2.1 {
|
361 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_sendError()");
|
362 lawrence.luo 1.1.2.1
|
363 dl.meetei 1.1.2.4 Uint32 statusC = Uint32(statusCode);
|
364 lawrence.luo 1.1.2.1 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,"WebServer::_sendError"
|
365 dl.meetei 1.1.2.4 "(Uint32 statusCode, Uint32 queueId, String debugMsg) - "
366 "statusCode: %d, QueueId: %d, debugMsg: %s",
367 statusCode, queueId, (const char*)debugMsg.getCString()));
|
368 lawrence.luo 1.1.2.1
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 _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 lawrence.luo 1.1.2.1 */
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 dl.meetei 1.1.2.5 "(Uint32 statusCode, Uint32 queueId, String debugMsg) - "
396 "response:\n%s\n",
397 Tracer::getHTTPRequestMessage(_message).get()));
|
398 lawrence.luo 1.1.2.1
399 // create response message
400 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 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_sendRepsonse()");
|
411 lawrence.luo 1.1.2.1 _webServer->handleResponse(response);
412 PEG_METHOD_EXIT();
413 }
414
415 String WebProcessor::getErrorPage(Uint32& statusCode, String& debugMsg)
416 {
|
417 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::getErrorPage()");
|
418 lawrence.luo 1.1.2.1 String page = String("<html><head><title>");
419 page.reserveCapacity(debugMsg.size() + 512);// 512 for the html-strings
420 page.append("Error");
421 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 dl.meetei 1.1.2.4
429 PEG_METHOD_EXIT();
|
430 lawrence.luo 1.1.2.1 return page;
431 }
432
433
434 Uint32 WebProcessor::_getFileNameForURI(String& requestURI, String& absPath)
435 {
|
436 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_getFileNameForURI()");
|
437 lawrence.luo 1.1.2.1
438 if (requestURI.size() == Uint32(0))
439 {
440 // bad request, no uri supplied
441 PEG_METHOD_EXIT();
442 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 lawrence.luo 1.1.2.1 else
459 {
460 fileName = requestURI;
461 }
462
463 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 lawrence.luo 1.1.2.3 String resolvedPath = FileSystem::getAbsoluteFileName(webRoot,fileName);
|
474 lawrence.luo 1.1.2.1
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 dl.meetei 1.1.2.4 "Directory access to %s is not allowed!",
479 (const char*)resolvedPath.getCString()));
|
480 lawrence.luo 1.1.2.1 PEG_METHOD_EXIT();
481 return HTTP_STATUSCODE_FORBIDDEN;
482 }
483
484 if (resolvedPath == "")
485 {
486 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,
|
487 dl.meetei 1.1.2.4 "Cannot resolve file path %s",
488 (const char*)fullPath.getCString()));
|
489 lawrence.luo 1.1.2.1 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 {// directory traversal attack
506 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL1,
|
507 dl.meetei 1.1.2.4 "Mismatch in resolved path: %s resolves to %s",
508 (const char*)fullPath.getCString(),
509 (const char*)resolvedPath.getCString()));
|
510 lawrence.luo 1.1.2.1 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 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_writeTextBody()");
|
524 lawrence.luo 1.1.2.1 String line;
525 ifstream infile(fileName.getCString());
526
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 dl.meetei 1.1.2.4 PEG_METHOD_EXIT();
|
537 lawrence.luo 1.1.2.1 }
538
539
540 Boolean WebProcessor::_getContentType(String& fileName, String& contentType)
541 {
|
542 dl.meetei 1.1.2.4 PEG_METHOD_ENTER(TRC_WEBSERVER, "WebProcessor::_getContentType()");
|
543 lawrence.luo 1.1.2.1
544 //find last dot in filename
545 int found = fileName.reverseFind('.');
546 if (found <= 0) {// security
547 //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 dl.meetei 1.1.2.4 Boolean rslt = _webConfig.getMimeTypes().lookup(fileExtension, contentType);
|
553 lawrence.luo 1.1.2.1
554 PEG_TRACE((TRC_WEBSERVER,Tracer::LEVEL4,
|
555 dl.meetei 1.1.2.4 "File extension is %s, contentType is %s",
556 (const char*)fileExtension.getCString(),
557 (const char*)contentType.getCString()));
|
558 lawrence.luo 1.1.2.1
|
559 dl.meetei 1.1.2.4 PEG_METHOD_EXIT();
560 return rslt;
|
561 lawrence.luo 1.1.2.1 }
562
563
564 char* WebProcessor::_getCurrentDate()
565 {
566 // time_t t;
567 // time(&t);
568 // return asctime(gmtime(&t));
569
570 time_t currentTime;
571 struct tm* gmtTime;
572 char* timeValue = (char*) malloc(30);
573 time(¤tTime);
574 gmtTime = gmtime(¤tTime);
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 lawrence.luo 1.1.2.1 // 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 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 lawrence.luo 1.1.2.1 statusMsg = HTTP_REASONPHRASE_OK;
604 break;
605
606 /*
607 * 4xx
608 */
609 case HTTP_STATUSCODE_BADREQUEST:
610 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 lawrence.luo 1.1.2.1 case HTTP_STATUSCODE_REQUESTURITOOLONG:
625 statusMsg = HTTP_REASONPHRASE_REQUESTURITOOLONG;
626 break;
627 /*
628 * 5xx
629 */
630 case HTTP_STATUSCODE_VERSIONNOTSUPPORTED:
631 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 lawrence.luo 1.1.2.1 // default
646 resValue.append(prefValue);
647
648 if (headerLine.size() > Uint32(0))
649 {
650
651 Array<String> values = _split(headerLine, ",");
652 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 lawrence.luo 1.1.2.1 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 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 lawrence.luo 1.1.2.1 /*
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 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 lawrence.luo 1.1.2.1 }
709 return HTTP_STATUSCODE_OK;
710 }
711
712 Array<String> WebProcessor::_split(String& s, const char* delimiter)
713 {
714 Array<String> result;
715 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 lawrence.luo 1.1.2.1 // remove leading whitespace
730 while (s.size() > Uint32(0) && s[0] == " ")
731 {
732 s = s.subString(1);
733 }
734 }
735 return result;
736 }
737 /* END */
738
739 PEGASUS_NAMESPACE_END
|