LEX_SINGLE('{', TOK_LBRACE) LEX_SINGLE('}', TOK_RBRACE) LEX_SINGLE('[', TOK_LBRACKET) LEX_SINGLE(']', TOK_RBRACKET) LEX_SINGLE(',', TOK_COMMA) LEX_SINGLE(';', TOK_SEMICOLON) LEX_SINGLE('=', TOK_EQ) else { LONInputRead(state->input); } break; case LEX_NAME: if (isalpha(c)) { LEX_EAT_ONE() } else { if (strcmp(BUF_STR(t->buf), "true") == 0) { t->type = TOK_TRUE; } else if (strcmp(BUF_STR(t->buf), "false") == 0) { t->type = TOK_FALSE; } else if (strcmp(BUF_STR(t->buf), "nil") == 0) { t->type = TOK_NULL; } else { t->type = TOK_NAME; } state->type = LEX_DEFAULT; } break; case LEX_STRING: if (c != '"') { LEX_EAT_ONE() } else {
static handler_t proxy_http_parse_chunked_stream(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) { protocol_state_data *data = (protocol_state_data *)sess->proxy_con->protocol_data; char *err = NULL; off_t we_have = 0, we_want = 0; off_t chunk_len = 0; off_t offset = 0; buffer *b; chunk *c; char ch = '\0'; int finished = 0; UNUSED(srv); for (c = in->first; c && !finished;) { if(c->mem->used == 0) { c = c->next; continue; } switch(data->chunk_parse_state) { case HTTP_CHUNK_LEN: /* parse chunk len. */ for(offset = c->offset; (size_t)(offset) < (c->mem->used - 1) ; offset++) { ch = c->mem->ptr[offset]; if(!light_isxdigit(ch)) break; } if(offset > c->offset) { buffer_append_string_len(data->buf, (c->mem->ptr + c->offset), offset - c->offset); in->bytes_out += (offset - c->offset); c->offset = offset; } if (!(ch == ' ' || ch == '\r' || ch == ';')) { if (ch == '\0') { /* get next chunk from queue */ break; } /* protocol error. bad http-chunk len */ return HANDLER_ERROR; } data->chunk_len = strtol(BUF_STR(data->buf), &err, 16); data->chunk_offset = 0; buffer_reset(data->buf); data->chunk_parse_state = HTTP_CHUNK_EXTENSION; case HTTP_CHUNK_EXTENSION: /* find CRLF. discard chunk-extension */ for(ch = 0; (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) { ch = c->mem->ptr[c->offset]; c->offset++; in->bytes_out++; } if(ch != '\n') { /* get next chunk from queue */ break; } if(data->chunk_len > 0) { data->chunk_parse_state = HTTP_CHUNK_DATA; } else { data->chunk_parse_state = HTTP_CHUNK_END; } case HTTP_CHUNK_DATA: chunk_len = data->chunk_len - data->chunk_offset; /* copy chunk_len bytes from in queue to out queue. */ we_have = c->mem->used - c->offset - 1; we_want = chunk_len > we_have ? we_have : chunk_len; if (c->offset == 0 && we_want == we_have) { /* we are copying the whole buffer, just steal it */ chunkqueue_steal_chunk(out, c); /* c is an empty chunk now */ } else { b = chunkqueue_get_append_buffer(out); buffer_copy_string_len(b, c->mem->ptr + c->offset, we_want); c->offset += we_want; } chunk_len -= we_want; out->bytes_in += we_want; in->bytes_out += we_want; data->chunk_offset += we_want; if(chunk_len > 0) { /* get next chunk from queue */ break; } data->chunk_offset = 0; data->chunk_parse_state = HTTP_CHUNK_END; case HTTP_CHUNK_END: /* discard CRLF.*/ for(ch = 0; c->mem->used > 0 && (size_t)(c->offset) < (c->mem->used - 1) && ch != '\n' ;) { ch = c->mem->ptr[c->offset]; c->offset++; in->bytes_out++; } if(ch != '\n') { /* get next chunk from queue */ break; } /* final chunk */ if(data->chunk_len == 0) { finished = 1; } /* finished http-chunk. reset and parse next chunk. */ protocol_state_data_reset(data); break; } if((size_t)(c->offset) == c->mem->used - 1) { c = c->next; } } chunkqueue_remove_finished_chunks(in); if (finished) { sess->is_request_finished = 1; return HANDLER_FINISHED; } /* ran out of data. */ return HANDLER_GO_ON; }
int http_response_handle_cachable(server *srv, connection *con, buffer *mtime, buffer *etag) { data_string *http_if_none_match; data_string *http_if_modified_since; UNUSED(srv); /* * 14.26 If-None-Match * [...] * If none of the entity tags match, then the server MAY perform the * requested method as if the If-None-Match header field did not exist, * but MUST also ignore any If-Modified-Since header field(s) in the * request. That is, if no entity tags match, then the server MUST NOT * return a 304 (Not Modified) response. */ http_if_none_match = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("if-none-match")); http_if_modified_since = (data_string *)array_get_element(con->request.headers, CONST_STR_LEN("if-modified-since")); /* last-modified handling */ if (http_if_none_match) { if (etag_is_equal(etag, BUF_STR(http_if_none_match->value))) { if (con->request.http_method == HTTP_METHOD_GET || con->request.http_method == HTTP_METHOD_HEAD) { /* check if etag + last-modified */ if (http_if_modified_since) { size_t used_len; char *semicolon; if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) { used_len = http_if_modified_since->value->used - 1; } else { used_len = semicolon - BUF_STR(http_if_modified_since->value); } if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) { if ('\0' == mtime->ptr[used_len]) con->http_status = 304; return HANDLER_FINISHED; } else { #ifdef HAVE_STRPTIME char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; time_t t_header, t_file; struct tm tm; /* check if we can safely copy the string */ if (used_len >= sizeof(buf)) { TRACE("last-mod check failed as timestamp was too long: %s: %zu, %zu", SAFE_BUF_STR(http_if_modified_since->value), used_len, sizeof(buf) - 1); con->http_status = 412; return HANDLER_FINISHED; } strncpy(buf, BUF_STR(http_if_modified_since->value), used_len); buf[used_len] = '\0'; if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) { con->http_status = 412; return HANDLER_FINISHED; } tm.tm_isdst = 0; t_header = mktime(&tm); strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm); tm.tm_isdst = 0; t_file = mktime(&tm); if (t_file > t_header) return HANDLER_GO_ON; con->http_status = 304; return HANDLER_FINISHED; #else return HANDLER_GO_ON; #endif } } else { con->http_status = 304; return HANDLER_FINISHED; } } else { con->http_status = 412; return HANDLER_FINISHED; } } } else if (http_if_modified_since) { size_t used_len; char *semicolon; if (NULL == (semicolon = strchr(BUF_STR(http_if_modified_since->value), ';'))) { used_len = http_if_modified_since->value->used - 1; } else { used_len = semicolon - BUF_STR(http_if_modified_since->value); } if (0 == strncmp(BUF_STR(http_if_modified_since->value), mtime->ptr, used_len)) { if ('\0' == mtime->ptr[used_len]) con->http_status = 304; return HANDLER_FINISHED; } else { #ifdef HAVE_STRPTIME char buf[sizeof("Sat, 23 Jul 2005 21:20:01 GMT")]; time_t t_header, t_file; struct tm tm; /* convert to timestamp */ if (used_len >= sizeof(buf)) return HANDLER_GO_ON; strncpy(buf, BUF_STR(http_if_modified_since->value), used_len); buf[used_len] = '\0'; if (NULL == strptime(buf, "%a, %d %b %Y %H:%M:%S GMT", &tm)) { return HANDLER_GO_ON; } tm.tm_isdst = 0; t_header = mktime(&tm); strptime(mtime->ptr, "%a, %d %b %Y %H:%M:%S GMT", &tm); tm.tm_isdst = 0; t_file = mktime(&tm); if (t_file > t_header) return HANDLER_GO_ON; con->http_status = 304; return HANDLER_FINISHED; #else return HANDLER_GO_ON; #endif } } return HANDLER_GO_ON; }