一、HttpResponse的定义
1.定义状态码枚举
// 定义状态码枚举
enum HttpStatusCode {
Unknown = 0,
OK = 200,
MovedPermanently = 301,
MovedTemporarily = 302,
BadRequest = 400,
NotFound = 404
};
2.HTTP 响应报文格式
这个数据块主要是分为四部分
- 第一部分是状态行
- 第二部分是响应头
- 第三部分是一个空行
- 第四部分是给客户端回复的数据块
// 定义响应的结构体
struct ResponseHeader {
char key[32];
char value[128];
};
// 定义一个函数指针,用来组织要回复给客户端的数据块
typedef void (*responseBody) (const char* fileName,struct Buffer* sendBuf,int socket);
// 定义结构体
struct HttpResponse {
// 状态行:状态码,状态描述
enum HttpStatusCode statusCode;
char statusMsg[128];
// 响应头 - 键值对
struct ResponseHeader* headers;
int headerNum;
responseBody sendDataFunc;
// 文件名
char fileName[128];
};
服务器回复给客户端的数据,取决于客户端向服务器请求了什么类型的资源,有可能它请求的是一个目录,有可能请求的是一个文件,这个文件有可能是一个文本文件,也可能是一个图片,还可能是mp3...需要根据客户端的请求去回复相应的数据。所以如何去组织这个需要回复的数据块呢?
// 定义一个函数指针,用来组织要回复给客户端的数据块
typedef void (*responseBody) (const char* fileName,struct Buffer* sendBuf,int socket);
fileName:分成两类,一类是目录类型,一类是非目录类型的文件
- 如果是目录,就去遍历目录
- 如果是文件,就读取其内容
sendBuf:在进行套接字的通信过程中:
- 如果要回复数据(给客户端发数据),发送的数据要先存储到sendBuf里边,再发送给客户端.
socket:就是用来通信的文件描述符,通过这个用于通信的文件描述符,就能够把写入到sendBuf里边的数据发送给客户端,sendBuf里边的数据就是我们组织好的Http响应的数据块
- 定义一个函数指针,用来组织要回复给客户端的数据块
responseBody sendDataFunc;
二、HttpResponse的初始化
// 初始化
struct HttpResponse* httpResponseInit();
#define ResHeaderSize 16
// 初始化
struct HttpResponse* httpResponseInit() {
struct HttpResponse* response = (struct HttpResponse*)malloc(sizeof(struct HttpResponse));
// 状态行:状态码,状态描述
response->statusCode = Unknown;
bzero(response->statusMsg,sizeof(response->statusMsg));
// 响应头 - 键值对
int size = sizeof(struct ResponseHeader) * ResHeaderSize;
response->headers = (struct ResponseHeader*)malloc(size);
bzero(response->headers, size);
response->headerNum = 0;
// 函数指针
response->sendDataFunc = NULL;
// 文件名
bzero(response->fileName,sizeof(response->fileName));
return response;
}
三、HttpResponse的销毁 内存释放
// 销毁
void httpResponseDestroy(struct HttpResponse* response);
// 销毁
void httpResponseDestroy(struct HttpResponse* response) {
if(response!=NULL) {
free(response->headers);
free(response);
}
}
四、添加响应头
// 添加响应头
void httpResponseAddHeader(struct HttpResponse* response,const char* key,const char* value);
// 添加响应头
void httpResponseAddHeader(struct HttpResponse* response,const char* key,const char* value){
if(response == NULL || key == NULL || value == NULL) {
return;
}
strcpy(response->headers[response->headerNum].key,key);
strcpy(response->headers[response->headerNum].value,value);
response->headerNum++;
}
五、组织http响应数据
// 组织http响应数据
void httpResponsePrepareMsg(struct HttpResponse* response,struct Buffer* sendBuf,int socket);
// 组织http响应数据
void httpResponsePrepareMsg(struct HttpResponse* response,struct Buffer* sendBuf,int socket) {
// 状态行
char tmp[1024] = {0};
sprintf(tmp,"HTTP/1.1 %d %s\r\n",response->statusCode,response->statusMsg);
bufferAppendString(sendBuf,tmp);
// 响应头
for(int i=0;i<response->headerNum;++i) {
// memset(tmp,0,sizeof(tmp)); ?????????
sprintf(tmp,"%s: %s\r\n",response->headers[i].key,response->headers[i].value);
bufferAppendString(sendBuf,tmp);
}
// 空行
bufferAppendString(sendBuf,"\r\n");
// 回复的数据
response->sendDataFunc(response->fileName,sendBuf,socket);
}