src/server/safs/service.c

changeset 596
dc7cfde0f3bc
parent 584
f3ddd6dc8e7b
child 597
ca54033c7db1
equal deleted inserted replaced
595:2c316612f648 596:dc7cfde0f3bc
38 #include "../daemon/protocol.h" 38 #include "../daemon/protocol.h"
39 #include "../daemon/vfs.h" 39 #include "../daemon/vfs.h"
40 40
41 #include "../util/strbuf.h" 41 #include "../util/strbuf.h"
42 #include <cx/string.h> 42 #include <cx/string.h>
43 #include <cx/linked_list.h>
43 #include <cx/printf.h> 44 #include <cx/printf.h>
44 45
45 #include <errno.h> 46 #include <errno.h>
46 47
47 /* 48 /*
713 714
714 ws.on_message = ws_msghandler; 715 ws.on_message = ws_msghandler;
715 return http_handle_websocket(sn, rq, &ws); 716 return http_handle_websocket(sn, rq, &ws);
716 } 717 }
717 718
719
720 // TODO: maybe move these util functions to another file or library
721 static char* util_size_str2(const CxAllocator *a, WSBool iscollection, uint64_t contentlength, uint64_t dimension, int precision) {
722 char *str = cxMalloc(a, 16);
723 uint64_t size = contentlength;
724
725 if(iscollection) {
726 str[0] = '\0'; // currently no information for collections
727 } else if(dimension < 0x400) {
728 snprintf(str, 16, "%" PRIu64 " bytes", size);
729 } else if(dimension < 0x100000) {
730 float s = (float)size/0x400;
731 int diff = (s*100 - (int)s*100);
732 if(diff > 90) {
733 diff = 0;
734 s += 0.10f;
735 }
736 if(dimension < 0x2800 && diff != 0) {
737 // size < 10 KiB
738 snprintf(str, 16, "%.*f KiB", precision, s);
739 } else {
740 snprintf(str, 16, "%.0f KiB", s);
741 }
742 } else if(dimension < 0x40000000) {
743 float s = (float)size/0x100000;
744 int diff = (s*100 - (int)s*100);
745 if(diff > 90) {
746 diff = 0;
747 s += 0.10f;
748 }
749 if(dimension < 0xa00000 && diff != 0) {
750 // size < 10 MiB
751 snprintf(str, 16, "%.*f MiB", precision, s);
752 } else {
753 size /= 0x100000;
754 snprintf(str, 16, "%.0f MiB", s);
755 }
756 } else if(dimension < 0x1000000000ULL) {
757 float s = (float)size/0x40000000;
758 int diff = (s*100 - (int)s*100);
759 if(diff > 90) {
760 diff = 0;
761 s += 0.10f;
762 }
763 if(dimension < 0x280000000 && diff != 0) {
764 // size < 10 GiB
765 snprintf(str, 16, "%.*f GiB", precision, s);
766 } else {
767 size /= 0x40000000;
768 snprintf(str, 16, "%.0f GiB", s);
769 }
770 } else {
771 size /= 1024;
772 float s = (float)size/0x40000000;
773 int diff = (s*100 - (int)s*100);
774 if(diff > 90) {
775 diff = 0;
776 s += 0.10f;
777 }
778 if(dimension < 0x280000000 && diff != 0) {
779 // size < 10 TiB
780 snprintf(str, 16, "%.*f TiB", precision, s);
781 } else {
782 size /= 0x40000000;
783 snprintf(str, 16, "%.0f TiB", s);
784 }
785 }
786 return str;
787 }
788
789 static char* util_size_str(const CxAllocator *a, WSBool iscollection, uint64_t contentlength) {
790 return util_size_str2(a, iscollection, contentlength, contentlength, 1);
791 }
792
793 static char* util_date_str(const CxAllocator *a, time_t tm) {
794 struct tm t;
795 struct tm n;
796 time_t now = time(NULL);
797 #ifdef _WIN32
798 memcpy(&t, localtime(&tm), sizeof(struct tm));
799 memcpy(&n, localtime(&now), sizeof(struct tm));
800 #else
801 localtime_r(&tm, &t);
802 localtime_r(&now, &n);
803 #endif /* _WIN32 */
804 char *str = cxMalloc(a, 16);
805 if(t.tm_year == n.tm_year) {
806 strftime(str, 16, "%b %d %H:%M", &t);
807 } else {
808 strftime(str, 16, "%b %d %Y", &t);
809 }
810 return str;
811 }
812
813 static int cmp_file_type_name(IndexEntry *a, IndexEntry *b) {
814 if(a->isdir != b->isdir) {
815 return a->isdir ? -1 : 1;
816 }
817 return strcmp(a->name, b->name);
818 }
819
718 int service_index(pblock *pb, Session *sn, Request *rq) { 820 int service_index(pblock *pb, Session *sn, Request *rq) {
719 //printf("service_index\n"); 821 //printf("service_index\n");
822 const CxAllocator *a = pool_allocator(sn->pool);
720 823
721 char *path = pblock_findkeyval(pb_key_path, rq->vars); 824 char *path = pblock_findkeyval(pb_key_path, rq->vars);
722 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); 825 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb);
723
724 cxstring r_uri = cx_str(uri);
725 826
726 // open the file 827 // open the file
727 VFSContext *vfs = vfs_request_context(sn, rq); 828 VFSContext *vfs = vfs_request_context(sn, rq);
728 VFS_DIR dir = vfs_opendir(vfs, path); 829 VFS_DIR dir = vfs_opendir(vfs, path);
729 if(!dir) { 830 if(!dir) {
731 } 832 }
732 833
733 sbuf_t *out = sbuf_new(1024); // output buffer 834 sbuf_t *out = sbuf_new(1024); // output buffer
734 835
735 // write html header 836 // write html header
736 sbuf_puts(out, "<html>\n<head>\n<title>Index of "); 837 sbuf_puts(out, "<!DOCTYPE html>\n<html>\n<head>\n<title>Index of ");
737 sbuf_puts(out, uri); 838 sbuf_puts(out, uri);
738 sbuf_puts(out, "</title>\n</head><body>\n<h1>Index of "); 839 sbuf_puts(out, "</title>\n");
840 sbuf_puts(out, "<style>\n");
841 sbuf_puts(out, "th { text-align: left; }\n");
842 sbuf_puts(out, "td { padding-right: 1em; }\n");
843 sbuf_puts(out, "</style>\n");
844 sbuf_puts(out, "</head><body>\n<h1>Index of ");
739 sbuf_puts(out, uri); 845 sbuf_puts(out, uri);
740 sbuf_puts(out, "</h1><hr>\n\n"); 846 sbuf_puts(out, "</h1><hr>\n\n");
741 847
742 // list directory 848 CxList *files = cxLinkedListCreate(a, (cx_compare_func)cmp_file_type_name, sizeof(IndexEntry));
849 if(!files) {
850 return REQ_ABORTED;
851 }
852
853 // read directory at store entries in the files list
854 int ret = REQ_PROCEED;
743 VFS_ENTRY f; 855 VFS_ENTRY f;
744 while(vfs_readdir(dir, &f)) { 856 while(vfs_readdir_stat(dir, &f)) {
745 cxstring filename = cx_str(f.name); 857 IndexEntry entry;
746 858 entry.name = pool_strdup(sn->pool, f.name);
859 if(!entry.name) {
860 ret = REQ_ABORTED;
861 break;
862 }
863 if(f.stat_errno == 0) {
864 entry.isdir = S_ISDIR(f.stat.st_mode);
865 entry.size = (size_t)f.stat.st_size;
866 entry.size_str = util_size_str(a, entry.isdir, entry.size);
867 entry.lastmodified = util_date_str(a, f.stat.st_mtime);
868 } else {
869 entry.isdir = 0;
870 entry.lastmodified = NULL;
871 entry.size_str = NULL;
872 entry.size = 0;
873 }
874
875 if(cxListAdd(files, &entry)) {
876 ret = REQ_ABORTED;
877 break;
878 }
879 }
880
881 // generate html output
882 sbuf_puts(out, "<table>\n<tr><th>Type</th><th>Name</th><th>Size</th><th>Last Modified</th></tr>\n");
883 cxListSort(files);
884 CxIterator i = cxListIterator(files);
885 cx_foreach(IndexEntry *, entry, i) {
886 sbuf_puts(out, "<tr>\n");
887
888 sbuf_puts(out, "<td>");
889 sbuf_puts(out, entry->isdir ? "[DIR]" : "[FILE]");
890 sbuf_puts(out, "</td>");
891
892 sbuf_puts(out, "<td>");
747 sbuf_puts(out, "<a href=\""); 893 sbuf_puts(out, "<a href=\"");
748 sbuf_append(out, r_uri); 894 sbuf_puts(out, entry->name);
749 sbuf_append(out, filename);
750 sbuf_puts(out, "\">"); 895 sbuf_puts(out, "\">");
751 sbuf_append(out, filename); 896 sbuf_puts(out, entry->name);
752 sbuf_puts(out, "</a><br>\n"); 897 sbuf_puts(out, "</a>");
753 } 898 sbuf_puts(out, "</td>");
754 899
755 sbuf_puts(out, "\n</body>\n</html>\n"); 900 sbuf_puts(out, "<td>");
901 if(entry->size_str) {
902 sbuf_puts(out, entry->size_str);
903 }
904 sbuf_puts(out, "</td>");
905
906 sbuf_puts(out, "<td>");
907 if(entry->size_str) {
908 sbuf_puts(out, entry->lastmodified);
909 }
910 sbuf_puts(out, "</td>");
911
912 sbuf_puts(out, "</tr>\n");
913 }
914
915 sbuf_puts(out, "</table>\n</body>\n</html>\n");
756 916
757 // send stuff to client 917 // send stuff to client
758 pblock_removekey(pb_key_content_type, rq->srvhdrs); 918 if(ret == REQ_PROCEED) {
759 pblock_kvinsert(pb_key_content_type, "text/html", 9, rq->srvhdrs); 919 pblock_removekey(pb_key_content_type, rq->srvhdrs);
760 pblock_nninsert("content-length", out->length, rq->srvhdrs); 920 pblock_kvinsert(pb_key_content_type, "text/html; charset=utf-8", 24, rq->srvhdrs);
761 protocol_status(sn, rq, 200, NULL); 921 pblock_nninsert("content-length", out->length, rq->srvhdrs);
762 http_start_response(sn, rq); 922 protocol_status(sn, rq, 200, NULL);
763 923 http_start_response(sn, rq);
764 net_write(sn->csd, out->ptr, out->length); 924
925 net_write(sn->csd, out->ptr, out->length);
926 }
765 927
766 // close 928 // close
767 vfs_closedir(dir); 929 vfs_closedir(dir);
768 sbuf_free(out); 930 sbuf_free(out);
769 931
770 return REQ_PROCEED; 932 return ret;
771 } 933 }
772 934
773 int send_options(pblock *pb, Session *sn, Request *rq) { 935 int send_options(pblock *pb, Session *sn, Request *rq) {
774 char *allow = "HEAD, GET, PUT, DELETE, TRACE, OPTIONS, MOVE, COPY, " 936 char *allow = "HEAD, GET, PUT, DELETE, TRACE, OPTIONS, MOVE, COPY, "
775 "PROPFIND, PROPPATCH, MKCOL, LOCK, UNLOCK, ACL, REPORT"; 937 "PROPFIND, PROPPATCH, MKCOL, LOCK, UNLOCK, ACL, REPORT";

mercurial