#include <malloc.h>
+#include <stdlib.h>
#include <string.h>
+#include <time.h>
#include "debug.h"
+#include "file.h"
#include "http.h"
+#define BUFFER_SIZE 128
+
#define HTTP_VERSION "HTTP/1.0"
#define SERVER_NAME "Webserver/0.0.1"
-char **codes = {
+char *codes[15] = {
"200 OK",
"201 Created",
"202 Accepted",
char *www_authenticate;
} header_t;
+typedef struct {
+ char *ext;
+ char *type;
+ char *charset;
+} mime_t;
+
+#define NB_MIMES 8
+
+mime_t mimes[NB_MIMES] = {
+ {"js", "application/javascript", "iso-8859-1"},
+ {"css", "text/css", "iso-8859-1"},
+ {"htm", "text/html", "iso-8859-1"},
+ {"html", "text/html", "iso-8859-1"},
+ {"png", "image/png", NULL},
+ {"jpeg", "image/jpeg", NULL},
+ {"jpg", "image/jpeg", NULL},
+ {"txt", "text/plain", "iso-8859-1"}
+};
+
+/* find mime type */
+
+mime_t *find_mime_type (char *filename)
+{
+ /* find extention */
+ char *ext = filename + strlen (filename);
+ while (--ext > filename) {
+ if (ext[-1] == '.') {
+ break;
+ }
+ }
+ if (ext == filename) {
+ return NULL;
+ }
+
+ /* find mime */
+ int i;
+ for (i = 0; i < NB_MIMES; i++) {
+ if (strcmp (ext, (mimes + i)->ext) == 0) {
+ return mimes + i;
+ }
+ }
+
+ return NULL;
+}
+
/* print header values */
void print_header_values (header_t *header)
{
- printf ("allow = '%s'\n", header->allow);
- printf ("authorization = '%s'\n", header->authorization);
- printf ("content_encoding = '%s'\n", header->content_encoding);
- printf ("content_length = '%s'\n", header->content_length);
- printf ("content_type = '%s'\n", header->content_type);
- printf ("date = '%s'\n", header->date);
- printf ("expires = '%s'\n", header->expires);
- printf ("from = '%s'\n", header->from);
- printf ("if_modified_since = '%s'\n", header->if_modified_since);
- printf ("last_modified = '%s'\n", header->last_modified);
- printf ("location = '%s'\n", header->location);
- printf ("pragma = '%s'\n", header->pragma);
- printf ("referer = '%s'\n", header->referer);
- printf ("server = '%s'\n", header->server);
- printf ("user_agent = '%s'\n", header->user_agent);
- printf ("www_authenticate = '%s'\n", header->www_authenticate);
+ printf ("Header values\n");
+ if (header->allow) printf ("allow = '%s'\n", header->allow);
+ if (header->authorization) printf ("authorization = '%s'\n", header->authorization);
+ if (header->content_encoding) printf ("content_encoding = '%s'\n", header->content_encoding);
+ if (header->content_length) printf ("content_length = '%s'\n", header->content_length);
+ if (header->content_type) printf ("content_type = '%s'\n", header->content_type);
+ if (header->date) printf ("date = '%s'\n", header->date);
+ if (header->expires) printf ("expires = '%s'\n", header->expires);
+ if (header->from) printf ("from = '%s'\n", header->from);
+ if (header->if_modified_since) printf ("if_modified_since = '%s'\n", header->if_modified_since);
+ if (header->last_modified) printf ("last_modified = '%s'\n", header->last_modified);
+ if (header->location) printf ("location = '%s'\n", header->location);
+ if (header->pragma) printf ("pragma = '%s'\n", header->pragma);
+ if (header->referer) printf ("referer = '%s'\n", header->referer);
+ if (header->server) printf ("server = '%s'\n", header->server);
+ if (header->user_agent) printf ("user_agent = '%s'\n", header->user_agent);
+ if (header->www_authenticate) printf ("www_authenticate = '%s'\n", header->www_authenticate);
}
/* find sequence*/
/* response entity */
-int add_status_line (char **buffer, int len)
+int add_line (char **buffer, char *str)
{
+ VERBOSE (DEBUG, PRINT ("add line: %s\n", str));
+ int len = ((*buffer) ? strlen (*buffer) : 0) + strlen (str) + 3;
+ VERBOSE (DEBUG, PRINT ("len: %d\n", len));
+ if (*buffer) {
+ *buffer = (char *)realloc (*buffer, len);
+ } else {
+ *buffer = (char *)calloc (len, 1);
+ }
+ strcat (*buffer, str);
+ strcat (*buffer, "\r\n");
return len;
}
-int add_general_header (char **buffer, int len)
+int add_status_line (char **buffer, code_t code)
{
- return len;
+ char tmp[BUFFER_SIZE] = {0};
+
+ /* Status */
+ sprintf (tmp, "%s %s", HTTP_VERSION, codes[code]);
+ add_line (buffer, tmp);
+
+ return strlen (*buffer);
}
-int add_response_header (char **buffer, int len)
+int add_general_header (char **buffer)
{
- return len;
+ char tmp[BUFFER_SIZE] = {0};
+
+ /* Date */
+ time_t ts = time (NULL);
+ sprintf (tmp, "Date: %s", ctime (&ts));
+ tmp[strlen (tmp) - 1] = 0; // remove last \n
+ add_line (buffer, tmp);
+
+ /* Pragma */
+
+ return strlen (*buffer);
+}
+
+int add_response_header (char **buffer, char *uri)
+{
+ char tmp[BUFFER_SIZE] = {0};
+
+ /* Location */
+ sprintf (tmp, "Location: %s", uri);
+ add_line (buffer, tmp);
+
+ /* Server */
+ sprintf (tmp, "Server: %s", SERVER_NAME);
+ add_line (buffer, tmp);
+
+ /* WWW-Authentificate */
+
+ return strlen (*buffer);
}
-int add_entity (char **buffer, int len, unsigned char *entity, int size, char *type)
+int add_entity (char **buffer, char *entity, int size, char *type, char *encoding)
{
+ char tmp[BUFFER_SIZE] = {0};
+ int len = strlen (*buffer);
+
+ /* Allow */
+ /* Expires */
+ /* Last-Modified */
+
+ if (entity != NULL) {
+
+ /* Content-Encoding */
+ if (encoding != NULL) {
+ sprintf (tmp, "Content-Encoding: %s", encoding);
+ add_line (buffer, tmp);
+ }
+
+ /* Content-Length */
+ sprintf (tmp, "Content-Length: %d", size);
+ add_line (buffer, tmp);
+
+ /* Content-Type */
+ sprintf (tmp, "Content-Type: %s", type);
+ add_line (buffer, tmp);
+
+ add_line (buffer, "");
+
+ /* Entity */
+ len = strlen (*buffer);
+ *buffer = realloc (*buffer, len + size);
+ memcpy (*buffer + len, entity, size);
+ len += size;
+ }
+
return len;
}
int error_400 (char **buffer)
{
-
+ add_status_line (buffer, c400);
+ add_general_header (buffer);
+ add_response_header (buffer, NULL);
+
+ char *response = "<html><head><title>Error 400</title></head><body><p>Bad Request</p></body></html>";
+ return add_entity (buffer, response, strlen (response), "text/html", "iso-8859-1");
+}
+
+/* error 404 */
+
+int error_404 (char **buffer, char *uri)
+{
+ add_status_line (buffer, c404);
+ add_general_header (buffer);
+ add_response_header (buffer, uri);
+
+ char *response = "<html><head><title>Error 404</title></head><body><p>File not found</p></body></html>";
+ return add_entity (buffer, response, strlen (response), "text/html", "iso-8859-1");
+}
+
+/* generic response */
+
+int generic_response (char **buffer, char *location, char *response, int size)
+{
+ int len = 0;
+ VERBOSE (DEBUG, PRINT ("add_status_line %d\n", len));
+ len = add_status_line (buffer, c200);
+ VERBOSE (DEBUG, PRINT ("add_general_header %d\n", len));
+ len = add_general_header (buffer);
+ VERBOSE (DEBUG, PRINT ("add_response_header %d\n", len));
+ len = add_response_header (buffer, location);
+ mime_t *mime = find_mime_type (location);
+
+ VERBOSE (DEBUG, PRINT ("add_entity %d\n", len));
+ return add_entity (buffer, response, size, mime->type, mime->charset);
}
/* trim string */
/* main HTTP processing */
-int processing (char *data, int len, char **pdata)
+int processing (char *data, int len, conf_t *conf, char **pdata)
{
char *saved_data = data;
+ char location[BUFFER_SIZE] = {0};
VERBOSE (DEBUG, PRINT ("Start processing\n"));
/* check method */
- char *line = find_sequence (data, len, "\r\n", &data);
+ char *line = find_sequence (data, len + data - saved_data, "\r\n", &data);
if (line == NULL) {
VERBOSE (WARNING, PRINT ("Unknown received data\n"));
if (pdata != NULL) {
type = post_e;
} else {
VERBOSE (WARNING, PRINT ("Unkown method: %s\n", method));
- } else {
- free (saved_data);
return error_400 (pdata);
}
VERBOSE (INFO, PRINT ("%s %s (%s)\n", (type == get_e) ? "Get" : (type == head_e) ? "Head" : "Post", uri, version));
+ /* analyse uri */
+ char *filename = strtok (uri, "&");
+ char *variables = strtok (NULL, "\n");
+ char *path = (char *) calloc (strlen (conf->root) + strlen (filename) + 2, 1);
+ //sprintf (filename, "%s%s%s", conf->root, ((conf->root[strlen (conf->root) - 1] != '/') && (uri[0] != '/')) ? "/" : "", uri);
+ sprintf (path, "%s/%s", conf->root, filename);
+
/* check header */
header_t header = {0};
- while (strcmp (line = find_sequence (data, len, "\r\n", &data), "") != 0) {
+ while (strcmp (line = find_sequence (data, len + data - saved_data, "\r\n", &data), "") != 0) {
VERBOSE (DEBUG, PRINT ("Header line: '%s'\n", line));
char *field = strtok (line, ":");
char *value = trim (strtok (NULL, "\r"));
}
VERBOSE (DEBUG, PRINT ("Analyse field\n"));
- if (strcmp (field, "Allow") == 0) {
- header.allow = value;
- } else if (strcmp (field, "Authorization") == 0) {
- header.authorization = value;
- } else if (strcmp (field, "Content-Encoding") == 0) {
- header.content_encoding = value;
- } else if (strcmp (field, "Content-Length") == 0) {
- header.content_length = value;
- } else if (strcmp (field, "Content-Type") == 0) {
- header.content_type = value;
- } else if (strcmp (field, "Date") == 0) {
- header.date = value;
- } else if (strcmp (field, "Expires") == 0) {
- header.expires = value;
- } else if (strcmp (field, "From") == 0) {
- header.from = value;
- } else if (strcmp (field, "If-Modified-Since") == 0) {
- header.if_modified_since = value;
- } else if (strcmp (field, "Last-Modified") == 0) {
- header.last_modified = value;
- } else if (strcmp (field, "Location") == 0) {
- header.location = value;
- } else if (strcmp (field, "Pragma") == 0) {
- header.pragma = value;
- } else if (strcmp (field, "Referer") == 0) {
- header.referer = value;
- } else if (strcmp (field, "Server") == 0) {
- header.server = value;
- } else if (strcmp (field, "User-Agent") == 0) {
- header.user_agent = value;
- } else if (strcmp (field, "WWW-Authenticate") == 0) {
- header.www_authenticate = value;
- } else {
- VERBOSE (WARNING, PRINT ("Unknown header field: '%s'\n", field));
- }
+ if (strcmp (field, "Allow") == 0) { header.allow = value; }
+ else if (strcmp (field, "Authorization") == 0) { header.authorization = value; }
+ else if (strcmp (field, "Content-Encoding") == 0) { header.content_encoding = value; }
+ else if (strcmp (field, "Content-Length") == 0) { header.content_length = value; }
+ else if (strcmp (field, "Content-Type") == 0) { header.content_type = value; }
+ else if (strcmp (field, "Date") == 0) { header.date = value; }
+ else if (strcmp (field, "Expires") == 0) { header.expires = value; }
+ else if (strcmp (field, "From") == 0) { header.from = value; }
+ else if (strcmp (field, "If-Modified-Since") == 0) { header.if_modified_since = value; }
+ else if (strcmp (field, "Last-Modified") == 0) { header.last_modified = value; }
+ else if (strcmp (field, "Location") == 0) { header.location = value; }
+ else if (strcmp (field, "Pragma") == 0) { header.pragma = value; }
+ else if (strcmp (field, "Referer") == 0) { header.referer = value; }
+ else if (strcmp (field, "Server") == 0) { header.server = value; }
+ else if (strcmp (field, "User-Agent") == 0) { header.user_agent = value; }
+ else if (strcmp (field, "WWW-Authenticate") == 0) { header.www_authenticate = value; }
+ else { VERBOSE (WARNING, PRINT ("Unknown header field: '%s'\n", field)); }
}
VERBOSE (DEBUG, print_header_values (&header));
- /* processing data */
- if (data) {
- VERBOSE (DEBUG, PRINT ("Processing data: %s\n", data));
+ /* body */
+ char *body = data;
+ len -= saved_data - data;
+ if (len != (header.content_length ? atoi (header.content_length) : 0)) {
+ VERBOSE (WARNING, PRINT ("Incoherent size (%d <> %s)\n", len, header.content_length));
+ }
+
+ /* response */
+ char *buffer = NULL;
+ FILE *fid = NULL;
+ switch (type) {
+ case get_e:
+ case post_e: /* fall through */
+ VERBOSE (DEBUG, PRINT ("Read file %s\n", path));
+ len = readfile (&buffer, path);
+ if (len < 0) {
+ sprintf (location, "http://%s/", conf->servername);
+ len = error_404 (pdata, location);
+ } else {
+ sprintf (location, "http://%s%s", conf->servername, path);
+ len = generic_response (pdata, location, buffer, len);
+ free (buffer);
+ }
+ break;
+ case head_e:
+ VERBOSE (DEBUG, PRINT ("Test file %s\n", path));
+ fid = fopen (path, "rb");
+ if (fid == NULL) {
+ sprintf (location, "http://%s/", conf->servername);
+ len = error_404 (pdata, location);
+ } else {
+ fclose (fid);
+ sprintf (location, "http://%s%s", conf->servername, path);
+ len = generic_response (pdata, location, NULL, 0);
+ }
+ break;
+ case not_supported_e:
+ break;
}
/* cleaning */
- free (saved_data);
+ VERBOSE (DEBUG, PRINT ("Cleaning\n"));
+ if (path) {
+ VERBOSE (DEBUG, PRINT ("Cleaning path\n"));
+ free (path);
+ }
- /* response */
- *pdata = strdup ("HTTP/1.0 200 OK\r\nDate: Sat, 20 May 2023 16:37:46 GMT\r\nServer: Webserver/0.0.1 (Debian)\r\nLocation: http://localhost/\r\nContent-Length: 77\r\nContent-Type: text/html; charset=iso-8859-1\r\n\r\n<html><head><title>Test</title></head><body><p>This a test</p></body></html>");
- return strlen (*pdata);
+ return len;
}
/* vim: set ts=4 sw=4 et: */