src/server/safs/cgi.c

changeset 431
032b0ad35ee3
parent 430
83560f32e7d5
child 433
39fe86ae4db0
equal deleted inserted replaced
430:83560f32e7d5 431:032b0ad35ee3
141 system_close(handler->process.in[1]); 141 system_close(handler->process.in[1]);
142 handler->process.in[1] = -1; 142 handler->process.in[1] = -1;
143 143
144 handler->parser = cgi_parser_new(sn, rq); 144 handler->parser = cgi_parser_new(sn, rq);
145 145
146 // set pipes non-blocking
147 int flags;
148 if ((flags = fcntl(handler->process.err[0], F_GETFL, 0)) == -1) {
149 flags = 0;
150 }
151 if (fcntl(handler->process.err[0], F_SETFL, flags | O_NONBLOCK) != 0) {
152 log_ereport(LOG_FAILURE, "cgi-bin: fcntl err[0] failed: %s", strerror(errno));
153 }
154 if ((flags = fcntl(handler->process.out[0], F_GETFL, 0)) == -1) {
155 flags = 0;
156 }
157 if (fcntl(handler->process.out[0], F_SETFL, flags | O_NONBLOCK) != 0) {
158 log_ereport(LOG_FAILURE, "cgi-bin: fcntl out[0] failed: %s", strerror(errno));
159 }
160
161 // create events for reading cgi's stdout/stderr
146 Event *readev = pool_malloc(sn->pool, sizeof(Event)); 162 Event *readev = pool_malloc(sn->pool, sizeof(Event));
147 ZERO(readev, sizeof(Event)); 163 ZERO(readev, sizeof(Event));
148 readev->cookie = handler; 164 readev->cookie = handler;
149 readev->fn = cgi_stdout_readevent; 165 readev->fn = cgi_stdout_readevent;
150 readev->finish = cgi_event_finish; 166 readev->finish = cgi_event_finish;
159 ZERO(writeev, sizeof(Event)); 175 ZERO(writeev, sizeof(Event));
160 writeev->cookie = handler; 176 writeev->cookie = handler;
161 // TODO: fn 177 // TODO: fn
162 178
163 handler->writeev = writeev; 179 handler->writeev = writeev;
180 handler->stderrev = stderr_readev;
164 181
165 // add poll events for cgi stdout/stderr 182 // add poll events for cgi stdout/stderr
166 int error = 0; 183 int error = 0;
167 if(ev_pollin(sn->ev, handler->process.err[0], stderr_readev)) { 184 if(ev_pollin(sn->ev, handler->process.err[0], stderr_readev)) {
168 log_ereport(LOG_FAILURE, "send-cgi: stderr ev_pollin failed"); 185 log_ereport(LOG_FAILURE, "send-cgi: stderr ev_pollin failed");
228 break; 245 break;
229 } 246 }
230 } 247 }
231 } 248 }
232 if(r < 0 && errno == EWOULDBLOCK) { 249 if(r < 0 && errno == EWOULDBLOCK) {
233 event->events = EVENT_POLLIN;
234 return 1; 250 return 1;
235 } 251 }
236 252
237 char *ctlen_header = pblock_findkeyval(pb_key_content_length, rq->srvhdrs); 253 char *ctlen_header = pblock_findkeyval(pb_key_content_length, rq->srvhdrs);
238 if(ctlen_header) { 254 if(ctlen_header) {
252 return 0; 268 return 0;
253 } 269 }
254 270
255 int cgi_stderr_readevent(EventHandler *ev, Event *event) { 271 int cgi_stderr_readevent(EventHandler *ev, Event *event) {
256 CGIHandler *handler = event->cookie; 272 CGIHandler *handler = event->cookie;
273 pool_handle_t *pool = handler->parser->sn->pool;
257 274
258 char buf[4096]; 275 char buf[4096];
259 ssize_t r = read(handler->process.err[0], buf, 4096); 276 char *line = buf;
260 log_ereport(LOG_INFORM, "cgi pid %d %s stderr: %.*s", (int)handler->process.pid, handler->path, (int)r, buf); 277 int line_start = 0;
261 278 ssize_t r;
279 while((r = read(handler->process.err[0], buf, 4096)) > 0) {
280 int pos = 0;
281 // log stderr output lines
282 for(int i=0;i<r;i++) {
283 if(buf[i] == '\n') {
284 log_ereport(
285 LOG_INFORM,
286 "cgi pid %d %s stderr: %.*s%.*s",
287 (int)handler->process.pid,
288 handler->path,
289 (int)handler->stderr_tmplen,
290 handler->stderr_tmp,
291 i - line_start,
292 line + line_start);
293 line_start = i+1;
294 pos = i+1;
295
296 if(handler->stderr_tmp) {
297 pool_free(pool, handler->stderr_tmp);
298 handler->stderr_tmp = NULL;
299 handler->stderr_tmplen = 0;
300 }
301 }
302 }
303
304 // check for incomplete line
305 if(pos < r) {
306 int tmplen = r-pos;
307 if(handler->stderr_tmp) {
308 handler->stderr_tmp = pool_realloc(pool, handler->stderr_tmp, handler->stderr_tmplen + tmplen);
309 memcpy(handler->stderr_tmp + handler->stderr_tmplen, line + line_start, tmplen);
310 handler->stderr_tmplen += tmplen;
311 } else {
312 handler->stderr_tmp = pool_malloc(pool, tmplen);
313 memcpy(handler->stderr_tmp, line + line_start, tmplen);
314 handler->stderr_tmplen = tmplen;
315 }
316 } else {
317 pool_free(pool, handler->stderr_tmp);
318 handler->stderr_tmp = NULL;
319 handler->stderr_tmplen = 0;
320 }
321 }
322
323
324 if(r < 0 && errno == EWOULDBLOCK) {
325 return 1;
326 }
327
328 if(handler->stderr_tmp) {
329 pool_free(handler->parser->sn->pool, handler->stderr_tmp);
330 }
331 handler->stderr_finished = TRUE;
262 return 0; 332 return 0;
263 } 333 }
264 334
265 int cgi_event_finish(EventHandler *ev, Event *event) { 335 int cgi_event_finish(EventHandler *ev, Event *event) {
266 CGIHandler *handler = event->cookie; 336 CGIHandler *handler = event->cookie;
267 CGIResponseParser *parser = handler->parser; 337 CGIResponseParser *parser = handler->parser;
268 Session *sn = parser->sn; 338 Session *sn = parser->sn;
269 Request *rq = parser->rq; 339 Request *rq = parser->rq;
270 340
271 if(handler->result == REQ_ABORTED) { 341 if(handler->result == REQ_ABORTED) {
272 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", handler->path); 342 log_ereport(LOG_FAILURE, "cgi-send: kill script: %s", handler->path);
273 kill(handler->process.pid, SIGKILL); 343 kill(handler->process.pid, SIGKILL);
344 }
345
346 if(!handler->stderr_finished) {
347 // stderr handler is still active
348 // set stderr event finish function, to run the finish code later
349 handler->stderrev->finish = cgi_event_finish;
350 return 0;
274 } 351 }
275 352
276 int exit_code = cgi_close(&handler->process); 353 int exit_code = cgi_close(&handler->process);
277 if(exit_code != 0) { 354 if(exit_code != 0) {
278 log_ereport(LOG_FAILURE, "send-cgi: script: %s exited with code %d", handler->path, exit_code); 355 log_ereport(LOG_FAILURE, "send-cgi: script: %s exited with code %d", handler->path, exit_code);

mercurial