58 Star 430 Fork 129

GVPwinshining / nginx-http-flv-module

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
ngx_rtmp_parse.c 19.07 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820
/*
* Copyright (C) Igor Sysoev
* Copyright (C) Nginx, Inc.
* Copyright (C) Winshining
*/
#include <ngx_config.h>
#include <ngx_core.h>
#include "ngx_rtmp.h"
#define NGX_RTMP_PARSE_INVALID_REQUEST 11
static uint32_t usual[] = {
0xffffdbfe, /* 1111 1111 1111 1111 1101 1011 1111 1110 */
/* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */
0x7fff37d6, /* 0111 1111 1111 1111 0011 0111 1101 0110 */
/* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */
#if (NGX_WIN32)
0xefffffff, /* 1110 1111 1111 1111 1111 1111 1111 1111 */
#else
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
#endif
/* ~}| {zyx wvut srqp onml kjih gfed cba` */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */
0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */
};
ngx_int_t
ngx_rtmp_parse_request_line(ngx_rtmp_session_t *s, ngx_buf_t *b)
{
u_char c, ch, *p;
enum {
sw_start = 0,
sw_schema,
sw_schema_slash,
sw_schema_slash_slash,
sw_host_start,
sw_host,
sw_host_end,
sw_host_ip_literal,
sw_port,
sw_after_slash_in_uri,
sw_check_uri,
sw_uri
} state;
state = sw_start;
for (p = b->pos; p < b->last; p++) {
ch = *p;
switch (state) {
case sw_start:
s->schema_start = p;
state = sw_schema;
/* fall through */
case sw_schema:
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'z') {
break;
}
switch (ch) {
case ':':
s->schema_end = p;
state = sw_schema_slash;
break;
default:
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
break;
case sw_schema_slash:
switch (ch) {
case '/':
state = sw_schema_slash_slash;
break;
default:
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
break;
case sw_schema_slash_slash:
switch (ch) {
case '/':
state = sw_host_start;
break;
default:
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
break;
case sw_host_start:
s->host_start = p;
if (ch == '[') {
state = sw_host_ip_literal;
break;
}
state = sw_host;
/* fall through */
case sw_host:
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'z') {
break;
}
if ((ch >= '0' && ch <= '9') || ch == '.' || ch == '-') {
break;
}
/* fall through */
case sw_host_end:
s->host_end = p;
switch (ch) {
case ':':
s->port_start = p + 1;
state = sw_port;
break;
case '/':
s->uri_start = p;
state = sw_after_slash_in_uri;
break;
default:
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
break;
case sw_host_ip_literal:
if (ch >= '0' && ch <= '9') {
break;
}
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'z') {
break;
}
switch (ch) {
case ':':
break;
case ']':
state = sw_host_end;
break;
case '-':
case '.':
case '_':
case '~':
/* unreserved */
break;
case '!':
case '$':
case '&':
case '\'':
case '(':
case ')':
case '*':
case '+':
case ',':
case ';':
case '=':
/* sub-delims */
break;
default:
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
break;
case sw_port:
if (ch >= '0' && ch <= '9') {
break;
}
switch (ch) {
case '/':
s->port_end = p;
s->uri_start = p;
state = sw_after_slash_in_uri;
break;
default:
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
break;
/* check "/.", "//", "%", and "\" (Win32) in URI */
case sw_after_slash_in_uri:
if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
state = sw_check_uri;
break;
}
switch (ch) {
case '.':
s->complex_uri = 1;
state = sw_uri;
break;
case '%':
s->quoted_uri = 1;
state = sw_uri;
break;
case '/':
s->complex_uri = 1;
state = sw_uri;
break;
#if (NGX_WIN32)
case '\\':
s->complex_uri = 1;
state = sw_uri;
break;
#endif
case '?':
s->args_start = p + 1;
state = sw_uri;
break;
case '#':
s->complex_uri = 1;
state = sw_uri;
break;
case '+':
s->plus_in_uri = 1;
break;
case '\0':
return NGX_RTMP_PARSE_INVALID_REQUEST;
default:
state = sw_check_uri;
break;
}
break;
/* check "/", "%" and "\" (Win32) in URI */
case sw_check_uri:
if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
break;
}
switch (ch) {
case '/':
state = sw_after_slash_in_uri;
break;
case '.':
break;
#if (NGX_WIN32)
case '\\':
s->complex_uri = 1;
state = sw_after_slash_in_uri;
break;
#endif
case '%':
s->quoted_uri = 1;
state = sw_uri;
break;
case '?':
s->args_start = p + 1;
state = sw_uri;
break;
case '#':
s->complex_uri = 1;
state = sw_uri;
break;
case '+':
s->plus_in_uri = 1;
break;
case '\0':
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
break;
/* URI */
case sw_uri:
if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
break;
}
switch (ch) {
case '#':
s->complex_uri = 1;
break;
case '\0':
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
}
}
/* end of request line */
s->uri_end = p;
return NGX_OK;
}
ngx_int_t
ngx_rtmp_process_request_uri(ngx_rtmp_session_t *s)
{
ngx_rtmp_core_srv_conf_t *cscf;
if (s->args_start) {
s->uri.len = s->args_start - 1 - s->uri_start;
} else {
s->uri.len = s->uri_end - s->uri_start;
}
if (s->complex_uri || s->quoted_uri) {
s->uri.data = ngx_pnalloc(s->connection->pool, s->uri.len + 1);
if (s->uri.data == NULL) {
return NGX_ERROR;
}
cscf = ngx_rtmp_get_module_srv_conf(s, ngx_rtmp_core_module);
if (ngx_rtmp_parse_complex_uri(s, cscf->merge_slashes) != NGX_OK) {
s->uri.len = 0;
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"client sent invalid request");
return NGX_ERROR;
}
} else {
s->uri.data = s->uri_start;
}
s->unparsed_uri.len = s->uri_end - s->uri_start;
s->unparsed_uri.data = s->uri_start;
s->valid_unparsed_uri = s->space_in_uri ? 0 : 1;
if (s->args_start && s->uri_end > s->args_start) {
s->args.len = s->uri_end - s->args_start;
s->args.data = s->args_start;
}
#if (NGX_WIN32)
{
u_char *p, *last;
p = s->uri.data;
last = s->uri.data + s->uri.len;
while (p < last) {
if (*p++ == ':') {
/*
* this check covers "::$data", "::$index_allocation" and
* ":$i30:$index_allocation"
*/
if (p < last && *p == '$') {
ngx_log_error(NGX_LOG_INFO, s->connection->log, 0,
"client sent unsafe win32 URI");
return NGX_ERROR;
}
}
}
p = s->uri.data + s->uri.len - 1;
while (p > s->uri.data) {
if (*p == ' ') {
p--;
continue;
}
if (*p == '.') {
p--;
continue;
}
break;
}
if (p != s->uri.data + s->uri.len - 1) {
s->uri.len = p + 1 - s->uri.data;
}
}
#endif
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"rtmp uri: \"%V\"", &s->uri);
ngx_log_debug1(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"rtmp args: \"%V\"", &s->args);
return NGX_OK;
}
ngx_int_t
ngx_rtmp_parse_complex_uri(ngx_rtmp_session_t *s, ngx_uint_t merge_slashes)
{
u_char c, ch, decoded, *p, *u;
enum {
sw_usual = 0,
sw_slash,
sw_dot,
sw_dot_dot,
sw_quoted,
sw_quoted_second
} state, quoted_state;
#if (NGX_SUPPRESS_WARN)
decoded = '\0';
quoted_state = sw_usual;
#endif
state = sw_usual;
p = s->uri_start;
u = s->uri.data;
s->args_start = NULL;
ch = *p++;
while (p <= s->uri_end) {
/*
* we use "ch = *p++" inside the cycle, it is safe,
* because after the URI there is a character: '\r'
*/
ngx_log_debug3(NGX_LOG_DEBUG_RTMP, s->connection->log, 0,
"s:%d in:'%Xd:%c'", state, ch, ch);
switch (state) {
case sw_usual:
if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
*u++ = ch;
ch = *p++;
break;
}
switch (ch) {
#if (NGX_WIN32)
case '\\':
if (u - 2 >= s->uri.data
&& *(u - 1) == '.' && *(u - 2) != '.')
{
u--;
}
if (p == s->uri_start + s->uri.len) {
/*
* we omit the last "\" to cause redirect because
* the browsers do not treat "\" as "/" in relative URL path
*/
break;
}
state = sw_slash;
*u++ = '/';
break;
#endif
case '/':
#if (NGX_WIN32)
if (u - 2 >= s->uri.data
&& *(u - 1) == '.' && *(u - 2) != '.')
{
u--;
}
#endif
state = sw_slash;
*u++ = ch;
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
s->args_start = p;
goto args;
case '#':
goto done;
case '.':
*u++ = ch;
break;
case '+':
s->plus_in_uri = 1;
/* fall through */
default:
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_slash:
if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
}
switch (ch) {
#if (NGX_WIN32)
case '\\':
break;
#endif
case '/':
if (!merge_slashes) {
*u++ = ch;
}
break;
case '.':
state = sw_dot;
*u++ = ch;
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
s->args_start = p;
goto args;
case '#':
goto done;
case '+':
s->plus_in_uri = 1;
/* fall through */
default:
state = sw_usual;
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_dot:
if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
}
switch (ch) {
#if (NGX_WIN32)
case '\\':
#endif
case '/':
state = sw_slash;
u--;
break;
case '.':
state = sw_dot_dot;
*u++ = ch;
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
s->args_start = p;
goto args;
case '#':
goto done;
case '+':
s->plus_in_uri = 1;
/* fall through */
default:
state = sw_usual;
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_dot_dot:
if (usual[ch >> 5] & (1U << (ch & 0x1f))) {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
}
switch (ch) {
#if (NGX_WIN32)
case '\\':
#endif
case '/':
state = sw_slash;
u -= 5;
for ( ;; ) {
if (u < s->uri.data) {
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
if (*u == '/') {
u++;
break;
}
u--;
}
break;
case '%':
quoted_state = state;
state = sw_quoted;
break;
case '?':
s->args_start = p;
goto args;
case '#':
goto done;
case '+':
s->plus_in_uri = 1;
/* fall through */
default:
state = sw_usual;
*u++ = ch;
break;
}
ch = *p++;
break;
case sw_quoted:
s->quoted_uri = 1;
if (ch >= '0' && ch <= '9') {
decoded = (u_char) (ch - '0');
state = sw_quoted_second;
ch = *p++;
break;
}
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'f') {
decoded = (u_char) (c - 'a' + 10);
state = sw_quoted_second;
ch = *p++;
break;
}
return NGX_RTMP_PARSE_INVALID_REQUEST;
case sw_quoted_second:
if (ch >= '0' && ch <= '9') {
ch = (u_char) ((decoded << 4) + ch - '0');
if (ch == '%' || ch == '#') {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
} else if (ch == '\0') {
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
state = quoted_state;
break;
}
c = (u_char) (ch | 0x20);
if (c >= 'a' && c <= 'f') {
ch = (u_char) ((decoded << 4) + c - 'a' + 10);
if (ch == '?') {
state = sw_usual;
*u++ = ch;
ch = *p++;
break;
} else if (ch == '+') {
s->plus_in_uri = 1;
}
state = quoted_state;
break;
}
return NGX_RTMP_PARSE_INVALID_REQUEST;
}
}
done:
s->uri.len = *u == CR ? (u - s->uri.data) : (u - s->uri.data + 1);
return NGX_OK;
args:
while (p < s->uri_end) {
if (*p++ != '#') {
continue;
}
s->args.len = p - 1 - s->args_start;
s->args.data = s->args_start;
s->args_start = NULL;
break;
}
s->uri.len = u - s->uri.data;
return NGX_OK;
}
ngx_int_t
ngx_rtmp_process_request_line(ngx_rtmp_session_t *s, const u_char *name,
const u_char *args, const u_char *cmd)
{
size_t rlen = 0;
s->stream.len = name ? ngx_strlen(name) : 0;
if (s->stream.len) {
s->stream.data = ngx_palloc(s->connection->pool, s->stream.len);
if (s->stream.data == NULL) {
return NGX_ERROR;
}
ngx_memcpy(s->stream.data, name, ngx_strlen(name));
}
if (s->tc_url.data[s->tc_url.len - 1] == '/') {
s->tc_url.len -= 1;
}
rlen = s->tc_url.len;
if (s->stream.len) {
rlen += 1 + s->stream.len;
}
if (args && args[0]) {
rlen += 1 + ngx_strlen(args);
}
s->request_line = ngx_create_temp_buf(s->connection->pool, rlen + 1);
if (s->request_line == NULL) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"%s: failed to ngx_pcalloc for request_line", cmd);
return NGX_ERROR;
}
if (s->stream.len) {
if (args && args[0]) {
*ngx_snprintf(s->request_line->pos, rlen + 1, "%V/%V?%s", &s->tc_url,
&s->stream, args) = CR;
} else {
*ngx_snprintf(s->request_line->pos, rlen + 1, "%V/%V", &s->tc_url,
&s->stream) = CR;
}
} else {
if (args && args[0]) {
*ngx_snprintf(s->request_line->pos, rlen + 1, "%V?%s", &s->tc_url,
args) = CR;
} else {
*ngx_snprintf(s->request_line->pos, rlen + 1, "%V", &s->tc_url)
= CR;
}
}
s->request_line->last += rlen;
if (ngx_rtmp_parse_request_line(s, s->request_line) != NGX_OK) {
ngx_log_error(NGX_LOG_ERR, s->connection->log, 0,
"%s: invalid request line: '%s'", cmd, s->request_line->pos);
return NGX_ERROR;
}
if (ngx_rtmp_process_request_uri(s) != NGX_OK) {
return NGX_ERROR;
}
*s->request_line->last = 0;
return NGX_OK;
}
C
1
https://gitee.com/winshining/nginx-http-flv-module.git
git@gitee.com:winshining/nginx-http-flv-module.git
winshining
nginx-http-flv-module
nginx-http-flv-module
master

搜索帮助