📄 http_request.cpp
字号:
// HTTP_Request.cpp,v 1.32 2003/11/01 11:15:22 dhinton Exp
#include "ace/Message_Block.h"
#include "HTTP_Request.h"
#include "HTTP_Helpers.h"
#include "HTTP_Config.h"
#include "ace/OS_NS_string.h"
#include "ace/OS_NS_pwd.h"
#include "ace/Log_Msg.h"
ACE_RCSID(server, HTTP_Request, "HTTP_Request.cpp,v 1.32 2003/11/01 11:15:22 dhinton Exp")
const char *const
HTTP_Request::static_header_strings_[HTTP_Request::NUM_HEADER_STRINGS] =
{
"Date",
"Pragma",
"Authorization",
"From",
"If-Modified-Since",
"Referrer",
"User-Agent",
"Allow",
"Content-Encoding",
"Content-Length",
"Content-Type",
"Expires",
"Last-Modified"
};
const char *const
HTTP_Request::static_method_strings_[HTTP_Request::NUM_METHOD_STRINGS] =
{
"GET",
"HEAD",
"POST",
"PUT"
};
// For reasons of efficiency, this class expects buffer to be
// null-terminated, and buflen does NOT include the \0.
HTTP_Request::HTTP_Request (void)
: got_request_line_ (0),
method_ (0),
uri_ (0),
version_ (0),
path_ (0),
cgi_ (0),
cgi_env_ (0),
cgi_args_ (0),
query_string_ (0),
path_info_ (0),
header_strings_ (HTTP_Request::static_header_strings_),
method_strings_ (HTTP_Request::static_method_strings_)
{
for (size_t i = 0;
i < HTTP_Request::NUM_HEADER_STRINGS;
i++)
this->headers_.recognize (this->header_strings_[i]);
}
HTTP_Request::~HTTP_Request (void)
{
ACE_OS::free (this->method_);
ACE_OS::free (this->uri_);
ACE_OS::free (this->version_);
ACE_OS::free (this->path_);
ACE_OS::free (this->query_string_);
ACE_OS::free (this->path_info_);
delete [] this->cgi_env_;
}
int
HTTP_Request::parse_request (ACE_Message_Block &mb)
{
mb.wr_ptr ()[0] = '\0';
// Note that RFC 822 does not mention the maximum length of a header
// line. So in theory, there is no maximum length.
// In Apache, they assume that each header line should not exceed
// 8K.
int result = this->headers_.complete_header_line (mb.rd_ptr ());
if (result != 0)
{
if (!this->got_request_line ())
{
this->parse_request_line (mb.rd_ptr ());
while (this->headers_.complete_header_line (mb.rd_ptr ()) > 0)
this->headers_.parse_header_line (mb.rd_ptr ());
}
else if (result > 0)
do
this->headers_.parse_header_line (mb.rd_ptr ());
while (this->headers_.complete_header_line (mb.rd_ptr ()) > 0);
}
mb.wr_ptr (ACE_OS::strlen(mb.rd_ptr ()) - mb.length ());
if (this->headers_.end_of_headers ()
|| (this->got_request_line () && this->version () == 0))
return this->init (mb.rd_ptr (), mb.length ());
else
return 0;
}
void
HTTP_Request::parse_request_line (char *const request_line)
{
char *ptr = request_line;
char *buf = request_line;
int offset = 1;
this->status_ = HTTP_Status_Code::STATUS_OK;
ptr = ACE_OS::strchr (request_line, '\n');
if (ptr > request_line && ptr[-1] == '\r')
ptr--, offset++;
if (ptr == request_line)
{
this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
return;
}
*ptr = '\0';
ptr += offset;
char *lasts = 0; // for strtok_r
// Get the request type.
this->got_request_line_ = 1;
if (this->method (ACE_OS::strtok_r (buf, " \t", &lasts))
&& this->uri (ACE_OS::strtok_r (NULL, " \t", &lasts)))
{
this->type (this->method ());
if (this->version (ACE_OS::strtok_r (NULL, " \t", &lasts)) == 0
&& this->type () != HTTP_Request::GET)
this->status_ = HTTP_Status_Code::STATUS_NOT_IMPLEMENTED;
if (this->path (this->uri ()) == 0)
this->status_ = HTTP_Status_Code::STATUS_NOT_FOUND;
}
ACE_DEBUG ((LM_DEBUG, " (%t) request %s %s %s parsed\n",
(this->method () ? this->method () : "-"),
(this->uri () ? this->uri () : "="),
(this->version () ? this->version () : "HTTP/0.9")));
ACE_OS::memmove (buf, ptr, ACE_OS::strlen (ptr)+1);
}
int
HTTP_Request::init (char *const buffer,
int buflen)
{
// Initialize these every time.
content_length_ = -1;
// Extract the data pointer.
data_ = buffer;
datalen_ = 0;
// Set the datalen
if (data_ != NULL)
datalen_ = buflen;
else
datalen_ = 0;
ACE_DEBUG ((LM_DEBUG, " (%t) init has initialized\n"));
return 1;
}
const char *
HTTP_Request::method (void) const
{
return this->method_;
}
const char *
HTTP_Request::uri (void) const
{
return this->uri_;
}
const char *
HTTP_Request::version (void) const
{
return this->version_;
}
const char *
HTTP_Request::path (void) const
{
return this->path_;
}
int
HTTP_Request::cgi (void) const
{
return this->cgi_;
}
const char **
HTTP_Request::cgi_env (void) const
{
return (const char **)this->cgi_env_;
}
const char *
HTTP_Request::cgi_args (void) const
{
return this->cgi_args_;
}
const char *
HTTP_Request::query_string (void) const
{
return this->query_string_;
}
const char *
HTTP_Request::path_info (void) const
{
return this->path_info_;
}
int
HTTP_Request::got_request_line (void) const
{
return this->got_request_line_;
}
int
HTTP_Request::type (void) const
{
return type_;
}
const Headers &
HTTP_Request::headers (void) const
{
return this->headers_;
}
const char *
HTTP_Request::header_strings (int index) const
{
const char *hs = 0;
if (0 <= index && index < NUM_HEADER_STRINGS)
hs = this->header_strings_[index];
return hs;
}
const char *
HTTP_Request::header_values (int index) const
{
const char *hs = 0;
const char *hv = 0;
if (0 <= index && index < NUM_HEADER_STRINGS)
{
hs = this->header_strings_[index];
hv = this->headers_[hs].value ();
}
return hv;
}
char *
HTTP_Request::data (void)
{
return data_;
}
int
HTTP_Request::data_length (void)
{
return datalen_;
}
int
HTTP_Request::content_length (void)
{
if (this->content_length_ == -1)
{
const char * clv = this->headers_["Content-length"].value ();
this->content_length_ = (clv ? ACE_OS::atoi (clv) : 0);
}
return this->content_length_;
}
int
HTTP_Request::status (void)
{
return this->status_;
}
const char *
HTTP_Request::status_string (void)
{
return HTTP_Status_Code::instance ()[this->status_];
}
void
HTTP_Request::dump (void)
{
ACE_DEBUG ((LM_DEBUG, "%s command.\n"
"filename is %s,"
" length of the file is %d,"
" data string is %s,"
" datalen is %d,"
" status is %d, which is %s\n\n",
this->method () ? this->method () : "EMPTY",
this->uri () ? this->uri () : "EMPTY",
this->content_length (),
this->data () ? this->data () : "EMPTY",
this->data_length (),
this->status (),
this->status_string ()));
}
const char *
HTTP_Request::method (const char *method_string)
{
if (this->method_)
ACE_OS::free (this->method_);
if (method_string == 0)
{
this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
this->method_ = 0;
}
else
this->method_ = ACE_OS::strdup (method_string);
return this->method_;
}
const char *
HTTP_Request::uri (char *uri_string)
{
if (this->uri_)
ACE_OS::free (this->uri_);
if (uri_string == 0)
{
this->status_ = HTTP_Status_Code::STATUS_BAD_REQUEST;
this->uri_ = 0;
}
else
{
this->uri_ = ACE_OS::strdup (uri_string);
this->cgi (this->uri_);
HTTP_Helper::HTTP_decode_string (this->uri_);
}
return this->uri_;
}
const char *
HTTP_Request::version (const char *version_string)
{
if (this->version_)
ACE_OS::free (this->version_);
if (version_string)
this->version_ = ACE_OS::strdup (version_string);
else
this->version_ = 0;
return this->version_;
}
int
HTTP_Request::type (const char *type_string)
{
this->type_ = HTTP_Request::NO_TYPE;
if (type_string == 0)
return this->type_;
for (size_t i = 0;
i < HTTP_Request::NUM_METHOD_STRINGS;
i++)
if (ACE_OS::strcmp (type_string, this->method_strings_[i]) == 0)
{
this->type_ = i;
break;
}
if (this->type_ == HTTP_Request::NO_TYPE)
this->status_ = HTTP_Status_Code::STATUS_NOT_IMPLEMENTED;
return this->type_;
}
int
HTTP_Request::cgi (char *uri_string)
{
this->cgi_ = 0;
this->cgi_env_ = 0;
this->cgi_args_ = 0;
ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi (%s)\n", uri_string));
if (uri_string == 0 || ACE_OS::strlen (uri_string) == 0)
return 0;
// There are 2 cases where a file could be a CGI script
//
// (1) the file has a CGI extension.
// (2) the file resides in a CGI bin directory.
char *extra_path_info = 0;
if (this->cgi_in_path (uri_string, extra_path_info)
|| this->cgi_in_extension (uri_string, extra_path_info))
{
cgi_args_and_env (extra_path_info);
if (extra_path_info)
{
this->path_info_ = ACE_OS::strdup (extra_path_info);
HTTP_Helper::HTTP_decode_string (this->path_info_);
*extra_path_info = '\0';
}
}
return this->cgi_;
}
int
HTTP_Request::cgi_in_path (char *uri_string, char *&extra_path_info)
{
char *cgi_path;
ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi_in_path (%s)\n",
uri_string));
if (HTTP_Config::instance ()->cgi_path ())
cgi_path = ACE_OS::strdup (HTTP_Config::instance ()->cgi_path ());
else
cgi_path = ACE_OS::strdup ("");
// error checking considered helpful!
if (cgi_path == 0)
return 0;
char *lasts = 0;
char *cgi_path_next = ACE_OS::strtok_r (cgi_path, ":", &lasts);
if (cgi_path_next)
do
{
int len = ACE_OS::strlen (cgi_path_next);
// match path to cgi path
int in_cgi_path = 0;
if (*cgi_path_next == '/')
{
// cgi path next points to an ``absolute'' path
extra_path_info = uri_string;
in_cgi_path =
(ACE_OS::strncmp (extra_path_info, cgi_path_next, len) == 0);
}
else
{
// cgi path next points to a ``relative'' path
extra_path_info = ACE_OS::strstr (uri_string, cgi_path_next);
in_cgi_path = (extra_path_info != 0);
}
if (in_cgi_path)
{
if (extra_path_info[len] == '/')
{
this->cgi_ = 1;
extra_path_info += len;
// move past the executable name
do
extra_path_info++;
while (*extra_path_info != '/'
&& *extra_path_info != '?'
&& *extra_path_info != '\0');
if (*extra_path_info == '\0')
extra_path_info = 0;
break;
}
}
extra_path_info = 0;
cgi_path_next = ACE_OS::strtok_r (NULL, ":", &lasts);
}
while (cgi_path_next);
ACE_OS::free (cgi_path);
return this->cgi_;
}
int
HTTP_Request::cgi_in_extension (char *uri_string, char *&extra_path_info)
{
extra_path_info = ACE_OS::strstr (uri_string, ".cgi");
ACE_DEBUG ((LM_DEBUG, " (%t) HTTP_Request::cgi_in_extension (%s)\n",
uri_string));
while (extra_path_info != 0)
{
extra_path_info += 4;
// skip past ``.cgi''
switch (*extra_path_info)
{
case '\0':
extra_path_info = 0;
break;
case '/':
case '?':
break;
default:
extra_path_info = ACE_OS::strstr (extra_path_info, ".cgi");
continue;
}
this->cgi_ = 1;
break;
}
return this->cgi_;
}
void
HTTP_Request::cgi_args_and_env (char *&extra_path_info)
{
char *cgi_question = 0;
if (extra_path_info)
cgi_question = ACE_OS::strchr (extra_path_info, '?');
if (extra_path_info == cgi_question)
extra_path_info = 0;
if (cgi_question)
{
*cgi_question++ = '\0';
if (*cgi_question != '\0')
{
// We need the ``original'' QUERY_STRING for the
// environment. We will substitute '+'s for spaces in the
// other copy.
this->query_string_ = ACE_OS::strdup (cgi_question);
char *ptr = cgi_question;
int count = 0;
do
if (*ptr == '+')
*ptr = ' ';
else if (*ptr == '&' || *ptr == '=')
count++;
while (*++ptr);
count++;
if (ACE_OS::strchr (cgi_question, '='))
{
ACE_NEW (this->cgi_env_, char *[count+1]);
int i = 0;
ptr = cgi_question;
do
{
this->cgi_env_ [i++] = ptr;
while (*ptr++)
if (*ptr == '&' || *ptr == '=')
*ptr = '\0';
HTTP_Helper::HTTP_decode_string (this->cgi_env_[i-1]);
}
while (i < count);
this->cgi_env_[count] = 0;
}
else
{
this->cgi_args_ = cgi_question;
HTTP_Helper::HTTP_decode_string (cgi_question);
}
}
}
}
const char *
HTTP_Request::path (const char *uri_string)
{
char const *file_name = uri_string;
char buf[MAXPATHLEN + 1];
buf[0] = '\0';
if (file_name == 0) return 0;
if (*file_name == '/')
{
file_name++;
if (*file_name == '~')
{
char *ptr = buf;
while (*++file_name && *file_name != '/')
*ptr++ = *file_name;
*ptr = '\0';
if (ptr == buf)
ACE_OS::strcpy (buf, ACE_OS::getenv ("HOME"));
else
{
#if !defined (ACE_WIN32) && !defined (VXWORKS)
char pw_buf[BUFSIZ];
struct passwd pw_struct;
if (ACE_OS::getpwnam_r (buf, &pw_struct, pw_buf, sizeof (pw_buf))
== 0)
return 0;
ACE_OS::strcpy (buf, pw_struct.pw_dir);
#endif /* NOT ACE_WIN32 AND NOT VXWORKS */
}
ACE_OS::strcat (buf, "/");
ACE_OS::strcat (buf, HTTP_Config::instance ()->user_dir ());
ACE_OS::strcat (buf, file_name);
}
else
{
// With a starting '/' but no '~'
ACE_OS::strcat (buf, HTTP_Config::instance ()->document_root ());
ACE_OS::strcat (buf, file_name - 1);
}
}
if (*buf != '\0')
this->path_ = ACE_OS::strdup (buf);
return this->path_;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -