32 |
32 |
33 #include "service.h" |
33 #include "service.h" |
34 #include "../util/io.h" |
34 #include "../util/io.h" |
35 #include "../util/pblock.h" |
35 #include "../util/pblock.h" |
36 #include "../daemon/protocol.h" |
36 #include "../daemon/protocol.h" |
|
37 #include "../daemon/vfs.h" |
37 |
38 |
38 #include <sys/sendfile.h> |
39 #include <sys/sendfile.h> |
39 #include "../util/strbuf.h" |
40 #include "../util/strbuf.h" |
40 |
41 |
41 #include <errno.h> |
42 #include <errno.h> |
52 /* |
53 /* |
53 * prepares for servicing a file |
54 * prepares for servicing a file |
54 * |
55 * |
55 * adds content-length header and starts the response |
56 * adds content-length header and starts the response |
56 * |
57 * |
57 * return the file descriptor or -1 |
58 * return the opened file |
58 */ |
59 */ |
59 int prepare_service_file(Session *sn, Request *rq) { |
60 SYS_FILE prepare_service_file(Session *sn, Request *rq, struct stat *s) { |
60 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); |
61 char *ppath = pblock_findkeyval(pb_key_ppath, rq->vars); |
61 |
62 |
62 /* open the file */ |
63 /* open the file */ |
63 int fd = open(ppath, O_RDONLY); |
64 VFSContext *vfs = vfs_request_context(sn, rq); |
64 if(fd < 0) { |
65 SYS_FILE fd = vfs_open(vfs, ppath, O_RDONLY); |
65 //perror("prepare_service_file: open"); |
66 if(!fd) { |
66 |
67 // vfs_open sets http status code |
67 int status = 500; |
68 return NULL; |
68 int en = errno; |
|
69 switch(en) { |
|
70 case EACCES: { |
|
71 status = 403; |
|
72 break; |
|
73 } |
|
74 case ENOENT: { |
|
75 status = 404; |
|
76 break; |
|
77 } |
|
78 } |
|
79 protocol_status(sn, rq, status, NULL); |
|
80 return -1; |
|
81 } |
69 } |
82 |
70 |
83 /* get stat */ |
71 /* get stat */ |
84 struct stat stat; |
72 if (vfs_fstat(vfs, fd, s) != 0) { |
85 if (fstat(fd, &stat) != 0) { |
|
86 //perror("prepare_service_file: stat"); |
73 //perror("prepare_service_file: stat"); |
87 |
|
88 protocol_status(sn, rq, 500, NULL); |
74 protocol_status(sn, rq, 500, NULL); |
89 return -1; |
75 return NULL; |
90 } |
76 } |
91 |
77 |
92 /* add content-length header*/ |
78 /* add content-length header*/ |
93 char contentLength[32]; |
79 char contentLength[32]; |
94 int len = snprintf(contentLength, 32, "%d", stat.st_size); |
80 int len = snprintf(contentLength, 32, "%d", s->st_size); |
95 |
81 |
96 pblock_kvinsert(pb_key_content_length, contentLength, len, rq->srvhdrs); |
82 pblock_kvinsert(pb_key_content_length, contentLength, len, rq->srvhdrs); |
97 |
83 |
98 /* start response */ |
84 /* start response */ |
99 protocol_status(sn, rq, 200, NULL); |
85 protocol_status(sn, rq, 200, NULL); |
101 |
87 |
102 return fd; |
88 return fd; |
103 } |
89 } |
104 |
90 |
105 int send_file(pblock *pb, Session *sn, Request *rq) { |
91 int send_file(pblock *pb, Session *sn, Request *rq) { |
106 int fd = prepare_service_file(sn, rq); |
92 struct stat s; |
107 if(fd < 0) { |
93 SYS_FILE fd = prepare_service_file(sn, rq, &s); |
|
94 if(!fd) { |
108 // if an error occurs, prepare_service_file sets the http status code |
95 // if an error occurs, prepare_service_file sets the http status code |
109 // we can just return REQ_ABORTED |
96 // we can just return REQ_ABORTED |
110 return REQ_ABORTED; |
97 return REQ_ABORTED; |
111 } |
98 } |
|
99 |
|
100 // send file |
|
101 sendfiledata sfd; |
|
102 sfd.fd = fd; |
|
103 sfd.len = s.st_size; |
|
104 sfd.offset = 0; |
|
105 sfd.header = NULL; |
|
106 sfd.trailer = NULL; |
|
107 net_sendfile(sn->csd, &sfd); |
|
108 |
|
109 vfs_close(fd); |
|
110 |
112 |
111 |
113 /* send file*/ |
112 /* send file*/ |
114 SystemIOStream *io = (SystemIOStream*) sn->csd; |
113 //SystemIOStream *io = (SystemIOStream*) sn->csd; |
115 |
114 //off_t fileoffset = 0; |
116 off_t fileoffset = 0; |
115 //int len = atoi(pblock_findkeyval(pb_key_content_length, rq->srvhdrs)); |
117 int len = atoi(pblock_findkeyval(pb_key_content_length, rq->srvhdrs)); |
116 //sendfile(io->fd, fd->fd, &fileoffset, len); |
118 sendfile(io->fd, fd, &fileoffset, len); |
117 |
119 |
118 //close(fd); |
120 close(fd); |
|
121 |
119 |
122 return REQ_PROCEED; |
120 return REQ_PROCEED; |
123 } |
121 } |
124 |
122 |
125 int service_hello(pblock *pb, Session *sn, Request *rq) { |
123 int service_hello(pblock *pb, Session *sn, Request *rq) { |