static ngx_int_t ngx_http_vod_hls_parse_uri_file_name( ngx_http_request_t *r, ngx_http_vod_loc_conf_t *conf, u_char* start_pos, u_char* end_pos, request_params_t* request_params, const ngx_http_vod_request_t** request) { uint32_t flags; ngx_int_t rc; // ts segment if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hls.m3u8_config.segment_file_name_prefix, ts_file_ext)) { start_pos += conf->hls.m3u8_config.segment_file_name_prefix.len; end_pos -= (sizeof(ts_file_ext) - 1); *request = &hls_ts_segment_request; flags = PARSE_FILE_NAME_EXPECT_SEGMENT_INDEX; } // vtt segment else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hls.m3u8_config.segment_file_name_prefix, vtt_file_ext)) { start_pos += conf->hls.m3u8_config.segment_file_name_prefix.len; end_pos -= (sizeof(vtt_file_ext) - 1); *request = &hls_vtt_segment_request; flags = PARSE_FILE_NAME_EXPECT_SEGMENT_INDEX; } // manifest else if (ngx_http_vod_ends_with_static(start_pos, end_pos, m3u8_file_ext)) { end_pos -= (sizeof(m3u8_file_ext) - 1); // make sure the file name begins with 'index' or 'iframes' if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.m3u8_config.index_file_name_prefix)) { *request = &hls_index_request; start_pos += conf->hls.m3u8_config.index_file_name_prefix.len; flags = 0; } else if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.iframes_file_name_prefix)) { *request = &hls_iframes_request; start_pos += conf->hls.iframes_file_name_prefix.len; flags = 0; } else if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.master_file_name_prefix)) { *request = &hls_master_request; start_pos += conf->hls.master_file_name_prefix.len; flags = PARSE_FILE_NAME_MULTI_STREAMS_PER_TYPE; } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_hls_parse_uri_file_name: unidentified m3u8 request"); return NGX_HTTP_BAD_REQUEST; } } // encryption key else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hls.m3u8_config.encryption_key_file_name, key_file_ext) && !conf->drm_enabled) { start_pos += conf->hls.m3u8_config.encryption_key_file_name.len; end_pos -= (sizeof(key_file_ext) - 1); *request = &hls_enc_key_request; flags = 0; } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_hls_parse_uri_file_name: unidentified request"); return NGX_HTTP_BAD_REQUEST; } // parse the required tracks string rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, flags, request_params); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_hls_parse_uri_file_name: ngx_http_vod_parse_uri_file_name failed %i", rc); return rc; } return NGX_OK; }
ngx_int_t ngx_http_vod_mss_parse_uri_file_name( ngx_http_request_t *r, ngx_http_vod_loc_conf_t *conf, u_char* start_pos, u_char* end_pos, ngx_http_vod_request_params_t* request_params) { fragment_params_t fragment_params; ngx_int_t rc; // fragment if (end_pos[-1] == ')') { if (!ngx_http_vod_parse_string(fragment_match_definition, start_pos, end_pos, &fragment_params)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: ngx_http_vod_parse_string failed"); return NGX_HTTP_BAD_REQUEST; } if (fragment_params.media_type.len != sizeof(MSS_STREAM_TYPE_VIDEO) - 1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: invalid media type length %uz", fragment_params.media_type.len); return NGX_HTTP_BAD_REQUEST; } request_params->required_files = (1 << MSS_FILE_INDEX(fragment_params.bitrate)); if (ngx_memcmp(fragment_params.media_type.data, MSS_STREAM_TYPE_VIDEO, sizeof(MSS_STREAM_TYPE_VIDEO) - 1) == 0) { request_params->required_tracks[MEDIA_TYPE_VIDEO] = (1 << MSS_TRACK_INDEX(fragment_params.bitrate)); } else if (ngx_memcmp(fragment_params.media_type.data, MSS_STREAM_TYPE_AUDIO, sizeof(MSS_STREAM_TYPE_AUDIO) - 1) == 0) { request_params->required_tracks[MEDIA_TYPE_AUDIO] = (1 << MSS_TRACK_INDEX(fragment_params.bitrate)); } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: invalid media type %V", &fragment_params.media_type); return NGX_HTTP_BAD_REQUEST; } request_params->segment_index = segmenter_get_segment_index(&conf->segmenter, fragment_params.time / 10000); request_params->request = conf->drm_enabled ? &mss_playready_fragment_request : &mss_fragment_request; return NGX_OK; } // manifest if (!ngx_http_vod_starts_with(start_pos, end_pos, &conf->mss.manifest_file_name_prefix)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: unidentified request"); return NGX_HTTP_BAD_REQUEST; } request_params->request = &mss_manifest_request; start_pos += conf->mss.manifest_file_name_prefix.len; rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, FALSE, request_params); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: ngx_http_vod_parse_uri_file_name failed %i", rc); return rc; } return NGX_OK; }
static ngx_int_t ngx_http_vod_hls_parse_uri_file_name( ngx_http_request_t *r, ngx_http_vod_loc_conf_t *conf, u_char* start_pos, u_char* end_pos, request_params_t* request_params, const ngx_http_vod_request_t** request) { bool_t expect_segment_index; ngx_int_t rc; // segment if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hls.m3u8_config.segment_file_name_prefix, ts_file_ext)) { start_pos += conf->hls.m3u8_config.segment_file_name_prefix.len; end_pos -= (sizeof(ts_file_ext) - 1); *request = &hls_segment_request; expect_segment_index = TRUE; } // manifest else if (ngx_http_vod_ends_with_static(start_pos, end_pos, m3u8_file_ext)) { end_pos -= (sizeof(m3u8_file_ext) - 1); // make sure the file name begins with 'index' or 'iframes' if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.m3u8_config.index_file_name_prefix)) { *request = &hls_index_request; start_pos += conf->hls.m3u8_config.index_file_name_prefix.len; } else if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.iframes_file_name_prefix)) { *request = &hls_iframes_request; start_pos += conf->hls.iframes_file_name_prefix.len; } else if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hls.master_file_name_prefix)) { *request = &hls_master_request; start_pos += conf->hls.master_file_name_prefix.len; } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_hls_parse_uri_file_name: unidentified m3u8 request"); return NGX_HTTP_BAD_REQUEST; } expect_segment_index = FALSE; } // encryption key else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hls.m3u8_config.encryption_key_file_name, key_file_ext)) { start_pos += conf->hls.m3u8_config.encryption_key_file_name.len; end_pos -= (sizeof(key_file_ext) - 1); *request = &hls_enc_key_request; expect_segment_index = FALSE; } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_hls_parse_uri_file_name: unidentified request"); return NGX_HTTP_BAD_REQUEST; } // parse the required tracks string rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, expect_segment_index, request_params); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_hls_parse_uri_file_name: ngx_http_vod_parse_uri_file_name failed %i", rc); return rc; } return NGX_OK; }
static ngx_int_t ngx_http_vod_hds_parse_uri_file_name( ngx_http_request_t *r, ngx_http_vod_loc_conf_t *conf, u_char* start_pos, u_char* end_pos, request_params_t* request_params, const ngx_http_vod_request_t** request) { ngx_int_t rc; // fragment request if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->hds.manifest_config.fragment_file_name_prefix)) { // sample fragment file name: frag-f3-v1-a1-Seg1-Frag1 start_pos += conf->hds.manifest_config.fragment_file_name_prefix.len; // parse the fragment index end_pos = ngx_http_vod_extract_uint32_token_reverse(start_pos, end_pos, &request_params->segment_index); if (request_params->segment_index == 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_hds_parse_uri_file_name: failed to parse fragment index"); return NGX_HTTP_BAD_REQUEST; } request_params->segment_index--; // convert to 0-based // extract the '-Seg1-Frag' part end_pos -= sizeof("-Seg1-Frag") - 1; if (end_pos < start_pos || ngx_memcmp(end_pos, "-Seg1-Frag", sizeof("-Seg1-Frag") - 1) != 0) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_hds_parse_uri_file_name: invalid segment / fragment requested"); return NGX_HTTP_BAD_REQUEST; } *request = &hds_fragment_request; } // manifest request else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hds.manifest_file_name_prefix, manifest_file_ext)) { start_pos += conf->hds.manifest_file_name_prefix.len; end_pos -= (sizeof(manifest_file_ext) - 1); *request = &hds_manifest_request; } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_hds_parse_uri_file_name: unidentified request"); return NGX_HTTP_BAD_REQUEST; } // parse the required tracks string rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, FALSE, request_params); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_hds_parse_uri_file_name: ngx_http_vod_parse_uri_file_name failed %i", rc); return rc; } return NGX_OK; }
ngx_int_t ngx_http_vod_mss_parse_uri_file_name( ngx_http_request_t *r, ngx_http_vod_loc_conf_t *conf, u_char* start_pos, u_char* end_pos, request_params_t* request_params, const ngx_http_vod_request_t** request) { fragment_params_t fragment_params; ngx_int_t rc; // fragment if (end_pos[-1] == ')') { if (!ngx_http_vod_parse_string(fragment_match_definition, start_pos, end_pos, &fragment_params)) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: ngx_http_vod_parse_string failed"); return NGX_HTTP_BAD_REQUEST; } if (fragment_params.media_type.len != sizeof(MSS_STREAM_TYPE_VIDEO) - 1) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: invalid media type length %uz", fragment_params.media_type.len); return NGX_HTTP_BAD_REQUEST; } request_params->sequences_mask = (1 << mss_sequence_index(fragment_params.bitrate)); if (ngx_memcmp(fragment_params.media_type.data, MSS_STREAM_TYPE_VIDEO, sizeof(MSS_STREAM_TYPE_VIDEO) - 1) == 0) { request_params->tracks_mask[MEDIA_TYPE_VIDEO] = (1 << mss_track_index(fragment_params.bitrate)); } else if (ngx_memcmp(fragment_params.media_type.data, MSS_STREAM_TYPE_AUDIO, sizeof(MSS_STREAM_TYPE_AUDIO) - 1) == 0) { request_params->tracks_mask[MEDIA_TYPE_AUDIO] = (1 << mss_track_index(fragment_params.bitrate)); } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: invalid media type %V", &fragment_params.media_type); return NGX_HTTP_BAD_REQUEST; } request_params->segment_time = fragment_params.time / 10000; // Note: assuming no discontinuity, if this changes the segment index will be recalculated request_params->segment_index = segmenter_get_segment_index_no_discontinuity( &conf->segmenter, request_params->segment_time); *request = conf->drm_enabled ? &mss_playready_fragment_request : &mss_fragment_request; return NGX_OK; } // manifest else if (ngx_http_vod_starts_with(start_pos, end_pos, &conf->mss.manifest_file_name_prefix)) { *request = &mss_manifest_request; start_pos += conf->mss.manifest_file_name_prefix.len; rc = ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, FALSE, request_params); if (rc != NGX_OK) { ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: ngx_http_vod_parse_uri_file_name failed %i", rc); return rc; } return NGX_OK; } // fragment with non-standard format (used with redirect) else if (ngx_http_vod_match_prefix_postfix(start_pos, end_pos, &conf->hls.m3u8_config.segment_file_name_prefix, m4s_file_ext)) { start_pos += conf->hls.m3u8_config.segment_file_name_prefix.len; end_pos -= (sizeof(m4s_file_ext) - 1); *request = conf->drm_enabled ? &mss_playready_fragment_request : &mss_fragment_request; return ngx_http_vod_parse_uri_file_name(r, start_pos, end_pos, TRUE, request_params); } else { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "ngx_http_vod_mss_parse_uri_file_name: unidentified request"); return NGX_HTTP_BAD_REQUEST; } }