~ubuntu-branches/ubuntu/hardy/lighttpd/hardy

« back to all changes in this revision

Viewing changes to src/mod_cgi.c

  • Committer: Bazaar Package Importer
  • Author(s): Soren Hansen
  • Date: 2007-09-05 09:30:15 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20070905093015-pm98jekbu9ylcd3w
Tags: 1.4.17-1ubuntu1
* Merge from Debian unstable, remaining changes:
  - Update maintainer field in debian/control.
  - Build against libgamin-dev rather than libfam-dev (fixes a warning
    during startup)
  - Make sure that upgrades succeed, even if we can't restart lighttpd.
  - Clean environment in init.d script.

Show diffs side-by-side

added added

removed removed

Lines of Context:
222
222
        return 0;
223
223
}
224
224
 
225
 
static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in, int eol) {
 
225
static int cgi_response_parse(server *srv, connection *con, plugin_data *p, buffer *in) {
226
226
        char *ns;
227
227
        const char *s;
228
228
        int line = 0;
232
232
        buffer_copy_string_buffer(p->parse_response, in);
233
233
 
234
234
        for (s = p->parse_response->ptr;
235
 
             NULL != (ns = (eol == EOL_RN ? strstr(s, "\r\n") : strchr(s, '\n')));
236
 
             s = ns + (eol == EOL_RN ? 2 : 1), line++) {
 
235
             NULL != (ns = strchr(s, '\n'));
 
236
             s = ns + 1, line++) {
237
237
                const char *key, *value;
238
238
                int key_len;
239
239
                data_string *ds;
240
240
 
 
241
                /* strip the \n */
241
242
                ns[0] = '\0';
242
243
 
 
244
                if (ns > s && ns[-1] == '\r') ns[-1] = '\0';
 
245
 
243
246
                if (line == 0 &&
244
247
                    0 == strncmp(s, "HTTP/1.", 7)) {
245
248
                        /* non-parsed header ... we parse them anyway */
252
255
 
253
256
                                status = strtol(s+9, NULL, 10);
254
257
 
255
 
                                if (con->http_status >= 100 &&
256
 
                                    con->http_status < 1000) {
 
258
                                if (status >= 100 &&
 
259
                                    status < 1000) {
257
260
                                        /* we expected 3 digits and didn't got them */
258
261
                                        con->parsed_response |= HTTP_STATUS;
259
262
                                        con->http_status = status;
260
263
                                }
261
264
                        }
262
265
                } else {
263
 
 
 
266
                        /* parse the headers */
264
267
                        key = s;
265
268
                        if (NULL == (value = strchr(s, ':'))) {
266
269
                                /* we expect: "<key>: <value>\r\n" */
362
365
                /* split header from body */
363
366
 
364
367
                if (con->file_started == 0) {
365
 
                        char *c;
366
 
                        int in_header = 0;
367
 
                        int header_end = 0;
368
 
                        int cp, eol = EOL_UNSET;
369
 
                        size_t used = 0;
 
368
                        int is_header = 0;
 
369
                        int is_header_end = 0;
 
370
                        size_t last_eol = 0;
 
371
                        size_t i;
370
372
 
371
373
                        buffer_append_string_buffer(hctx->response_header, hctx->response);
372
374
 
 
375
                        /**
 
376
                         * we have to handle a few cases:
 
377
                         *
 
378
                         * nph:
 
379
                         * 
 
380
                         *   HTTP/1.0 200 Ok\n
 
381
                         *   Header: Value\n
 
382
                         *   \n
 
383
                         *
 
384
                         * CGI:
 
385
                         *   Header: Value\n
 
386
                         *   Status: 200\n
 
387
                         *   \n
 
388
                         *
 
389
                         * and different mixes of \n and \r\n combinations
 
390
                         * 
 
391
                         * Some users also forget about CGI and just send a response and hope 
 
392
                         * we handle it. No headers, no header-content seperator
 
393
                         * 
 
394
                         */
 
395
                        
373
396
                        /* nph (non-parsed headers) */
374
 
                        if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) in_header = 1;
375
 
 
376
 
                        /* search for the \r\n\r\n or \n\n in the string */
377
 
                        for (c = hctx->response_header->ptr, cp = 0, used = hctx->response_header->used - 1; used; c++, cp++, used--) {
378
 
                                if (*c == ':') in_header = 1;
379
 
                                else if (*c == '\n') {
380
 
                                        if (in_header == 0) {
381
 
                                                /* got a response without a response header */
382
 
 
383
 
                                                c = NULL;
384
 
                                                header_end = 1;
385
 
                                                break;
386
 
                                        }
387
 
 
388
 
                                        if (eol == EOL_UNSET) eol = EOL_N;
389
 
 
390
 
                                        if (*(c+1) == '\n') {
391
 
                                                header_end = 1;
392
 
                                                break;
393
 
                                        }
394
 
 
395
 
                                } else if (used > 1 && *c == '\r' && *(c+1) == '\n') {
396
 
                                        if (in_header == 0) {
397
 
                                                /* got a response without a response header */
398
 
 
399
 
                                                c = NULL;
400
 
                                                header_end = 1;
401
 
                                                break;
402
 
                                        }
403
 
 
404
 
                                        if (eol == EOL_UNSET) eol = EOL_RN;
405
 
 
406
 
                                        if (used > 3 &&
407
 
                                            *(c+2) == '\r' &&
408
 
                                            *(c+3) == '\n') {
409
 
                                                header_end = 1;
410
 
                                                break;
411
 
                                        }
412
 
 
413
 
                                        /* skip the \n */
414
 
                                        c++;
415
 
                                        cp++;
416
 
                                        used--;
 
397
                        if (0 == strncmp(hctx->response_header->ptr, "HTTP/1.", 7)) is_header = 1;
 
398
                                
 
399
                        for (i = 0; !is_header_end && i < hctx->response_header->used - 1; i++) {
 
400
                                char c = hctx->response_header->ptr[i];
 
401
 
 
402
                                switch (c) {
 
403
                                case ':':
 
404
                                        /* we found a colon
 
405
                                         *
 
406
                                         * looks like we have a normal header 
 
407
                                         */
 
408
                                        is_header = 1;
 
409
                                        break;
 
410
                                case '\n':
 
411
                                        /* EOL */
 
412
                                        if (is_header == 0) {
 
413
                                                /* we got a EOL but we don't seem to got a HTTP header */
 
414
 
 
415
                                                is_header_end = 1;
 
416
 
 
417
                                                break;
 
418
                                        }
 
419
 
 
420
                                        /**
 
421
                                         * check if we saw a \n(\r)?\n sequence 
 
422
                                         */
 
423
                                        if (last_eol > 0 && 
 
424
                                            ((i - last_eol == 1) || 
 
425
                                             (i - last_eol == 2 && hctx->response_header->ptr[i - 1] == '\r'))) {
 
426
                                                is_header_end = 1;
 
427
                                                break;
 
428
                                        }
 
429
 
 
430
                                        last_eol = i;
 
431
 
 
432
                                        break;
417
433
                                }
418
434
                        }
419
435
 
420
 
                        if (header_end) {
421
 
                                if (c == NULL) {
 
436
                        if (is_header_end) {
 
437
                                if (!is_header) {
422
438
                                        /* no header, but a body */
423
439
 
424
440
                                        if (con->request.http_version == HTTP_VERSION_1_1) {
428
444
                                        http_chunk_append_mem(srv, con, hctx->response_header->ptr, hctx->response_header->used);
429
445
                                        joblist_append(srv, con);
430
446
                                } else {
431
 
                                        size_t hlen = c - hctx->response_header->ptr + (eol == EOL_RN ? 4 : 2);
432
 
                                        size_t blen = hctx->response_header->used - hlen - 1;
433
 
 
434
 
                                        /* a small hack: terminate after at the second \r */
435
 
                                        hctx->response_header->used = hlen + 1 - (eol == EOL_RN ? 2 : 1);
436
 
                                        hctx->response_header->ptr[hlen - (eol == EOL_RN ? 2 : 1)] = '\0';
437
 
 
 
447
                                        const char *bstart;
 
448
                                        size_t blen;
 
449
                                        
 
450
                                        /**
 
451
                                         * i still points to the char after the terminating EOL EOL
 
452
                                         *
 
453
                                         * put it on the last \n again
 
454
                                         */
 
455
                                        i--;
 
456
                                        
 
457
                                        /* the body starts after the EOL */
 
458
                                        bstart = hctx->response_header->ptr + (i + 1);
 
459
                                        blen = (hctx->response_header->used - 1) - (i + 1);
 
460
                                        
 
461
                                        /* string the last \r?\n */
 
462
                                        if (i > 0 && (hctx->response_header->ptr[i - 1] == '\r')) {
 
463
                                                i--;
 
464
                                        }
 
465
 
 
466
                                        hctx->response_header->ptr[i] = '\0';
 
467
                                        hctx->response_header->used = i + 1; /* the string + \0 */
 
468
                                        
438
469
                                        /* parse the response header */
439
 
                                        cgi_response_parse(srv, con, p, hctx->response_header, eol);
 
470
                                        cgi_response_parse(srv, con, p, hctx->response_header);
440
471
 
441
472
                                        /* enable chunked-transfer-encoding */
442
473
                                        if (con->request.http_version == HTTP_VERSION_1_1 &&
444
475
                                                con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED;
445
476
                                        }
446
477
 
447
 
                                        if ((hctx->response->used != hlen) && blen > 0) {
448
 
                                                http_chunk_append_mem(srv, con, c + (eol == EOL_RN ? 4: 2), blen + 1);
 
478
                                        if (blen > 0) {
 
479
                                                http_chunk_append_mem(srv, con, bstart, blen + 1);
449
480
                                                joblist_append(srv, con);
450
481
                                        }
451
482
                                }
782
813
 
783
814
                cgi_env_add(&env, CONST_STR_LEN("SERVER_PROTOCOL"), s, strlen(s));
784
815
 
785
 
                ltostr(buf,
 
816
                LI_ltostr(buf,
786
817
#ifdef HAVE_IPV6
787
818
                        ntohs(srv_sock->addr.plain.sa_family == AF_INET6 ? srv_sock->addr.ipv6.sin6_port : srv_sock->addr.ipv4.sin_port)
788
819
#else
828
859
#endif
829
860
                cgi_env_add(&env, CONST_STR_LEN("REMOTE_ADDR"), s, strlen(s));
830
861
 
831
 
                ltostr(buf,
 
862
                LI_ltostr(buf,
832
863
#ifdef HAVE_IPV6
833
864
                        ntohs(con->dst_addr.plain.sa_family == AF_INET6 ? con->dst_addr.ipv6.sin6_port : con->dst_addr.ipv4.sin_port)
834
865
#else
849
880
#endif
850
881
 
851
882
                /* request.content_length < SSIZE_MAX, see request.c */
852
 
                ltostr(buf, con->request.content_length);
 
883
                LI_ltostr(buf, con->request.content_length);
853
884
                cgi_env_add(&env, CONST_STR_LEN("CONTENT_LENGTH"), buf, strlen(buf));
854
885
                cgi_env_add(&env, CONST_STR_LEN("SCRIPT_FILENAME"), CONST_BUF_LEN(con->physical.path));
855
886
                cgi_env_add(&env, CONST_STR_LEN("SCRIPT_NAME"), CONST_BUF_LEN(con->uri.path));