编程实战:自己编写HTTP服务器(系列7:用户功能接口)

系列入口:编程实战:自己编写HTTP服务器(系列1:概述和应答)-CSDN博客

         本文介绍用户功能接口。

目录

一、概述

二、执行接口

三、接口设置

3.1 主要属性

3.2 CWebCommandParam

3.3 添加参数

3.4 生成form


一、概述

        作为通常的执行功能的接口,一般就是三个功能:初始化、执行、退出(清理)。

        本web服务器呢,因为要考虑浏览器界面,让用户能从浏览器上直接调用功能,所以还包括了生成用户界面的部分。

        整个接口的名称为CWebCommand,后面介绍的代码都是这个类的一部分。

二、执行接口

        执行接口很简单,只有三个函数:

编程实战:自己编写HTTP服务器(系列7:用户功能接口)_第1张图片        初始化和卸载很简单。执行接口则有三个参数:请求、应答和socket。

        请求和应答很容易理解,为什么要提供socket呢?因为如果页面比较大的话,可能需要提前输出内容,不让用户等得太着急。

        如果提前返回一部分应答,那么就无法再添加内容长度头标了,因为投标部分已经发送,不可能再更改,应答对象对此做了检查。

        如果用户功能很特殊,仅仅直接使用socket而不使用应答对象也是可以的(也就是说,完全可以当作一个普通socket连接来使用)。

        一个示例:

	class CWebCommand_SetDebug : public CWebCommand
	{
	public:
		CWebCommand_SetDebug()
		{
			clear();
			AddWebCommandParam("SetDebug", "SetDebug", "1:开启调试/0:关闭调试", "");
			SetWebCommand("SetDebug", "设置调试开关", "开启G_IS_DEBUG,注意,开启后产生海量日志");
		}

		virtual bool doWebFunction(CHttpRequest const * pRequest, CSocket & s, CHttpRespond * pRespond)
		{
			string param = pRequest->GetParam("SetDebug");

			if ("1" == param)
			{
				G_IS_DEBUG = true;
				pRespond->AppendBody("打开调试成功");
			}
			else if ("0" == param)
			{
				G_IS_DEBUG = false;
				pRespond->AppendBody("关闭调试成功");
			}
			else
			{
				pRespond->AppendBody("非法参数,超出限制");
			}
			return true;
		}
	};

        这个示例很简单,根据参数设置调试开关,完全没有使用socket。构造函数设置了自身的参数,后面详细介绍。初始化和卸载没有使用。

三、接口设置

3.1 主要属性

		bool isAdmin;//是否是内置页面
		bool notonhomepage;//是否不出现在首页
		bool hide;//是否隐藏,只能通过直接命令调用
		bool AutoRefresh;//是否允许自动刷新
		bool NotStdPage;//非标准页面,不生成标准数据,所有数据,包括应答头都由命令自己生成
		string command_id;//命令ID,也作为页面名称,但不包括后缀名
		string name;//显示名称
		string note;

		vector params;//命令参数

        前面几个bool的含义是很明显的,由框架来控制各种行为。后面ID、名称和说明也很显然。最后的CWebCommandParam是重点,决定了需要用户输入几个参数,这个类会自动生成HTML的form代码。

3.2 CWebCommandParam

        这个类相当的繁琐,其实就是HTML的基本的form内容,供C++程序员快速生成form表单,如果想要奇幻的效果,可以请前端给做一个css。

	//命令接口
	class CWebCommandParam
	{
	public:
		string id;//唯一标识
		string name;//显示名称
		string note;//说明

		bool isCheckBox;//是否是选择框
		bool isChecked;//是否选中

		string defaultvalue;//默认值
		bool isNotNull;//是否必填
		bool isSelectOnly;//是否只能在选项表选择
		bool isHide;//是否隐藏
		bool isPassword;//是否是密码输入
		bool isReadOnly;//是否只读
		long size;//宽度
		long rows;//行数,改值不为0则显示为textaera
		vector > optionvalue;//选项集合

		CWebCommandParam() { clear(); }
		void clear()
		{
			isCheckBox = isChecked = false;
			isNotNull = isSelectOnly = isHide = isPassword = isReadOnly = false;
			id = name = note = defaultvalue = "";
			size = rows = 0;
			optionvalue.clear();
		}
		void SetFormatInput(char const * _id, char const * _name, long _size, long _rows = 0, char const * _default = "", char const * _note = "")
		{
			clear();
			id = _id;
			name = _name;
			size = _size;
			rows = _rows;
			defaultvalue = _default;
			note = _note;
		}
		void SetFormatPasswd(char const * _id, char const * _name, long _size, char const * _default = "", char const * _note = "")
		{
			clear();
			isPassword = true;
			id = _id;
			name = _name;
			size = _size;
			defaultvalue = _default;
			note = _note;
		}
		void ReadOnly() { isReadOnly = true; }
		string toHtmlInputOnly(char const* value, char const* desc, bool canEdit)
		{
			CWebCommandParam tmp = *this;
			tmp.isReadOnly = !canEdit;
			return tmp._toHtmlInput(false, false, value, desc, false);
		}
		string toHtmlInput(bool smallinput = false, bool showParamId = false, string NewDefault = "")
		{
			return _toHtmlInput(smallinput, showParamId, NewDefault);
		}
		string _toHtmlInput(bool smallinput = false, bool showParamId = false, string NewDefault = "", char const* desc = NULL, bool showName = true)
		{
			char buf[10240];
			string type;
			string ret;
			CHTMLEncode encode;

			char namestr[256];
			if (showName)sprintf(namestr, "%s %s%s", encode(name).c_str(), encode(note).c_str(), (isNotNull ? "*" : ""));
			else strcpy(namestr, "");

			//从请求更新参数的值
			if (0 != NewDefault.size())
			{
				if (isCheckBox && "1" == NewDefault)isChecked = true;
				else defaultvalue = NewDefault;
			}

			if (isHide)
			{
				sprintf(buf, ""
					, encode(id).c_str(), encode(defaultvalue).c_str());
				ret += buf;
				return ret;
			}

			if (showParamId)
			{
				ret = id + " : ";
			}
			if (this->isCheckBox)
			{
				sprintf(buf, "%s"
					, (this->isChecked ? "checked" : ""), this->id.c_str(), this->name.c_str());
				ret += buf;
			}
			else
			{
				if (isReadOnly && !isPassword)
				{
					string _desc;
					if (NULL == desc || 0 == strlen(desc))_desc = defaultvalue;
					else _desc = desc;
					sprintf(buf, "%s%s"
						, namestr, encode(id).c_str(), encode(defaultvalue).c_str(), encode(_desc).c_str());
					ret += buf;
				}
				else
				{
					if (rows != 0)
					{
						sprintf(buf, ""
							, namestr, (isReadOnly ? "READONLY" : ""), (smallinput ? 16 : size), (smallinput ? 1 : rows), encode(id).c_str(), encode(defaultvalue).c_str());
						ret += buf;
					}
					else
					{
						if (optionvalue.size() != 0)
						{
							sprintf(buf, "");
							ret += buf;
						}
						else
						{
							if (this->isPassword)type = "PASSWORD";
							else type = "INPUT";

							sprintf(buf, ""
								, namestr, (isReadOnly ? "READONLY" : ""), type.c_str(), (smallinput ? 16 : size), encode(id).c_str(), encode(defaultvalue).c_str());
							ret += buf;
						}
					}
				}
			}

			return ret;
		}
	};

        代码没什么奥秘,就是根据参数组合出HTML代码。

3.3 添加参数

        为了简化代码,提供了几个快速添加参数的函数:

		void AddWebCommandParam(char const * _id, char const * _name, char const * _note, char const * _default, bool isPassword = false, bool isNotNull = false, long size = 16, long rows = 0, vector > * _optionvalue = NULL)
		{
			CWebCommandParam tmp;
			tmp.id = _id;
			tmp.name = _name;
			tmp.note = _note;
			tmp.defaultvalue = _default;
			tmp.isPassword = isPassword;
			tmp.isNotNull = isNotNull;
			tmp.size = size;
			tmp.rows = rows;
			if (NULL != _optionvalue)tmp.optionvalue = *_optionvalue;
			else tmp.optionvalue.clear();
			this->params.push_back(tmp);
		}
		void AddWebCommandParamCheckBox(char const * _id, char const * _name, char const * _note, bool isChecked)
		{
			CWebCommandParam tmp;
			tmp.id = _id;
			tmp.name = _name;
			tmp.note = _note;
			tmp.isCheckBox = true;
			tmp.isChecked = isChecked;
			this->params.push_back(tmp);
		}

3.4 生成form

        由于某种原因生成form被分为两部分,一部分包含form开始和参数,另一部分包含提交和结束:

		string toHtmlFormInput(bool smallinput, bool showParamId, CHttpRequest const * pRequest)
		{
			string str;

			if (command_id.size() != 0)
			{
				str += "
\r\n"; } else { str += "\r\n"; } //添加命令ID str += ""; //添加每个参数 if (0 != params.size()) { for (vector::size_type i = 0; i < params.size(); ++i) { str += params[i].toHtmlInput(smallinput, showParamId, pRequest->GetParam(params[i].id)); str += "
\r\n"; } } else { str += " "; } return str; } string toHtmlFormSubmit(bool disable, bool both) { char buf[1024]; if (disable) { sprintf(buf, "
不可用\r\n\r\n"); } else { if (both) { sprintf(buf, "" "\r\n\r\n" , name.c_str(), GetFormName().c_str(), name.c_str(), GetFormName().c_str()); } else { sprintf(buf, "
\r\n\r\n" , name.c_str(), GetFormName().c_str()); } } return buf; }

        这两个函数连起来就是一个完整的form表单。

(这里是结束,但不是整个系列的结束)

你可能感兴趣的:(C++嵌入式HTTP服务器,服务器,http,嵌入式)