码迷,mamicode.com
首页 > 编程语言 > 详细

TinyWS —— 一个C++写的简易WEB服务器(二)

时间:2015-01-12 23:46:35      阅读:245      评论:0      收藏:0      [点我收藏+]

标签:

写在前面

代码已经托管在 https://git.oschina.net/augustus/TinyWS.git

可以用git clone下来。由于我可能会偶尔做一些修改,不能保证git 库上的代码与blog里的完全一致(实际上也不可能把所有的代码都贴在这里)。另外,TinyWS是基于linux写的(ubuntu 14.10 + eclipse luna,eclipse工程我也push到了git库),故在Windows上可能无法正常编译(主要是系统调用 部分可能会不同)。

前面的内容可参考上一篇  http://www.cnblogs.com/cuiluo/p/4217205.html

GetRequest

接上一篇,这个类就是处理GET方法的强求的。它继承自Request,需要override doExecute方法。它的功能是解析出请求的URI,并将其传给Response类的对象进一步处理。目前的实现中,使用CGI的方式处理动态请求(所谓动态请求,就是浏览器的请求中指明要运行服务器端的某个程序,并得到返回结果),但是这部分代码其实是没有测试过的。本类中,后面三个方法都是处理动态请求的uri和参数的。

// GetRequest.h
class
GetRequest : public Request { virtual void doExecute(); bool parseUri(std::string& filename, std::string& cgiargs); bool parseStaticContentUri(std::string& filename); bool parseDynamicContentUri(std::string& filename, std::string& cgiargs); void assignCigArgs(std::string& cgiargs); void doAssignCigArgs(std::string::size_type pos, std::string& cgiargs); };

在具体实现中,静态网页的存储路径是"test-files",这个主要是为了测试,如果请求没有携带指定的文件名,那么就返回此路径下的"index.html"文件。服务于动态请求的程序都存放在"cgi-bin"目录下,当然,目前此路径下也没有程序。在doExecute方法中,解析了URI后,就直接创建一个Response的对象做进一步处理。

// GetRequest.cpp
void GetRequest::doExecute()
{
    std::string filename, cgiargs;

    bool isStatic = parseUri(filename, cgiargs);
    Response(getFileDescriptor(), filename, cgiargs, isStatic).respond();
}

bool GetRequest::parseUri(std::string& filename, std::string& cgiargs)
{
    if (getUri().find("cgi-bin") == std::string::npos)
        return parseStaticContentUri(filename);
    else
        return parseDynamicContentUri(filename, cgiargs);
}

bool GetRequest::parseStaticContentUri(std::string& filename)
{
    std::string uri = getUri();

    filename = "test-files" + uri;

    if (uri[uri.length() - 1] == /)
        filename += "index.html";

    return true;
}

bool GetRequest::parseDynamicContentUri(std::string& filename, std::string& cgiargs)
{
    assignCigArgs(cgiargs);

    filename = "." +  getUri();

    return false;
}

void GetRequest::assignCigArgs(std::string& cgiargs)
{
    std::string uri = getUri();
    std::string::size_type pos = uri.find_first_of("?");

    doAssignCigArgs(pos, cgiargs);
}

void GetRequest::doAssignCigArgs(std::string::size_type pos, std::string& cgiargs)
{
    if (pos != std::string::npos)
        cgiargs = getUri().substr(pos, getUri().length() - 1);
    else
        cgiargs.clear();
}

Response

Response类的作用是,根据请求的uri,返回被请求的文件,如果是动态请求,则执行相关的程序。

Response的设计很不好。首先,他的构造函数需要一个bool值标识是否为静态网页,这会引起内部处理的很多if ... else分支,这其实是我十分痛恨的;其次它的一个成员是struct stat 类型,此为linux系统调用提供的一个标识文件属性的结构,它本不应该属于这个层级,Response应该是专注业务的,和操作系统打交道的工作应该交给别人。

所以这里是后面我重构的重点,或许可以使用工厂或状态模式等方法处理一下,不过对于一个只有两种选择的状态,用工厂就显得太兴师动众了。目前打算使用状态模式,已经加了一个 enum State { STATIC, DYNAMIC},不过还没有继续。后续如果修改了代码,会提到git库,这里就不会再同步修改了。

class Response
{
public:
    Response(int fd, std::string name, std::string cgiargs, bool isStc);
    void respond();

private:
    const std::string getFiletype();
    void preResond();
    void respondOK();
    void respondStatic();
    void respondDynamic();
    const void execveCgiProgram();
    const void doExecveCgiProgram();
    const std::string buildRespond0KHeaders();
    const std::string buildRespondStaticHeaders();
    const std::string buildForbiddenMsg();
    const std::string buildRespondErrorHeaders(const std::string errNum, const std::string shortMsg);
    const std::string buildRespondErrorBody(const std::string errNum, const std::string shortMsg, const std::string longMsg);
    void respondError(const std::string errNum, const std::string shortMsg, const std::string longMsg);
private:
    enum State { STATIC, DYNAMIC};
    struct stat sbuf;
    int fileDescriptor;
    std::string fileName;
    std::string cgiArgs;
    bool isStatic;
};

下一步

现在,关于TinyWS上层业务相关的部分就介绍完了。后面的部分会涉及到Socket和IO操作相关的内容,留作下次再说。

TinyWS —— 一个C++写的简易WEB服务器(二)

标签:

原文地址:http://www.cnblogs.com/cuiluo/p/4219946.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!