34 |
34 |
35 #include <sys/types.h> |
35 #include <sys/types.h> |
36 #include <signal.h> |
36 #include <signal.h> |
37 #include <sys/wait.h> |
37 #include <sys/wait.h> |
38 |
38 |
39 #include <ucx/string.h> |
39 #include <cx/string.h> |
40 |
40 |
41 #include "../util/util.h" |
41 #include "../util/util.h" |
42 #include "../util/pblock.h" |
42 #include "../util/pblock.h" |
43 #include "../daemon/netsite.h" |
43 #include "../daemon/netsite.h" |
44 #include "../util/io.h" |
44 #include "../util/io.h" |
214 p->pid = fork(); |
214 p->pid = fork(); |
215 if(p->pid == 0) { |
215 if(p->pid == 0) { |
216 // child |
216 // child |
217 |
217 |
218 // get script directory and script name |
218 // get script directory and script name |
219 sstr_t script = sstr(path); |
219 cxstring script = cx_str(path); |
220 sstr_t parent; |
220 cxmutstr parent; |
221 int len = strlen(path); |
221 int len = strlen(path); |
222 for(int i=len-1;i>=0;i--) { |
222 for(int i=len-1;i>=0;i--) { |
223 if(path[i] == '/') { |
223 if(path[i] == '/') { |
224 script = sstrn(path + i + 1, len - i); |
224 script = cx_strn(path + i + 1, len - i); |
225 parent = sstrdup(sstrn(path, i)); |
225 parent = cx_strdup(cx_strn(path, i)); |
226 if(chdir(parent.ptr)) { |
226 if(chdir(parent.ptr)) { |
227 perror("cgi_start: chdir"); |
227 perror("cgi_start: chdir"); |
228 free(parent.ptr); |
228 free(parent.ptr); |
229 exit(-1); |
229 exit(-1); |
230 } |
230 } |
279 |
279 |
280 CGIResponseParser* cgi_parser_new(Session *sn, Request *rq) { |
280 CGIResponseParser* cgi_parser_new(Session *sn, Request *rq) { |
281 CGIResponseParser* parser = pool_malloc(sn->pool, sizeof(CGIResponseParser)); |
281 CGIResponseParser* parser = pool_malloc(sn->pool, sizeof(CGIResponseParser)); |
282 parser->sn = sn; |
282 parser->sn = sn; |
283 parser->rq = rq; |
283 parser->rq = rq; |
284 parser->tmp = ucx_buffer_new(NULL, 64, UCX_BUFFER_AUTOEXTEND); |
|
285 parser->status = 0; |
284 parser->status = 0; |
286 parser->msg = NULL; |
285 parser->msg = NULL; |
|
286 cxBufferInit(&parser->tmp, NULL, 64, pool_allocator(sn->pool), CX_BUFFER_AUTO_EXTEND|CX_BUFFER_FREE_CONTENTS); |
287 return parser; |
287 return parser; |
288 } |
288 } |
289 |
289 |
290 void cgi_parser_free(CGIResponseParser *parser) { |
290 void cgi_parser_free(CGIResponseParser *parser) { |
291 if(parser->tmp) { |
291 if(parser->tmp.space) { |
292 ucx_buffer_free(parser->tmp); |
292 cxBufferDestroy(&parser->tmp); |
293 } |
293 } |
294 pool_free(parser->sn->pool, parser); |
294 pool_free(parser->sn->pool, parser); |
295 } |
295 } |
296 |
296 |
297 /* |
297 /* |
300 * 1: successfully parsed lines |
300 * 1: successfully parsed lines |
301 * 2: cgi response header complete (empty line) |
301 * 2: cgi response header complete (empty line) |
302 * -1: error |
302 * -1: error |
303 */ |
303 */ |
304 static int parse_lines(CGIResponseParser *parser, char *buf, size_t len, int *pos) { |
304 static int parse_lines(CGIResponseParser *parser, char *buf, size_t len, int *pos) { |
305 UcxAllocator a = util_pool_allocator(parser->sn->pool); |
305 CxAllocator *a = pool_allocator(parser->sn->pool); |
306 sstr_t name; |
306 cxmutstr name; |
307 sstr_t value; |
307 cxmutstr value; |
308 WSBool space = TRUE; |
308 WSBool space = TRUE; |
309 int i; |
309 int i; |
310 |
310 |
311 int line_begin = 0; |
311 int line_begin = 0; |
312 int value_begin = 0; |
312 int value_begin = 0; |
313 for(i=0;i<len;i++) { |
313 for(i=0;i<len;i++) { |
314 char c = buf[i]; |
314 char c = buf[i]; |
315 if(value_begin == line_begin && c == ':') { |
315 if(value_begin == line_begin && c == ':') { |
316 name = sstrn(buf + line_begin, i - line_begin); |
316 name = cx_mutstrn(buf + line_begin, i - line_begin); |
317 value_begin = i + 1; |
317 value_begin = i + 1; |
318 } else if(c == '\n') { |
318 } else if(c == '\n') { |
319 if(value_begin == line_begin) { |
319 if(value_begin == line_begin) { |
320 if(space) { |
320 if(space) { |
321 *pos = i + 1; |
321 *pos = i + 1; |
323 } else { |
323 } else { |
324 // line ends with content but without ':' -> error |
324 // line ends with content but without ':' -> error |
325 return -1; |
325 return -1; |
326 } |
326 } |
327 } |
327 } |
328 value = sstrn(buf + value_begin, i - value_begin); |
328 value = cx_mutstrn(buf + value_begin, i - value_begin); |
329 |
329 |
330 name = sstrlower_a(&a, sstrtrim(name)); |
330 cx_strlower(name); |
331 value = sstrtrim(value); |
331 name = cx_strdup_a(a, cx_strtrim((cxstring){name.ptr, name.length})); |
|
332 value = cx_strtrim_m(value); |
332 |
333 |
333 if(name.length == 0 || value.length == 0) { |
334 if(name.length == 0 || value.length == 0) { |
334 return -1; |
335 return -1; |
335 } |
336 } |
336 |
337 |
337 if(!sstrcmp(name, S("status"))) { |
338 if(!cx_strcmp((cxstring){name.ptr, name.length}, (cxstring)CX_STR("status"))) { |
338 sstr_t codestr = value; |
339 cxmutstr codestr = value; |
339 int j; |
340 int j; |
340 for(j=0;j<codestr.length;j++) { |
341 for(j=0;j<codestr.length;j++) { |
341 if(!isdigit(codestr.ptr[j])) { |
342 if(!isdigit(codestr.ptr[j])) { |
342 break; |
343 break; |
343 } |
344 } |
349 |
350 |
350 int64_t s = 0; |
351 int64_t s = 0; |
351 util_strtoint(codestr.ptr, &s); |
352 util_strtoint(codestr.ptr, &s); |
352 parser->status = (int)s; |
353 parser->status = (int)s; |
353 |
354 |
354 sstr_t msg = sstrtrim(sstrsubs(value, j + 1)); |
355 cxmutstr msg = cx_strtrim_m(cx_strsubs_m(value, j + 1)); |
355 |
356 |
356 if(msg.length > 0) { |
357 if(msg.length > 0) { |
357 parser->msg = sstrdup_pool(parser->sn->pool, msg).ptr; |
358 parser->msg = cx_strdup_pool(parser->sn->pool, msg).ptr; |
358 } |
359 } |
359 } else { |
360 } else { |
360 pblock_nvlinsert( |
361 pblock_nvlinsert( |
361 name.ptr, |
362 name.ptr, |
362 name.length, |
363 name.length, |
386 * 1: complete |
387 * 1: complete |
387 */ |
388 */ |
388 int cgi_parse_response(CGIResponseParser *parser, char *buf, size_t len, size_t *bpos) { |
389 int cgi_parse_response(CGIResponseParser *parser, char *buf, size_t len, size_t *bpos) { |
389 *bpos = 0; |
390 *bpos = 0; |
390 int pos = 0; |
391 int pos = 0; |
391 if(parser->tmp->pos > 0) { |
392 if(parser->tmp.pos > 0) { |
392 // the tmp buffer contains an unfinished line |
393 // the tmp buffer contains an unfinished line |
393 // fill up the buffer until the line is complete |
394 // fill up the buffer until the line is complete |
394 WSBool nb = FALSE; |
395 WSBool nb = FALSE; |
395 for(pos=0;pos<len;pos++) { |
396 for(pos=0;pos<len;pos++) { |
396 if(buf[pos] == '\n') { |
397 if(buf[pos] == '\n') { |
397 nb = TRUE; |
398 nb = TRUE; |
398 break; |
399 break; |
399 } |
400 } |
400 } |
401 } |
401 ucx_buffer_write(buf, 1, pos, parser->tmp); |
402 cxBufferWrite(buf, 1, pos, &parser->tmp); |
402 |
403 |
403 if(nb) { |
404 if(nb) { |
404 // line complete |
405 // line complete |
405 int npos; |
406 int npos; |
406 int r = parse_lines(parser, parser->tmp->space, parser->tmp->pos, &npos); |
407 int r = parse_lines(parser, parser->tmp.space, parser->tmp.pos, &npos); |
407 switch(r) { |
408 switch(r) { |
408 case -1: return -1; |
409 case -1: return -1; |
409 case 0: return -1; |
410 case 0: return -1; |
410 case 1: break; |
411 case 1: break; |
411 case 2: { |
412 case 2: { |
412 *bpos = pos + 1; |
413 *bpos = pos + 1; |
413 return 1; |
414 return 1; |
414 } |
415 } |
415 } |
416 } |
416 // reset tmp buffer |
417 // reset tmp buffer |
417 parser->tmp->pos = 0; |
418 parser->tmp.pos = 0; |
418 } else { |
419 } else { |
419 if(parser->tmp->pos > CGI_RESPONSE_MAX_LINE_LENGTH) { |
420 if(parser->tmp.pos > CGI_RESPONSE_MAX_LINE_LENGTH) { |
420 return -1; |
421 return -1; |
421 } |
422 } |
422 } |
423 } |
423 } |
424 } |
424 |
425 |