49 * |
50 * |
50 * adds content-length header |
51 * adds content-length header |
51 * |
52 * |
52 * return the opened file |
53 * return the opened file |
53 */ |
54 */ |
54 SYS_FILE prepare_service_file(Session *sn, Request *rq, VFSContext *vfs, struct stat *s) { |
55 SYS_FILE prepare_service_file(Session *sn, Request *rq, VFSContext *vfs, struct stat *s, int *ret) { |
55 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
56 char *path = pblock_findkeyval(pb_key_path, rq->vars); |
56 |
57 |
57 // open the file |
58 // open the file |
58 SYS_FILE fd = vfs_open(vfs, path, O_RDONLY); |
59 SYS_FILE fd = vfs_open(vfs, path, O_RDONLY); |
59 if(!fd) { |
60 if(!fd) { |
68 return NULL; |
69 return NULL; |
69 } |
70 } |
70 |
71 |
71 // check if the file is a directory |
72 // check if the file is a directory |
72 if(S_ISDIR(s->st_mode)) { |
73 if(S_ISDIR(s->st_mode)) { |
73 pblock_nvinsert("content-length", "0", rq->srvhdrs); |
|
74 pblock_removekey(pb_key_content_type, rq->srvhdrs); |
74 pblock_removekey(pb_key_content_type, rq->srvhdrs); |
75 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); |
75 char *uri = pblock_findkeyval(pb_key_uri, rq->reqpb); |
76 size_t urilen = strlen(uri); |
76 size_t urilen = strlen(uri); |
77 char *location = pool_malloc(sn->pool, urilen + 2); |
77 if(urilen > 0 && uri[urilen-1] != '/') { |
78 memcpy(location, uri, urilen); |
78 pblock_nvinsert("content-length", "0", rq->srvhdrs); |
79 location[urilen] = '/'; |
79 char *location = pool_malloc(sn->pool, urilen + 2); |
80 location[urilen+1] = '\0'; |
80 memcpy(location, uri, urilen); |
81 pblock_kvinsert(pb_key_location, location, urilen + 1, rq->srvhdrs); |
81 location[urilen] = '/'; |
82 protocol_status(sn, rq, 302, NULL); |
82 location[urilen+1] = '\0'; |
83 http_start_response(sn, rq); |
83 pblock_kvinsert(pb_key_location, location, urilen + 1, rq->srvhdrs); |
|
84 protocol_status(sn, rq, 302, NULL); |
|
85 http_start_response(sn, rq); |
|
86 *ret = REQ_PROCEED; |
|
87 } else { |
|
88 // set content-type to "internal/directory" and ret to REQ_NOACTION |
|
89 // maybe a SAF will respond to that |
|
90 pblock_kvinsert( |
|
91 pb_key_content_type, |
|
92 OBJTYPE_INTERNAL_DIRECTORY, |
|
93 sizeof(OBJTYPE_INTERNAL_DIRECTORY)-1, |
|
94 rq->srvhdrs); |
|
95 *ret = REQ_NOACTION; |
|
96 } |
84 vfs_close(fd); |
97 vfs_close(fd); |
85 return NULL; |
98 return NULL; |
86 } |
99 } |
87 |
100 |
88 // sets last-modified, content-length and checks conditions |
101 // sets last-modified, content-length and checks conditions |
89 const char *etag = vfs_getetag(fd); // optionally, get etag from file |
102 const char *etag = vfs_getetag(fd); // optionally, get etag from file |
90 if(http_set_finfo_etag(sn, rq, s, etag) != REQ_PROCEED) { |
103 if(http_set_finfo_etag(sn, rq, s, etag) != REQ_PROCEED) { |
91 vfs_close(fd); |
104 vfs_close(fd); |
|
105 *ret = REQ_ABORTED; |
92 return NULL; |
106 return NULL; |
93 } |
107 } |
94 |
108 |
95 // TODO: check if vfs can seek |
109 // TODO: check if vfs can seek |
96 pblock_kvinsert(pb_key_accept_ranges, "bytes", 5, rq->srvhdrs); |
110 pblock_kvinsert(pb_key_accept_ranges, "bytes", 5, rq->srvhdrs); |
572 pool_free(sn->pool, r); |
586 pool_free(sn->pool, r); |
573 return 0; |
587 return 0; |
574 } |
588 } |
575 |
589 |
576 int send_file(pblock *pb, Session *sn, Request *rq) { |
590 int send_file(pblock *pb, Session *sn, Request *rq) { |
|
591 int ret = REQ_NOACTION; |
577 struct stat s; |
592 struct stat s; |
578 VFSContext *vfs = vfs_request_context(sn, rq); |
593 VFSContext *vfs = vfs_request_context(sn, rq); |
579 SYS_FILE fd = prepare_service_file(sn, rq, vfs, &s); |
594 SYS_FILE fd = prepare_service_file(sn, rq, vfs, &s, &ret); |
580 if(!fd) { |
595 if(!fd) { |
581 // if an error occurs, prepare_service_file sets the http status code |
596 // if an error occurs, prepare_service_file sets the http status code |
582 // we can just return REQ_ABORTED |
597 // in case fd is a directory and the uri already ends with an trailing |
583 return REQ_ABORTED; |
598 // '/', ret is set to REQ_NOACTION |
|
599 return ret; |
584 } |
600 } |
585 |
601 |
586 // get and validate range header |
602 // get and validate range header |
587 char *range_header = pblock_findkeyval(pb_key_range, rq->headers); |
603 char *range_header = pblock_findkeyval(pb_key_range, rq->headers); |
588 HttpRange *range = NULL; |
604 HttpRange *range = NULL; |