编程实战:自己编写HTTP服务器(系列4:查看文件、下载等一般功能)

news2024/11/22 22:19:52

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

        本文介绍各种功能的实现。大部分是特定内置入口。

目录

一、默认页

二、查看文件

三、关闭服务

四、下载页面


一、默认页

        前面在已经介绍过重定向,默认页可以通过重定向转到指定的页面,因为我这里的主要目的是提供嵌入功能,所以提供了一个内置的默认页:

        如果资源名称是这“/default.asp”或“/default.htm”,就执行默认功能,HTML页面的框架已经用OnPageStart和OnPageEnd构建,专用的代码放在doPageDefault里面:

		bool ShowStopServer()
		{
			string str;

			//str="<BR><BR><A href=\"/shell.asp?curdir="+m_root+"\" target=\"_blank\">Shell</A><P>\n";
			//m_respond.AppendBody(str);

			str="<BR><BR><FORM ACTION=\"/stopserver.asp\" METHOD=\"POST\" target=\"_blank\">\n"
				"<CODE>关闭服务器需要口令:</CODE><BR><INPUT TYPE=\"password\" SIZE=\"30\" NAME=\"password\" >\n"
				"<INPUT TYPE=SUBMIT VALUE=\"关闭服务器\" >\n"
				"</FORM>\n";
			m_respond.AppendBody(str);

			return true;
		}
		bool doPageDefault()
		{
			ShowFunctionList(false);
			ShowStopServer();
			return true;
		}

        ShowFunctionList()是显示功能列表,是真正面向嵌入的C++程序的部分,后面会详细介绍。

        ShowStopServer()是显示关闭服务器的功能的用户入口,就是一个HTML表单(我用到的HTML功能都是基于HTML4的),你需要学习一下HTML,不过只需要最基本的就可以了。

        看完这个应该就明白了,所谓嵌入式web服务器,就是用C++代码生成HTML给浏览器而已。

        上面的代码中注释掉的一部分是另一个功能的入口,"/shell.asp"是执行后台命令的接口,因为执行权限很大,所以一般隐藏入口。

二、查看文件

        查看文件的入口代码:

				else if("/ViewFile.asp"==m_request.GetResource())
				{
					char buf[2048];
					sprintf(buf,"查看文件 %s ",m_request.GetParam("file").c_str());
					OnPageStart(buf);
					doPageViewFile();
					OnPageEnd();
					m_s.Close();//所有此类页面都可能无法预先确定输出长度
					isKeepAlive=false;
				}

        以“file”为查询参数,也就是类似这样的请求:“http://ip:port/ViewFile.asp?file=文件名”。

        输出是HTML,OnPageStart和OnPageEnd处理HTML文件的开始和结束。主体部分则由doPageViewFile()提供:

		bool doPageViewFile()
		{
			ifstream f;
			char * buf;
			long bufsize=1024*1024;
			long count,len,outcount;
			string file=m_request.GetParam("file");
			string autorefresh=m_request.GetParam("autorefresh");
			long start=atol(m_request.GetParam("start").c_str());
			long end=atol(m_request.GetParam("end").c_str());
			long origin_start=start;//原始start
			long maxcount=atol(m_request.GetParam("maxcount").c_str());
			if(0==maxcount)maxcount=500;//默认值
			if(maxcount<0 || maxcount>50000)maxcount=50000;//最大行数限制

			while(true)
			{
				if(NULL==(buf=new char[bufsize]))
				{
					m_respond.AppendBody("内存不足<P>");
					break;
				}
				if(file.size()==0)
				{
					m_respond.AppendBody("没有文件名<P>");
					break;
				}
				m_respond.AppendBody("文件名: ");
				m_respond.AppendBody(file);
				m_respond.AppendBody("<BR>");
				//打开文件
				f.open(file.c_str(),ios::in);
				if(!f.good())
				{
					m_respond.AppendBody("打开文件错误<P>");
					break;
				}
				//获取长度
				f.seekg(0,ios::end);
				len=f.tellg();
				if(end>0)
				{
					sprintf(buf,"文件长度: %ld,开始位置:%ld,结束位置: %ld,请求的总长度:%ld<BR>------------------------------------------<P>\n",len,start,end,end-start);
					len=end;
				}
				else
				{
					sprintf(buf,"文件长度: %ld,开始位置:%ld,请求的总长度:%ld<BR>------------------------------------------<P>\n",len,start,len-start);
				}
				m_respond.AppendBody(buf);
				if(!m_respond.Flush(m_s))return true;
				//读取内容
				if(start<0)start=len+start;//负值代表从结束开始往前
				if(start<0)start=0;//如果还是负的说明参数错误
				f.seekg(start,ios::beg);
				outcount=0;
				count=0;
				while(f.good())
				{
					if(count>=maxcount)break;//超过输出量限制
					f.getline(buf,bufsize-1);
					buf[bufsize-1]='\0';
					m_respond.AppendBody(LogToHtml(buf,false,true));
					++count;
					if(count%100==0)
					{
						m_respond.AppendBodyHtmlScroll();
						if(!m_respond.Flush(m_s))break;
					}
					outcount=f.tellg()-start;
					if(f.tellg()>=len)
					{
						break;
					}
				}
				m_respond.Flush(m_s);
				f.close();
				m_respond.AppendBody("<P>------------------------------------------<P>");
				sprintf(buf,"剩余字节数: %ld",len-start-outcount);
				m_respond.AppendBody(buf);

				break;
			}
			if(!m_respond.Flush(m_s))return true;

			char buf2[10240];
			sprintf(buf2,
				"<FORM METHOD=\"GET\" name=\"form_view\">\n"
				"<INPUT TYPE=\"hidden\" NAME=\"file\" VALUE=\"%s\" >\n"
				"<INPUT TYPE=\"hidden\" NAME=\"autorefresh\" VALUE=\"%s\" >\n"
				"起点(从0开始,负值代表从文件尾倒数):<INPUT TYPE=\"text\" SIZE=\"30\" NAME=\"start\" VALUE=\"%ld\"><BR>\n"
				"终点(从0开始,负值代表从文件尾倒数):<INPUT TYPE=\"text\" SIZE=\"30\" NAME=\"end\" VALUE=\"%ld\"><BR>\n"
				"最大输出行数: <INPUT TYPE=\"text\" SIZE=\"30\" NAME=\"maxcount\" VALUE=\"%ld\">\n"
				"<INPUT TYPE=SUBMIT VALUE=\"执行\" >\n"
				"</FORM>\n"
				,file.c_str(),autorefresh.c_str(),(origin_start<0?origin_start:start+outcount),end,maxcount);
			m_respond.AppendBody(buf2);
			bool isAutoRefresh=(m_request.GetParam("autorefresh")=="true");
			sprintf(buf2,
				"<BUTTON NAME=\"autorefresh\" onclick=\"timer=setTimeout('window.form_view.submit()',10000);window.form_view.autorefresh.value='true';window.autorefresh.disabled=true;window.stoprefresh.disabled=false;\">自动刷新</BUTTON>\n"
				"<button NAME=\"stoprefresh\" disabled onclick=\"clearTimeout(timer);window.form_view.autorefresh.value='';window.autorefresh.disabled=false;window.stoprefresh.disabled=true;\">停止刷新</BUTTON><BR>\n"
				"%s<BR>\n"
				,(isAutoRefresh?"<script language=\"JavaScript\">window.autorefresh.onclick()</script>":""));
			m_respond.AppendBody(buf2);
			if(!m_respond.Flush(m_s))return true;

			delete[] buf;
			return true;
		}

        嘿嘿,现在明白为什么需要一个专门的功能了吧。这个功能支持指定开始位置和结束位置,并且可以自动刷新、自动滚动,还给文件内容增加了格式处理(LogToHtml()函数给日志根据类型上色)

三、关闭服务

        默认页提供了关闭服务的用户入口,用户入口会传到这个页面来:

				else if("/stopserver.asp"==m_request.GetResource())
				{
					OnPageStart("stop server",true);
					if(NULL!=pfCheckAdmin && !pfCheckAdmin(m_request.GetParam("password").c_str()))
					{
						m_respond.AppendBody("口令错误");
						OnPageEnd();
					}
					else
					{
						(*pShutDown) = true;
						m_respond.AppendBody("收到停止信号,服务正在停止......");
						m_respond.Flush(m_s);
						OnPageEnd();
					}
					isKeepAlive=false;
					m_s.Close();
				}

        首先检查管理员密码对不对(普通用户不能关闭服务器),然后返回“服务正在停止”页面给用户,最后退出服务程序。

四、下载页面

        前面已经介绍过下载的实际功能代码,这是入口点:

				else if("/DownFile.asp"==m_request.GetResource())
				{
					if(doPageFile(m_request.GetParam("file").c_str()))
					{
						m_respond.Flush(s);
					}
					else
					{
						m_respond.Flush(s);
						m_s.Close();//所有此类页面都可能无法预先确定输出长度
						isKeepAlive=false;
					}
				}

        也是以“file”为参数。实际功能入口和静态文件是一样的,区别是会设置头标指示是文件下载。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1304035.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

UE4/UE5 修改/还原场景所有Actor的材质

使用蓝图方法&#xff1a; 1.修改场景所有Actor 材质&#xff1a; Wirframe&#xff1a;一个材质类 MatList&#xff1a;获取到的所有模型的全部材质 的列表 TempAllClass&#xff1a;场景中所有获取的 Actor 的列表 功能方法如下&#xff1a; 蓝图代码可复制在&#xff1a…

MongoDB在Windows系统和Linux系统中实现自动定时备份

本文主要介绍MongoDB在Windows系统和Linux系统中如何实现自动定时备份。 目录 MongoDB在Windows系统中实现自动定时备份MongoDB在Linux系统中实现自动定时备份备份步骤备份恢复 MongoDB在Windows系统中实现自动定时备份 要在Windows系统中实现自动定时备份MongoDB数据库&#…

界面控件DevExpress中文教程 - 如何用Office File API组件填充PDF表单

DevExpress Office File API是一个专为C#, VB.NET 和 ASP.NET等开发人员提供的非可视化.NET库。有了这个库&#xff0c;不用安装Microsoft Office&#xff0c;就可以完全自动处理Excel、Word等文档。开发人员使用一个非常易于操作的API就可以生成XLS, XLSx, DOC, DOCx, RTF, CS…

《Spring Cloud Alibaba 从入门到实战》分布式消息(事件)驱动

分布式消息&#xff08;事件&#xff09;驱动 1、简介 事件驱动架构(Event-driven 架构&#xff0c;简称 EDA)是软件设计领域内的一套程序设计模型。 这套模型的意义是所有的操作通过事件的发送/接收来完成。 传统软件设计 举个例子&#xff0c;比如一个订单的创建在传统软…

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 NLP 部分

【CCF BDCI 2023】多模态多方对话场景下的发言人识别 Baseline 0.71 NLP 部分 概述NLP 简介文本处理词嵌入上下文理解 文本数据加载to_device 函数构造数据加载样本数量 len获取样本 getitem 分词构造函数调用函数轮次嵌入 RobertaRoberta 创新点NSP (Next Sentence Prediction…

如何将用户有过行为的item用list形式记录下来,另外如何计算list里的个数

导语&#xff1a; 最近做项目&#xff0c;发现有些语法想一想是知道&#xff0c;但实际操作起来跟想的情况不一样哈哈。不是遇见bug就是输出的结果不是自己想要的&#xff0c;CSDN跟知乎找了很多没怎么解决&#xff0c;后面多摸索多实操终于解决&#xff01; test_data[item_…

Oracle中LISTAGG 函数 的使用

概念&#xff1a;对于查询中的每个组&#xff0c;LISTAGG 聚合函数根据 ORDER BY 表达式对该组的行进行排序&#xff0c;然后将值串联成一个字符串

Appium微信小程序自动化环境准备

一、前置说明 微信从8.0.19开始内核从x5换成xweb之后&#xff0c;原先的开启webview调试的原方案已经会报503错误。 点击下面的链接&#xff0c;都会报503错误&#xff1a; http://debugmm.qq.com/?forcex5ture http://debugx5.qq.com 微信内核升级为xweb之后&#xff0c;需要…

数据结构之----逻辑结构、物理结构

数据结构之----逻辑结构、物理结构 目前我们常见的数据结构分别有&#xff1a; 数组、链表、栈、队列、哈希表、树、堆、图 而它们可以从 逻辑结构和物理结构两个维度进行分类。 什么是逻辑结构&#xff1f; 逻辑结构是指数据元素之间的逻辑关系&#xff0c;而逻辑结构又分为…

有趣的数学 数学建模入门三 数学建模入门示例两例 利用微积分求解

一、入门示例1 1、问题描述 某宾馆有150间客房&#xff0c;经过一段时间的经营&#xff0c;该宾馆经理得到一些数据&#xff1a;如果每间客房定价为200元&#xff0c;入住率为55&#xff05;&#xff1b;定价为180元&#xff0c;入住率为65&#xff05;&#xff1b;定价为160元…

PyTorch张量:内存布局

你可能对 torch 上的某些函数感到困惑&#xff0c;它们执行相同的操作但名称不同。 例如&#xff1a; reshape()、view()、permute()、transpose() 等。 这些函数的做法真的不同吗&#xff1f; 不&#xff01; 但为了理解它&#xff0c;我们首先需要了解一下张量在 pytorch 中…

AR-LDM原理及代码分析

AR-LDM原理AR-LDM代码分析pytorch_lightning(pl)的hook流程main.py 具体分析TrainSampleLightningDatasetARLDM blip mm encoder AR-LDM原理 左边是模仿了自回归地从1, 2, ..., j-1来构造 j 时刻的 frame 的过程。 在普通Stable Diffusion的基础上&#xff0c;使用了1, 2, .…

人工智能|深度学习——知识蒸馏

一、引言 1.1 深度学习的优点 特征学习代替特征工程&#xff1a;深度学习通过从数据中自己学习出有效的特征表示&#xff0c;代替以往机器学习中繁琐的人工特征工程过程&#xff0c;举例来说&#xff0c;对于图片的猫狗识别问题&#xff0c;机器学习需要人工的设计、提取出猫的…

产品<Axure的安装以及组件介绍

Axure介绍&#xff1a; Axure是一款用户体验设计工具&#xff0c;可以用于创建交互式原型、线框图和设计文档。它支持快速原型开发、界面设计、信息架构、流程图和注释等功能&#xff0c;可以帮助设计师快速地创建和共享交互式原型&#xff0c;从而更好地与客户和团队协作。 …

从 MQTT、InfluxDB 将数据无缝接入 TDengine,接入功能与 Logstash 类似

利用 TDengine Enterprise 和 TDengine Cloud 的数据接入功能&#xff0c;我们现在能够将 MQTT、InfluxDB 中的数据通过规则无缝转换至 TDengine 中&#xff0c;在降低成本的同时&#xff0c;也为用户的数据转换工作提供了极大的便捷性。由于该功能在实现及使用上与 Logstash 类…

「差生文具多系列」推荐两个好看的 Redis 客户端

&#x1f4e2; 声明&#xff1a; &#x1f344; 大家好&#xff0c;我是风筝 &#x1f30d; 作者主页&#xff1a;【古时的风筝CSDN主页】。 ⚠️ 本文目的为个人学习记录及知识分享。如果有什么不正确、不严谨的地方请及时指正&#xff0c;不胜感激。 直达博主&#xff1a;「…

总结6种@Transactional注解的失效场景

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 引言 昨天有粉丝咨询了…

【漏洞修复】Cisco IOS XE软件Web UI权限提升漏洞及修复方法

关于Cisco IOS XE软件Web UI权限提升漏洞及修复方法 文章目录 漏洞基本信息漏洞影响范围确认设备是否受影响漏洞修复方法推荐阅读 漏洞基本信息 Cisco IOS XE Unauthenticatd Remote Command Execution (CVE-2023-20198) (Direct Check) Severity:Critical Vulnerability Pri…

【Jeecg Boot 3 - 第二天】2.1、nginx 部署 JEECGBOOT VUE3

一、场景 二、实战 ▶ 2.1、打包&#xff08;build 前端&#xff09; &#xff1e; Stage 1&#xff1a;修改配置文件 .env.production&#xff08;作用&#xff1a;指向后端接口地址&#xff09; &#xff1e; Stage 2&#xff1a;点击build&#xff08;作用&#xff1…

动态规划——数塔问题(三维数组的应用)

一、例题要求及理论分析 声明&#xff1a;理论指导《算法设计与分析 第四版》 因为这个地方用到了三维数组&#xff0c;感觉很有意思就故意挑出来分享给大家&#xff08;三维数组可以看成很多页二维数组&#xff09; 4.5.1认识动态规划数塔问题&#xff1a; 如图4-12所示的一…