为了更好的了解HTTP协议, 特意谢了一个简单HTTP服务器, 代码只有400行. 因为很简单, 所以效率也不怎么高,
而且支持的特性也不多, 不过也可以运行, 性能跟Apache差不多.
=============================================================================================
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define BUFFER_INIT_SIZE 512
enum {
mickey_reading_header_stage,
mickey_writing_header_stage,
mickey_writing_body_stage,
mickey_closing_stage
};
enum {
mickey_http_ok,
mickey_http_notfound,
mickey_http_error
};
enum {
mickey_method_get,
mickey_method_head,
mickey_method_unknow
};
typedef struct {
char
*buff;
int
size;
int
free;
} mickey_buffer_t;
typedef struct {
int
sock;
mickey_buffer_t *request;
mickey_buffer_t *response;
int
keepalive;
int
method;
mickey_buffer_t *uri;
int
status;
int
stage;
FILE
*handle;
} mickey_connection_t;
static int srv_sock;
mickey_buffer_t *mickey_buffer_new() {
mickey_buffer_t *object;
object =
malloc(sizeof(*object));
if (object)
{
object->buff = malloc(BUFFER_INIT_SIZE + 1);
if (!object->buff) {
free(object);
return NULL;
}
object->size = BUFFER_INIT_SIZE;
object->free = BUFFER_INIT_SIZE;
}
return
object;
}
int mickey_buffer_append_length(mickey_buffer_t *buf, void
*data, int length) {
int lack,
need = 0;
char
*temp;
if (length
> buf->free) {
lack = length - buf->free;
while (need < lack)
need += BUFFER_INIT_SIZE;
temp = realloc(buf->buff, buf->size +
need + 1);
if (!temp)
return -1;
buf->buff = temp;
buf->size += need;
buf->free += need;
}
memcpy(buf->buff + (buf->size -
buf->free), data, length);
buf->free -= length;
buf->buff[buf->size -
buf->free] = '\0';
return
0;
}
int mickey_buffer_append(mickey_buffer_t *buf, void *data)
{
return
mickey_buffer_append_length(buf, data, strlen((char *)data));
}
int mickey_buffer_find_string(mickey_buffer_t *buf, char *str)
{
int idx =
buf->size - buf->free;
int slen =
strlen(str);
int i;
for (i = 0;
i < idx; i++) {
if (idx - i >= slen) {
if (!memcmp(buf->buff + i, str, slen)) return
1;
} else {
break;
}
}
return
0;
}
int mickey_buffer_length(mickey_buffer_t *buf) {
return
buf->size - buf->free;
}
void mickey_buffer_print(mickey_buffer_t *buf) {
fprintf(stderr, "%s", buf->buff);
}
void mickey_buffer_clean(mickey_buffer_t *buf) {
buf->free = buf->size;
}
void mickey_buffer_free(mickey_buffer_t *buf) {
if
(!buf)
return;
if
(buf->buff)
free(buf->buff);
free(buf);
}
int mickey_header_finish(mickey_connection_t *conn) {
int end =
conn->request->size -
conn->request->free;
if
(conn->request->buff[end - 1] == '\n'
&&
conn->request->buff[end - 2] == '\r'
&&
conn->request->buff[end - 3] == '\n'
&&
conn->request->buff[end - 4] ==
'\r')
return 1;
return
0;
}
void mickey_parse_header(mickey_connection_t *conn) {
char
*eol;
char
method[16], uri[256], protocol[32];
eol =
strchr(conn->request->buff,
'\n');
if (eol ==
NULL) {
conn->stage = mickey_closing_stage;
return;
}
if (*(eol-1)
== '\r')
*(eol-1) = '\0';
*eol =
'\0';
sscanf(conn->request->buff, "s %6s
2s", method, uri, protocol);
if
(!strcmp(method, "GET")) {
conn->method = mickey_method_get;
} else if
(!strcmp(method, "HEAD")) {
conn->method = mickey_method_head;
} else
{
conn->method = mickey_method_unknow;
}
mickey_buffer_append(conn->uri, ".");
mickey_buffer_append(conn->uri, uri);
if
(mickey_buffer_find_string(conn->uri, "..")) {
fprintf(stderr, "[x] mickey found connection header exists
(..)\n");
conn->stage = mickey_closing_stage;
}
}
void connection_reading_header(mickey_connection_t *conn)
{
char
buff[1024];
int
nrecv;
nrecv =
read(conn->sock, buff, 1024);
if (nrecv
> 0) {
mickey_buffer_append_length(conn->request, buff,
nrecv);
if (mickey_header_finish(conn)) {
mickey_parse_header(conn);
conn->stage = mickey_writing_header_stage;
}
} else
{
fprintf(stderr, "[x] mickey cannot read data from
connection.\n");
conn->stage = mickey_closing_stage;
}
}
void connection_make_header(mickey_connection_t *conn) {
struct stat
stat_buf;
if
(stat(conn->uri->buff,
&stat_buf) == -1) {
conn->status = mickey_http_notfound;
mickey_buffer_append(conn->response, "HTTP/1.0 404
Not Found\r\n");
} else
{
if (S_ISDIR(stat_buf.st_mode)) {
mickey_buffer_append(conn->uri, "index.html");
if (stat(conn->uri->buff,
&stat_buf) == -1) {
conn->status = mickey_http_notfound;
mickey_buffer_append(conn->response, "HTTP/1.0 404
Not Found\r\n");
} else {
char content_length[256];
conn->handle =
fopen(conn->uri->buff, "r");
if (!conn->handle) {
mickey_buffer_append(conn->response, "HTTP/1.0 500
Internal Server Error\r\n");
} else {
mickey_buffer_append(conn->response, "HTTP/1.0 200
OK\r\n");
sprintf(content_length, "Content-Length: %d\r\n",
stat_buf.st_size);