36 #include "../util/util.h" |
36 #include "../util/util.h" |
37 #include "../daemon/protocol.h" |
37 #include "../daemon/protocol.h" |
38 #include "../daemon/vfs.h" |
38 #include "../daemon/vfs.h" |
39 |
39 |
40 #include "../util/strbuf.h" |
40 #include "../util/strbuf.h" |
41 #include <ucx/string.h> |
41 #include <cx/string.h> |
42 #include <ucx/utils.h> |
42 #include <cx/utils.h> |
|
43 #include <cx/printf.h> |
43 |
44 |
44 #include <errno.h> |
45 #include <errno.h> |
45 |
46 |
46 /* |
47 /* |
47 * prepares servicing a file |
48 * prepares servicing a file |
110 } |
111 } |
111 |
112 |
112 static HttpRange* parse_range(Session *sn, char *header, int *status) { |
113 static HttpRange* parse_range(Session *sn, char *header, int *status) { |
113 *status = PROTOCOL_OK; |
114 *status = PROTOCOL_OK; |
114 |
115 |
115 sstr_t range = sstrtrim(sstr(header)); |
116 cxstring range = cx_strtrim(cx_str(header)); |
116 if(!sstrprefix(range, S("bytes="))) { |
117 if(!cx_strprefix(range, (cxstring)CX_STR("bytes="))) { |
117 // unknown range unit - ignore range header |
118 // unknown range unit - ignore range header |
118 return NULL; |
119 return NULL; |
119 } |
120 } |
120 |
121 |
121 // get byte-range-set |
122 // get byte-range-set |
122 range = sstrsubs(range, 6); |
123 range = cx_strsubs(range, 6); |
123 if(range.length < 1) { |
124 if(range.length < 1) { |
124 return NULL; |
125 return NULL; |
125 } |
126 } |
126 |
127 |
127 HttpRange *range_list = NULL; |
128 HttpRange *range_list = NULL; |
130 int start = 0; |
131 int start = 0; |
131 int hasbegin = 0; |
132 int hasbegin = 0; |
132 for(int i=0;i<=range.length;i++) { |
133 for(int i=0;i<=range.length;i++) { |
133 char c = range.ptr[i]; |
134 char c = range.ptr[i]; |
134 if(c == '-') { |
135 if(c == '-') { |
135 sstr_t num = sstrsubsl(range, start, i-start); |
136 cxstring num = cx_strsubsl(range, start, i-start); |
136 if(num.length == 0) { |
137 if(num.length == 0) { |
137 // empty string before '-' is legal |
138 // empty string before '-' is legal |
138 hasbegin = 1; |
139 hasbegin = 1; |
139 begin = -1; |
140 begin = -1; |
140 start = i+1; |
141 start = i+1; |
150 // syntax error |
151 // syntax error |
151 free_range(sn, range_list); |
152 free_range(sn, range_list); |
152 return NULL; |
153 return NULL; |
153 } |
154 } |
154 } else if(c == ',' || c == '\0') { |
155 } else if(c == ',' || c == '\0') { |
155 sstr_t num = sstrsubsl(range, start, i-start); |
156 cxstring num = cx_strsubsl(range, start, i-start); |
156 if(hasbegin) { |
157 if(hasbegin) { |
157 long long n; |
158 long long n; |
158 if(num.length == 0) { |
159 if(num.length == 0) { |
159 // empty string after '-' is legal |
160 // empty string after '-' is legal |
160 n = -1; |
161 n = -1; |
493 |
494 |
494 return REQ_PROCESSING; |
495 return REQ_PROCESSING; |
495 } |
496 } |
496 |
497 |
497 struct multi_range_elm { |
498 struct multi_range_elm { |
498 sstr_t header; |
499 cxmutstr header; |
499 off_t offset; |
500 off_t offset; |
500 off_t length; |
501 off_t length; |
501 }; |
502 }; |
502 |
503 |
503 static int send_multi_range(Session *sn, Request *rq, SYS_FILE fd, off_t filelen, HttpRange *range) { |
504 static int send_multi_range(Session *sn, Request *rq, SYS_FILE fd, off_t filelen, HttpRange *range) { |
|
505 CxAllocator *a = pool_allocator(sn->pool); |
|
506 |
504 pb_param *content_type = pblock_remove("content-type", rq->srvhdrs); |
507 pb_param *content_type = pblock_remove("content-type", rq->srvhdrs); |
505 |
508 |
506 char sep[64]; |
509 char sep[64]; |
507 int seplen = util_mime_separator(sep); |
510 int seplen = util_mime_separator(sep); |
508 |
511 |
509 sstr_t newct = ucx_sprintf("multipart/byteranges; boundary=%s", sep+4); |
512 cxmutstr newct = cx_asprintf_a(a, "multipart/byteranges; boundary=%s", sep+4); |
510 pblock_kvinsert( |
513 pblock_kvinsert( |
511 pb_key_content_type, |
514 pb_key_content_type, |
512 newct.ptr, |
515 newct.ptr, |
513 newct.length, |
516 newct.length, |
514 rq->srvhdrs); |
517 rq->srvhdrs); |
515 free(newct.ptr); |
518 cxFree(a, newct.ptr); |
516 |
519 |
517 // calculate content-length |
520 // calculate content-length |
518 off_t response_len = 0; |
521 off_t response_len = 0; |
519 |
522 |
520 int nrange = 0; |
523 int nrange = 0; |
522 while(rangeelm) { |
525 while(rangeelm) { |
523 nrange++; |
526 nrange++; |
524 rangeelm = rangeelm->next; |
527 rangeelm = rangeelm->next; |
525 } |
528 } |
526 |
529 |
527 struct multi_range_elm *r = calloc(nrange, sizeof(struct multi_range_elm)); |
530 struct multi_range_elm *r = pool_calloc(sn->pool, nrange, sizeof(struct multi_range_elm)); |
528 rangeelm = range; |
531 rangeelm = range; |
529 int i=0; |
532 int i=0; |
530 while(rangeelm) { |
533 while(rangeelm) { |
531 range2off(rangeelm, filelen, &(r[i].offset), &(r[i].length)); |
534 range2off(rangeelm, filelen, &(r[i].offset), &(r[i].length)); |
532 r[i].header = ucx_sprintf( |
535 r[i].header = cx_asprintf_a( |
|
536 a, |
533 "%s\r\nContent-Type: %s\r\nContent-Range: bytes %lld-%lld/%lld\r\n\r\n", |
537 "%s\r\nContent-Type: %s\r\nContent-Range: bytes %lld-%lld/%lld\r\n\r\n", |
534 sep, |
538 sep, |
535 content_type->value, |
539 content_type->value, |
536 (long long)r[i].offset, |
540 (long long)r[i].offset, |
537 (long long)r[i].offset+r[i].length - 1, |
541 (long long)r[i].offset+r[i].length - 1, |
563 rangeelm = rangeelm->next; |
567 rangeelm = rangeelm->next; |
564 i++; |
568 i++; |
565 } |
569 } |
566 net_printf(sn->csd, "%s--\r\n", sep); |
570 net_printf(sn->csd, "%s--\r\n", sep); |
567 |
571 |
568 free(r); |
572 pool_free(sn->pool, r); |
569 return 0; |
573 return 0; |
570 } |
574 } |
571 |
575 |
572 int send_file(pblock *pb, Session *sn, Request *rq) { |
576 int send_file(pblock *pb, Session *sn, Request *rq) { |
573 struct stat s; |
577 struct stat s; |
694 //printf("service_index\n"); |
698 //printf("service_index\n"); |
695 |
699 |
696 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
700 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
697 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); |
701 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); |
698 |
702 |
699 sstr_t r_uri = sstr(uri); |
703 cxstring r_uri = cx_str(uri); |
700 |
704 |
701 // open the file |
705 // open the file |
702 VFSContext *vfs = vfs_request_context(sn, rq); |
706 VFSContext *vfs = vfs_request_context(sn, rq); |
703 VFS_DIR dir = vfs_opendir(vfs, path); |
707 VFS_DIR dir = vfs_opendir(vfs, path); |
704 if(!dir) { |
708 if(!dir) { |
715 sbuf_puts(out, "</h1><hr>\n\n"); |
719 sbuf_puts(out, "</h1><hr>\n\n"); |
716 |
720 |
717 // list directory |
721 // list directory |
718 VFS_ENTRY f; |
722 VFS_ENTRY f; |
719 while(vfs_readdir(dir, &f)) { |
723 while(vfs_readdir(dir, &f)) { |
720 sstr_t filename = sstr(f.name); |
724 cxstring filename = cx_str(f.name); |
721 |
725 |
722 sbuf_puts(out, "<a href=\""); |
726 sbuf_puts(out, "<a href=\""); |
723 sbuf_append(out, r_uri); |
727 sbuf_append(out, r_uri); |
724 sbuf_append(out, filename); |
728 sbuf_append(out, filename); |
725 sbuf_puts(out, "\">"); |
729 sbuf_puts(out, "\">"); |