小的纯cwebserver实现

/* Copyright (C) 2007 Cosmin Gorgovan <cosmin@linux-geek.org>

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, version 2 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */

/* qshttpd is a lightweight http server. It was tested only under Linux.
It is quite fast when handling small files, actually about 6 times faster
then Apache. I think it is useful to serve static content from your site. 
Home page: www.linux-geek.org/qshttpd/ */

/* Version 0.3.0 - alpha software
See qshttpd.conf for a configuration example. */

/* TODO: logging, virtual hosts */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <pwd.h>
#include <grp.h>

#define BACKLOG 10

//Variables used in get_conf().
char conf[5], dir[500], port[10], charset[200], user[100], group[100];
int portf;

//Sockets stuff
int sockfd, new_fd;
struct sockaddr_in their_addr;
socklen_t sin_size;
struct sigaction sa;

//Other global variables
int buffer_counter;
char * buffer;
FILE *openfile;

void read_chunk() {
    fread (buffer,1,1048576,openfile);
    buffer_counter++;
}

void sigchld_handler(int s)
{
    while(waitpid(-1, NULL, WNOHANG) > 0);
}

//Chroot and change user and group to nobody. Got this function from Simple HTTPD 1.0.
void drop_privileges() {
    struct passwd *pwd;
    struct group *grp;

    if ((pwd = getpwnam(user)) == 0)
    {
    	fprintf(stderr, "User not found in /etc/passwd\n");
    	exit(1);
    }

    if ((grp = getgrnam(group)) == 0)
    {
    	fprintf(stderr, "Group not found in /etc/group\n");
    	exit(1);
    }
    if (chdir(dir) != 0)
    {
    	fprintf(stderr, "chdir(...) failed\n");
    	exit(1);
    }

    if (chroot(dir) != 0)
    {
    	fprintf(stderr, "chroot(...) failed\n");
    	exit(1);
    }

    if (setgid(grp->gr_gid) != 0)
    {
    	fprintf(stderr, "setgid(...) failed\n");
    	exit(1);
    }

    if (setuid(pwd->pw_uid) != 0)
    {
    	fprintf(stderr, "setuid(...) failed\n");
    	exit(1);
    }

}

void get_conf() {
    FILE *conffile;
    conffile = fopen ("/etc/qshttpd.conf", "r");

    while (fgets (conf , 6, conffile)) {
    if (strcmp (conf, "ROOT=") == 0){
        fgets (dir, 500, conffile);
        strtok(dir, "\n");
    }
    if (strcmp (conf, "PORT=") == 0){
        fgets (port, 10, conffile);
        portf=atoi(port);
    }
    if (strcmp (conf, "CHAR=") == 0){
        fgets (charset, 200, conffile);
        strtok(charset, "\n");
    }
    if (strcmp (conf, "USER=") == 0){
        fgets (user, 100, conffile);
        strtok(user, "\n");
    }
    if (strcmp (conf, "GRUP=") == 0){
        fgets (group, 100, conffile);
        strtok(group, "\n");
    }
    } 
    fclose (conffile);
}

void create_and_bind() {
    int yes=1;
    struct sockaddr_in my_addr;

    if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) == -1) {
        perror("socket");
        exit(1);
    }

    if (setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int)) == -1) {
        perror("setsockopt");
        exit(1);
    }

    my_addr.sin_family = AF_INET;
    my_addr.sin_port = htons(portf);
    my_addr.sin_addr.s_addr = INADDR_ANY;
    memset(&(my_addr.sin_zero), '\0', 8);

    if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
        perror("bind");
        exit(1);
    }

    drop_privileges();

    if (listen(sockfd, BACKLOG) == -1) {
        perror("listen");
        exit(1);
    }

    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART;
    if (sigaction(SIGCHLD, &sa, NULL) == -1) {
        perror("sigaction");
        exit(1);
    }
}

int main(void)
{
    char in[3000],  sent[500], code[50], file[200], mime[100], moved[200], length[100], auth[200], auth_dir[500], start[100], end[100];
    char *result=NULL, *hostname, *hostnamef, *lines, *ext=NULL, *extf, *auth_dirf=NULL, *authf=NULL, *rangetmp;
    int buffer_chunks;
    long filesize, range=0;

    get_conf();
    create_and_bind();

    //Important stuff happens here.

    while(1) {
        sin_size = sizeof(struct sockaddr_in);
        if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == -1) {
            perror("accept");
            continue;
        }

        if (!fork()) {
            close(sockfd);
        if (read(new_fd, in, 3000) == -1) {
    	perror("recive");
        } else {
    	lines = strtok(in, "\n\r");
    	do {
    	    hostname = strtok(NULL, "\n\r");
    		if (hostname[0] == 'R' && hostname[1] == 'a' && hostname[2] == 'n' && hostname[3] == 'g' && hostname[4] == 'e') {
    			rangetmp = hostname;
    			strcpy(code, "206 Partial Content");
    		}
    	} while (hostname[0] != 'H' || hostname[1] != 'o' || hostname[2] != 's' || hostname[3] != 't');
    	hostnamef = strtok(hostname, " ");
    	hostnamef = strtok(NULL, " ");
    	result = strtok(lines, " ");
    	result = strtok(NULL, " ");
    	if (strcmp(code, "206 Partial Content") == 0 ) {
    		rangetmp = strtok(strpbrk(rangetmp, "="), "=-");
    		range = atoi(rangetmp);
    	}

    	strcpy(file, result);
    	if (opendir(file)){
    	    if (file[strlen(file)-1] == '/'){
                    strcat(file, "/index.html");
    		openfile=fopen (file, "r");
                        if (openfile){
                            strcpy(code, "200 OK");
                        } else {
    		    //Here should be some kind of directory listing
    		    strcpy(file, "/404.html");
    		    openfile = fopen (file, "r");
    		    strcpy(code, "404 Not Found");
    		}
    	    } else {
    		strcpy(code, "301 Moved Permanently");
    		strcpy(moved, "Location: http://");
    		strcat(moved, hostnamef);
    		strcat(moved, result);
    		strcat(moved, "/");
    	    }
    	} else {
    	    openfile=fopen (file, "rb");
                if (openfile){
    		if (strlen(code) < 1) {
                    	strcpy (code, "200 OK");
    		}
                } else {
    		strcpy(file, "/404.html");
    		openfile = fopen (file, "r");
                    strcpy(code, "404 Not Found");
                }
                }
        }
        if (strcmp(code, "301 Moved Permanently") != 0){
    	fseek (openfile , 0 , SEEK_END);
                filesize = ftell (openfile);
        	rewind (openfile);
    	if (range > 0) {
    		sprintf(end, "%d", filesize);
    		filesize = filesize - range;
    		sprintf(start, "%d", range);
    		fseek (openfile , range , SEEK_SET);
    	}
    	buffer_chunks = filesize/1048576;
    	if(filesize%1048576 > 0){
    		buffer_chunks++;
    	}
    	sprintf(length, "%d", filesize);
    	buffer_counter = 0;
    	buffer = (char*) malloc (sizeof(char)*1048576);
        }

        if (strcmp(code, "404 Not Found") != 0 && strcmp(code, "301 Moved Permanently") !=0){
    	ext = strtok(file, ".");
            while(ext != NULL){
    	    ext = strtok(NULL, ".");
        	    if (ext != NULL){
    		extf = ext;
    	    }
    	}
        } else {
    	extf="html";
        }

        /* Maybe I should read mime types from a file. At least for now, add here what you need.*/

        if (strcmp(extf, "html") == 0){
    	strcpy (mime, "text/html");
            } else if(strcmp(extf, "jpg") == 0){
    	strcpy (mime, "image/jpeg");
        } else if(strcmp(extf, "gif") == 0){
    	strcpy (mime, "image/gif");
        } else if(strcmp(extf, "css") == 0){
    	strcpy (mime, "text/css");
        } else {
    	strcpy(mime, "application/octet-stream");
        }

        strcpy(sent, "HTTP/1.1 ");
        strcat(sent, code);
        strcat(sent, "\nServer: qshttpd 0.3.0\n");
        if(strcmp(code, "301 Moved Permanently") == 0){
    	strcat(sent, moved);
    	strcat(sent, "\n");
        }

        strcat(sent, "Content-Length: ");
        if(strcmp(code, "301 Moved Permanently") != 0){
            strcat(sent, length);
        } else {
    	strcat(sent, "0");
        }
        if(strcmp(code, "206 Partial Content") == 0) {
    	strcat(sent, "\nContent-Range: bytes ");
    	strcat(sent, start);
    	strcat(sent, "-");
    	strcat(sent, end);
    	strcat(sent, "/");
    	strcat(sent, end);
    }
        strcat(sent, "\nConnection: close\nContent-Type: ");
        strcat(sent, mime);
        strcat(sent, "; charset=");
        strcat(sent, charset);
        strcat(sent, "\n\n");
        write(new_fd, sent, strlen(sent));
    	while (buffer_counter < buffer_chunks) {
    		read_chunk();
    		write(new_fd, buffer, 1048576);
    	}
        close(new_fd);
            exit(0);
        }
        close(new_fd);
    }
    return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: vbrichclient5.cwebserver是一个使用VBRichClient 5平台开发的C语言网络服务器程序。VBRichClient 5是一个用于开发跨平台桌面应用程序的集成开发环境(IDE),它支持C、C++和其他语言的开发,并提供了丰富的图形用户界面(GUI)和网络通信功能。 vbrichclient5.cwebserver使用C语言编写,主要用于创建和管理基于Web的应用程序。它具有基本的网络服务器功能,能够处理HTTP请求并提供响应。通过这个服务器程序,开发人员可以创建Web应用程序并支持网页浏览器的访问。 vbrichclient5.cwebserver使用了VBRichClient 5提供的网络通信库,从而实现了与客户端的TCP/IP通信。它能够处理来自客户端的请求,如GET、POST等,并根据请求的内容生成相应的响应。同时,vbrichclient5.cwebserver还支持会话管理、身份验证等功能,保证了安全和可靠的通信。 vbrichclient5.cwebserver在功能和性能上比较灵活和可靠。它提供了多线程和并发处理能力,能够同时处理多个客户端的请求。此外,它还支持自定义的插件和扩展功能,方便开发人员根据实际需求进行功能的定制和扩展。 总而言之,vbrichclient5.cwebserver是一个基于VBRichClient 5平台开发的C语言网络服务器程序,它提供了基本的Web服务器功能,能够处理HTTP请求并生成相应的响应。它具有灵活的功能和良好的性能,适用于开发各种Web应用程序。 ### 回答2: vbrichclient5.cwebserver是一个基于VB Rich Client技术开发的用于构建和管理Web服务器应用程序的工具。它提供了一套强大的功能,使开发者能够轻松地创建具有交互性和动态性的Web应用程序。 该工具的优势在于它具有用户友好的界面和简化的操作流程,使开发者能够快速地构建出高效和安全的Web服务器应用。同时,它还提供了丰富的功能模块,包括但不限于:路由管理、会话管理、数据库连接、安全性控制等。使用这些功能,开发者可以轻松地完成Web服务器应用的开发和部署。 vbrichclient5.cwebserver还支持多种开发语言和框架,如VB.NET、ASP.NET等。这样一来,开发者可以根据自己的喜好和需求选择合适的语言和框架进行开发。另外,该工具还提供了一系列的API和插件,方便开发者进行二次开发和定制。 该工具还具有高性能和可扩展性的特点。它使用了先进的技术和优化的算法,能够在高并发的情况下保持良好的性能。同时,它还具备可扩展性,可以方便地与其他系统进行集成和交互,在满足不同业务需求的同时保持系统的稳定性。 总之,vbrichclient5.cwebserver是一个功能强大且易于使用的Web服务器开发工具。它能够帮助开发者快速构建高效、安全和可扩展的Web应用程序,并提供丰富的功能模块和插件供开发者使用。无论是初学者还是有经验的开发者,都可以通过这个工具轻松实现他们的Web服务器开发需求。 ### 回答3: vbrichclient5.cwebserver是一个具有丰富功能的VB(Visual Basic)代码库,它提供了用于创建和管理基于Web的应用程序的工具和功能。 首先,vbrichclient5.cwebserver包含了一些用于处理HTTP请求和响应的函数和方法。这些函数和方法使我们能够轻松地创建和管理Web服务器,包括处理GET和POST请求,解析URL参数和表单数据,以及生成和发送HTTP响应。 其次,vbrichclient5.cwebserver还提供了一些用于处理会话管理和用户认证的功能。通过这些功能,我们可以轻松地创建和管理用户会话,对用户进行身份验证,并限制对某些资源的访问。这对于创建安全和受保护的Web应用程序是非常有用的。 此外,vbrichclient5.cwebserver还包含了一些用于处理静态和动态内容的函数和方法。这些功能使我们能够轻松地向Web服务器添加静态文件(如HTML,CSS和JavaScript文件)和动态内容(如ASP和VBScript代码),并且能够动态生成和呈现内容。 另外,vbrichclient5.cwebserver还包含了一些用于处理数据库连接和查询的工具和功能。通过这些工具和功能,我们可以轻松地连接和查询数据库,执行各种数据库操作,如插入,更新和删除数据,从数据库中检索数据,并将其用于Web应用程序中。 总之,vbrichclient5.cwebserver是一个非常有用的VB代码库,它提供了丰富的功能和工具,用于创建和管理基于Web的应用程序。无论是处理HTTP请求和响应,还是进行会话管理和用户认证,还是处理静态和动态内容,甚至是连接和查询数据库,vbrichclient5.cwebserver都能够方便地帮助我们实现这些功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值