代码语言:javascript复制
/*
* Copyright (C) Igor Sysoev
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
/*
* the single part format:
*
* "HTTP/1.0 206 Partial Content" CRLF
* ... header ...
* "Content-Type: image/jpeg" CRLF
* "Content-Length: SIZE" CRLF
* "Content-Range: bytes START-END/SIZE" CRLF
* CRLF
* ... data ...
*
*
* the mutlipart format:
*
* "HTTP/1.0 206 Partial Content" CRLF
* ... header ...
* "Content-Type: multipart/byteranges; boundary=0123456789" CRLF
* CRLF
* CRLF
* "--0123456789" CRLF
* "Content-Type: image/jpeg" CRLF
* "Content-Range: bytes START0-END0/SIZE" CRLF
* CRLF
* ... data ...
* CRLF
* "--0123456789" CRLF
* "Content-Type: image/jpeg" CRLF
* "Content-Range: bytes START1-END1/SIZE" CRLF
* CRLF
* ... data ...
* CRLF
* "--0123456789--" CRLF
*/
typedef struct {
ngx_str_t boundary_header;
} ngx_http_range_filter_ctx_t;
static ngx_int_t ngx_http_range_header_filter_init(ngx_cycle_t *cycle);
static ngx_int_t ngx_http_range_body_filter_init(ngx_cycle_t *cycle);
...
static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
static ngx_int_t ngx_http_range_header_filter(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_uint_t boundary, suffix, i;
u_char *p;
size_t len;
off_t start, end;
ngx_http_range_t *range;
ngx_http_range_filter_ctx_t *ctx;
if (r->http_version < NGX_HTTP_VERSION_10
|| r->headers_out.status != NGX_HTTP_OK
|| r->headers_out.content_length_n == -1
|| !r->filter_allow_ranges)
{
return ngx_http_next_header_filter(r);
}
if (r->headers_in.range == NULL
|| r->headers_in.range->value.len < 7
|| ngx_strncasecmp(r->headers_in.range->value.data, "bytes=", 6) != 0)
{
r->headers_out.accept_ranges = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.accept_ranges == NULL) {
return NGX_ERROR;
}
r->headers_out.accept_ranges->key.len = sizeof("Accept-Ranges") - 1;
r->headers_out.accept_ranges->key.data = (u_char *) "Accept-Ranges";
r->headers_out.accept_ranges->value.len = sizeof("bytes") - 1;
r->headers_out.accept_ranges->value.data = (u_char *) "bytes";
return ngx_http_next_header_filter(r);
}
// 申请5个range
ngx_init_array(r->headers_out.ranges, r->pool, 5, sizeof(ngx_http_range_t),
NGX_ERROR);
rc = 0;
range = NULL;
// 拿到客户端请求的range范围
p = r->headers_in.range->value.data 6;
// 每一个循环解析一个range
for ( ;; ) {
start = 0;
end = 0;
suffix = 0;
// 容错,跳过空格
while (*p == ' ') { p ; }
/*
格式:
a-b
-b
a-
a-b,c-
-a
不写开头则说明是从倒数abs(-a)字节开始,不写结尾则说明是到最后一个字节,
内容可能是多个以上的组合
*/
// 第一个有效字符不是-,则说明是属于a-[b]格式,b可能没有
if (*p != '-') {
// 不是数字则报错
if (*p < '0' || *p > '9') {
rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
break;
}
// 整数化a,直到遇到第一个非数字
while (*p >= '0' && *p <= '9') {
start = start * 10 *p - '0';
}
// 容错,过滤空格
while (*p == ' ') { p ; }
// 第一个数字后面不是-则报错
if (*p != '-') {
rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
break;
}
// 请求的范围大于返回内容的大小范围,则报错
if (start >= r->headers_out.content_length_n) {
rc = NGX_HTTP_RANGE_NOT_SATISFIABLE;
break;
}
// 容错,过滤-后面的空格
while (*p == ' ') { p ; }
// 如果a-后面是逗号或者 则说明是最后一个range
if (*p == ',' || *p == '