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"
10 HTTP_Request::static_header_strings_
[HTTP_Request::NUM_HEADER_STRINGS
] =
28 HTTP_Request::static_method_strings_
[HTTP_Request::NUM_METHOD_STRINGS
] =
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),
50 header_strings_ (HTTP_Request::static_header_strings_
),
51 method_strings_ (HTTP_Request::static_method_strings_
)
54 i
< HTTP_Request::NUM_HEADER_STRINGS
;
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_
;
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
82 int result
= this->headers_
.complete_header_line (mb
.rd_ptr ());
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 ());
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 ());
108 HTTP_Request::parse_request_line (char *const request_line
)
110 char *ptr
= request_line
;
111 char *buf
= request_line
;
114 this->status_
= HTTP_Status_Code::STATUS_OK
;
116 ptr
= ACE_OS::strchr (request_line
, '\n');
118 if (ptr
> request_line
&& ptr
[-1] == '\r')
121 if (ptr
== request_line
)
123 this->status_
= HTTP_Status_Code::STATUS_BAD_REQUEST
;
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
,
160 // Initialize these every time.
161 content_length_
= -1;
163 // Extract the data pointer.
173 ACE_DEBUG ((LM_DEBUG
, " (%t) init has initialized\n"));
179 HTTP_Request::method () const
181 return this->method_
;
185 HTTP_Request::uri () const
191 HTTP_Request::version () const
193 return this->version_
;
197 HTTP_Request::path () const
203 HTTP_Request::cgi () const
209 HTTP_Request::cgi_env () const
211 return (const char **)this->cgi_env_
;
215 HTTP_Request::cgi_args () const
217 return this->cgi_args_
;
221 HTTP_Request::query_string () const
223 return this->query_string_
;
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
245 HTTP_Request::headers () const
247 return this->headers_
;
251 HTTP_Request::header_strings (int index
) const
255 if (0 <= index
&& index
< NUM_HEADER_STRINGS
)
256 hs
= this->header_strings_
[index
];
262 HTTP_Request::header_values (int index
) const
267 if (0 <= index
&& index
< NUM_HEADER_STRINGS
)
269 hs
= this->header_strings_
[index
];
270 hv
= this->headers_
[hs
].value ();
277 HTTP_Request::data ()
283 HTTP_Request::data_length ()
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_
;
307 HTTP_Request::status_string ()
309 return HTTP_Status_Code::instance ()[this->status_
];
313 HTTP_Request::dump ()
315 ACE_DEBUG ((LM_DEBUG
, "%s command.\n"
317 " length of the file is %d,"
318 " data string is %s,"
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 (),
327 this->status_string ()));
331 HTTP_Request::method (const char *method_string
)
334 ACE_OS::free (this->method_
);
336 if (method_string
== 0)
338 this->status_
= HTTP_Status_Code::STATUS_BAD_REQUEST
;
342 this->method_
= ACE_OS::strdup (method_string
);
344 return this->method_
;
348 HTTP_Request::uri (char *uri_string
)
351 ACE_OS::free (this->uri_
);
355 this->status_
= HTTP_Status_Code::STATUS_BAD_REQUEST
;
360 this->uri_
= ACE_OS::strdup (uri_string
);
361 this->cgi (this->uri_
);
362 HTTP_Helper::HTTP_decode_string (this->uri_
);
369 HTTP_Request::version (const char *version_string
)
372 ACE_OS::free (this->version_
);
375 this->version_
= ACE_OS::strdup (version_string
);
379 return this->version_
;
383 HTTP_Request::type (const char *type_string
)
385 this->type_
= HTTP_Request::NO_TYPE
;
387 if (type_string
== 0)
391 i
< HTTP_Request::NUM_METHOD_STRINGS
;
394 if (ACE_OS::strcmp (type_string
, this->method_strings_
[i
]) == 0)
400 if (this->type_
== HTTP_Request::NO_TYPE
)
401 this->status_
= HTTP_Status_Code::STATUS_NOT_IMPLEMENTED
;
407 HTTP_Request::cgi (char *uri_string
)
413 ACE_DEBUG ((LM_DEBUG
, " (%t) HTTP_Request::cgi (%s)\n", uri_string
));
415 if (uri_string
== 0 || ACE_OS::strlen (uri_string
) == 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
);
431 this->path_info_
= ACE_OS::strdup (extra_path_info
);
432 HTTP_Helper::HTTP_decode_string (this->path_info_
);
433 *extra_path_info
= '\0';
441 HTTP_Request::cgi_in_path (char *uri_string
, char *&extra_path_info
)
445 ACE_DEBUG ((LM_DEBUG
, " (%t) HTTP_Request::cgi_in_path (%s)\n",
448 if (HTTP_Config::instance ()->cgi_path ())
449 cgi_path
= ACE_OS::strdup (HTTP_Config::instance ()->cgi_path ());
451 cgi_path
= ACE_OS::strdup ("");
453 // error checking considered helpful!
458 char *cgi_path_next
= ACE_OS::strtok_r (cgi_path
, ":", &lasts
);
463 int len
= ACE_OS::strlen (cgi_path_next
);
465 // match path to cgi path
468 if (*cgi_path_next
== '/')
470 // cgi path next points to an ``absolute'' path
471 extra_path_info
= uri_string
;
473 (ACE_OS::strncmp (extra_path_info
, cgi_path_next
, len
) == 0);
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);
484 if (extra_path_info
[len
] == '/')
487 extra_path_info
+= len
;
489 // move past the executable name
492 while (*extra_path_info
!= '/'
493 && *extra_path_info
!= '?'
494 && *extra_path_info
!= '\0');
496 if (*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
);
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",
521 while (extra_path_info
!= 0)
523 extra_path_info
+= 4;
524 // skip past ``.cgi''
526 switch (*extra_path_info
)
535 extra_path_info
= ACE_OS::strstr (extra_path_info
, ".cgi");
546 HTTP_Request::cgi_args_and_env (char *&extra_path_info
)
548 char *cgi_question
= 0;
551 cgi_question
= ACE_OS::strchr (extra_path_info
, '?');
553 if (extra_path_info
== 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
566 this->query_string_
= ACE_OS::strdup (cgi_question
);
568 char *ptr
= cgi_question
;
573 else if (*ptr
== '&' || *ptr
== '=')
579 if (ACE_OS::strchr (cgi_question
, '='))
581 ACE_NEW (this->cgi_env_
, char *[count
+1]);
587 this->cgi_env_
[i
++] = ptr
;
590 if (*ptr
== '&' || *ptr
== '=')
593 HTTP_Helper::HTTP_decode_string (this->cgi_env_
[i
-1]);
597 this->cgi_env_
[count
] = 0;
601 this->cgi_args_
= cgi_question
;
602 HTTP_Helper::HTTP_decode_string (cgi_question
);
609 HTTP_Request::path (const char *uri_string
)
611 char const *file_name
= uri_string
;
612 char buf
[MAXPATHLEN
+ 1];
615 if (file_name
== 0) return 0;
617 if (*file_name
== '/')
620 if (*file_name
== '~')
624 while (*++file_name
&& *file_name
!= '/')
630 ACE_OS::strcpy (buf
, ACE_OS::getenv ("HOME"));
633 #if !defined (ACE_WIN32) && !defined (VXWORKS)
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)
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
);
650 // With a starting '/' but no '~'
651 ACE_OS::strcat (buf
, HTTP_Config::instance ()->document_root ());
652 ACE_OS::strcat (buf
, file_name
- 1);
657 this->path_
= ACE_OS::strdup (buf
);