⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 request.cxx

📁 PTypes (C++ Portable Types Library) is a simple alternative to the STL that includes multithreading
💻 CXX
📖 第 1 页 / 共 2 页
字号:
/* * *  C++ Portable Types Library (PTypes) *  Version 1.7.5   Released 9-Mar-2003 * *  Copyright (c) 2001, 2002, 2003 Hovik Melikyan * *  http://www.melikyan.com/ptypes/ *  http://ptypes.sourceforge.net/ * */#include <stdlib.h>#include <limits.h>#include "config.h"#include "log.h"#include "utils.h"#include "sysutils.h"#include "request.h"#include "clients.h"#include "modules.h"USING_PTYPESconst char* http_version_str[HTTP_VER_MAX] = {"", "HTTP/1.0", "HTTP/1.1", "HTTP/1.1"};// const char* http_method_str[HTTP_METHOD_MAX] = {"GET", "HEAD", ""};const char* stat_str[STAT_MAX] = {"READ   ", "WRITE  ", "WAIT   "};request_rec::request_rec(instm& isockin, outstm& isockout, ipaddress iclient_ip)    : started(now()), rsp_code(0), stat(STAT_READ), sockin(&isockin), sockout(&isockout), client_ip(iclient_ip),       version(HTTP_VER_10), method(HTTP_GET), method_str(), keep_alive(false), if_modified(invdatetime),       req_line(), uri(), host(), referer(), partial(false), range_min(0), range_max(0), headers(),      url(), file_type(FT_ERROR), sym_link(false), executable(false), abs_path(), rel_path(),       file_name(), file_ext(), user(0),      location(), hdr_size(0){}request_rec::~request_rec(){    delete user;}void request_rec::put_header(const char* name, const char* value){    if (version > HTTP_VER_09)    {        sockout->put(name);        sockout->put(": ");        sockout->put(value);        sockout->put("\r\n");    }}void request_rec::put_header(const char* name, const string& value){    if (version > HTTP_VER_09)    {        sockout->put(name);        sockout->put(": ");        sockout->put(value);        sockout->put("\r\n");    }}void request_rec::put_content_type(const char* mime){    if (method != HTTP_HEAD)        put_header("Content-Type", mime);}void request_rec::put_content_length(int length){    if (method != HTTP_HEAD)    {        char buf[32];        snprintf(buf, sizeof(buf), "%d", length);        put_header("Content-Length", buf);    }}void request_rec::end_headers(){    if (version > HTTP_VER_09)        sockout->put("\r\n");    hdr_size = sockout->tell();    if (method == HTTP_HEAD)        end_response();}void request_rec::begin_response(int code, const char* msg){    rsp_code = code;    stat = STAT_WRITE;    if (version > HTTP_VER_09)    {        sockout->putf("%s %d %s\r\n", http_version_str[version], code, msg);        put_header("Date", http_time_stamp(now(true)));        put_header("Server", SERVER_APP_NAME);        //    put_header("Accept-Ranges", "bytes");                if (!isempty(location))            put_header("Location", location);                static const char* sconn[2] = {"close", "keep-alive"};        if (version < HTTP_VER_11)            put_header("Connection", sconn[keep_alive]);        else if (!keep_alive)   // HTTP/1.1            put_header("Connection", "close");    }}void request_rec::std_response(bool conn_close, int code, const char* msg, const char* descr){    if (conn_close)        keep_alive = false;    // we need a memory stream to temporarily store the response    outmemory s(4096);    string smsg = msg;    // write out the standard response page in HTML format    // to the memory stream    s.open();    if (strlen(descr) != 0)    {        std_html_header(s, itostring(code) + ' ' + smsg);        s.put("<p>");        html_encode(s, descr);        s.put("</p>\n");        std_html_footer(s);    }    // send the response    begin_response(code, msg);    if (s.tell() > 0)    // some responses do not return any content, e.g. 304    {        put_content_type("text/html");        put_content_length(s.tell());    }    end_headers();    if (s.tell() > 0)        sockout->write(s.get_data(), s.tell());    end_response();}void request_rec::std_response(bool conn_close, int code, const char* msg, const char* descr, const string& dparam){    char buf[1024];    snprintf(buf, sizeof(buf), descr, pconst(dparam));    std_response(conn_close, code, msg, buf);}void request_rec::rsp_not_found(){    std_response(false, 404, "Not found", "The requested object %s was not found on this server.", url.path);}void request_rec::rsp_bad_request(){    std_response(true, 400, "Bad request", "Your browser sent a request that this server could not understand.");}void request_rec::rsp_uri_too_long(){    std_response(true, 414, "Request-URI too long", "The request-URI string sent by your browser is too long.");}void request_rec::rsp_forbidden(){    std_response(false, 403, "Forbidden", "You don't have permission to access %s on this server", url.path);}void request_rec::rsp_dir_index_forbidden(){    std_response(false, 403, "Directory index forbidden", "Directory index forbidden: %s", url.path);}void request_rec::rsp_redirect(const string& newurl){    location = newurl;    std_response(false, 301, "Moved permanently", "The document has moved to %s", newurl);}void request_rec::rsp_overloaded(){    std_response(true, 504, "Service unavailable", "The server is overloaded. Please, try again later.");}void request_rec::rsp_not_modified(){    std_response(false, 304, "Not modified", "");}void request_rec::abort_request(){#ifdef DEBUG    syslog_write(SYSLOG_WARNING, "Request from %s aborted", pconst(iptostring(client_ip)));#endif    keep_alive = false;    throw ehttp(0);}void request_rec::end_response(){    throw ehttp(rsp_code);}//// request parsers//const cset method_chars = "A-Z";const cset uri_chars = "~21-~FF";const cset field_chars = uri_chars - cset(":");const cset ws_chars = "~20";string request_rec::get_token(const cset& chars){    char buf[MAX_TOKEN];    int bufsize = sockin->token(chars, buf, sizeof(buf));    if (bufsize == 0 || bufsize >= MAX_TOKEN)        rsp_bad_request();    return string(buf, bufsize);}string request_rec::get_uri(){    char buf[MAX_REQUEST_URI];    int bufsize = sockin->token(uri_chars, buf, sizeof(buf));    if (bufsize == 0)        rsp_bad_request();    if (bufsize >= MAX_REQUEST_URI)        rsp_uri_too_long();    return string(buf, bufsize);}void request_rec::parse_method(){    while (!sockin->get_eof() && sockin->get_eol())        sockin->skipline();    method_str = get_token(method_chars);    req_line = method_str;    if (method_str == "GET")        method = HTTP_GET;    else if (method_str == "HEAD")        method = HTTP_HEAD;    else if (length(method_str) == 0)        abort_request();    else    {        // try to pass this method to a registered method handler.        // the rest of the request line can be parsed using         // parse_request_line(), if it's HTTP/1.1-like.        handler_info* h = find_handler(method_list, method_str);        if (h != 0)        {            method_callback(h->callback)(*this);            // the handler must throw an ehttp exception            fatal(252, "Internal error 252");        }        else            rsp_bad_request();    }}void request_rec::parse_request_line(){    if (sockin->skiptoken(ws_chars) == 0)        abort_request();    // read the request URI    uri = get_uri();    req_line += ' ' + uri;    // read the version number, if present    if (sockin->get_eol())        version = HTTP_VER_09;    else    {        string s;        if (sockin->skiptoken(ws_chars) == 0)            abort_request();        s = get_token(uri_chars);        req_line += ' ' + s;        const char* p = s;        if (length(s) < 8 || strncmp(p, "HTTP/1.", 7) != 0)            rsp_bad_request();        if (p[7] == '0')            version = HTTP_VER_10;        else if (p[7] == '1')            version = HTTP_VER_11;        else            version = HTTP_VER_UNKNOWN; // 1.x is ok for us    }    // HTTP/1.1 requires to keep the connection alive by default;    // can be overridden by `Connection:' header    keep_alive = version >= HTTP_VER_11;    if (!sockin->get_eol())        rsp_bad_request();    if (version > HTTP_VER_09)        sockin->skipline();}void request_rec::parse_hdr(string& fname, string& fvalue){    fname = get_token(field_chars);             // read the field name    sockin->skiptoken(ws_chars);    if (sockin->get() != ':')                   // malformed header (no colon)        rsp_bad_request();        do {        sockin->skiptoken(ws_chars);            // skip leading ws chars        do {            if (sockin->get_eol())              // the value may be empty (?)		break;            string t = get_token(uri_chars);    // read field value            if (!isempty(fvalue))                fvalue += ' ';            fvalue += t;            if (length(fvalue) > MAX_TOKEN)                rsp_bad_request();        // according to RFC2616 all ws chars inside the field value        // can become a single space        } while (sockin->skiptoken(ws_chars) > 0);                if (!sockin->get_eol())            rsp_bad_request();        sockin->skipline();    } while (sockin->preview() & ws_chars); // see if field value continues on the next line}void request_rec::parse_headers(){    while (!sockin->get_eol())    {        string fname, fvalue;        parse_hdr(fname, fvalue);        fname = lowercase(fname);        if (fname == "host")            host = fvalue;        else if (fname == "connection")        {            fvalue = lowercase(fvalue);            if (fvalue == "close")                keep_alive = false;            else if (fvalue == "keep-alive")                keep_alive = true;        }        else if (fname == "if-modified-since")        {            if_modified = parse_http_date(fvalue);            if (if_modified == invdatetime)                rsp_bad_request();        }        else if (fname == "referer")            referer = fvalue;        else if (fname == "range")        {            if (strncmp(fvalue, "bytes=", 6) == 0)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -