src/server/safs/cgi.c

changeset 162
b169992137a8
parent 161
aadda87bad1b
child 164
6f47eb624665
equal deleted inserted replaced
161:aadda87bad1b 162:b169992137a8
30 30
31 #include <stdio.h> 31 #include <stdio.h>
32 #include <stdlib.h> 32 #include <stdlib.h>
33 #include <unistd.h> 33 #include <unistd.h>
34 34
35 #include <sys/types.h>
36 #include <signal.h>
37 #include <sys/wait.h>
38
35 #include "../util/util.h" 39 #include "../util/util.h"
36 #include "../util/pblock.h" 40 #include "../util/pblock.h"
37 #include "../../ucx/string.h" 41 #include "../../ucx/string.h"
38 42
39 #include "../util/io.h" 43 #include "../util/io.h"
97 if(content_length > 0) { 101 if(content_length > 0) {
98 ssize_t n = 0; 102 ssize_t n = 0;
99 while(n < content_length) { 103 while(n < content_length) {
100 r = netbuf_getbytes(sn->inbuf, buf, 4096); 104 r = netbuf_getbytes(sn->inbuf, buf, 4096);
101 if(r <= 0) { 105 if(r <= 0) {
102 // TODO: handleerror 106 // TODO: handle error
107 log_ereport(
108 LOG_FAILURE,
109 "send-cgi: script: %s: cannot read request body",
110 path);
111 kill(cgip.pid, SIGTERM);
103 cgi_close(&cgip); 112 cgi_close(&cgip);
104 return REQ_ABORTED; 113 return REQ_ABORTED;
105 } 114 }
106 write(cgip.in[1], buf, r); 115 ssize_t w = write(cgip.in[1], buf, r);
116 if(w <= 0) {
117 // TODO: handle error
118 log_ereport(
119 LOG_FAILURE,
120 "send-cgi: script: %s: cannot send request body to cgi process",
121 path);
122 kill(cgip.pid, SIGKILL);
123 cgi_close(&cgip);
124 return REQ_ABORTED;
125 }
107 n += r; 126 n += r;
108 } 127 }
109 } 128 }
110 close(cgip.in[1]); 129 close(cgip.in[1]);
111 cgip.in[1] = -1; 130 cgip.in[1] = -1;
112 131
113 // read from child 132 // read from child
114 CGIResponseParser *parser = cgi_parser_new(sn, rq); 133 CGIResponseParser *parser = cgi_parser_new(sn, rq);
115 WSBool cgiheader = TRUE; 134 WSBool cgiheader = TRUE;
116 ssize_t wr = 0; 135 ssize_t wr = 0;
117 int result = REQ_PROCEED; 136 int result = REQ_PROCEED;
137 size_t response_length = 0;
118 while((r = read(cgip.out[0], buf, 4096)) > 0) { 138 while((r = read(cgip.out[0], buf, 4096)) > 0) {
119 if(cgiheader) { 139 if(cgiheader) {
120 size_t pos; 140 size_t pos;
121 ret = cgi_parse_response(parser, buf, r, &pos); 141 ret = cgi_parse_response(parser, buf, r, &pos);
122 if(ret == -1) { 142 if(ret == -1) {
143 log_ereport(
144 LOG_FAILURE,
145 "broken cgi script response: path: %s", path);
123 protocol_status(sn, rq, 500, NULL); 146 protocol_status(sn, rq, 500, NULL);
124 result = REQ_ABORTED; 147 result = REQ_ABORTED;
125 break; 148 break;
126 } else if(ret == 0) {
127
128 } else if(ret == 1) { 149 } else if(ret == 1) {
129 cgiheader = FALSE; 150 cgiheader = FALSE;
130 if(parser->status > 0) { 151 if(parser->status > 0) {
131 protocol_status(sn, rq, parser->status, parser->msg); 152 protocol_status(sn, rq, parser->status, parser->msg);
132 } 153 }
133 http_start_response(sn, rq); 154 http_start_response(sn, rq);
134 if(pos < r) { 155 if(pos < r) {
156 response_length += r-pos;
135 wr = net_write(sn->csd, &buf[pos], r-pos); 157 wr = net_write(sn->csd, &buf[pos], r-pos);
136 if(wr <= 0) { 158 if(wr <= 0) {
137 result = REQ_ABORTED; 159 result = REQ_ABORTED;
138 break; 160 break;
139 } 161 }
140 } 162 }
141 } 163 }
142 } else { 164 } else {
165 response_length = r;
143 wr = net_write(sn->csd, buf, r); 166 wr = net_write(sn->csd, buf, r);
144 if(wr <= 0) { 167 if(wr <= 0) {
145 result = REQ_ABORTED; 168 result = REQ_ABORTED;
146 break; 169 break;
147 } 170 }
148 } 171 }
149 } 172 }
150 173
151 cgi_close(&cgip); 174 char *ctlen_header = pblock_findkeyval(pb_key_content_length, rq->srvhdrs);
175 if(ctlen_header) {
176 int64_t ctlenhdr;
177 if(util_strtoint(ctlen_header, &ctlenhdr)) {
178 if(ctlenhdr != response_length) {
179 log_ereport(
180 LOG_FAILURE,
181 "cgi-send: script: %s: content length mismatch",
182 path);
183 rq->rq_attr.keep_alive = 0;
184 result = REQ_ABORTED;
185 }
186 }
187 }
188
189 if(result == REQ_ABORTED) {
190 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", path);
191 kill(cgip.pid, SIGKILL);
192 }
193 cgi_close(&cgip); // TODO: check return value
152 194
153 cgi_parser_free(parser); 195 cgi_parser_free(parser);
154 return result; 196 return result;
155 } 197 }
156 198
207 } 249 }
208 250
209 return REQ_PROCEED; 251 return REQ_PROCEED;
210 } 252 }
211 253
212 void cgi_close(CGIProcess *p) { 254 int cgi_close(CGIProcess *p) {
255 int status = -1;
256 waitpid(p->pid, &status, 0);
257
213 if(p->in[0] != -1) { 258 if(p->in[0] != -1) {
214 close(p->in[0]); 259 close(p->in[0]);
215 } 260 }
216 if(p->in[1] != -1) { 261 if(p->in[1] != -1) {
217 close(p->in[1]); 262 close(p->in[1]);
220 close(p->out[0]); 265 close(p->out[0]);
221 } 266 }
222 if(p->out[1] != -1) { 267 if(p->out[1] != -1) {
223 close(p->out[1]); 268 close(p->out[1]);
224 } 269 }
270
271 return 0;
225 } 272 }
226 273
227 CGIResponseParser* cgi_parser_new(Session *sn, Request *rq) { 274 CGIResponseParser* cgi_parser_new(Session *sn, Request *rq) {
228 CGIResponseParser* parser = pool_malloc(sn->pool, sizeof(CGIResponseParser)); 275 CGIResponseParser* parser = pool_malloc(sn->pool, sizeof(CGIResponseParser));
229 parser->sn = sn; 276 parser->sn = sn;
385 *bpos = pos + npos; 432 *bpos = pos + npos;
386 return 1; 433 return 1;
387 } 434 }
388 } 435 }
389 } 436 }
390

mercurial