mirror of
https://github.com/nghttp2/nghttp2.git
synced 2026-03-24 23:16:15 +08:00
Compare commits
10 Commits
v1.68.1
...
copilot/fi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e926d50dd | ||
|
|
29a014a418 | ||
|
|
4af1e4cf55 | ||
|
|
4334ded205 | ||
|
|
a99e209b2e | ||
|
|
3fa6a6349c | ||
|
|
6c0fd9400d | ||
|
|
de81da7621 | ||
|
|
8593b1f46c | ||
|
|
0e9d325dee |
2
.github/workflows/fuzz.yml
vendored
2
.github/workflows/fuzz.yml
vendored
@@ -24,7 +24,7 @@ jobs:
|
||||
fuzz-seconds: 600
|
||||
dry-run: false
|
||||
- name: Upload Crash
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v5
|
||||
if: failure()
|
||||
with:
|
||||
name: artifacts
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.14)
|
||||
# XXX using 1.8.90 instead of 1.9.0-DEV
|
||||
project(nghttp2 VERSION 1.68.1 LANGUAGES C)
|
||||
project(nghttp2 VERSION 1.68.90 LANGUAGES C)
|
||||
|
||||
# See versioning rule:
|
||||
# https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
set(LT_CURRENT 43)
|
||||
set(LT_REVISION 3)
|
||||
set(LT_REVISION 2)
|
||||
set(LT_AGE 29)
|
||||
|
||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})
|
||||
|
||||
88
UNUSED_SYMBOLS.md
Normal file
88
UNUSED_SYMBOLS.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# Unused Symbols Report
|
||||
|
||||
This document lists unused functions, macros, and enums found in the nghttp2 library.
|
||||
|
||||
**Analysis Date:** 2025-11-01
|
||||
**Scope:** Private symbols in `lib/` directory (excluding public API in `lib/includes/nghttp2/`)
|
||||
|
||||
## Summary
|
||||
|
||||
- **Unused Functions:** 0
|
||||
- **Unused Macros:** 3
|
||||
- **Unused Enums:** 2
|
||||
- **Total Unused Symbols:** 5
|
||||
|
||||
## Methodology
|
||||
|
||||
The analysis was performed by:
|
||||
1. Parsing all source files (`.c` and `.h`) in the `lib/` directory
|
||||
2. Extracting function definitions, macro definitions, and enum declarations
|
||||
3. Excluding symbols defined in the public API (`lib/includes/nghttp2/nghttp2.h`)
|
||||
4. Counting references to each symbol across the entire codebase (including `lib/`, `src/`, `examples/`, `tests/`)
|
||||
5. Identifying symbols that appear only once (in their definition) or have no references beyond their definition
|
||||
|
||||
Note: All private functions that were initially detected as potentially unused were found to actually be in use, either:
|
||||
- In conditional compilation paths (platform-specific code)
|
||||
- As static helper functions called within the same file
|
||||
- Through function pointers or callbacks
|
||||
|
||||
|
||||
## Unused Private Macros (3)
|
||||
|
||||
| Macro Name | File Location | Description |
|
||||
|-----------|---------------|-------------|
|
||||
| `NGHTTP2_PRIORITY_MASK` | lib/nghttp2_frame.h | Mask for priority value, defined but never used |
|
||||
| `NGHTTP2_PRI_GROUP_ID_MASK` | lib/nghttp2_frame.h | Mask for priority group ID, defined but never used |
|
||||
| `NGHTTP2_SETTINGS_ID_MASK` | lib/nghttp2_frame.h | Mask for settings ID, defined but never used |
|
||||
|
||||
**Note:** The SFPARSE_STATE_* macros (`SFPARSE_STATE_DICT`, `SFPARSE_STATE_ITEM`, `SFPARSE_STATE_LIST`) were initially identified as unused, but they are actually used through token concatenation in macro expansions (e.g., `SFPARSE_STATE_##NAME`). They are not truly unused.
|
||||
|
||||
## Unused Private Enums (2)
|
||||
|
||||
| Enum Name | File Location | Description |
|
||||
|-----------|---------------|-------------|
|
||||
| `NGHTTP2_ERR_CREDENTIAL_PENDING` | lib/nghttp2_int.h | Error code (-101), defined but never referenced |
|
||||
| `NGHTTP2_TYPEMASK_NONE` | lib/nghttp2_session.h | Type mask value (0), defined but never referenced |
|
||||
|
||||
## Notes
|
||||
|
||||
- All symbols listed are **private** (not part of the public API in `lib/includes/nghttp2/`)
|
||||
- These symbols have only one reference (their definition) in the entire codebase
|
||||
- All detected private functions were found to be in active use through various means (conditional compilation, static helpers, callbacks)
|
||||
|
||||
**Important Note:** This analysis uses simple pattern matching and may not detect all forms of indirect usage, particularly:
|
||||
- Macro token concatenation (e.g., `##NAME` in macro expansions)
|
||||
- Function pointers passed through complex call chains
|
||||
- Symbols used in platform-specific conditional compilation
|
||||
|
||||
## Detailed Findings
|
||||
|
||||
### Macros
|
||||
The 3 unused macros are frame header masks that appear to be leftover definitions from earlier versions or reserved for future use:
|
||||
|
||||
- **NGHTTP2_PRIORITY_MASK**: Mask for priority value
|
||||
- **NGHTTP2_PRI_GROUP_ID_MASK**: Mask for priority group ID
|
||||
- **NGHTTP2_SETTINGS_ID_MASK**: Mask for settings ID
|
||||
|
||||
### Enums
|
||||
Both unused enum values appear to be reserved for specific features:
|
||||
|
||||
1. **NGHTTP2_ERR_CREDENTIAL_PENDING**: Error code -101, possibly reserved for future credential handling features
|
||||
2. **NGHTTP2_TYPEMASK_NONE**: A zero-value type mask that may have been used historically but is no longer needed
|
||||
|
||||
## Recommendations
|
||||
|
||||
1. **Review each symbol** to determine if it should be removed or is kept for a specific reason (e.g., future use, compatibility)
|
||||
2. **Consider adding comments** to explain why symbols are kept if they appear unused but serve a purpose
|
||||
3. **Remove confirmed unused symbols** to reduce code complexity and maintenance burden
|
||||
4. **Update documentation** if any symbols were intended for public use but are not actually exposed
|
||||
|
||||
## Re-running the Analysis
|
||||
|
||||
A Python script is provided to re-run this analysis:
|
||||
|
||||
```bash
|
||||
python3 find_unused_symbols.py
|
||||
```
|
||||
|
||||
This script can be used to verify that unused symbols have been removed or to check for new unused symbols in the future.
|
||||
@@ -25,7 +25,7 @@ dnl Do not change user variables!
|
||||
dnl https://www.gnu.org/software/automake/manual/html_node/Flag-Variables-Ordering.html
|
||||
|
||||
AC_PREREQ(2.61)
|
||||
AC_INIT([nghttp2], [1.68.1], [t-tujikawa@users.sourceforge.net])
|
||||
AC_INIT([nghttp2], [1.69.0-DEV], [t-tujikawa@users.sourceforge.net])
|
||||
AC_CONFIG_AUX_DIR([.])
|
||||
AC_CONFIG_MACRO_DIR([m4])
|
||||
AC_CONFIG_HEADERS([config.h])
|
||||
@@ -45,7 +45,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
|
||||
dnl See versioning rule:
|
||||
dnl https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html
|
||||
AC_SUBST(LT_CURRENT, 43)
|
||||
AC_SUBST(LT_REVISION, 3)
|
||||
AC_SUBST(LT_REVISION, 2)
|
||||
AC_SUBST(LT_AGE, 29)
|
||||
|
||||
major=`echo $PACKAGE_VERSION |cut -d. -f1 | sed -e "s/[^0-9]//g"`
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "H2LOAD" "1" "Mar 18, 2026" "1.68.1" "nghttp2"
|
||||
.TH "H2LOAD" "1" "Oct 25, 2025" "1.68.0" "nghttp2"
|
||||
.SH NAME
|
||||
h2load \- HTTP/2 benchmarking tool
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTP" "1" "Mar 18, 2026" "1.68.1" "nghttp2"
|
||||
.TH "NGHTTP" "1" "Oct 25, 2025" "1.68.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttp \- HTTP/2 client
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTPD" "1" "Mar 18, 2026" "1.68.1" "nghttp2"
|
||||
.TH "NGHTTPD" "1" "Oct 25, 2025" "1.68.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpd \- HTTP/2 server
|
||||
.SH SYNOPSIS
|
||||
|
||||
@@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
|
||||
..
|
||||
.TH "NGHTTPX" "1" "Mar 18, 2026" "1.68.1" "nghttp2"
|
||||
.TH "NGHTTPX" "1" "Oct 25, 2025" "1.68.0" "nghttp2"
|
||||
.SH NAME
|
||||
nghttpx \- HTTP/2 proxy
|
||||
.SH SYNOPSIS
|
||||
|
||||
265
find_unused_symbols.py
Executable file
265
find_unused_symbols.py
Executable file
@@ -0,0 +1,265 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Find unused functions, macros, and enums in the nghttp2 library.
|
||||
Excludes symbols defined in lib/includes/nghttp2/ (public API).
|
||||
|
||||
Usage:
|
||||
python3 find_unused_symbols.py
|
||||
|
||||
This script analyzes the nghttp2 library source code to find private symbols
|
||||
(functions, macros, enums) that are defined but never used. It excludes symbols
|
||||
that are part of the public API.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_lib_files(lib_dir):
|
||||
"""Get all .c and .h files in lib directory, excluding public headers."""
|
||||
files = []
|
||||
public_dir = os.path.join(lib_dir, 'includes', 'nghttp2')
|
||||
|
||||
for root, dirs, filenames in os.walk(lib_dir):
|
||||
if os.path.abspath(root).startswith(os.path.abspath(public_dir)):
|
||||
continue
|
||||
|
||||
for filename in filenames:
|
||||
if filename.endswith(('.c', '.h')):
|
||||
files.append(os.path.join(root, filename))
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def get_all_project_files(base_dir):
|
||||
"""Get all source files in the entire project."""
|
||||
files = []
|
||||
|
||||
for root, dirs, filenames in os.walk(base_dir):
|
||||
if '.git' in root or 'build' in root:
|
||||
continue
|
||||
|
||||
for filename in filenames:
|
||||
if filename.endswith(('.c', '.h', '.cc', '.cpp')):
|
||||
files.append(os.path.join(root, filename))
|
||||
|
||||
return files
|
||||
|
||||
|
||||
def get_public_api_symbols(public_header):
|
||||
"""Extract all symbols from the public API header."""
|
||||
symbols = set()
|
||||
|
||||
if not os.path.exists(public_header):
|
||||
return symbols
|
||||
|
||||
with open(public_header, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
content = f.read()
|
||||
|
||||
# Remove comments
|
||||
content = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
|
||||
content = re.sub(r'//.*?$', '', content, flags=re.MULTILINE)
|
||||
|
||||
# Extract all symbols that look like functions, types, macros, enums
|
||||
for match in re.finditer(r'\b([a-zA-Z_][a-zA-Z0-9_]*)\b', content):
|
||||
name = match.group(1)
|
||||
if name.startswith('nghttp2_') or name.startswith('NGHTTP2_') or name.startswith('sfparse_'):
|
||||
symbols.add(name)
|
||||
|
||||
return symbols
|
||||
|
||||
|
||||
def extract_definitions(filepath):
|
||||
"""Extract function, macro, and enum definitions from a file."""
|
||||
functions = {}
|
||||
macros = {}
|
||||
enums = {}
|
||||
|
||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
content = f.read()
|
||||
|
||||
no_comments = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
|
||||
no_comments = re.sub(r'//.*?$', '', no_comments, flags=re.MULTILINE)
|
||||
|
||||
# Extract function definitions
|
||||
func_pattern = r'\b(?:static\s+)?(?:inline\s+|STIN\s+)?(?:const\s+)?([a-zA-Z_][a-zA-Z0-9_*\s]+)\s+([a-zA-Z_][a-zA-Z0-9_]*)\s*\([^)]*\)\s*\{'
|
||||
for match in re.finditer(func_pattern, no_comments):
|
||||
func_name = match.group(2).strip()
|
||||
if func_name not in ['if', 'for', 'while', 'switch', 'main']:
|
||||
functions[func_name] = filepath
|
||||
|
||||
# Extract macros (uppercase convention only - lowercase macros not detected)
|
||||
# This is intentional to focus on constant-like macros and avoid false positives
|
||||
macro_pattern = r'^\s*#define\s+([A-Z_][A-Z0-9_]*)'
|
||||
for match in re.finditer(macro_pattern, content, re.MULTILINE):
|
||||
macro_name = match.group(1)
|
||||
if not (macro_name.endswith('_H') or macro_name.endswith('_H_')):
|
||||
macros[macro_name] = filepath
|
||||
|
||||
# Extract enum type names and members
|
||||
enum_pattern = r'(?:typedef\s+)?enum\s+([a-zA-Z_][a-zA-Z0-9_]*)'
|
||||
for match in re.finditer(enum_pattern, no_comments):
|
||||
enums[match.group(1)] = filepath
|
||||
|
||||
enum_member_pattern = r'(?:typedef\s+)?enum\s*(?:[a-zA-Z_][a-zA-Z0-9_]*)?\s*\{([^}]+)\}'
|
||||
for match in re.finditer(enum_member_pattern, no_comments, re.DOTALL):
|
||||
members = match.group(1)
|
||||
for member in re.finditer(r'\b([A-Z_][A-Z0-9_]*)\s*(?:=|,|(?=\}))', members):
|
||||
member_name = member.group(1)
|
||||
if member_name not in ['INT32_MIN', 'INT32_MAX', 'UINT32_MAX']:
|
||||
enums[member_name] = filepath
|
||||
|
||||
return functions, macros, enums
|
||||
|
||||
|
||||
def count_symbol_usage(files, symbol, is_macro=False):
|
||||
"""Count how many times a symbol is referenced.
|
||||
|
||||
Note: This function uses simple pattern matching and may not detect all
|
||||
forms of indirect usage, such as macro token concatenation (##NAME).
|
||||
"""
|
||||
count = 0
|
||||
|
||||
for filepath in files:
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
|
||||
content = f.read()
|
||||
except (IOError, OSError):
|
||||
continue
|
||||
|
||||
# Remove comments
|
||||
no_comments = re.sub(r'/\*.*?\*/', '', content, flags=re.DOTALL)
|
||||
no_comments = re.sub(r'//.*?$', '', no_comments, flags=re.MULTILINE)
|
||||
|
||||
if is_macro:
|
||||
# For macros, check various uses
|
||||
patterns = [
|
||||
r'#\s*if(?:n?def)?\s+' + re.escape(symbol) + r'\b',
|
||||
r'#\s*if\s+.*\bdefined\s*\(\s*' + re.escape(symbol) + r'\s*\)',
|
||||
r'\b' + re.escape(symbol) + r'\b',
|
||||
]
|
||||
|
||||
for pattern in patterns:
|
||||
count += len(re.findall(pattern, no_comments))
|
||||
else:
|
||||
# For functions/enums, count occurrences
|
||||
pattern = r'\b' + re.escape(symbol) + r'\b'
|
||||
count += len(re.findall(pattern, no_comments))
|
||||
|
||||
return count
|
||||
|
||||
|
||||
def main():
|
||||
# Determine base directory (script location or current directory)
|
||||
script_dir = Path(__file__).parent.absolute()
|
||||
if (script_dir / 'lib').exists():
|
||||
base_dir = str(script_dir)
|
||||
else:
|
||||
base_dir = os.getcwd()
|
||||
|
||||
lib_dir = os.path.join(base_dir, 'lib')
|
||||
public_header = os.path.join(lib_dir, 'includes', 'nghttp2', 'nghttp2.h')
|
||||
|
||||
if not os.path.exists(lib_dir):
|
||||
print(f"Error: lib directory not found at {lib_dir}")
|
||||
print("Please run this script from the nghttp2 repository root")
|
||||
return 1
|
||||
|
||||
print("Analyzing nghttp2 for unused private symbols...")
|
||||
print("=" * 70)
|
||||
|
||||
lib_files = get_lib_files(lib_dir)
|
||||
all_files = get_all_project_files(base_dir)
|
||||
|
||||
print(f"Found {len(lib_files)} library source files (excluding public headers)")
|
||||
print(f"Found {len(all_files)} total source files in project")
|
||||
|
||||
public_symbols = get_public_api_symbols(public_header)
|
||||
print(f"Found {len(public_symbols)} public API symbols")
|
||||
|
||||
all_functions = {}
|
||||
all_macros = {}
|
||||
all_enums = {}
|
||||
|
||||
for filepath in lib_files:
|
||||
functions, macros, enums = extract_definitions(filepath)
|
||||
all_functions.update(functions)
|
||||
all_macros.update(macros)
|
||||
all_enums.update(enums)
|
||||
|
||||
private_functions = {k: v for k, v in all_functions.items() if k not in public_symbols}
|
||||
private_macros = {k: v for k, v in all_macros.items() if k not in public_symbols}
|
||||
private_enums = {k: v for k, v in all_enums.items() if k not in public_symbols}
|
||||
|
||||
print(f"\nFound {len(private_functions)} private function definitions")
|
||||
print(f"Found {len(private_macros)} private macro definitions")
|
||||
print(f"Found {len(private_enums)} private enum definitions/members")
|
||||
|
||||
unused_functions = []
|
||||
unused_macros = []
|
||||
unused_enums = []
|
||||
|
||||
print("\nChecking for unused private functions...")
|
||||
for i, (func, filepath) in enumerate(sorted(private_functions.items())):
|
||||
if (i + 1) % 50 == 0:
|
||||
print(f" Checked {i + 1}/{len(private_functions)}...")
|
||||
usage_count = count_symbol_usage(all_files, func, is_macro=False)
|
||||
# If symbol appears only once (its definition), it's unused
|
||||
if usage_count <= 1:
|
||||
unused_functions.append((func, filepath, usage_count))
|
||||
|
||||
print("Checking for unused private macros...")
|
||||
for i, (macro, filepath) in enumerate(sorted(private_macros.items())):
|
||||
usage_count = count_symbol_usage(all_files, macro, is_macro=True)
|
||||
# Macros often appear twice (definition + possible use in #ifdef)
|
||||
if usage_count <= 1:
|
||||
unused_macros.append((macro, filepath, usage_count))
|
||||
|
||||
print("Checking for unused private enums...")
|
||||
for i, (enum, filepath) in enumerate(sorted(private_enums.items())):
|
||||
if (i + 1) % 50 == 0:
|
||||
print(f" Checked {i + 1}/{len(private_enums)}...")
|
||||
usage_count = count_symbol_usage(all_files, enum, is_macro=False)
|
||||
if usage_count <= 1:
|
||||
unused_enums.append((enum, filepath, usage_count))
|
||||
|
||||
# Print results
|
||||
print("\n" + "=" * 70)
|
||||
print("RESULTS")
|
||||
print("=" * 70)
|
||||
|
||||
if unused_functions:
|
||||
print(f"\nUnused Private Functions ({len(unused_functions)}):")
|
||||
for func, filepath, count in sorted(unused_functions):
|
||||
rel_path = os.path.relpath(filepath, base_dir)
|
||||
print(f" - {func:50s} in {rel_path} (refs: {count})")
|
||||
|
||||
if unused_macros:
|
||||
print(f"\nUnused Private Macros ({len(unused_macros)}):")
|
||||
for macro, filepath, count in sorted(unused_macros):
|
||||
rel_path = os.path.relpath(filepath, base_dir)
|
||||
print(f" - {macro:50s} in {rel_path} (refs: {count})")
|
||||
|
||||
if unused_enums:
|
||||
print(f"\nUnused Private Enums ({len(unused_enums)}):")
|
||||
for enum, filepath, count in sorted(unused_enums):
|
||||
rel_path = os.path.relpath(filepath, base_dir)
|
||||
print(f" - {enum:50s} in {rel_path} (refs: {count})")
|
||||
|
||||
if not unused_functions and not unused_macros and not unused_enums:
|
||||
print("\nNo unused private symbols found!")
|
||||
else:
|
||||
print(f"\nTotal: {len(unused_functions)} functions, {len(unused_macros)} macros, {len(unused_enums)} enums")
|
||||
print("\nNote: This analysis uses simple pattern matching and may not detect:")
|
||||
print(" - Macro token concatenation (e.g., ##NAME in macro expansions)")
|
||||
print(" - Function pointers passed through complex call chains")
|
||||
print(" - Symbols used only in platform-specific conditional compilation")
|
||||
print("\nManual verification is recommended before removing any symbols.")
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main())
|
||||
@@ -750,16 +750,6 @@ void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
uint8_t *p;
|
||||
|
||||
altsvc = frame->payload;
|
||||
|
||||
if (payloadlen == 0) {
|
||||
altsvc->origin = NULL;
|
||||
altsvc->origin_len = 0;
|
||||
altsvc->field_value = NULL;
|
||||
altsvc->field_value_len = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
p = payload;
|
||||
|
||||
altsvc->origin = p;
|
||||
|
||||
@@ -5466,10 +5466,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
busy = 1;
|
||||
|
||||
rv = session_on_data_received_fail_fast(session);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
@@ -5490,6 +5486,10 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
break;
|
||||
}
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = inbound_frame_handle_pad(iframe, &iframe->frame.hd);
|
||||
if (rv < 0) {
|
||||
rv = nghttp2_session_terminate_session_with_reason(
|
||||
@@ -5573,10 +5573,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
on_begin_frame_called = 1;
|
||||
|
||||
rv = session_process_headers_frame(session);
|
||||
@@ -6045,10 +6041,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6301,10 +6293,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
session_inbound_frame_reset(session);
|
||||
|
||||
break;
|
||||
@@ -6611,10 +6599,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
} else {
|
||||
iframe->state = NGHTTP2_IB_IGN_HEADER_BLOCK;
|
||||
}
|
||||
@@ -6787,17 +6771,13 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
rv = session->callbacks.on_data_chunk_recv_callback(
|
||||
session, iframe->frame.hd.flags, iframe->frame.hd.stream_id,
|
||||
in - readlen, (size_t)data_readlen, session->user_data);
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
if (rv == NGHTTP2_ERR_PAUSE) {
|
||||
return (nghttp2_ssize)(in - first);
|
||||
}
|
||||
|
||||
if (nghttp2_is_fatal(rv)) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6881,10 +6861,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
busy = 1;
|
||||
|
||||
@@ -6903,10 +6879,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
session_inbound_frame_reset(session);
|
||||
|
||||
break;
|
||||
@@ -6935,10 +6907,6 @@ nghttp2_ssize nghttp2_session_mem_recv2(nghttp2_session *session,
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (iframe->state == NGHTTP2_IB_IGN_ALL) {
|
||||
return (nghttp2_ssize)inlen;
|
||||
}
|
||||
|
||||
session_inbound_frame_reset(session);
|
||||
|
||||
break;
|
||||
|
||||
73
src/util.h
73
src/util.h
@@ -375,18 +375,23 @@ constexpr size_t quote_stringlen(R &&r) {
|
||||
return n;
|
||||
}
|
||||
|
||||
inline constexpr auto hexdigits = []() {
|
||||
constexpr char LOWER_XDIGITS[] = "0123456789abcdef";
|
||||
inline constexpr char LOWER_XDIGITS[] = "0123456789abcdef";
|
||||
|
||||
std::array<char, 512> tbl;
|
||||
template <std::weakly_incrementable O>
|
||||
requires(std::indirectly_writable<O, char>)
|
||||
constexpr O format_hex_uint8(uint8_t b, O result) {
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif // __GNUC__
|
||||
*result++ = LOWER_XDIGITS[b >> 4];
|
||||
*result++ = LOWER_XDIGITS[b & 0xf];
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif // __GNUC__
|
||||
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
tbl[i * 2] = LOWER_XDIGITS[static_cast<size_t>(i >> 4)];
|
||||
tbl[i * 2 + 1] = LOWER_XDIGITS[static_cast<size_t>(i & 0xf)];
|
||||
}
|
||||
|
||||
return tbl;
|
||||
}();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Converts a range [|first|, |last|) in hex format, and stores the
|
||||
// result in another range, beginning at |result|. It returns an
|
||||
@@ -396,9 +401,7 @@ requires(std::indirectly_writable<O, char> &&
|
||||
sizeof(std::iter_value_t<I>) == sizeof(uint8_t))
|
||||
constexpr O format_hex(I first, I last, O result) {
|
||||
for (; first != last; ++first) {
|
||||
result = std::ranges::copy_n(
|
||||
hexdigits.data() + static_cast<uint8_t>(*first) * 2, 2, result)
|
||||
.out;
|
||||
result = format_hex_uint8(static_cast<uint8_t>(*first), result);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -449,7 +452,7 @@ template <std::unsigned_integral T, std::weakly_incrementable O>
|
||||
requires(std::indirectly_writable<O, char>)
|
||||
constexpr O format_hex(T n, O result) {
|
||||
if constexpr (sizeof(n) == 1) {
|
||||
return std::ranges::copy_n(hexdigits.data() + n * 2, 2, result).out;
|
||||
return format_hex_uint8(n, result);
|
||||
}
|
||||
|
||||
if constexpr (std::endian::native == std::endian::little) {
|
||||
@@ -457,38 +460,36 @@ constexpr O format_hex(T n, O result) {
|
||||
auto p = end + sizeof(n);
|
||||
|
||||
for (; p != end; --p) {
|
||||
result =
|
||||
std::ranges::copy_n(hexdigits.data() + *(p - 1) * 2, 2, result).out;
|
||||
result = format_hex_uint8(*(p - 1), result);
|
||||
}
|
||||
} else {
|
||||
auto p = reinterpret_cast<uint8_t *>(&n);
|
||||
auto end = p + sizeof(n);
|
||||
|
||||
for (; p != end; ++p) {
|
||||
result = std::ranges::copy_n(hexdigits.data() + *p * 2, 2, result).out;
|
||||
result = format_hex_uint8(*p, result);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline constexpr auto upper_hexdigits = []() {
|
||||
constexpr char UPPER_XDIGITS[] = "0123456789ABCDEF";
|
||||
|
||||
std::array<char, 512> tbl;
|
||||
|
||||
for (size_t i = 0; i < 256; ++i) {
|
||||
tbl[i * 2] = UPPER_XDIGITS[static_cast<size_t>(i >> 4)];
|
||||
tbl[i * 2 + 1] = UPPER_XDIGITS[static_cast<size_t>(i & 0xf)];
|
||||
}
|
||||
|
||||
return tbl;
|
||||
}();
|
||||
inline constexpr char UPPER_XDIGITS[] = "0123456789ABCDEF";
|
||||
|
||||
template <std::weakly_incrementable O>
|
||||
requires(std::indirectly_writable<O, char>)
|
||||
constexpr O format_upper_hex(uint8_t c, O result) {
|
||||
return std::ranges::copy_n(upper_hexdigits.data() + c * 2, 2, result).out;
|
||||
constexpr O format_upper_hex_uint8(uint8_t b, O result) {
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wsign-conversion"
|
||||
#endif // __GNUC__
|
||||
*result++ = UPPER_XDIGITS[b >> 4];
|
||||
*result++ = UPPER_XDIGITS[b & 0xf];
|
||||
#ifdef __GNUC__
|
||||
# pragma GCC diagnostic pop
|
||||
#endif // __GNUC__
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// decode_hex decodes hex string in a range [|first|, |last|), and
|
||||
@@ -558,7 +559,7 @@ constexpr O percent_encode_token(I first, I last, O result) noexcept {
|
||||
}
|
||||
|
||||
*result++ = '%';
|
||||
result = format_upper_hex(c, result);
|
||||
result = format_upper_hex_uint8(c, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -893,11 +894,11 @@ struct CompactHexFormatter {
|
||||
assert(p != end);
|
||||
|
||||
if (*(p - 1) < 16) {
|
||||
*result++ = static_cast<result_type>(upper_hexdigits[*--p * 2 + 1]);
|
||||
*result++ = static_cast<result_type>(UPPER_XDIGITS[(*--p) & 0xf]);
|
||||
}
|
||||
|
||||
for (; p != end; --p) {
|
||||
result = format_upper_hex(*(p - 1), result);
|
||||
result = format_upper_hex_uint8(*(p - 1), result);
|
||||
}
|
||||
} else {
|
||||
auto p = reinterpret_cast<uint8_t *>(&n);
|
||||
@@ -907,11 +908,11 @@ struct CompactHexFormatter {
|
||||
;
|
||||
|
||||
if (*p < 16) {
|
||||
*result++ = static_cast<result_type>(upper_hexdigits[*p++ * 2 + 1]);
|
||||
*result++ = static_cast<result_type>(UPPER_XDIGITS[(*p++) & 0xf]);
|
||||
}
|
||||
|
||||
for (; p != end; ++p) {
|
||||
result = format_upper_hex(*p, result);
|
||||
result = format_upper_hex_uint8(*p, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ const MunitTest tests[]{
|
||||
munit_void_test(test_util_make_hostport),
|
||||
munit_void_test(test_util_random_alpha_digit),
|
||||
munit_void_test(test_util_format_hex),
|
||||
munit_void_test(test_util_format_upper_hex),
|
||||
munit_void_test(test_util_format_upper_hex_uint8),
|
||||
munit_void_test(test_util_is_hex_string),
|
||||
munit_void_test(test_util_decode_hex),
|
||||
munit_void_test(test_util_extract_host),
|
||||
@@ -890,31 +890,45 @@ void test_util_format_hex(void) {
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_hex(std::numeric_limits<uint64_t>::max(),
|
||||
std::ranges::begin(buf))}));
|
||||
|
||||
std::vector<char> char_vec;
|
||||
util::format_hex(0xdeadbeef, std::back_inserter(char_vec));
|
||||
|
||||
assert_stdsv_equal("deadbeef"sv,
|
||||
(std::string_view{std::ranges::begin(char_vec),
|
||||
std::ranges::end(char_vec)}));
|
||||
|
||||
std::vector<uint8_t> uint8_vec;
|
||||
util::format_hex(0xdeadbeef, std::back_inserter(uint8_vec));
|
||||
|
||||
assert_stdsv_equal(
|
||||
"deadbeef"sv,
|
||||
(std::string_view{reinterpret_cast<const char *>(uint8_vec.data()),
|
||||
uint8_vec.size()}));
|
||||
}
|
||||
|
||||
void test_util_format_upper_hex(void) {
|
||||
void test_util_format_upper_hex_uint8(void) {
|
||||
std::array<char, 64> buf;
|
||||
|
||||
assert_stdsv_equal("00"sv, (std::string_view{std::ranges::begin(buf),
|
||||
util::format_upper_hex_uint8(
|
||||
0, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"00"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_upper_hex(0, std::ranges::begin(buf))}));
|
||||
"0A"sv, (std::string_view{
|
||||
std::ranges::begin(buf),
|
||||
util::format_upper_hex_uint8(0xa, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"0A"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_upper_hex(0xa, std::ranges::begin(buf))}));
|
||||
"7C"sv, (std::string_view{
|
||||
std::ranges::begin(buf),
|
||||
util::format_upper_hex_uint8(0x07c, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"7C"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_upper_hex(0x07c, std::ranges::begin(buf))}));
|
||||
"EB"sv, (std::string_view{
|
||||
std::ranges::begin(buf),
|
||||
util::format_upper_hex_uint8(0xeb, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"EB"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_upper_hex(0xeb, std::ranges::begin(buf))}));
|
||||
assert_stdsv_equal(
|
||||
"FF"sv,
|
||||
(std::string_view{std::ranges::begin(buf),
|
||||
util::format_upper_hex(0xff, std::ranges::begin(buf))}));
|
||||
"FF"sv, (std::string_view{
|
||||
std::ranges::begin(buf),
|
||||
util::format_upper_hex_uint8(0xff, std::ranges::begin(buf))}));
|
||||
}
|
||||
|
||||
void test_util_is_hex_string(void) {
|
||||
|
||||
@@ -69,7 +69,7 @@ munit_void_test_decl(test_util_make_http_hostport)
|
||||
munit_void_test_decl(test_util_make_hostport)
|
||||
munit_void_test_decl(test_util_random_alpha_digit)
|
||||
munit_void_test_decl(test_util_format_hex)
|
||||
munit_void_test_decl(test_util_format_upper_hex)
|
||||
munit_void_test_decl(test_util_format_upper_hex_uint8)
|
||||
munit_void_test_decl(test_util_is_hex_string)
|
||||
munit_void_test_decl(test_util_decode_hex)
|
||||
munit_void_test_decl(test_util_extract_host)
|
||||
|
||||
@@ -515,24 +515,6 @@ void test_nghttp2_frame_pack_altsvc(void) {
|
||||
|
||||
nghttp2_frame_altsvc_free(&oframe, mem);
|
||||
nghttp2_frame_altsvc_free(&frame, mem);
|
||||
|
||||
/* 0 length origin and field_value */
|
||||
nghttp2_frame_altsvc_init(&frame, 0, NULL, 0, NULL, 0);
|
||||
|
||||
payloadlen = 2;
|
||||
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
nghttp2_frame_pack_altsvc(&bufs, &frame);
|
||||
|
||||
assert_size(NGHTTP2_FRAME_HDLEN + payloadlen, ==, nghttp2_bufs_len(&bufs));
|
||||
|
||||
nghttp2_frame_unpack_altsvc_payload(&oframe, 0, NULL, 0);
|
||||
|
||||
assert_size(0, ==, oaltsvc.origin_len);
|
||||
assert_null(oaltsvc.origin);
|
||||
assert_size(0, ==, oaltsvc.field_value_len);
|
||||
assert_null(oaltsvc.field_value);
|
||||
|
||||
nghttp2_bufs_free(&bufs);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,6 @@ static const MunitTest tests[] = {
|
||||
munit_void_test(test_nghttp2_session_set_stream_user_data),
|
||||
munit_void_test(test_nghttp2_session_no_rfc7540_priorities),
|
||||
munit_void_test(test_nghttp2_session_stream_reset_ratelim),
|
||||
munit_void_test(test_nghttp2_session_verify_iframe_state),
|
||||
munit_void_test(test_nghttp2_http_mandatory_headers),
|
||||
munit_void_test(test_nghttp2_http_content_length),
|
||||
munit_void_test(test_nghttp2_http_content_length_mismatch),
|
||||
@@ -10161,443 +10160,6 @@ void test_nghttp2_session_stream_reset_ratelim(void) {
|
||||
nghttp2_option_del(option);
|
||||
}
|
||||
|
||||
static int term_session_on_invalid_frame_recv_callback(
|
||||
nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code,
|
||||
void *user_data) {
|
||||
int rv;
|
||||
(void)frame;
|
||||
(void)lib_error_code;
|
||||
(void)user_data;
|
||||
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int term_session_on_begin_frame_callback(nghttp2_session *session,
|
||||
const nghttp2_frame_hd *hd,
|
||||
void *user_data) {
|
||||
int rv;
|
||||
(void)hd;
|
||||
(void)user_data;
|
||||
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int term_session_on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
int rv;
|
||||
(void)frame;
|
||||
(void)user_data;
|
||||
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int term_session_on_data_chunk_recv_callback(
|
||||
nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data) {
|
||||
int rv;
|
||||
(void)flags;
|
||||
(void)stream_id;
|
||||
(void)data;
|
||||
(void)len;
|
||||
(void)user_data;
|
||||
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int term_session_unpack_extension_callback(nghttp2_session *session,
|
||||
void **payload,
|
||||
const nghttp2_frame_hd *hd,
|
||||
void *user_data) {
|
||||
int rv;
|
||||
(void)payload;
|
||||
(void)hd;
|
||||
(void)user_data;
|
||||
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int term_session_on_extension_chunk_recv_callback(
|
||||
nghttp2_session *session, const nghttp2_frame_hd *hd, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
int rv;
|
||||
(void)hd;
|
||||
(void)data;
|
||||
(void)len;
|
||||
(void)user_data;
|
||||
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
|
||||
assert_int(0, ==, rv);
|
||||
|
||||
return NGHTTP2_ERR_CANCEL;
|
||||
}
|
||||
|
||||
void test_nghttp2_session_verify_iframe_state(void) {
|
||||
nghttp2_session *session;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
nghttp2_bufs bufs;
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_frame frame;
|
||||
nghttp2_extension extfr;
|
||||
nghttp2_ext_priority_update priority_update;
|
||||
nghttp2_ext_altsvc altsvc;
|
||||
nghttp2_frame_hd hd;
|
||||
uint8_t size_err_hd[NGHTTP2_FRAME_HDLEN];
|
||||
nghttp2_ssize rv;
|
||||
const char field_value[] = "i";
|
||||
nghttp2_option *option;
|
||||
nghttp2_hd_deflater deflater;
|
||||
size_t nvlen;
|
||||
nghttp2_nv *nva;
|
||||
nghttp2_mem *mem = nghttp2_mem_default();
|
||||
my_user_data ud;
|
||||
nghttp2_buf udbuf;
|
||||
const char uddata[] = "hello world";
|
||||
|
||||
nghttp2_frame_hd_init(&hd, 0, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, 1);
|
||||
nghttp2_frame_pack_frame_hd(size_err_hd, &hd);
|
||||
|
||||
nghttp2_buf_init2(&ud.scratchbuf, 4096, mem);
|
||||
nghttp2_buf_init2(&udbuf, 4096, mem);
|
||||
|
||||
nghttp2_frame_hd_init(&hd, sizeof(uddata) - 1, 111, 0xab, 1000000007);
|
||||
nghttp2_frame_pack_frame_hd(udbuf.last, &hd);
|
||||
udbuf.last += NGHTTP2_FRAME_HDLEN;
|
||||
udbuf.last = nghttp2_cpymem(udbuf.last, uddata, sizeof(uddata) - 1);
|
||||
|
||||
nghttp2_option_new(&option);
|
||||
nghttp2_option_set_builtin_recv_extension_type(option,
|
||||
NGHTTP2_PRIORITY_UPDATE);
|
||||
nghttp2_option_set_builtin_recv_extension_type(option, NGHTTP2_ALTSVC);
|
||||
nghttp2_option_set_user_recv_extension_type(option, 111);
|
||||
|
||||
frame_pack_bufs_init(&bufs);
|
||||
|
||||
/* ALTSVC + on_invalid_frame_recv_callback + FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_invalid_frame_recv_callback =
|
||||
term_session_on_invalid_frame_recv_callback;
|
||||
|
||||
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
|
||||
|
||||
extfr.payload = &altsvc;
|
||||
nghttp2_frame_altsvc_init(&extfr, 0, NULL, 0, NULL, 0);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
nghttp2_frame_pack_altsvc(&bufs, &extfr);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* HEADERS + on_begin_frame_callback + FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_begin_frame_callback = term_session_on_begin_frame_callback;
|
||||
|
||||
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||
|
||||
nvlen = ARRLEN(reqnv);
|
||||
nghttp2_nv_array_copy(&nva, reqnv, nvlen, mem);
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
||||
NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
|
||||
nghttp2_hd_deflate_init(&deflater, mem);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
|
||||
|
||||
assert_ptrdiff(0, ==, rv);
|
||||
|
||||
nghttp2_frame_headers_free(&frame.headers, mem);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* Any frame (other than HEADERS) + on_begin_frame_callback +
|
||||
FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_begin_frame_callback = term_session_on_begin_frame_callback;
|
||||
|
||||
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||
|
||||
nghttp2_frame_rst_stream_init(&frame.rst_stream, 1, NGHTTP2_NO_ERROR);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
nghttp2_frame_pack_rst_stream(&bufs, &frame.rst_stream);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* PRIORITY_UPDATE + on_frame_recv_callback + FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_frame_recv_callback = term_session_on_frame_recv_callback;
|
||||
|
||||
nghttp2_session_server_new2(&session, &callbacks, NULL, option);
|
||||
|
||||
extfr.payload = &priority_update;
|
||||
nghttp2_frame_priority_update_init(&extfr, 1, (uint8_t *)field_value,
|
||||
sizeof(field_value) - 1);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
nghttp2_frame_pack_priority_update(&bufs, &extfr);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* ALTSVC + on_frame_recv_callback + FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_frame_recv_callback = term_session_on_frame_recv_callback;
|
||||
|
||||
nghttp2_session_client_new2(&session, &callbacks, NULL, option);
|
||||
|
||||
extfr.payload = &altsvc;
|
||||
nghttp2_frame_altsvc_init(&extfr, 0, (uint8_t *)"nghttp2.org",
|
||||
sizeof("nghttp2.org") - 1, (uint8_t *)"h2",
|
||||
sizeof("h2") - 1);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
nghttp2_frame_pack_altsvc(&bufs, &extfr);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* user-defined extension frame + on_frame_recv_callback +
|
||||
FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_frame_recv_callback = term_session_on_frame_recv_callback;
|
||||
callbacks.unpack_extension_callback = unpack_extension_callback;
|
||||
|
||||
nghttp2_session_server_new2(&session, &callbacks, &ud, option);
|
||||
|
||||
nghttp2_buf_reset(&ud.scratchbuf);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, udbuf.pos, nghttp2_buf_len(&udbuf));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_buf_len(&udbuf), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* DATA + on_data_chunk_recv_callback + FRAME_SIZE_ERROR*/
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_data_chunk_recv_callback =
|
||||
term_session_on_data_chunk_recv_callback;
|
||||
|
||||
nghttp2_session_server_new(&session, &callbacks, NULL);
|
||||
|
||||
nvlen = ARRLEN(reqnv);
|
||||
nghttp2_nv_array_copy(&nva, reqnv, nvlen, mem);
|
||||
nghttp2_frame_headers_init(&frame.headers, NGHTTP2_FLAG_END_HEADERS, 1,
|
||||
NGHTTP2_HCAT_HEADERS, NULL, nva, nvlen);
|
||||
nghttp2_hd_deflate_init(&deflater, mem);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
rv = nghttp2_frame_pack_headers(&bufs, &frame.headers, &deflater);
|
||||
|
||||
assert_ptrdiff(0, ==, rv);
|
||||
|
||||
nghttp2_frame_headers_free(&frame.headers, mem);
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_READ_HEAD, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_frame_hd_init(&hd, 10, NGHTTP2_DATA, NGHTTP2_FLAG_NONE, 1);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
nghttp2_frame_pack_frame_hd(bufs.head->buf.last, &hd);
|
||||
bufs.head->buf.last += NGHTTP2_FRAME_HDLEN;
|
||||
memset(bufs.head->buf.last, 0, 10);
|
||||
bufs.head->buf.last += 10;
|
||||
|
||||
buf = &bufs.head->buf;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_hd_deflate_free(&deflater);
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* user-defined extension frame + on_extension_chunk_recv_callback +
|
||||
FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.on_extension_chunk_recv_callback =
|
||||
term_session_on_extension_chunk_recv_callback;
|
||||
callbacks.unpack_extension_callback = unpack_extension_callback;
|
||||
|
||||
nghttp2_session_server_new2(&session, &callbacks, &ud, option);
|
||||
|
||||
nghttp2_buf_reset(&ud.scratchbuf);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, udbuf.pos, nghttp2_buf_len(&udbuf));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_buf_len(&udbuf), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* user-defined extension frame + unpack_extension_callback +
|
||||
FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
callbacks.unpack_extension_callback = term_session_unpack_extension_callback;
|
||||
|
||||
nghttp2_session_server_new2(&session, &callbacks, &ud, option);
|
||||
|
||||
nghttp2_buf_reset(&ud.scratchbuf);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, udbuf.pos, nghttp2_buf_len(&udbuf));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_buf_len(&udbuf), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
/* PRIORITY_UPDATE on stream 1 + FRAME_SIZE_ERROR */
|
||||
memset(&callbacks, 0, sizeof(callbacks));
|
||||
|
||||
nghttp2_session_server_new2(&session, &callbacks, NULL, option);
|
||||
|
||||
extfr.payload = &priority_update;
|
||||
nghttp2_frame_priority_update_init(&extfr, 1, (uint8_t *)field_value,
|
||||
sizeof(field_value) - 1);
|
||||
nghttp2_bufs_reset(&bufs);
|
||||
nghttp2_frame_pack_priority_update(&bufs, &extfr);
|
||||
buf = &bufs.head->buf;
|
||||
/* Set invalid stream ID 1 */
|
||||
buf->pos[5 + sizeof(uint32_t) - 1] = 1;
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, buf->pos, nghttp2_bufs_len(&bufs));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)nghttp2_bufs_len(&bufs), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
rv = nghttp2_session_mem_recv2(session, size_err_hd, sizeof(size_err_hd));
|
||||
|
||||
assert_ptrdiff((nghttp2_ssize)sizeof(size_err_hd), ==, rv);
|
||||
assert_enum(nghttp2_inbound_state, NGHTTP2_IB_IGN_ALL, ==,
|
||||
session->iframe.state);
|
||||
|
||||
nghttp2_session_del(session);
|
||||
|
||||
nghttp2_buf_free(&udbuf, mem);
|
||||
nghttp2_buf_free(&ud.scratchbuf, mem);
|
||||
nghttp2_bufs_free(&bufs);
|
||||
nghttp2_option_del(option);
|
||||
}
|
||||
|
||||
typedef struct check_http_opts {
|
||||
int server;
|
||||
int connect_protocol;
|
||||
|
||||
@@ -153,7 +153,6 @@ munit_void_test_decl(test_nghttp2_session_no_closed_streams)
|
||||
munit_void_test_decl(test_nghttp2_session_set_stream_user_data)
|
||||
munit_void_test_decl(test_nghttp2_session_no_rfc7540_priorities)
|
||||
munit_void_test_decl(test_nghttp2_session_stream_reset_ratelim)
|
||||
munit_void_test_decl(test_nghttp2_session_verify_iframe_state)
|
||||
munit_void_test_decl(test_nghttp2_http_mandatory_headers)
|
||||
munit_void_test_decl(test_nghttp2_http_content_length)
|
||||
munit_void_test_decl(test_nghttp2_http_content_length_mismatch)
|
||||
|
||||
Reference in New Issue
Block a user