25#include <sys/select.h>
26#include <sys/socket.h>
35#include <netinet/in.h>
37#include "../dpip/dpip.h"
45#define MSG(...) printf("[file dpi]: " __VA_ARGS__)
47#define MSG_RAW(...) printf(__VA_ARGS__)
51#define HIDE_DOTFILES TRUE
119 while (fd >= 0 && close(fd) < 0 && errno == EINTR)
133 static const char *Types[] = {
134 "application/octet-stream",
135 "text/html",
"text/plain",
136 "image/gif",
"image/png",
"image/jpeg",
142 _MSG(
"File_get_content_type_from_data:: Size = %zu\n", Size);
145 for (i = 0; i < Size &&
dIsspace(p[i]); ++i);
156 }
else if (Size >= 4 && !strncmp(p,
"GIF8", 4)) {
158 }
else if (Size >= 4 && !strncmp(p,
"\x89PNG", 4)) {
160 }
else if (Size >= 2 && !strncmp(p,
"\xff\xd8", 2)) {
170 Size =
MIN (Size, 256);
171 for (i = 0; i < Size; i++)
175 Type = (non_ascci > 10) ? 0 : 2;
177 Type = (non_ascci > 0) ? 0 : 2;
181 return (Types[Type]);
188static int File_comp(
const FileInfo *f1,
const FileInfo *f2)
190 if (S_ISDIR(f1->mode)) {
191 if (S_ISDIR(f2->mode)) {
192 return strcmp(f1->filename, f2->filename);
197 if (S_ISDIR(f2->mode)) {
200 return strcmp(f1->filename, f2->filename);
218 if (!(dir = opendir(dirname)))
221 Ddir =
dNew(DilloDir, 1);
222 Ddir->dirname =
dStrdup(dirname);
225 dirname_len = strlen(Ddir->dirname);
228 while ((de = readdir(dir)) != 0) {
229 if (!strcmp(de->d_name,
".") || !strcmp(de->d_name,
".."))
234 if (de->d_name[0] ==
'.' ||
235 de->d_name[0] ==
'#' ||
236 (de->d_name[0] !=
'\0' &&
237 de->d_name[strlen(de->d_name) - 1] ==
'~'))
241 fname =
dStrconcat(Ddir->dirname, de->d_name, NULL);
242 if (stat(fname, &sb) == -1) {
247 finfo =
dNew(FileInfo, 1);
248 finfo->full_path = fname;
249 finfo->filename = fname + dirname_len;
250 finfo->size = sb.st_size;
251 finfo->mode = sb.st_mode;
252 finfo->mtime = sb.st_mtime;
277 dFree(finfo->full_path);
282 dFree(Ddir->dirname);
291 if (strcmp(dirname,
"/") != 0) {
292 char *p, *parent, *HUparent, *Uparent;
296 parent[strlen(parent) - 1] =
'\0';
298 if ((p = strrchr(parent,
'/')))
304 "<a href='file:%s'>Parent directory</a>", HUparent);
316 char *ds = ctime(&mtime);
319 if (client->old_style) {
321 if (time(NULL) - mtime > 15811200) {
328 "<td>%.3s %.2s %.5s", ds + 4, ds + 8,
330 (time(NULL) - mtime > 15811200) ? ds + 20 : ds + 11);
342 char *Uref, *HUref, *Hname;
343 const char *ref, *filecont, *name = finfo->filename;
345 if (finfo->size <= 9999) {
348 }
else if (finfo->size / 1024 <= 9999) {
349 size = finfo->size / 1024 + (finfo->size % 1024 >= 1024 / 2);
352 size = finfo->size / 1048576 + (finfo->size % 1048576 >= 1048576 / 2);
357 if (S_ISDIR (finfo->mode)) {
358 filecont =
"Directory";
359 }
else if (finfo->mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
360 filecont =
"Executable";
363 if (!filecont || !strcmp(filecont,
"application/octet-stream"))
364 filecont =
"unknown";
380 if (client->old_style) {
381 char *dots =
".. .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..";
384 "%s<a href='%s'>%s</a>"
387 S_ISDIR (finfo->mode) ?
">" :
" ", HUref, Hname,
388 dots + 50 - (ndots > 0 ? ndots : 0),
389 filecont, size, sizeunits);
393 "<tr align=center %s><td>%s<td align=left><a href='%s'>%s</a>"
394 "<td>%s<td>%d %s",
395 (n & 1) ?
"bgcolor=#dcdcdc" :
"",
396 S_ISDIR (finfo->mode) ?
">" :
" ", HUref, Hname,
397 filecont, size, sizeunits);
413 char *d_cmd, *Hdirname, *Udirname, *HUdirname;
414 DilloDir *Ddir = client->d_dir;
424 }
else if (client->state ==
st_dpip) {
433 "HTTP/1.1 200 OK\r\n"
434 "Content-Type: text/html\r\n"
436 "<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN'>\n"
437 "<HTML>\n<HEAD>\n <BASE href='file:%s'>\n"
438 " <TITLE>file:%s</TITLE>\n</HEAD>\n"
439 "<BODY><H1>Directory listing of %s</H1>\n",
440 HUdirname, Hdirname, Hdirname);
445 if (client->old_style) {
454 " <a href='dpi:/file/toggle'>%</a>\n");
457 if (client->old_style) {
462 "<table border=0 cellpadding=1 cellspacing=0"
463 " bgcolor=#E0E0E0 width=100%>\n"
464 "<tr align=center>\n"
466 "<td width=60%><b>Filename</b>"
469 "<td><b>Modified at</b>\n");
476 }
else if (client->state ==
st_http) {
482 if (client->old_style) {
501 if (!(e = strrchr(filename,
'.')))
514 return "image/svg+xml";
541 if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) != -1) {
542 if ((buf_size = read(fd, buf, 256)) == 256 ) {
545 }
else if (stat(filename, &sb) != -1 &&
546 buf_size > 0 && buf_size == sb.st_size) {
552 _MSG(
"File_content_type: name=%s ct=%s\n", filename, ct);
560 const char *orig_url)
563 client->err_code = res;
564 client->orig_url =
dStrdup(orig_url);
565 client->flags &= ~FILE_READ;
578 if (client->err_code == EACCES) {
579 status =
"403 Forbidden";
580 }
else if (client->err_code == ENOENT) {
581 status =
"404 Not Found";
584 status =
"500 Internal Server Error";
598 "Content-Type: text/plain\r\n"
599 "Content-Length: %d\r\n"
602 status, body->
len, body->
str);
612 const char *DirName,
const char *orig_url)
619 if (ds_dirname->
str[ds_dirname->
len - 1] !=
'/')
627 client->orig_url =
dStrdup(orig_url);
628 client->d_dir = Ddir;
630 client->flags &= ~FILE_READ;
641 const char *filename,
642 const char *orig_url)
647 if (stat(filename, &sb) != 0) {
650 }
else if ((fd = open(filename, O_RDONLY | O_NONBLOCK)) < 0) {
655 client->file_fd = fd;
656 client->file_sz = sb.st_size;
657 client->d_dir = NULL;
659 client->filename =
dStrdup(filename);
660 client->orig_url =
dStrdup(orig_url);
661 client->flags &= ~FILE_READ;
671static void File_get(ClientInfo *client,
const char *filename,
672 const char *orig_url)
677 if (stat(filename, &sb) != 0) {
680 }
else if (S_ISDIR(sb.st_mode)) {
701 const char *unknown_type =
"application/octet-stream";
702 char buf[
LBUF], *d_cmd, *name;
703 int st, st2, namelen;
714 }
else if (client->state ==
st_dpip) {
718 namelen = strlen(client->filename);
728 name =
dStrndup(client->filename, namelen);
738 if (!gzipped || strcmp(ct, unknown_type)) {
744 "Content-Length: %ld\r\n"
749 }
else if (client->state ==
st_http) {
752 client->flags |= (st == -3) ?
FILE_ERR : 0;
756 st2 = read(client->file_fd, buf,
LBUF);
757 }
while (st2 < 0 && errno == EINTR);
759 MSG(
"\nERROR while reading from file '%s': %s\n\n",
762 }
else if (st2 == 0) {
768 client->flags |= (st == -3) ?
FILE_ERR : 0;
785 if ((hex[0] = s[0]) && (hex[1] = s[1])) {
787 hex_value = strtol(hex, &tail, 16);
803 char *str = (
char *) orig, *basename = NULL, *ret = NULL, *p;
816 if (str[0] ==
'~' && (str[1] ==
'/' || str[1] ==
'\0')) {
820 char *sep = home[strlen(home) - 1] ==
'/' ?
"" :
"/";
821 char *next = str + 1;
824 str = tmp =
dStrconcat(home, sep, next, NULL);
831 while (str[0] ==
'/' && str[1] ==
'/')
838 basename ? basename :
"",
846 for (i = 0; ds->
str[i]; ++i) {
847 if (ds->
str[i] ==
'%' &&
854 if ((p = strrchr(ds->
str,
'#')) != NULL && access(ds->
str, F_OK) != 0)
881 MSG(
"\nexit(signum), signum=%d\n\n", signum);
893 ClientInfo *new_client;
895 new_client =
dNew(ClientInfo, 1);
897 new_client->orig_url = NULL;
898 new_client->filename = NULL;
899 new_client->file_fd = -1;
900 new_client->file_sz = 0;
901 new_client->d_dir = NULL;
902 new_client->state = 0;
903 new_client->err_code = 0;
918 _MSG(
"Closing Socket Handler\n");
922 dFree(client->orig_url);
923 dFree(client->filename);
934 char *dpip_tag = NULL, *cmd = NULL, *url = NULL, *
path;
935 ClientInfo *client = data;
939 _MSG(
"File_serve_client %p, flags=%d state=%d\n",
940 client, client->flags, client->state);
945 _MSG(
"dpip_tag={%s}\n", dpip_tag);
954 _MSG(
"a_Dpip_check_auth returned %d\n", st);
962 if (strcmp(cmd,
"DpiBye") == 0) {
964 MSG(
"(pid %d): Got DpiBye.\n", (
int)getpid());
967 strcmp(url+4,
"/file/toggle") == 0) {
973 MSG(
"ERROR: URL was %s\n", url);
984 }
else if (f_write) {
986 if (client->state ==
st_err)
988 else if (client->d_dir)
1005 int i, f_read, f_write;
1009 f_read = FD_ISSET(client->sh->fd_in, &
read_set);
1010 f_write = FD_ISSET(client->sh->fd_out, &
write_set);
1011 if (!f_read && !f_write)
1031 struct timeval timeout;
1039 FD_SET (client->sh->fd_in, &
read_set);
1041 FD_SET (client->sh->fd_out, &
write_set);
1046 timeout.tv_sec = seconds;
1047 timeout.tv_usec = 0;
1051 }
while (st == -1 && errno == EINTR);
1069 struct sockaddr_in sin;
1071 int sock_fd, c_st, st = 1;
1075 signal (SIGINT, SIG_IGN);
1077 signal (SIGHUP, SIG_IGN);
1079 signal (SIGTERM, SIG_IGN);
1081 MSG(
"(v.2) accepting connections...\n");
1090 fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK | fcntl(STDIN_FILENO, F_GETFL));
1096 sin_sz =
sizeof(sin);
1103 }
while (c_st == 0 && !
DPIBYE);
1111 if (FD_ISSET(STDIN_FILENO, &
read_set)) {
1114 sock_fd = accept(STDIN_FILENO, (
struct sockaddr *)&sin, &sin_sz);
1115 }
while (sock_fd < 0 && errno == EINTR);
1116 if (sock_fd == -1) {
1117 if (errno == EAGAIN)
1122 _MSG(
" accept() fd=%d\n", sock_fd);
1124 fcntl(sock_fd, F_SETFL, O_NONBLOCK | fcntl(sock_fd, F_GETFL));
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
int dStrAsciiCasecmp(const char *s1, const char *s2)
void dStr_append(Dstr *ds, const char *s)
Append a C string to a Dstr.
char * dStrdup(const char *s)
Dlist * dList_new(int size)
Create a new empty list.
Dstr * dStr_sized_new(int sz)
Create a new string with a given size.
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
void dStr_erase(Dstr *ds, int pos_0, int len)
Erase a substring.
int dList_length(Dlist *lp)
For completing the ADT.
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
void dStr_free(Dstr *ds, int all)
Free a dillo string.
char * dStrndup(const char *s, size_t sz)
void dStr_sprintf(Dstr *ds, const char *format,...)
Printf-like function.
void dList_sort(Dlist *lp, dCompareFunc func)
Sort the list using a custom function.
Dstr * dStr_new(const char *s)
Create a new string.
void dList_append(Dlist *lp, void *data)
Append a data item to the list.
void dList_free(Dlist *lp)
Free a list (not its elements)
void dStr_truncate(Dstr *ds, int len)
Truncate a Dstr to be 'len' bytes long.
void dList_remove(Dlist *lp, const void *data)
char * dGethomedir(void)
Return the home directory in a static string (don't free)
int(* dCompareFunc)(const void *a, const void *b)
#define dNew(type, count)
int a_Dpip_dsh_trywrite(Dsh *dsh, const char *Data, int DataSize)
void a_Dpip_dsh_free(Dsh *dsh)
Free the SockHandler structure.
char * a_Dpip_build_cmd(const char *format,...)
Printf like function for building dpip commands.
int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str)
Convenience function.
char * a_Dpip_get_attr(const char *tag, const char *attrname)
Task: given a tag and an attribute name, return its value.
char * a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
Return a newlly allocated string with the next dpip token in the socket.
void a_Dpip_dsh_close(Dsh *dsh)
Close this socket for reading and writing.
int a_Dpip_check_auth(const char *auth_tag)
Check whether the given 'auth' string equals what dpid saved.
int a_Dpip_dsh_tryflush(Dsh *dsh)
Dsh * a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
Create and initialize a dpip socket handler.
#define a_Dpip_dsh_printf(sh, flush,...)
char * Escape_html_str(const char *str)
char * Escape_uri_str(const char *str, const char *p_esc_set)
static int File_prepare_send_dir(ClientInfo *client, const char *DirName, const char *orig_url)
static void File_close(int fd)
static const char * File_get_content_type_from_data(void *Data, size_t Size)
static int File_send_file(ClientInfo *client)
static int File_comp(const FileInfo *f1, const FileInfo *f2)
static void File_dillodir_free(DilloDir *Ddir)
static DilloDir * File_dillodir_new(char *dirname)
static const char * File_ext(const char *filename)
static int File_check_fds(uint_t seconds)
static void File_prepare_send_error_page(ClientInfo *client, int res, const char *orig_url)
static void File_toggle_html_style(ClientInfo *client)
static void File_print_mtime(ClientInfo *client, time_t mtime)
static void termination_handler(int signum)
static void File_info2html(ClientInfo *client, FileInfo *finfo, int n)
static void File_print_parent_dir(ClientInfo *client, const char *dirname)
static int File_parse_hex_octet(const char *s)
static char * File_normalize_path(const char *orig)
static void File_remove_client(ClientInfo *client)
static void File_serve_clients(void)
static void File_send_dir(ClientInfo *client)
static void File_get(ClientInfo *client, const char *filename, const char *orig_url)
static int File_prepare_send_file(ClientInfo *client, const char *filename, const char *orig_url)
static void File_send_error_page(ClientInfo *client)
static void File_serve_client(void *data, int f_write)
static ClientInfo * File_add_client(int sock_fd)
static const char * File_content_type(const char *filename)
Dpip socket handler type.