/*******************************************************
> File Name: test.c
> Author: hsz
> Mail:
> Created Time: Fri 11 Oct 2019 09:42:44 PM CST
******************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <error.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h> // the fellowing is linux header
#include <pthread.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define DEBUG
#define SERVER_STRING "Server: hszhttpd/1.0\r\n"
#define ROOT "/home/hsz/www/html"
#define isSpace(character) ((character == ' ') ? 1 : 0)
#ifdef DEBUG
#define ALOGD(fmt, ...) printf(fmt, ##__VA_ARGS__)
#else
#define ALOGD(fmt, ...) \
do{} while (0)
#endif
#define ALOGI(fmt, ...) printf(fmt, ##__VA_ARGS__)
int initSocket(uint16_t port);
void header(const int client, const char *type, const size_t length);
void notFoundHeader(int client, const char *type, const size_t length);
int getLine(const char *buf, char *dst, const uint16_t dstSize);
void getFileType(const char *src, char *fileType, uint32_t fileTypeBufSize);
void getContentType(const char *src, char *contentType, uint32_t contentTypeBufSize);
void process(int client);
void acceptRequest(void *val);
void doResponse(const int client, const char *recvBuf, const char *method, const char *url);
bool strCaseCmp(const char *str1, const char *str2);
void upper(char *str);
void sendHtml(const int client, const char *filePath);
int main()
{
uint16_t port = 80;
int httpd = initSocket(port);
if (httpd < 0)
{
return 1;
}
int client = 0;
struct sockaddr_in addr;
socklen_t addrSize = sizeof(struct sockaddr_in);
ALOGI("waiting for client...\n");
while (1)
{
client = accept(httpd, (struct sockaddr *)&addr, &addrSize);
if (client > 0)
{
ALOGI("[%s:%u] connected\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port));
process(client);
}
}
return 0;
}
void acceptRequest(void *val)
{
int client = (int)(intptr_t)val;
char recvBuf[1024];
int recvBufSize = sizeof(recvBuf);
while (1)
{
memset(recvBuf, 0, recvBufSize);
int length = recv(client, recvBuf, recvBufSize, 0);
if (length == 0)
{
ALOGI("client disconnected...\n");
break;
}
if (length < 0)
{
ALOGD("recv error: %s\n", strerror(errno));
break;
}
char line[512] = {0};
char url[256] = {0};
char method[16] = {0};
getLine(recvBuf, line, sizeof(line) - 1);
int i = 0, j = 0;
int lineSize = strlen(line);
for (; i < lineSize; ++i)
{
if (isSpace(line[i]))
{
method[i] = '\0';
break;
}
method[i] = line[i];
}
++i;
strcpy(url, ROOT);
j += strlen(ROOT);
for (; i < lineSize; ++i, ++j)
{
if (isSpace(line[i]))
{
url[j] = '\0';
break;
}
url[j] = line[i];
}
ALOGD("method: %s, url: \"%s\"\n", method, url);
doResponse(client, recvBuf, method, url);
}
ALOGD("--------------------------------------\n");
}
void doResponse(const int client, const char *recvBuf, const char *method, const char *url)
{
if (strCaseCmp(method, "POST"))
{
char *dataStartPos = strstr(recvBuf, "\r\n\r\n");
dataStartPos += strlen("\r\n\r\n") + 1;
ALOGD("%s() data: %s\n", __func__, dataStartPos);
// 处理数据
if (strstr(url, "login"))
{
}
}
if (strCaseCmp(method, "GET"))
{
if (strlen(url) < 20) // only /home/hsz/www/html/
{
sendHtml(client, "/home/hsz/www/html/login.html");
return;
}
sendHtml(client, url);
}
}
void sendHtml(const int client, const char *filePath)
{
char buf[1024];
char contentType[128] = {0};
char fileType[32] = {0};
getFileType(filePath, fileType, sizeof(fileType));
getContentType(fileType, contentType, sizeof(contentType));
FILE *fp = fopen(filePath, "r");
if(fp == NULL)
{
perror("fopen error");
FILE *fp404 = fopen("/home/hsz/www/html/404.html", "r");
if(fp404 == NULL)
{
ALOGD("connot found 404.html\n");
char *notFoundPage = "<html>"
"<TITLE>Not Found</TITLE>"
"<body>"
"<P>The server could not fulfill your request because the resource is unavailable.</P>"
"</body></html>";
notFoundHeader(client, "text/html", strlen(notFoundPage));
send(client, notFoundPage, strlen(notFoundPage), 0);
return;
}
fseek(fp404, 0, SEEK_END);
size_t length = ftell(fp404);
fseek(fp404, 0, SEEK_SET);
notFoundHeader(client, "text/html", length);
while (!feof(fp404))
{
memset(buf, 0, sizeof(buf));
size_t readSize = fread(buf, sizeof(buf[0]), sizeof(buf), fp404);
send(client, buf, readSize, 0);
}
fclose(fp404);
return;
}
fseek(fp, 0, SEEK_END);
size_t length = ftell(fp);
fseek(fp, 0, SEEK_SET);
header(client, contentType, length);
while (!feof(fp))
{
memset(buf, 0, sizeof(buf));
size_t readSize = fread(buf, sizeof(buf[0]), sizeof(buf), fp);
send(client, buf, readSize, 0);
}
fclose(fp);
}
void getFileType(const char *src, char *fileType, uint32_t fileTypeBufSize)
{
size_t size = strlen(src);
size_t index = size;
for(size_t i = size - 1; i > 0; --i)
{
if(src[i] == '.')
{
index = i + 1;
break;
}
}
if(strlen(src + index) < fileTypeBufSize)
{
strcpy(fileType, src + index);
}
}
void getContentType(const char *src, char *contentType, uint32_t contentTypeBufSize)
{
if(strCaseCmp(src, "html"))
{
snprintf(contentType, contentTypeBufSize, "text/html");
return;
}
if(strCaseCmp(src, "css"))
{
snprintf(contentType, contentTypeBufSize, "text/css");
return;
}
if(strCaseCmp(src, "js"))
{
snprintf(contentType, contentTypeBufSize, "application/x-javascript");
return;
}
if(strCaseCmp(src, "ico"))
{
snprintf(contentType, contentTypeBufSize, "image/x-icon");
return;
}
if(strCaseCmp(src, "jpg") || strCaseCmp(src, "jpeg"))
{
snprintf(contentType, contentTypeBufSize, "image/jpeg");
return;
}
if(strCaseCmp(src, "png"))
{
snprintf(contentType, contentTypeBufSize, "image/png");
return;
}
ALOGI("unknown type \"%s\"\n", src);
}
bool strCaseCmp(const char *str1, const char *str2)
{
size_t size1 = strlen(str1);
size_t size2 = strlen(str2);
if (size1 != size2)
{
return false;
}
char *tmp1 = (char *)malloc(size1 + 1);
char *tmp2 = (char *)malloc(size1 + 1);
strcpy(tmp1, str1);
strcpy(tmp2, str2);
upper(tmp1);
upper(tmp2);
bool index = true;
for (size_t i = 0; i < size1; ++i)
{
if (tmp1[i] != tmp2[i])
{
index = false;
break;
}
}
free(tmp1);
free(tmp2);
return index;
}
void upper(char *str)
{
size_t size = strlen(str);
for (size_t i = 0; i < size; ++i)
{
if ('a' <= str[i] && str[i] <= 'z')
{
str[i] = str[i] - 'a' + 'A';
}
}
}
void process(int client)
{
pthread_t pid;
pthread_attr_t attrDetach;
pthread_attr_init(&attrDetach);
pthread_attr_setdetachstate(&attrDetach, PTHREAD_CREATE_DETACHED);
pthread_create(&pid, &attrDetach, (void *)acceptRequest, (void *)(intptr_t)client);
}
int initSocket(uint16_t port)
{
int httpd = 0;
struct sockaddr_in srvAddr;
httpd = socket(AF_INET, SOCK_STREAM, 0);
if (httpd < 0)
{
perror("socket error");
return -1;
}
memset(&srvAddr, 0, sizeof(srvAddr));
srvAddr.sin_family = AF_INET;
srvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
srvAddr.sin_port = htons(port);
int value = 1;
if (setsockopt(httpd, SOL_SOCKET, SO_REUSEADDR, (const void *)&value, sizeof(int)) < 0)
{
perror("setsockopt error");
return -1;
}
if (bind(httpd, (struct sockaddr *)&srvAddr, sizeof(srvAddr)) < 0)
{
perror("bind error");
return -1;
}
if (listen(httpd, 16) < 0)
{
perror("listen error");
return -1;
}
return httpd;
}
void header(const int client, const char *type, const size_t length)
{
if (client <= 0 || !type || length <= 0)
{
ALOGD("check your param\n");
return;
}
char buf[1024] = {0};
sprintf(buf, "HTTP/1.1 200 OK\r\n"
"%s"
"Content-Length: %zu\r\n"
"Content-Type: %s\r\n\r\n",
SERVER_STRING, length, type);
send(client, buf, strlen(buf), 0);
}
void notFoundHeader(int client, const char *type, const size_t length)
{
if (client <= 0 || !type || length <= 0)
{
ALOGD("check your param\n");
return;
}
char buf[1024] = {0};
sprintf(buf, "HTTP/1.1 404 NOT FOUND\r\n"
"%s"
"Content-Length: %zu\r\n"
"Content-Type: %s\r\n\r\n",
SERVER_STRING, length, type);
send(client, buf, strlen(buf), 0);
}
int getLine(const char *buf, char *dst, const uint16_t dstSize)
{
if (!buf || !dst || dstSize <= 0)
{
ALOGD("check your param\n");
return -1;
}
int bufSize = strlen(buf);
int i;
for (i = 0; i < bufSize && i < dstSize; ++i)
{
if (buf[i] == '\r' && buf[i + 1] == '\n')
{
dst[i] = '\0';
break;
}
dst[i] = buf[i];
}
return i;
}
C实现的小型的httpserver
最新推荐文章于 2024-03-04 00:13:09 发布
本文介绍了一个简易HTTP服务器的实现过程,包括初始化套接字、处理客户端请求、发送响应头及内容等关键步骤。服务器能够解析HTTP请求,支持GET和POST方法,并能根据不同文件类型返回相应的Content-Type。
3721

被折叠的 条评论
为什么被折叠?



