/* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* byterange_filter.c --- HTTP byterange filter and friends.
*/
#include "apr.h"
#include "apr_strings.h"
#include "apr_buckets.h"
#include "apr_lib.h"
#include "apr_signal.h"
#define APR_WANT_STRFUNC
#define APR_WANT_MEMFUNC
#include "apr_want.h"
#include "util_filter.h"
#include "ap_config.h"
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_protocol.h"
#include "http_main.h"
#include "http_request.h"
#include "http_vhost.h"
#include "http_log.h" /* For errors detected in basic auth common
* support code... */
#include "apr_date.h" /* For apr_date_parse_http and APR_DATE_BAD */
#include "util_charset.h"
#include "util_ebcdic.h"
#include "util_time.h"
#include "mod_core.h"
#include <stdarg.h>
#endif
#include <unistd.h>
#endif
#ifndef AP_DEFAULT_MAX_RANGES
#endif
#ifndef AP_DEFAULT_MAX_OVERLAPS
#endif
#ifndef AP_DEFAULT_MAX_REVERSALS
#endif
typedef struct indexes_t {
} indexes_t;
/*
* Returns: number of ranges (merged) or -1 for no-good
*/
{
const char *range;
const char *ct;
char *cur;
int in_merge = 0;
int i;
const char *it;
*overlaps = 0;
*reversals = 0;
if (r->assbackwards) {
return 0;
}
return 0;
}
/* is content already a single range? */
return 0;
}
/* is content already a multiple range? */
return 0;
}
/*
* Check the If-Range header for Etag or Date.
*/
return 0;
}
range += 6;
while (*it) {
if (*it++ == ',') {
ranges++;
}
}
if (ranges > MAX_PREALLOC_RANGES) {
}
char *dash;
char *errp;
if (!*cur)
break;
/*
* Per RFC 2616 14.35.1: If there is at least one syntactically invalid
* byte-range-spec, we must ignore the whole header.
*/
return 0;
}
/* In the form "-5" */
return 0;
}
if (number < 1) {
return 0;
}
}
else {
*dash++ = '\0';
return 0;
}
if (*dash) {
return 0;
}
return 0;
}
}
else { /* "5-" */
/*
* special case: 0-
* ignore all other ranges provided
* return as a single range: 0-
*/
if (start == 0) {
num_ranges = 0;
sum_lengths = 0;
in_merge = 1;
break;
}
}
}
if (start < 0) {
start = 0;
}
unsatisfiable = 1;
continue;
}
}
if (!in_merge) {
/* new set */
in_merge = 1;
continue;
}
in_merge = 0;
in_merge = 1;
}
++*reversals;
in_merge = 1;
}
in_merge = 1;
}
if (in_merge) {
++*overlaps;
continue;
} else {
/* new set again */
in_merge = 1;
num_ranges++;
}
}
if (in_merge) {
num_ranges++;
}
else if (num_ranges == 0 && unsatisfiable) {
/* If all ranges are unsatisfiable, we should return 416 */
return -1;
}
if (sum_lengths > clength) {
"Sum of ranges larger than file, ignoring.");
return 0;
}
/*
* create the merged table now, now that we know we need it
*/
}
r->status = HTTP_PARTIAL_CONTENT;
return num_ranges;
}
{
/*
* Once we know that start and end are >= 0 convert everything to apr_uint64_t.
* See the comments in apr_brigade_partition why.
* In short apr_off_t (for values >= 0)and apr_size_t fit into apr_uint64_t.
*/
return APR_EINVAL;
for (e = APR_BRIGADE_FIRST(bb);
e != APR_BRIGADE_SENTINEL(bb);
e = APR_BUCKET_NEXT(e))
{
/* we know that no bucket has undefined length (-1) */
first = e;
}
last = e;
break;
}
}
return APR_EINVAL;
e = first;
while (1)
{
if (rv != APR_SUCCESS) {
return rv;
}
if (e == first) {
if (rv != APR_SUCCESS) {
return rv;
}
}
else {
}
}
if (e == last) {
if (e == first) {
}
if (rv != APR_SUCCESS) {
return rv;
}
}
}
break;
}
e = APR_BUCKET_NEXT(e);
}
return APR_SUCCESS;
}
{
apr_bucket *e;
conn_rec *c = f->r->connection;
f->r->pool, c->bucket_alloc);
e = apr_bucket_eos_create(c->bucket_alloc);
}
{
request_rec *r = f->r;
conn_rec *c = r->connection;
apr_bucket *e;
int found = 0;
int num_ranges;
int i;
int original_status;
max_overlaps = ( (core_conf->max_overlaps >= 0 || core_conf->max_overlaps == AP_MAXRANGES_UNLIMITED)
max_reversals = ( (core_conf->max_reversals >= 0 || core_conf->max_reversals == AP_MAXRANGES_UNLIMITED)
/*
* Iterate through the brigade until reaching EOS or a bucket with
* unknown length.
*/
for (e = APR_BRIGADE_FIRST(bb);
e = APR_BUCKET_NEXT(e)) {
}
/*
* Don't attempt to do byte range work if this brigade doesn't
* contain an EOS, or if any of the buckets has an unknown length;
* this avoids the cases where it is expensive to perform
* byteranging (i.e. may require arbitrary amounts of memory).
*/
if (!APR_BUCKET_IS_EOS(e) || clength <= 0) {
}
original_status = r->status;
/* No Ranges or we hit a limit? We have nothing to do, get out of the way. */
if (num_ranges == 0 ||
r->status = original_status;
}
/* this brigade holds what we will be sending */
if (num_ranges < 0)
if (num_ranges > 1) {
/* Is ap_make_content_type required here? */
"multipart/byteranges; boundary=",
if (orig_ct) {
CRLF "Content-type: ",
CRLF "Content-range: bytes ",
NULL);
}
else {
/* if we have no type for the content, do our best */
CRLF "Content-range: bytes ",
NULL);
}
}
if (rv != APR_SUCCESS ) {
"copy_brigade_range() failed [%" APR_OFF_T_FMT
continue;
}
found = 1;
/*
* For single range requests, we must produce Content-Range header.
* Otherwise, we need to produce the multipart boundaries.
*/
if (num_ranges == 1) {
}
else {
char *ts;
r->pool, c->bucket_alloc);
c->bucket_alloc);
}
if (i && !(i & 0x1F)) {
/*
* Every now and then, pass what we have down the filter chain.
* In this case, the content-length filter cannot calculate and
* set the content length and we must remove any Content-Length
* header already present.
*/
return rv;
}
}
if (found == 0) {
/* bsend is assumed to be empty if we get here. */
}
if (num_ranges > 1) {
char *end;
/* add the final boundary */
NULL);
}
e = apr_bucket_eos_create(c->bucket_alloc);
/* we're done with the original content - all of our data is in bsend. */
/* send our multipart output */
}