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