生成http响应数据【Linux服务器编程】

前言

非常感谢社长的开源项目TinyWebServer,让我这个自学服务器编程的小白也能感觉受益匪浅

所需前置知识

  1. va_list 解决变参问题 头文件:<stdarg.h> 重点!在本项目中实现了代码复用,减少代码量
  2. http响应报文格式
  3. 基础makefile知识

数据结构

http状态码

//本次仅用到个别状态,可根据需求更改代码
enum HTTP_CODE {
    NO_REQUEST = 0,//http解析用到
    GET_REQUEST,//http解析用到
    BAD_REQUEST,//http解析用到
    NO_RESOURCE,
    FORBIDDEN_REQUEST,
    FILE_REQUEST,
    INTERNAL_ERROR,
    CLOSED_CONNECTION
  };

状态码描述

//响应状态描述
const char *ok_200_title = "OK";
const char *ok_200_form = "<html><body></body></html>";
const char *error_400_title = "Bad Request";
const char *error_400_form = "Your request has bad syntax or is inherently impossible to staisfy.\n";
const char *error_403_title = "Forbidden";
const char *error_403_form = "You do not have permission to get file form this server.\n";
const char *error_404_title = "Not Found";
const char *error_404_form = "The requested file was not found on this server.\n";
const char *error_500_title = "Internal Error";
const char *error_500_form = "There was an unusual problem serving the request file.\n";

项目结构

在这里插入图片描述

SourceCode

http_respond.h

#ifndef HTTP_RESPOND_H
#define HTTP_RESPOND_H
#include <stdarg.h>
#include <stdio.h>

class Data {
public:
  static const int WRITE_BUFFER_SIZE = 2048;

  enum HTTP_CODE {
    NO_REQUEST = 0,
    GET_REQUEST,
    BAD_REQUEST,
    NO_RESOURCE,
    FORBIDDEN_REQUEST,
    FILE_REQUEST,
    INTERNAL_ERROR,
    CLOSED_CONNECTION
  };

public:
  Data() {}
  ~Data() {}

public:
  void init(int sockfd,bool is_alive); //初始化数据
  bool process_write(HTTP_CODE ret);

private:
  bool add_response(const char *format, ...); //可变参写入数据
  bool add_status_line(int status, const char *title);
  bool add_headers(int content_len);
  bool add_content(const char *content);
  bool add_content_type();
  bool add_content_length(int content_len);
  bool add_linger();
  bool add_blank_line();
  void init();

private:
  int m_sockfd;
  int m_write_index;
  int m_linger;
  char m_write_buf[WRITE_BUFFER_SIZE];
};

#endif

http_respond.cpp

#include "./http_respond.h"
#include "string.h"
#include "iostream"
#include "stdarg.h"

//响应状态描述
const char *ok_200_title = "OK";
const char *ok_200_form = "<html><body></body></html>";
const char *error_400_title = "Bad Request";
const char *error_400_form = "Your request has bad syntax or is inherently impossible to staisfy.\n";
const char *error_403_title = "Forbidden";
const char *error_403_form = "You do not have permission to get file form this server.\n";
const char *error_404_title = "Not Found";
const char *error_404_form = "The requested file was not found on this server.\n";
const char *error_500_title = "Internal Error";
const char *error_500_form = "There was an unusual problem serving the request file.\n";


void Data::init(int sockfd,bool is_alive){
    m_sockfd=sockfd;
    m_linger=is_alive;
    init();
}
void Data::init(){
    m_write_index=0;
    memset(m_write_buf,'\0',WRITE_BUFFER_SIZE);
}

bool Data::process_write(HTTP_CODE ret){
    switch(ret){
        case INTERNAL_ERROR:{
            add_status_line(500,error_500_title);
            add_headers(strlen(error_500_form));
            if(!add_content(error_500_form))
                return false;
            break;
        }
        case BAD_REQUEST:{
            add_status_line(404,error_404_title);
            add_headers(strlen(error_404_form));
            if(!add_content(error_404_form))
                return false;
            break;
        }
        case FORBIDDEN_REQUEST:{
            add_status_line(403,error_403_title);
            add_headers(strlen(error_403_form));
            if(!add_content(error_403_form))    
                return false;
            break;
        }
        case FILE_REQUEST:{
            add_status_line(200,ok_200_title);
            add_headers(strlen(ok_200_form));
            if(!add_content(ok_200_form))
                return false;
            break;
        }
        default:
            return false; 
    }
    std::cout<<m_sockfd<<"号客户http响应:"<<std::endl;
    std::cout<<m_write_buf<<std::endl;
}

// 可变参数写 核心代码
bool Data::add_response(const char *format,...){
    if(m_write_index>=WRITE_BUFFER_SIZE)
        return false;    

    va_list arg_list;
    va_start(arg_list,format);

    int len=vsnprintf(m_write_buf+m_write_index,WRITE_BUFFER_SIZE-1-m_write_index,format,arg_list);

    if(len>=WRITE_BUFFER_SIZE-1-m_write_index){
        va_end(arg_list);
        return false;
    }

    m_write_index+=len;

    va_end(arg_list);

    return true;
}


bool Data::add_status_line(int status,const char *title){
    return add_response("%s %d %s\r\n","HTTP/1.1",status,title);
}

bool Data::add_headers(int content_len){
    add_content_length(content_len);
    add_linger();
    add_blank_line();
}

bool Data::add_content_length(int content_len){
    return add_response("Content-Length:%d\r\n",content_len);
}

bool Data::add_content_type(){
    return add_response("Content-Type:%s\r\n","text/html");
}

bool Data::add_linger(){
    return add_response("Connection:%s\r\n",(m_linger==true)?"keep-alive":"close");
}

bool Data::add_content(const char *content){
    return add_response("%s",content);
}

bool Data::add_blank_line(){
    return add_response("%s","\r\n");
}

main.c

#include <iostream>
#include "http/http_respond.h"
int main(){
    Data client1;
    client1.init(1,true);
    client1.process_write(Data::BAD_REQUEST);

    Data client2;
    client2.init(2,false);
    client2.process_write(Data::FILE_REQUEST);

    Data client3;
    client1.init(3,true);
    client1.process_write(Data::INTERNAL_ERROR);

    Data client4;
    client1.init(4,true);
    client1.process_write(Data::FORBIDDEN_REQUEST);
}

makefile


target1 = response
target2= responseDebug
src = $(wildcard ./*.c ./http/*.cpp ./http/*.h)

#release版本 make response
$(target1):$(src)
	g++ $^ -o $@

#debug版本 make responseDebug
$(target2):$(src)
	g++ $^ -g -o $@
	
clean:
	-rm -f $(target1) $(target2)

结果

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值