| | 1929 | typedef struct { |
| | 1930 | buffer *b; |
| | 1931 | size_t len; |
| | 1932 | int type; |
| | 1933 | int padding; |
| | 1934 | size_t request_id; |
| | 1935 | } fastcgi_response_packet; |
| | 1936 | |
| | 1937 | static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_packet *packet) { |
| | 1938 | chunk * c; |
| | 1939 | size_t offset = 0; |
| | 1940 | size_t toread = 0; |
| | 1941 | FCGI_Header *header; |
| | 1942 | |
| | 1943 | if (!hctx->rb->first) return -1; |
| | 1944 | |
| | 1945 | packet->b = buffer_init(); |
| | 1946 | packet->len = 0; |
| | 1947 | packet->type = 0; |
| | 1948 | packet->padding = 0; |
| | 1949 | packet->request_id = 0; |
| | 1950 | |
| | 1951 | /* get at least the FastCGI header */ |
| | 1952 | for (c = hctx->rb->first; c; c = c->next) { |
| | 1953 | if (packet->b->used == 0) { |
| | 1954 | buffer_copy_string_len(packet->b, c->data.mem->ptr + c->offset, c->data.mem->used - c->offset - 1); |
| | 1955 | } else { |
| | 1956 | buffer_append_string_len(packet->b, c->data.mem->ptr + c->offset, c->data.mem->used - c->offset - 1); |
| | 1957 | } |
| | 1958 | |
| | 1959 | if (packet->b->used >= sizeof(*header) + 1) break; |
| | 1960 | } |
| | 1961 | |
| | 1962 | if ((packet->b->used == 0) || |
| | 1963 | (packet->b->used - 1 < sizeof(FCGI_Header))) { |
| | 1964 | /* no header */ |
| | 1965 | buffer_free(packet->b); |
| | 1966 | |
| | 1967 | log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header to small"); |
| | 1968 | return -1; |
| | 1969 | } |
| | 1970 | |
| | 1971 | /* we have at least a header, now check how much me have to fetch */ |
| | 1972 | header = (FCGI_Header *)(packet->b->ptr); |
| | 1973 | |
| | 1974 | packet->len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength; |
| | 1975 | packet->request_id = (header->requestIdB0 | (header->requestIdB1 << 8)); |
| | 1976 | packet->type = header->type; |
| | 1977 | packet->padding = header->paddingLength; |
| | 1978 | |
| | 1979 | /* the first bytes in packet->b are the header */ |
| | 1980 | offset = sizeof(*header); |
| | 1981 | |
| | 1982 | log_error_write(srv, __FILE__, __LINE__, "sddd", "FastCGI: got header:", packet->len, packet->request_id, packet->type); |
| | 1983 | |
| | 1984 | /* ->b should only be the content */ |
| | 1985 | buffer_reset(packet->b); |
| | 1986 | |
| | 1987 | if (packet->len) { |
| | 1988 | /* copy the content */ |
| | 1989 | for (; c && (packet->b->used < packet->len + 1); c = c->next) { |
| | 1990 | toread = c->data.mem->used - c->offset - offset - 1 > packet->len ? packet->len : c->data.mem->used - c->offset - offset - 1; |
| | 1991 | |
| | 1992 | log_error_write(srv, __FILE__, __LINE__, "sdd", "FastCGI: reading content:", packet->b->used, toread); |
| | 1993 | |
| | 1994 | buffer_append_string_len(packet->b, c->data.mem->ptr + c->offset + offset, toread); |
| | 1995 | offset = 0; |
| | 1996 | } |
| | 1997 | |
| | 1998 | if (packet->b->used < packet->len + 1) { |
| | 1999 | /* we didn't got the full packet */ |
| | 2000 | log_error_write(srv, __FILE__, __LINE__, "sdd", "FastCGI: not the full packet", packet->b->used, packet->len); |
| | 2001 | |
| | 2002 | buffer_free(packet->b); |
| | 2003 | return -1; |
| | 2004 | } |
| | 2005 | |
| | 2006 | packet->b->used -= packet->padding; |
| | 2007 | packet->b->ptr[packet->b->used - 1] = '\0'; |
| | 2008 | } |
| | 2009 | |
| | 2010 | /* tag the chunks as read */ |
| | 2011 | toread = packet->len + sizeof(FCGI_Header); |
| | 2012 | for (c = hctx->rb->first; c && toread; c = c->next) { |
| | 2013 | if (c->data.mem->used - c->offset - 1 <= toread) { |
| | 2014 | /* we read this whole buffer, move it to unused */ |
| | 2015 | toread -= c->data.mem->used - c->offset - 1; |
| | 2016 | c->offset = c->data.mem->used - 1; /* everthing has been written */ |
| | 2017 | } else { |
| | 2018 | c->offset += toread; |
| | 2019 | toread = 0; |
| | 2020 | } |
| | 2021 | } |
| | 2022 | |
| | 2023 | chunkqueue_remove_finished_chunks(hctx->rb); |
| | 2024 | |
| | 2025 | return 0; |
| | 2026 | } |
| 2008 | | size_t request_id; |
| 2009 | | |
| 2010 | | if (hctx->response_len == 0) { |
| 2011 | | FCGI_Header *header; |
| 2012 | | |
| 2013 | | if (hctx->rb->used - hctx->rb->offset < sizeof(*header)) { |
| 2014 | | /* didn't get the full header packet (most often 0), |
| 2015 | | * but didn't recieved the final packet either |
| | 2085 | fastcgi_response_packet packet; |
| | 2086 | |
| | 2087 | /* check if we have at least one packet */ |
| | 2088 | if (0 != fastcgi_get_packet(srv, hctx, &packet)) { |
| | 2089 | /* no full packet */ |
| | 2090 | |
| | 2091 | hctx->delayed = 1; |
| | 2092 | |
| | 2093 | break; |
| | 2094 | } |
| | 2095 | |
| | 2096 | switch(packet.type) { |
| | 2097 | case FCGI_STDOUT: |
| | 2098 | if (packet.len == 0) break; |
| | 2099 | |
| | 2100 | /* is the header already finished */ |
| | 2101 | if (0 == con->file_started) { |
| | 2102 | char *c; |
| | 2103 | size_t blen; |
| | 2104 | |
| | 2105 | /* search for header terminator |
| 2020 | | |
| 2021 | | hctx->delayed = 1; |
| 2022 | | #if 0 |
| 2023 | | log_error_write(srv, __FILE__, __LINE__, "sddd", "didn't get the full header: ", |
| 2024 | | hctx->rb->used - hctx->rb->offset, sizeof(*header), |
| 2025 | | fcgi_fd |
| 2026 | | ); |
| 2027 | | #endif |
| 2028 | | break; |
| 2029 | | } |
| 2030 | | #if 0 |
| 2031 | | fprintf(stderr, "fcgi-version: %02x\n", hctx->rb->ptr[hctx->rb->offset]); |
| 2032 | | #endif |
| 2033 | | |
| 2034 | | header = (FCGI_Header *)(hctx->rb->ptr + hctx->rb->offset); |
| 2035 | | hctx->rb->offset += sizeof(*header); |
| 2036 | | |
| 2037 | | len = (header->contentLengthB0 | (header->contentLengthB1 << 8)) + header->paddingLength; |
| 2038 | | request_id = (header->requestIdB0 | (header->requestIdB1 << 8)); |
| 2039 | | |
| 2040 | | hctx->response_len = len; |
| 2041 | | hctx->response_request_id = request_id; |
| 2042 | | hctx->response_type = header->type; |
| 2043 | | hctx->response_padding = header->paddingLength; |
| 2044 | | |
| 2045 | | #if 0 |
| 2046 | | log_error_write(srv, __FILE__, __LINE__, "sddd", "offset: ", |
| 2047 | | fcgi_fd, hctx->rb->offset, header->type |
| 2048 | | ); |
| 2049 | | #endif |
| 2050 | | |
| 2051 | | } else { |
| 2052 | | len = hctx->response_len; |
| 2053 | | } |
| 2054 | | |
| 2055 | | if (hctx->rb->used - hctx->rb->offset < hctx->response_len) { |
| 2056 | | /* we are not finished yet */ |
| 2057 | | break; |
| 2058 | | } |
| 2059 | | |
| 2060 | | hctx->response->ptr = hctx->rb->ptr + hctx->rb->offset; |
| 2061 | | hctx->rb->offset += hctx->response_len; |
| 2062 | | #if 0 |
| 2063 | | log_error_write(srv, __FILE__, __LINE__, "sdd", "offset: ", |
| 2064 | | fcgi_fd, hctx->rb->offset |
| 2065 | | ); |
| 2066 | | #endif |
| 2067 | | |
| 2068 | | /* remove padding */ |
| 2069 | | #if 0 |
| 2070 | | hctx->response->ptr[hctx->response_len - hctx->response_padding] = '\0'; |
| 2071 | | #endif |
| 2072 | | hctx->response->used = hctx->response_len - hctx->response_padding + 1; |
| 2073 | | |
| 2074 | | /* mark the fast-cgi packet as finished */ |
| 2075 | | hctx->response_len = 0; |
| 2076 | | |
| 2077 | | switch(hctx->response_type) { |
| 2078 | | case FCGI_STDOUT: |
| 2079 | | if (len) { |
| 2080 | | #if 0 |
| 2081 | | log_error_write(srv, __FILE__, __LINE__, "sdb", "len", len, hctx->response); |
| 2082 | | #endif |
| 2083 | | |
| 2084 | | if (0 == con->got_response) { |
| 2085 | | con->got_response = 1; |
| 2086 | | buffer_prepare_copy(hctx->response_header, 128); |
| | 2112 | |
| | 2113 | if (hctx->response_header->used == 0) { |
| | 2114 | buffer_copy_string_buffer(hctx->response_header, packet.b); |
| | 2115 | } else { |
| | 2116 | buffer_append_string_buffer(hctx->response_header, packet.b); |
| 2088 | | |
| 2089 | | if (0 == con->file_started) { |
| 2090 | | char *c; |
| 2091 | | size_t hlen; |
| 2092 | | |
| 2093 | | /* search for header terminator |
| 2094 | | * |
| 2095 | | * if we start with \r\n check if last packet terminated with \r\n |
| 2096 | | * if we start with \n check if last packet terminated with \n |
| 2097 | | * search for \r\n\r\n |
| 2098 | | * search for \n\n |
| 2099 | | */ |
| 2100 | | |
| 2101 | | if (hctx->response->used > 2 && |
| 2102 | | hctx->response->ptr[0] == '\r' && |
| 2103 | | hctx->response->ptr[1] == '\n' && |
| 2104 | | hctx->response_header->used > 3 && |
| 2105 | | hctx->response_header->ptr[hctx->response_header->used - 3] == '\r' && |
| 2106 | | hctx->response_header->ptr[hctx->response_header->used - 2] == '\n') { |
| 2107 | | hlen = 2; |
| 2108 | | c = hctx->response->ptr + 2; |
| 2109 | | } else if (hctx->response->used > 2 && |
| 2110 | | hctx->response->ptr[0] == '\n' && |
| 2111 | | hctx->response_header->used > 2 && |
| 2112 | | hctx->response_header->ptr[hctx->response_header->used - 2] == '\n') { |
| 2113 | | hlen = 1; |
| 2114 | | c = hctx->response->ptr + 1; |
| 2115 | | } else if (NULL != (c = buffer_search_string_len(hctx->response, "\r\n\r\n", 4))) { |
| 2116 | | c += 4; |
| 2117 | | hlen = c - hctx->response->ptr; |
| | 2118 | |
| | 2119 | if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\r\n\r\n")))) { |
| | 2120 | blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 4; |
| | 2121 | hctx->response_header->used = c - hctx->response_header->ptr; |
| | 2122 | c += 4; /* point the the start of the response */ |
| | 2123 | } else if (NULL != (c = buffer_search_string_len(hctx->response_header, CONST_STR_LEN("\n\n")))) { |
| | 2124 | blen = hctx->response_header->used - (c - hctx->response_header->ptr) - 2; |
| | 2125 | hctx->response_header->used = c - hctx->response_header->ptr; |
| | 2126 | c += 2; /* point the the start of the response */ |
| | 2127 | } else { |
| | 2128 | /* no luck, no header found */ |
| | 2129 | break; |
| | 2130 | } |
| | 2131 | |
| | 2132 | /* parse the response header */ |
| | 2133 | fcgi_response_parse(srv, con, p, hctx->response_header); |
| 2128 | | buffer_append_string_len(hctx->response_header, hctx->response->ptr, hlen); |
| 2129 | | #if 0 |
| 2130 | | log_error_write(srv, __FILE__, __LINE__, "ss", "Header:", hctx->response_header->ptr); |
| 2131 | | #endif |
| 2132 | | /* parse the response header */ |
| 2133 | | fcgi_response_parse(srv, con, p, hctx->response_header); |
| 2134 | | |
| 2135 | | if (host->mode != FCGI_AUTHORIZER || |
| 2136 | | !(con->http_status == 0 || |
| 2137 | | con->http_status == 200)) { |
| 2138 | | |
| 2139 | | con->file_started = 1; |
| 2140 | | |
| 2141 | | if (blen) { |
| 2142 | | /* enable chunked-transfer-encoding */ |
| 2143 | | if (con->request.http_version == HTTP_VERSION_1_1 && |
| 2144 | | !(con->parsed_response & HTTP_CONTENT_LENGTH)) { |
| 2145 | | con->response.transfer_encoding = HTTP_TRANSFER_ENCODING_CHUNKED; |
| 2146 | | } |
| 2147 | | |
| 2148 | | |