Init
This commit is contained in:
commit
d7b6efe058
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
*
|
||||
!.gitignore
|
||||
!CMakeLists.txt
|
||||
!httplib.h
|
||||
!httplib_internal.h
|
||||
!httplib.c
|
||||
!httputil.c
|
||||
!httpser.c
|
||||
!httpparse.c
|
6
CMakeLists.txt
Normal file
6
CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
cmake_minimum_required(VERSION 3.10.2)
|
||||
project(simplehttplib C)
|
||||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
|
||||
add_library(simplehttplib STATIC httplib.c httputil.c httpparse.c httpser.c httplib.h httplib_internal.h)
|
103
httplib.c
Normal file
103
httplib.c
Normal file
|
@ -0,0 +1,103 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "httplib.h"
|
||||
#include "httplib_internal.h"
|
||||
|
||||
int rfd;
|
||||
|
||||
int start_http_server(int port, http_request_handler handler) {
|
||||
|
||||
rfd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (rfd < 0) {
|
||||
return SOCKET_ERROR;
|
||||
}
|
||||
int option = 1;
|
||||
setsockopt(rfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(int));
|
||||
|
||||
struct sockaddr_in server;
|
||||
struct sockaddr client;
|
||||
socklen_t client_len = sizeof(struct sockaddr);
|
||||
|
||||
server.sin_family = AF_INET;
|
||||
server.sin_addr.s_addr = INADDR_ANY;
|
||||
server.sin_port = htons(port);
|
||||
if (bind(rfd, (const struct sockaddr *) &server, sizeof(server)) < 0) {
|
||||
return BIND_ERROR;
|
||||
}
|
||||
if (listen(rfd, 3) < 0) {
|
||||
return LISTEN_ERROR;
|
||||
}
|
||||
|
||||
int cfd;
|
||||
|
||||
while (1) {
|
||||
cfd = accept(rfd, &client, &client_len);
|
||||
if (cfd < 0) {
|
||||
printf("Connection Error, waiting for next connection\n");
|
||||
continue;
|
||||
}
|
||||
int pid = fork();
|
||||
if (pid == 0) {
|
||||
|
||||
http_request * req = new_request();
|
||||
|
||||
int result = receive(cfd, req);
|
||||
|
||||
http_response * res = new_response();
|
||||
|
||||
if (result == 1) handler(req, res); //TODO HTTP unsupported version response
|
||||
else if (result == 4) set_status(res, 400, "Bad Request");
|
||||
else set_status(res, 500, "Internal Server Error");
|
||||
|
||||
free_request(req);
|
||||
|
||||
respond(cfd, res);
|
||||
|
||||
close(cfd);
|
||||
exit(0);
|
||||
}
|
||||
close(cfd);
|
||||
}
|
||||
}
|
||||
|
||||
int receive(int cfd, http_request * req_out) {
|
||||
char buf[1024];
|
||||
size_t bytes_received;
|
||||
|
||||
enum req_pos pos = METHOD;
|
||||
int was_cr = 0;
|
||||
int result = 0;
|
||||
|
||||
struct tmp tmp;
|
||||
tmp.buf = malloc(1024);
|
||||
bzero(tmp.buf, 1024);
|
||||
tmp.size = 1024;
|
||||
tmp.pos = 0;
|
||||
|
||||
do {
|
||||
bytes_received = read(cfd, buf, 1024);
|
||||
if ((result = parse_buffer(buf, bytes_received, req_out, &tmp, &pos, &was_cr))) break;
|
||||
} while (bytes_received > 0);
|
||||
free(tmp.buf);
|
||||
return result;
|
||||
}
|
||||
|
||||
void respond(int cfd, http_response * res) {
|
||||
size_t res_size = response_size(res);
|
||||
char * res_bytes = malloc(res_size);
|
||||
int ser_err = serialize_response(res, res_bytes);
|
||||
if (ser_err != 0) {
|
||||
http_response * err_res = new_response();
|
||||
set_status(res, 500, "Internal Server Error");
|
||||
res_bytes = realloc(res_bytes, response_size(err_res));
|
||||
serialize_response(err_res, res_bytes);
|
||||
free(err_res);
|
||||
}
|
||||
free_response(res);
|
||||
write(cfd, res_bytes, res_size);
|
||||
free(res_bytes);
|
||||
}
|
||||
|
109
httplib.h
Normal file
109
httplib.h
Normal file
|
@ -0,0 +1,109 @@
|
|||
#ifndef SIMPLEHTTPLIB_HTTPLIB_H
|
||||
#define SIMPLEHTTPLIB_HTTPLIB_H
|
||||
|
||||
/**
|
||||
* Represents a HTTP request method.
|
||||
*/
|
||||
typedef enum http_method_enum {
|
||||
GET, POST, PUT, DELETE, PATCH, HEAD, CONNECT, OPTIONS, TRACE
|
||||
} http_method;
|
||||
/**
|
||||
* Represents a HTTP header. Contains the header field key, the value and a pointer
|
||||
* to the next header to form a linked list.
|
||||
* All pointers of this struct must point to allocated memory or 0.
|
||||
*/
|
||||
typedef struct http_header_struct {
|
||||
char * key;
|
||||
char * value;
|
||||
struct http_header_struct * next;
|
||||
} http_header;
|
||||
/**
|
||||
* Represents a HTTP request. Contains the request method, the HTTP path, a linked list
|
||||
* of headers, the query string (optional, without leading '?'), the request body (optional)
|
||||
* and the content length of the body (0 if there is no body).
|
||||
* All pointers of this struct must point to allocated memory or 0.
|
||||
*/
|
||||
typedef struct http_request_struct {
|
||||
http_method method;
|
||||
char * path;
|
||||
http_header * headers;
|
||||
char * query;
|
||||
size_t content_length;
|
||||
char * body;
|
||||
} http_request;
|
||||
/**
|
||||
* Represents a HTTP response. Contains the HTTP status code, the status message,
|
||||
* a linked list of headers, the response body (optional) and the content length
|
||||
* of the body (0 if there is no body).
|
||||
* All pointers of this struct must point to allocated memory or 0.
|
||||
*/
|
||||
typedef struct http_response_struct {
|
||||
int status_code;
|
||||
char * status_message;
|
||||
http_header * headers;
|
||||
size_t content_length;
|
||||
char * body;
|
||||
} http_response;
|
||||
/**
|
||||
* Function pointer type for the HTTP request handler function.
|
||||
*/
|
||||
typedef void (*http_request_handler) (http_request * req, http_response * res_out);
|
||||
|
||||
/**
|
||||
* Used to start the HTTP server.
|
||||
* @param port the port on which the server should listen
|
||||
* @param handler a function pointer to the request handler function
|
||||
* @return a negative integer, if the server exited with an error
|
||||
*/
|
||||
int start_http_server(int port, http_request_handler handler);
|
||||
/**
|
||||
* Helper function to add a header to a HTTP response.
|
||||
* @param self a pointer to the response struct
|
||||
* @param key the header field key
|
||||
* @param value the header value
|
||||
* @return 0 if the header was set, a negative value if the header was not valid
|
||||
*/
|
||||
int add_header(http_response * self, char * key, char * value);
|
||||
/**
|
||||
* Helper function to set the content length and to allocate the memory
|
||||
* for the body of a response struct
|
||||
* @param self a pointer to the response struct
|
||||
* @param length the content length
|
||||
*/
|
||||
void set_content_length(http_response * self, size_t length);
|
||||
/**
|
||||
* Helper function to set the response status of a response struct
|
||||
* @param self a pointer to the response struct
|
||||
* @param code the status code
|
||||
* @param message the status message
|
||||
*/
|
||||
void set_status(http_response * self, int code, char * message);
|
||||
/**
|
||||
* Helper function to get a header value from a HTTP.
|
||||
* Returned value is allocated memory and needs to be freed, if not null.
|
||||
* @param self a pointer to the request struct
|
||||
* @param key the header field key
|
||||
* @return the value of the header or null, if the header does not exist in the request
|
||||
*/
|
||||
char * get_header(http_request * self, char * key);
|
||||
/**
|
||||
* Helper function to get a query value from a HTTP request.
|
||||
* Returned value is allocated memory and needs to be freed, if not null.
|
||||
* @param self a pointer to the request struct
|
||||
* @param key the query key
|
||||
* @return the value of the query or null, if the query key does not exist in the request
|
||||
*/
|
||||
char * get_query_value(http_request * self, char * key);
|
||||
/**
|
||||
* Helper function to check if a header is valid.
|
||||
* @param key the header field key
|
||||
* @param value the header value
|
||||
* @return true if the header is valid, otherwise false
|
||||
*/
|
||||
int is_valid_header(const char * key, const char * value);
|
||||
|
||||
#define SOCKET_ERROR -1;
|
||||
#define BIND_ERROR -2;
|
||||
#define LISTEN_ERROR -3;
|
||||
|
||||
#endif //SIMPLEHTTPLIB_HTTPLIB_H
|
42
httplib_internal.h
Normal file
42
httplib_internal.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#ifndef SIMPLEHTTPLIB_HTTPLIB_INTERNAL_H
|
||||
#define SIMPLEHTTPLIB_HTTPLIB_INTERNAL_H
|
||||
|
||||
struct tmp {
|
||||
char * buf;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
};
|
||||
|
||||
enum req_pos {
|
||||
METHOD,
|
||||
PATH,
|
||||
QUERY,
|
||||
VERSION,
|
||||
HEADERS,
|
||||
BODY
|
||||
};
|
||||
|
||||
void free_request(http_request * self);
|
||||
void free_response(http_response * self);
|
||||
|
||||
http_header * new_header(char * key, char * value);
|
||||
http_request * new_request();
|
||||
http_response * new_response();
|
||||
|
||||
size_t header_string_size(http_header * header);
|
||||
int header_to_string(http_header * header, char * str_out);
|
||||
|
||||
size_t response_size(http_response * res);
|
||||
int serialize_response(http_response * res, char * str_out);
|
||||
|
||||
int parse_buffer(char * buf, size_t bytes, http_request * req, struct tmp * tmp, enum req_pos * pos, int * was_cr);
|
||||
int parse_method(char * method_str, http_method * method_out);
|
||||
int parse_header(http_request * self, char * str);
|
||||
|
||||
void increase_tmp(struct tmp * tmp);
|
||||
void reset_tmp(struct tmp * tmp);
|
||||
|
||||
int receive(int cfd, http_request * req_out);
|
||||
void respond(int cfd, http_response * res);
|
||||
|
||||
#endif //SIMPLEHTTPLIB_HTTPLIB_INTERNAL_H
|
168
httpparse.c
Normal file
168
httpparse.c
Normal file
|
@ -0,0 +1,168 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "httplib.h"
|
||||
#include "httplib_internal.h"
|
||||
|
||||
int parse_buffer(char * buf, size_t bytes, http_request * req, struct tmp * tmp, enum req_pos * pos, int * was_cr) {
|
||||
for (int i = 0; i < bytes; i++) {
|
||||
if (buf[i] == '\r') {
|
||||
*was_cr = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*pos == METHOD && buf[i] == ' ') {
|
||||
int res = parse_method(tmp->buf, &req->method);
|
||||
if (res < 0) {
|
||||
return 4;
|
||||
} else {
|
||||
*pos = PATH;
|
||||
reset_tmp(tmp);
|
||||
}
|
||||
} else if (*pos == QUERY && buf[i] == ' ') {
|
||||
req->query = malloc(strlen(tmp->buf) + 1);
|
||||
strcpy(req->query, tmp->buf);
|
||||
*pos = VERSION;
|
||||
reset_tmp(tmp);
|
||||
//TODO check if valid
|
||||
} else if (*pos == PATH && buf[i] == ' ') {
|
||||
*pos = VERSION;
|
||||
req->path = malloc(strlen(tmp->buf) + 1);
|
||||
strcpy(req->path, tmp->buf);
|
||||
reset_tmp(tmp);
|
||||
} else if (*pos == VERSION && *was_cr && buf[i] == '\n') {
|
||||
*pos = HEADERS;
|
||||
if (strcmp(tmp->buf, "HTTP/1.1") != 0) {
|
||||
return 3;
|
||||
}
|
||||
reset_tmp(tmp);
|
||||
} else if (*pos == PATH && buf[i] == '?') {
|
||||
*pos = QUERY;
|
||||
req->path = malloc(strlen(tmp->buf) + 1);
|
||||
strcpy(req->path, tmp->buf);
|
||||
reset_tmp(tmp);
|
||||
} else if (*pos == HEADERS && *was_cr && buf[i] == '\n') {
|
||||
int res = parse_header(req, tmp->buf);
|
||||
if (res < 0) {
|
||||
return 4;
|
||||
} else if (res > 0) {
|
||||
*pos = BODY;
|
||||
if (req->content_length > 0) {
|
||||
req->body = malloc(req->content_length);
|
||||
}
|
||||
}
|
||||
reset_tmp(tmp);
|
||||
} else if (*pos != BODY) {
|
||||
if (tmp->pos == tmp->size - 1) {
|
||||
increase_tmp(tmp);
|
||||
}
|
||||
tmp->buf[tmp->pos] = buf[i];
|
||||
tmp->pos++;
|
||||
} else if (req->content_length > tmp->pos) {
|
||||
req->body[tmp->pos] = buf[i];
|
||||
tmp->pos++;
|
||||
} else {
|
||||
//END OF BODY
|
||||
return 1;
|
||||
}
|
||||
|
||||
*was_cr = 0;
|
||||
}
|
||||
|
||||
if (*pos == BODY && req->content_length <= tmp->pos) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_method(char * method_str, http_method * method_out) {
|
||||
if (!strcmp(method_str, "GET")) {
|
||||
*method_out = GET;
|
||||
} else if (!strcmp(method_str, "POST")) {
|
||||
*method_out = POST;
|
||||
} else if (!strcmp(method_str, "PUT")) {
|
||||
*method_out = PUT;
|
||||
} else if (!strcmp(method_str, "DELETE")) {
|
||||
*method_out = DELETE;
|
||||
} else if (!strcmp(method_str, "PATCH")) {
|
||||
*method_out = PATCH;
|
||||
} else if (!strcmp(method_str, "HEAD")) {
|
||||
*method_out = HEAD;
|
||||
} else if (!strcmp(method_str, "CONNECT")) {
|
||||
*method_out = CONNECT;
|
||||
} else if (!strcmp(method_str, "OPTIONS")) {
|
||||
*method_out = OPTIONS;
|
||||
} else if (!strcmp(method_str, "TRACE")) {
|
||||
*method_out = TRACE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int parse_header(http_request * self, char * str) {
|
||||
size_t len = strlen(str);
|
||||
if (len == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
char * key = malloc(len);
|
||||
bzero(key, len);
|
||||
char * value = malloc(len);
|
||||
bzero(value, len);
|
||||
|
||||
int key_end = 0;
|
||||
int value_start = 0;
|
||||
char c;
|
||||
int i = 0;
|
||||
int pos = 0;
|
||||
while ((c = str[i]) != '\0') {
|
||||
if (!key_end) {
|
||||
if (c == ':') {
|
||||
key_end = 1;
|
||||
pos = 0;
|
||||
} else {
|
||||
key[pos] = c;
|
||||
pos++;
|
||||
}
|
||||
} else if (!value_start && c != ' ') {
|
||||
value_start = 1;
|
||||
}
|
||||
if (value_start) {
|
||||
value[pos] = c;
|
||||
pos++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
for (int j = pos - 1; j >= 0 ; j--) {
|
||||
if (value[j] == ' ') {
|
||||
value[j] = '\0';
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcasecmp("Content-Length", key) == 0) {
|
||||
self->content_length = strtoul(value, 0, 10);
|
||||
return 0;
|
||||
} else if (is_valid_header(key, value)) {
|
||||
if (self->headers == 0) {
|
||||
self->headers = new_header(key, value);
|
||||
} else {
|
||||
http_header * run = self->headers;
|
||||
while (run != 0) {
|
||||
if (run->next == 0) {
|
||||
run->next = new_header(key, value);
|
||||
break;
|
||||
}
|
||||
run = run->next;
|
||||
}
|
||||
}
|
||||
free(key);
|
||||
free(value);
|
||||
return 0;
|
||||
}
|
||||
free(key);
|
||||
free(value);
|
||||
return -1;
|
||||
}
|
75
httpser.c
Normal file
75
httpser.c
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include "httplib.h"
|
||||
#include "httplib_internal.h"
|
||||
|
||||
int header_to_string(http_header * header, char * str_out) {
|
||||
if (!is_valid_header(header->key, header->value))
|
||||
return -1;
|
||||
|
||||
strcpy(str_out, header->key);
|
||||
strcat(str_out, ":");
|
||||
strcat(str_out, header->value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t header_string_size(http_header * header) {
|
||||
size_t key_len = strlen(header->key);
|
||||
size_t value_len = strlen(header->value);
|
||||
return key_len + value_len + 2;
|
||||
}
|
||||
|
||||
int serialize_response(http_response * res, char * str_out) {
|
||||
strcpy(str_out, "HTTP/1.1 ");
|
||||
if (res->status_code < 100 || res->status_code > 599) return -1;
|
||||
char status[4];
|
||||
sprintf(status, "%i", res->status_code);
|
||||
strcat(str_out, status);
|
||||
strcat(str_out, " ");
|
||||
strcat(str_out, res->status_message);
|
||||
strcat(str_out, "\r\n");
|
||||
http_header * run = res->headers;
|
||||
while (run != 0) {
|
||||
char * tmp = malloc(header_string_size(run));
|
||||
int err = header_to_string(run, tmp);
|
||||
if (err != 0) return err;
|
||||
strcat(str_out, tmp);
|
||||
free(tmp);
|
||||
strcat(str_out, "\r\n");
|
||||
run = run->next;
|
||||
}
|
||||
if (res->content_length > 0) {
|
||||
strcat(str_out, "Content-Length:");
|
||||
char * tmp = malloc(2 + (res->content_length / 10));
|
||||
sprintf(tmp, "%lu", res->content_length);
|
||||
strcat(str_out, tmp);
|
||||
free(tmp);
|
||||
strcat(str_out, "\r\n");
|
||||
}
|
||||
strcat(str_out, "\r\n");
|
||||
size_t end_pos = 0;
|
||||
while (str_out[end_pos] != '\0') end_pos++;
|
||||
if (res->body != 0) {
|
||||
for (size_t i = 0; i < res->content_length; i++) {
|
||||
str_out[end_pos + i] = res->body[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t response_size(http_response * res) {
|
||||
size_t res_line = 15 + strlen(res->status_message); //"HTTP/1.1" 000 (message)\r\n
|
||||
size_t headers = 2; // \r\n
|
||||
http_header * run = res->headers;
|
||||
while (run != 0) {
|
||||
headers += header_string_size(run) + 1; // \r\n instead of \0
|
||||
run = run->next;
|
||||
}
|
||||
if (res->content_length > 0) {
|
||||
headers += 18;
|
||||
headers += res->content_length / 10;
|
||||
}
|
||||
size_t body = res->content_length;
|
||||
return res_line + headers + body;
|
||||
}
|
175
httputil.c
Normal file
175
httputil.c
Normal file
|
@ -0,0 +1,175 @@
|
|||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "httplib.h"
|
||||
#include "httplib_internal.h"
|
||||
#include <stdio.h>
|
||||
|
||||
http_header * new_header(char * key, char * value) {
|
||||
http_header * header = malloc(sizeof(http_header));
|
||||
header->next = 0;
|
||||
header->key = malloc(strlen(key)+1);
|
||||
header->value = malloc(strlen(value)+1);
|
||||
strcpy(header->key, key);
|
||||
strcpy(header->value, value);
|
||||
return header;
|
||||
}
|
||||
|
||||
http_request * new_request() {
|
||||
http_request * req = malloc(sizeof(http_request));
|
||||
req->method = GET;
|
||||
req->headers = 0;
|
||||
req->path = 0;
|
||||
req->query = 0;
|
||||
req->content_length = 0;
|
||||
req->body = 0;
|
||||
return req;
|
||||
}
|
||||
|
||||
http_response * new_response() {
|
||||
http_response * res = malloc(sizeof(http_request));
|
||||
res->status_message = 0;
|
||||
res->headers = 0;
|
||||
res->body = 0;
|
||||
res->content_length = 0;
|
||||
res->status_code = 100;
|
||||
return res;
|
||||
}
|
||||
|
||||
int add_header(http_response * self, char * key, char * value) {
|
||||
if (!is_valid_header(key, value)) return -1;
|
||||
if (self->headers == 0) {
|
||||
self->headers = new_header(key, value);
|
||||
} else {
|
||||
http_header * run = self->headers;
|
||||
while (run != 0) {
|
||||
if (run->next == 0) {
|
||||
run->next = new_header(key, value);
|
||||
break;
|
||||
}
|
||||
run = run->next;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * get_header(http_request * self, char * key) {
|
||||
http_header * run = self->headers;
|
||||
while (run != 0) {
|
||||
if (!strcasecmp(key, run->key)) {
|
||||
char * value = malloc(strlen(run->value)+1);
|
||||
strcpy(value, run->value);
|
||||
return value;
|
||||
}
|
||||
run = run->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int is_valid_header(const char * key, const char * value) {
|
||||
for (int i = 0; key[i] != '\0'; i++) {
|
||||
char c = key[i];
|
||||
if ((c < 65 && c != '-') || (c > 90 && c < 97 && c != '_') || c > 122) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
for (int i = 0; value[i] != '\0'; i++) {
|
||||
char c = value[i];
|
||||
if (c < 32 || c > 126) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void free_request(http_request * self) {
|
||||
if (self == 0) return;
|
||||
if (self->headers != 0) {
|
||||
http_header * run = self->headers;
|
||||
while (run != 0) {
|
||||
http_header * to_free = run;
|
||||
run = run->next;
|
||||
if (to_free->key != 0) free(to_free->key);
|
||||
if (to_free->value != 0) free(to_free->value);
|
||||
free(to_free);
|
||||
}
|
||||
}
|
||||
if (self->query != 0) free(self->query);
|
||||
if (self->body != 0) free(self->body);
|
||||
if (self->path != 0) free(self->path);
|
||||
free(self);
|
||||
}
|
||||
|
||||
void free_response(http_response * self) {
|
||||
if (self == 0) return;
|
||||
if (self->headers != 0) {
|
||||
http_header * run = self->headers;
|
||||
while (run != 0) {
|
||||
http_header * to_free = run;
|
||||
run = run->next;
|
||||
if (to_free->key != 0) free(to_free->key);
|
||||
if (to_free->value != 0) free(to_free->value);
|
||||
free(to_free);
|
||||
}
|
||||
}
|
||||
if (self->status_message != 0) free(self->status_message);
|
||||
if (self->body != 0) free(self->body);
|
||||
free(self);
|
||||
}
|
||||
|
||||
char * get_query_value(http_request * self, char * key) {
|
||||
if (self->query == 0) return NULL;
|
||||
char * tmp = malloc(strlen(self->query)+1);
|
||||
int pos = 0;
|
||||
int value_start = -1;
|
||||
for (int i = 0; self->query[i] != '\0'; i++) {
|
||||
if (self->query[i] == '=') {
|
||||
tmp[pos] = '\0';
|
||||
if (!strcmp(key, tmp)) {
|
||||
value_start = i+1;
|
||||
}
|
||||
pos = 0;
|
||||
} else if (self->query[i] == '&') {
|
||||
if (value_start > 0) {
|
||||
break;
|
||||
} else {
|
||||
pos = 0;
|
||||
}
|
||||
} else {
|
||||
tmp[pos] = self->query[i];
|
||||
pos++;
|
||||
}
|
||||
}
|
||||
tmp[pos] = '\0';
|
||||
|
||||
if (value_start > 0) {
|
||||
char * value = malloc(strlen(tmp)+1);
|
||||
strcpy(value, tmp);
|
||||
free(tmp);
|
||||
return value;
|
||||
}
|
||||
free(tmp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_content_length(http_response * self, size_t length) {
|
||||
self->content_length = length;
|
||||
if (length > 0)
|
||||
self->body = malloc(length);
|
||||
}
|
||||
|
||||
void set_status(http_response * self, int code, char * message) {
|
||||
self->status_code = code;
|
||||
self->status_message = malloc(strlen(message)+1);
|
||||
strcpy(self->status_message, message);
|
||||
}
|
||||
|
||||
void increase_tmp(struct tmp * tmp) {
|
||||
tmp->size += 1024;
|
||||
tmp->buf = realloc(tmp->buf, tmp->size);
|
||||
bzero(tmp->buf + tmp->pos, 1024);
|
||||
}
|
||||
|
||||
void reset_tmp(struct tmp * tmp) {
|
||||
tmp->pos = 0;
|
||||
bzero(tmp->buf, tmp->size);
|
||||
}
|
Loading…
Reference in a new issue