#include "header.h"
#include <sys/stat.h>
#ifdef __NetBSD__
#ifndef PATH_MAX
#include <sys/syslimits.h>
#endif
#endif
#ifdef __linux__
#ifndef PATH_MAX
#include <linux/limits.h> /* for PATH_MAX */
#endif
#endif
#if defined(__sun) && defined(__illumos__)
#include "/opt/magic/include/magic.h"
#else
#include <magic.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "structures.h"
#include "utils.h"
/*
* Writes 304 not modified header to the client.
*/
int
write_304_header(REQUEST* request)
{
char time_buf[BUFSIZ] = {0};
char buf[BUFSIZ] = {0};
char* err_msg = NULL;
struct stat st;
struct tm* time_info = NULL;
int len = snprintf(buf, sizeof(buf),
"Date: %s\r\n"
"Server: %s/%.1f\r\n",
request->request_time, SERVER_NAME, SERVER_VERSION);
if (len < 0)
{
err_msg = "snprintf failed while writing final headers";
goto not_mod_error;
}
if (stat(request->parsed_path, &st) != 0)
{
err_msg = "stat failed while writing final headers";
goto not_mod_error;
}
time_info = gmtime(&st.st_mtime);
if (strftime(time_buf, BUFSIZ, "%A, %d %b %Y %T GMT", time_info) == 0)
{
err_msg = "strftime failed while formatting Last-Modified header";
goto not_mod_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto not_mod_error;
}
len = snprintf(buf, sizeof(buf), "Last-Modified: %s\r\n", time_buf);
if (len < 0)
{
err_msg = "safe_write failed while writing final headers";
goto not_mod_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto not_mod_error;
}
return HTTP_OK;
not_mod_error:
if (err_msg != NULL)
{
fprintf(stderr, "%s: warning - %s: %s\n", getprogname(), err_msg,
strerror(errno));
}
return HTTP_ERROR;
}
/*
* Writes generic empty header when a 4XX or 5XX is returned.
*/
int
write_error_header(REQUEST* request)
{
char buf[BUFSIZ] = {0};
char* err_msg = NULL;
int len = snprintf(buf, sizeof(buf),
"Date: %s\r\n"
"Server: %s/%.1f\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: 0\r\n",
request->request_time, SERVER_NAME, SERVER_VERSION);
if (len < 0)
{
err_msg = "snprintf failed while writing final headers";
goto err_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto err_error;
}
return HTTP_OK;
err_error:
if (err_msg != NULL)
{
fprintf(stderr, "%s: warning - %s: %s\n", getprogname(), err_msg,
strerror(errno));
}
return HTTP_ERROR;
}
/*
* Writes the headers for a directory indexing request.
*/
int
write_dir_header(REQUEST* request, size_t content_length)
{
char time_buf[BUFSIZ] = {0};
char buf[BUFSIZ] = {0};
char* err_msg = NULL;
struct stat st;
struct tm* time_info = NULL;
int len = snprintf(buf, sizeof(buf),
"Date: %s\r\n"
"Server: %s/%.1f\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %ld\r\n",
request->request_time, SERVER_NAME, SERVER_VERSION,
content_length);
if (len < 0)
{
err_msg = "snprintf failed while writing final headers";
goto dir_error;
}
if (stat(request->parsed_path, &st) != 0)
{
err_msg = "stat failed while writing final headers";
goto dir_error;
}
time_info = gmtime(&st.st_mtime);
if (strftime(time_buf, BUFSIZ, "%A, %d %b %Y %T GMT", time_info) == 0)
{
err_msg = "strftime failed while formatting Last-Modified header";
goto dir_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto dir_error;
}
len = snprintf(buf, sizeof(buf), "Last-Modified: %s\r\n", time_buf);
if (len < 0)
{
err_msg = "safe_write failed while writing final headers";
goto dir_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto dir_error;
}
return HTTP_OK;
dir_error:
if (err_msg != NULL)
{
fprintf(stderr, "%s: warning - %s: %s\n", getprogname(), err_msg,
strerror(errno));
}
return HTTP_ERROR;
}
/*
* Writes the headers from a cgi_header upon success.
*/
int
write_cgi_header(CGI* cgi)
{
char time_buf[BUFSIZ] = {0};
char buf[BUFSIZ] = {0};
char* err_msg = NULL;
struct stat st;
struct tm* time_info = NULL;
int len = snprintf(buf, sizeof(buf),
"Date: %s\r\n"
"Server: %s/%.1f\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n",
cgi->http_request->request_time, SERVER_NAME,
SERVER_VERSION, cgi->content_type, cgi->content_length);
if (len < 0)
{
err_msg = "safe_write failed while writing error headers";
goto cgi_error;
}
if (stat(cgi->http_request->parsed_path, &st) != 0)
{
err_msg = "safe_write failed while writing error headers";
goto cgi_error;
}
time_info = gmtime(&st.st_mtime);
if (strftime(time_buf, BUFSIZ, "%A, %d %b %Y %T GMT", time_info) == 0)
{
err_msg = "strftime failed while formatting Last-Modified header";
goto cgi_error;
}
if (safe_write(cgi->http_request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto cgi_error;
}
len = snprintf(buf, sizeof(buf), "Last-Modified: %s\r\n", time_buf);
if (len < 0)
{
err_msg = "snprintf failed while writing final headers";
goto cgi_error;
}
if (safe_write(cgi->http_request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto cgi_error;
}
return HTTP_OK;
cgi_error:
if (err_msg != NULL)
{
fprintf(stderr, "%s: warning - %s: %s\n", getprogname(), err_msg,
strerror(errno));
}
return HTTP_ERROR;
}
int
write_header(REQUEST* request)
{
/* variables declared here to prevent the compiler from screaming because we
* used goto statements */
char time_buf[BUFSIZ] = {0};
char buf[BUFSIZ] = {0};
int len = 0;
char* err_msg = NULL;
magic_t magic = NULL;
struct stat st;
struct tm* time_info = NULL;
const char* ftype = NULL;
len = snprintf(buf, sizeof(buf),
"Date: %s\r\n"
"Server: %s/%.1f\r\n",
request->request_time, SERVER_NAME, SERVER_VERSION);
if (len < 0)
{
err_msg = "snprintf failed while writing Date & Server";
goto http_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing Date & Server";
goto http_error;
}
magic = magic_open(MAGIC_MIME_TYPE);
if (magic == NULL || magic_load(magic, NULL) < 0)
{
len = snprintf(buf, sizeof(buf),
"Content-Type: text/plain;charset=us-ascii\r\n"
"Content-Length: 0\r\n");
if (len < 0)
{
err_msg = "snprintf failed while writing magic headers";
goto http_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing magic headers";
}
goto http_error;
}
if (stat(request->parsed_path, &st) != 0)
{
len = snprintf(buf, sizeof(buf),
"Content-Type: text/plain;charset=us-ascii\r\n"
"Content-Length: 0\r\n");
if (len < 0)
{
err_msg = "snprintf failed while writing error headers";
goto http_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing error headers";
}
goto http_error;
}
time_info = gmtime(&st.st_mtime);
if (strftime(time_buf, BUFSIZ, "%A, %d %b %Y %T GMT", time_info) == 0)
{
err_msg = "strftime failed while formatting Last-Modified header";
goto http_error;
}
ftype = magic_file(magic, request->parsed_path);
if (ftype == NULL)
{
err_msg = "magic_file returned NULL";
goto http_error;
}
len = snprintf(buf, sizeof(buf),
"Last-Modified: %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %ld\r\n",
time_buf, ftype, st.st_size);
if (len < 0)
{
err_msg = "snprintf failed while writing final headers";
goto http_error;
}
if (safe_write(request->client_fd, buf, (size_t)len) == -1)
{
err_msg = "safe_write failed while writing final headers";
goto http_error;
}
magic_close(magic);
return HTTP_OK;
http_error:
if (magic != NULL)
{
magic_close(magic);
}
if (err_msg != NULL)
{
fprintf(stderr, "%s: warning - %s: %s\n", getprogname(), err_msg,
strerror(errno));
}
return HTTP_ERROR;
}