Revert "Use a variable on the stack to not have a temporary in the call"
[ACE_TAO.git] / ACE / apps / JAWS / server / HTTP_Request.cpp
blob457e0b8b0a500131ccb149d2a3fb5dcd0422e282
1 #include "ace/Message_Block.h"
2 #include "HTTP_Request.h"
3 #include "HTTP_Helpers.h"
4 #include "HTTP_Config.h"
5 #include "ace/OS_NS_string.h"
6 #include "ace/OS_NS_pwd.h"
7 #include "ace/Log_Msg.h"
9 const char *const
10 HTTP_Request::static_header_strings_[HTTP_Request::NUM_HEADER_STRINGS] =
12 "Date",
13 "Pragma",
14 "Authorization",
15 "From",
16 "If-Modified-Since",
17 "Referrer",
18 "User-Agent",
19 "Allow",
20 "Content-Encoding",
21 "Content-Length",
22 "Content-Type",
23 "Expires",
24 "Last-Modified"
27 const char *const
28 HTTP_Request::static_method_strings_[HTTP_Request::NUM_METHOD_STRINGS] =
30 "GET",
31 "HEAD",
32 "POST",
33 "PUT"
36 // For reasons of efficiency, this class expects buffer to be
37 // null-terminated, and buflen does NOT include the \0.
39 HTTP_Request::HTTP_Request ()
40 : got_request_line_ (0),
41 method_ (0),
42 uri_ (0),
43 version_ (0),
44 path_ (0),
45 cgi_ (0),
46 cgi_env_ (0),
47 cgi_args_ (0),
48 query_string_ (0),
49 path_info_ (0),
50 header_strings_ (HTTP_Request::static_header_strings_),
51 method_strings_ (HTTP_Request::static_method_strings_)
53 for (size_t i = 0;
54 i < HTTP_Request::NUM_HEADER_STRINGS;
55 i++)
56 this->headers_.recognize (this->header_strings_[i]);
59 HTTP_Request::~HTTP_Request ()
61 ACE_OS::free (this->method_);
62 ACE_OS::free (this->uri_);
63 ACE_OS::free (this->version_);
64 ACE_OS::free (this->path_);
65 ACE_OS::free (this->query_string_);
66 ACE_OS::free (this->path_info_);
68 delete [] this->cgi_env_;
71 int
72 HTTP_Request::parse_request (ACE_Message_Block &mb)
74 mb.wr_ptr ()[0] = '\0';
76 // Note that RFC 822 does not mention the maximum length of a header
77 // line. So in theory, there is no maximum length.
79 // In Apache, they assume that each header line should not exceed
80 // 8K.
82 int result = this->headers_.complete_header_line (mb.rd_ptr ());
84 if (result != 0)
86 if (!this->got_request_line ())
88 this->parse_request_line (mb.rd_ptr ());
89 while (this->headers_.complete_header_line (mb.rd_ptr ()) > 0)
90 this->headers_.parse_header_line (mb.rd_ptr ());
92 else if (result > 0)
94 this->headers_.parse_header_line (mb.rd_ptr ());
95 while (this->headers_.complete_header_line (mb.rd_ptr ()) > 0);
98 mb.wr_ptr (ACE_OS::strlen(mb.rd_ptr ()) - mb.length ());
100 if (this->headers_.end_of_headers ()
101 || (this->got_request_line () && this->version () == 0))
102 return this->init (mb.rd_ptr (), mb.length ());
103 else
104 return 0;
107 void
108 HTTP_Request::parse_request_line (char *const request_line)
110 char *ptr = request_line;
111 char *buf = request_line;
112 int offset = 1;
114 this->status_ = HTTP_Status_Code::STATUS_OK;
116 ptr = ACE_OS::strchr (request_line, '\n');
118 if (ptr > request_line && ptr[-1] == '\r')
119 ptr--, offset++;
121 if (ptr == request_line)
123 this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
124 return;
127 *ptr = '\0';
128 ptr += offset;
130 char *lasts = 0; // for strtok_r
132 // Get the request type.
133 this->got_request_line_ = 1;
135 if (this->method (ACE_OS::strtok_r (buf, " \t", &lasts))
136 && this->uri (ACE_OS::strtok_r (0, " \t", &lasts)))
138 this->type (this->method ());
140 if (this->version (ACE_OS::strtok_r (0, " \t", &lasts)) == 0
141 && this->type () != HTTP_Request::GET)
142 this->status_ = HTTP_Status_Code::STATUS_NOT_IMPLEMENTED;
144 if (this->path (this->uri ()) == 0)
145 this->status_ = HTTP_Status_Code::STATUS_NOT_FOUND;
148 ACE_DEBUG ((LM_DEBUG, " (%t) request %s %s %s parsed\n",
149 (this->method () ? this->method () : "-"),
150 (this->uri () ? this->uri () : "="),
151 (this->version () ? this->version () : "HTTP/0.9")));
153 ACE_OS::memmove (buf, ptr, ACE_OS::strlen (ptr)+1);
157 HTTP_Request::init (char *const buffer,
158 int buflen)
160 // Initialize these every time.
161 content_length_ = -1;
163 // Extract the data pointer.
164 data_ = buffer;
165 datalen_ = 0;
167 // Set the datalen
168 if (data_ != 0)
169 datalen_ = buflen;
170 else
171 datalen_ = 0;
173 ACE_DEBUG ((LM_DEBUG, " (%t) init has initialized\n"));
175 return 1;
178 const char *
179 HTTP_Request::method () const
181 return this->method_;
184 const char *
185 HTTP_Request::uri () const
187 return this->uri_;
190 const char *
191 HTTP_Request::version () const
193 return this->version_;
196 const char *
197 HTTP_Request::path () const
199 return this->path_;
203 HTTP_Request::cgi () const
205 return this->cgi_;
208 const char **
209 HTTP_Request::cgi_env () const
211 return (const char **)this->cgi_env_;
214 const char *
215 HTTP_Request::cgi_args () const
217 return this->cgi_args_;
220 const char *
221 HTTP_Request::query_string () const
223 return this->query_string_;
226 const char *
227 HTTP_Request::path_info () const
229 return this->path_info_;
233 HTTP_Request::got_request_line () const
235 return this->got_request_line_;
239 HTTP_Request::type () const
241 return type_;
244 const Headers &
245 HTTP_Request::headers () const
247 return this->headers_;
250 const char *
251 HTTP_Request::header_strings (int index) const
253 const char *hs = 0;
255 if (0 <= index && index < NUM_HEADER_STRINGS)
256 hs = this->header_strings_[index];
258 return hs;
261 const char *
262 HTTP_Request::header_values (int index) const
264 const char *hs = 0;
265 const char *hv = 0;
267 if (0 <= index && index < NUM_HEADER_STRINGS)
269 hs = this->header_strings_[index];
270 hv = this->headers_[hs].value ();
273 return hv;
276 char *
277 HTTP_Request::data ()
279 return data_;
283 HTTP_Request::data_length ()
285 return datalen_;
289 HTTP_Request::content_length ()
291 if (this->content_length_ == -1)
293 const char * clv = this->headers_["Content-length"].value ();
294 this->content_length_ = (clv ? ACE_OS::atoi (clv) : 0);
297 return this->content_length_;
301 HTTP_Request::status ()
303 return this->status_;
306 const char *
307 HTTP_Request::status_string ()
309 return HTTP_Status_Code::instance ()[this->status_];
312 void
313 HTTP_Request::dump ()
315 ACE_DEBUG ((LM_DEBUG, "%s command.\n"
316 "filename is %s,"
317 " length of the file is %d,"
318 " data string is %s,"
319 " datalen is %d,"
320 " status is %d, which is %s\n\n",
321 this->method () ? this->method () : "EMPTY",
322 this->uri () ? this->uri () : "EMPTY",
323 this->content_length (),
324 this->data () ? this->data () : "EMPTY",
325 this->data_length (),
326 this->status (),
327 this->status_string ()));
330 const char *
331 HTTP_Request::method (const char *method_string)
333 if (this->method_)
334 ACE_OS::free (this->method_);
336 if (method_string == 0)
338 this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
339 this->method_ = 0;
341 else
342 this->method_ = ACE_OS::strdup (method_string);
344 return this->method_;
347 const char *
348 HTTP_Request::uri (char *uri_string)
350 if (this->uri_)
351 ACE_OS::free (this->uri_);
353 if (uri_string == 0)
355 this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
356 this->uri_ = 0;
358 else
360 this->uri_ = ACE_OS::strdup (uri_string);
361 this->cgi (this->uri_);
362 HTTP_Helper::HTTP_decode_string (this->uri_);
365 return this->uri_;
368 const char *
369 HTTP_Request::version (const char *version_string)
371 if (this->version_)
372 ACE_OS::free (this->version_);
374 if (version_string)
375 this->version_ = ACE_OS::strdup (version_string);
376 else
377 this->version_ = 0;
379 return this->version_;
383 HTTP_Request::type (const char *type_string)
385 this->type_ = HTTP_Request::NO_TYPE;
387 if (type_string == 0)
388 return this->type_;
390 for (size_t i = 0;
391 i < HTTP_Request::NUM_METHOD_STRINGS;
392 i++)
394 if (ACE_OS::strcmp (type_string, this->method_strings_[i]) == 0)
396 this->type_ = i;
397 break;
400 if (this->type_ == HTTP_Request::NO_TYPE)
401 this->status_ = HTTP_Status_Code::STATUS_NOT_IMPLEMENTED;
403 return this->type_;
407 HTTP_Request::cgi (char *uri_string)
409 this->cgi_ = 0;
410 this->cgi_env_ = 0;
411 this->cgi_args_ = 0;
413 ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi (%s)\n", uri_string));
415 if (uri_string == 0 || ACE_OS::strlen (uri_string) == 0)
416 return 0;
418 // There are 2 cases where a file could be a CGI script
420 // (1) the file has a CGI extension.
421 // (2) the file resides in a CGI bin directory.
423 char *extra_path_info = 0;
424 if (this->cgi_in_path (uri_string, extra_path_info)
425 || this->cgi_in_extension (uri_string, extra_path_info))
427 cgi_args_and_env (extra_path_info);
429 if (extra_path_info)
431 this->path_info_ = ACE_OS::strdup (extra_path_info);
432 HTTP_Helper::HTTP_decode_string (this->path_info_);
433 *extra_path_info = '\0';
437 return this->cgi_;
441 HTTP_Request::cgi_in_path (char *uri_string, char *&extra_path_info)
443 char *cgi_path;
445 ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi_in_path (%s)\n",
446 uri_string));
448 if (HTTP_Config::instance ()->cgi_path ())
449 cgi_path = ACE_OS::strdup (HTTP_Config::instance ()->cgi_path ());
450 else
451 cgi_path = ACE_OS::strdup ("");
453 // error checking considered helpful!
454 if (cgi_path == 0)
455 return 0;
457 char *lasts = 0;
458 char *cgi_path_next = ACE_OS::strtok_r (cgi_path, ":", &lasts);
460 if (cgi_path_next)
463 int len = ACE_OS::strlen (cgi_path_next);
465 // match path to cgi path
466 int in_cgi_path = 0;
468 if (*cgi_path_next == '/')
470 // cgi path next points to an ``absolute'' path
471 extra_path_info = uri_string;
472 in_cgi_path =
473 (ACE_OS::strncmp (extra_path_info, cgi_path_next, len) == 0);
475 else
477 // cgi path next points to a ``relative'' path
478 extra_path_info = ACE_OS::strstr (uri_string, cgi_path_next);
479 in_cgi_path = (extra_path_info != 0);
482 if (in_cgi_path)
484 if (extra_path_info[len] == '/')
486 this->cgi_ = 1;
487 extra_path_info += len;
489 // move past the executable name
491 extra_path_info++;
492 while (*extra_path_info != '/'
493 && *extra_path_info != '?'
494 && *extra_path_info != '\0');
496 if (*extra_path_info == '\0')
497 extra_path_info = 0;
499 break;
502 extra_path_info = 0;
504 cgi_path_next = ACE_OS::strtok_r (0, ":", &lasts);
506 while (cgi_path_next);
508 ACE_OS::free (cgi_path);
510 return this->cgi_;
514 HTTP_Request::cgi_in_extension (char *uri_string, char *&extra_path_info)
516 extra_path_info = ACE_OS::strstr (uri_string, ".cgi");
518 ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi_in_extension (%s)\n",
519 uri_string));
521 while (extra_path_info != 0)
523 extra_path_info += 4;
524 // skip past ``.cgi''
526 switch (*extra_path_info)
528 case '\0':
529 extra_path_info = 0;
530 break;
531 case '/':
532 case '?':
533 break;
534 default:
535 extra_path_info = ACE_OS::strstr (extra_path_info, ".cgi");
536 continue;
538 this->cgi_ = 1;
539 break;
542 return this->cgi_;
545 void
546 HTTP_Request::cgi_args_and_env (char *&extra_path_info)
548 char *cgi_question = 0;
550 if (extra_path_info)
551 cgi_question = ACE_OS::strchr (extra_path_info, '?');
553 if (extra_path_info == cgi_question)
554 extra_path_info = 0;
556 if (cgi_question)
558 *cgi_question++ = '\0';
560 if (*cgi_question != '\0')
562 // We need the ``original'' QUERY_STRING for the
563 // environment. We will substitute '+'s for spaces in the
564 // other copy.
566 this->query_string_ = ACE_OS::strdup (cgi_question);
568 char *ptr = cgi_question;
569 int count = 0;
571 if (*ptr == '+')
572 *ptr = ' ';
573 else if (*ptr == '&' || *ptr == '=')
574 count++;
575 while (*++ptr);
577 count++;
579 if (ACE_OS::strchr (cgi_question, '='))
581 ACE_NEW (this->cgi_env_, char *[count+1]);
583 int i = 0;
584 ptr = cgi_question;
587 this->cgi_env_ [i++] = ptr;
589 while (*ptr++)
590 if (*ptr == '&' || *ptr == '=')
591 *ptr = '\0';
593 HTTP_Helper::HTTP_decode_string (this->cgi_env_[i-1]);
595 while (i < count);
597 this->cgi_env_[count] = 0;
599 else
601 this->cgi_args_ = cgi_question;
602 HTTP_Helper::HTTP_decode_string (cgi_question);
608 const char *
609 HTTP_Request::path (const char *uri_string)
611 char const *file_name = uri_string;
612 char buf[MAXPATHLEN + 1];
613 buf[0] = '\0';
615 if (file_name == 0) return 0;
617 if (*file_name == '/')
619 file_name++;
620 if (*file_name == '~')
622 char *ptr = buf;
624 while (*++file_name && *file_name != '/')
625 *ptr++ = *file_name;
627 *ptr = '\0';
629 if (ptr == buf)
630 ACE_OS::strcpy (buf, ACE_OS::getenv ("HOME"));
631 else
633 #if !defined (ACE_WIN32) && !defined (VXWORKS)
634 char pw_buf[BUFSIZ];
635 struct passwd pw_struct;
636 struct passwd *pw_struct_ptr;
637 if (ACE_OS::getpwnam_r (buf, &pw_struct, pw_buf,
638 sizeof (pw_buf), &pw_struct_ptr) == 0)
639 return 0;
640 ACE_OS::strcpy (buf, pw_struct.pw_dir);
641 #endif /* NOT ACE_WIN32 AND NOT VXWORKS */
644 ACE_OS::strcat (buf, "/");
645 ACE_OS::strcat (buf, HTTP_Config::instance ()->user_dir ());
646 ACE_OS::strcat (buf, file_name);
648 else
650 // With a starting '/' but no '~'
651 ACE_OS::strcat (buf, HTTP_Config::instance ()->document_root ());
652 ACE_OS::strcat (buf, file_name - 1);
656 if (*buf != '\0')
657 this->path_ = ACE_OS::strdup (buf);
659 return this->path_;