first commit
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
# vim: sts=2 ts=8 sw=2 tw=99 et ft=python:
|
||||
import os
|
||||
|
||||
builder.SetBuildFolder('libnghttp2')
|
||||
|
||||
rvalue = {}
|
||||
for cxx in builder.targets:
|
||||
binary = Extension.StaticLibrary(builder, cxx, 'nghttp2')
|
||||
binary.compiler.includes += [
|
||||
os.path.join(builder.sourcePath, 'nghttp2', 'lib'),
|
||||
os.path.join(builder.sourcePath, 'nghttp2', 'lib', 'includes'),
|
||||
]
|
||||
binary.compiler.defines += [
|
||||
'BUILDING_NGHTTP2',
|
||||
'NGHTTP2_STATICLIB',
|
||||
]
|
||||
|
||||
if binary.compiler.target.platform == 'linux':
|
||||
binary.compiler.defines += ['HAVE_NETINET_IN_H']
|
||||
elif binary.compiler.target.platform == 'windows':
|
||||
binary.compiler.defines += ['ssize_t=int']
|
||||
|
||||
if binary.compiler.family == 'clang':
|
||||
# https://llvm.org/bugs/show_bug.cgi?id=16428
|
||||
binary.compiler.cflags += ['-Wno-attributes']
|
||||
|
||||
# Defined as NGHTTP2_SOURCES in nghttp2/lib/CMakeLists.txt
|
||||
binary.sources += [
|
||||
'nghttp2_pq.c',
|
||||
'nghttp2_map.c',
|
||||
'nghttp2_queue.c',
|
||||
'nghttp2_frame.c',
|
||||
'nghttp2_buf.c',
|
||||
'nghttp2_stream.c',
|
||||
'nghttp2_outbound_item.c',
|
||||
'nghttp2_session.c',
|
||||
'nghttp2_submit.c',
|
||||
'nghttp2_helper.c',
|
||||
'nghttp2_npn.c',
|
||||
'nghttp2_hd.c',
|
||||
'nghttp2_hd_huffman.c',
|
||||
'nghttp2_hd_huffman_data.c',
|
||||
'nghttp2_version.c',
|
||||
'nghttp2_priority_spec.c',
|
||||
'nghttp2_option.c',
|
||||
'nghttp2_callbacks.c',
|
||||
'nghttp2_mem.c',
|
||||
'nghttp2_http.c',
|
||||
'nghttp2_rcbuf.c',
|
||||
'nghttp2_debug.c',
|
||||
'nghttp2_ksl.c',
|
||||
]
|
||||
|
||||
rvalue[binary.compiler.target.arch] = builder.Add(binary)
|
||||
@@ -0,0 +1,77 @@
|
||||
add_subdirectory(includes)
|
||||
|
||||
include_directories(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/includes"
|
||||
)
|
||||
|
||||
add_definitions(-DBUILDING_NGHTTP2)
|
||||
|
||||
set(NGHTTP2_SOURCES
|
||||
nghttp2_pq.c nghttp2_map.c nghttp2_queue.c
|
||||
nghttp2_frame.c
|
||||
nghttp2_buf.c
|
||||
nghttp2_stream.c nghttp2_outbound_item.c
|
||||
nghttp2_session.c nghttp2_submit.c
|
||||
nghttp2_helper.c
|
||||
nghttp2_npn.c
|
||||
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c
|
||||
nghttp2_version.c
|
||||
nghttp2_priority_spec.c
|
||||
nghttp2_option.c
|
||||
nghttp2_callbacks.c
|
||||
nghttp2_mem.c
|
||||
nghttp2_http.c
|
||||
nghttp2_rcbuf.c
|
||||
nghttp2_debug.c
|
||||
nghttp2_ksl.c
|
||||
)
|
||||
|
||||
set(NGHTTP2_RES "")
|
||||
|
||||
if(WIN32)
|
||||
configure_file(
|
||||
version.rc.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/version.rc
|
||||
@ONLY)
|
||||
|
||||
set(NGHTTP2_RES ${CMAKE_CURRENT_BINARY_DIR}/version.rc)
|
||||
endif()
|
||||
|
||||
# Public shared library
|
||||
if(ENABLE_SHARED_LIB)
|
||||
add_library(nghttp2 SHARED ${NGHTTP2_SOURCES} ${NGHTTP2_RES})
|
||||
set_target_properties(nghttp2 PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}"
|
||||
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
|
||||
C_VISIBILITY_PRESET hidden
|
||||
)
|
||||
target_include_directories(nghttp2 INTERFACE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/includes"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/includes"
|
||||
)
|
||||
|
||||
install(TARGETS nghttp2
|
||||
ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
|
||||
RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
|
||||
endif()
|
||||
|
||||
if(HAVE_CUNIT OR ENABLE_STATIC_LIB)
|
||||
# Static library (for unittests because of symbol visibility)
|
||||
add_library(nghttp2_static STATIC ${NGHTTP2_SOURCES})
|
||||
set_target_properties(nghttp2_static PROPERTIES
|
||||
COMPILE_FLAGS "${WARNCFLAGS}"
|
||||
VERSION ${LT_VERSION} SOVERSION ${LT_SOVERSION}
|
||||
ARCHIVE_OUTPUT_NAME nghttp2${STATIC_LIB_SUFFIX}
|
||||
)
|
||||
target_compile_definitions(nghttp2_static PUBLIC "-DNGHTTP2_STATICLIB")
|
||||
if(ENABLE_STATIC_LIB)
|
||||
install(TARGETS nghttp2_static
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnghttp2.pc"
|
||||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
|
||||
@@ -0,0 +1,74 @@
|
||||
# nghttp2 - HTTP/2 C Library
|
||||
|
||||
# Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
SUBDIRS = includes
|
||||
|
||||
EXTRA_DIST = Makefile.msvc CMakeLists.txt version.rc.in
|
||||
|
||||
AM_CFLAGS = $(WARNCFLAGS) $(EXTRACFLAG)
|
||||
AM_CPPFLAGS = -I$(srcdir)/includes -I$(builddir)/includes -DBUILDING_NGHTTP2 \
|
||||
@DEFS@
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libnghttp2.pc
|
||||
DISTCLEANFILES = $(pkgconfig_DATA)
|
||||
|
||||
lib_LTLIBRARIES = libnghttp2.la
|
||||
|
||||
OBJECTS = nghttp2_pq.c nghttp2_map.c nghttp2_queue.c \
|
||||
nghttp2_frame.c \
|
||||
nghttp2_buf.c \
|
||||
nghttp2_stream.c nghttp2_outbound_item.c \
|
||||
nghttp2_session.c nghttp2_submit.c \
|
||||
nghttp2_helper.c \
|
||||
nghttp2_npn.c \
|
||||
nghttp2_hd.c nghttp2_hd_huffman.c nghttp2_hd_huffman_data.c \
|
||||
nghttp2_version.c \
|
||||
nghttp2_priority_spec.c \
|
||||
nghttp2_option.c \
|
||||
nghttp2_callbacks.c \
|
||||
nghttp2_mem.c \
|
||||
nghttp2_http.c \
|
||||
nghttp2_rcbuf.c \
|
||||
nghttp2_debug.c \
|
||||
nghttp2_ksl.c
|
||||
|
||||
HFILES = nghttp2_pq.h nghttp2_int.h nghttp2_map.h nghttp2_queue.h \
|
||||
nghttp2_frame.h \
|
||||
nghttp2_buf.h \
|
||||
nghttp2_session.h nghttp2_helper.h nghttp2_stream.h nghttp2_int.h \
|
||||
nghttp2_npn.h \
|
||||
nghttp2_submit.h nghttp2_outbound_item.h \
|
||||
nghttp2_net.h \
|
||||
nghttp2_hd.h nghttp2_hd_huffman.h \
|
||||
nghttp2_priority_spec.h \
|
||||
nghttp2_option.h \
|
||||
nghttp2_callbacks.h \
|
||||
nghttp2_mem.h \
|
||||
nghttp2_http.h \
|
||||
nghttp2_rcbuf.h \
|
||||
nghttp2_debug.h \
|
||||
nghttp2_ksl.h
|
||||
|
||||
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS)
|
||||
libnghttp2_la_LDFLAGS = -no-undefined \
|
||||
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,287 @@
|
||||
#
|
||||
# GNU Makefile for nghttp2 / MSVC.
|
||||
#
|
||||
# By G. Vanem <[email protected]> 2013
|
||||
# Updated 3/2015 by Remo Eichenberger @remoe
|
||||
# The MIT License apply.
|
||||
#
|
||||
|
||||
#
|
||||
# Choose your weapons:
|
||||
# Set 'USE_CYTHON=1' to build and install the 'nghttp2.pyd' Python extension.
|
||||
#
|
||||
THIS_MAKEFILE := $(lastword $(MAKEFILE_LIST))
|
||||
|
||||
USE_CYTHON := 0
|
||||
#USE_CYTHON := 1
|
||||
|
||||
_VERSION := $(shell grep AC_INIT ../configure.ac | cut -d'[' -f3 | sed -e 's/-DEV//g' -e 's/], //g')
|
||||
_VERSION := $(subst ., ,$(_VERSION))
|
||||
VER_MAJOR := $(word 1,$(_VERSION))
|
||||
VER_MINOR := $(word 2,$(_VERSION))
|
||||
VER_MICRO := $(word 3,$(_VERSION))
|
||||
VERSION := $(VER_MAJOR).$(VER_MINOR).$(VER_MICRO)
|
||||
VERSION_NUM := (($(VER_MAJOR) << 16) + ($(VER_MINOR) << 8) + $(VER_MICRO))
|
||||
|
||||
GENERATED := 'Generated by $(realpath Makefile.MSVC)'
|
||||
|
||||
OBJ_DIR := MSVC_obj
|
||||
#SUFFIX :=-vc90-mt-x86
|
||||
|
||||
#
|
||||
# Where to copy nghttp2.dll + lib + headers to.
|
||||
# Note: 'make install' is not in default targets. Do it explicitly.
|
||||
#
|
||||
TARGET_DIR ?= ../_VC_ROOT
|
||||
VC_ROOT := $(abspath $(TARGET_DIR))
|
||||
INSTALL_BIN := $(VC_ROOT)/bin
|
||||
INSTALL_LIB := $(VC_ROOT)/lib
|
||||
INSTALL_HDR := $(VC_ROOT)/include
|
||||
DLL_R := $(OBJ_DIR)/nghttp2$(SUFFIX).dll
|
||||
DLL_D := $(OBJ_DIR)/nghttp2d$(SUFFIX).dll
|
||||
LIB_R := $(OBJ_DIR)/nghttp2-static.lib
|
||||
LIB_D := $(OBJ_DIR)/nghttp2d-static.lib
|
||||
IMP_R := $(OBJ_DIR)/nghttp2.lib
|
||||
IMP_D := $(OBJ_DIR)/nghttp2d.lib
|
||||
|
||||
#
|
||||
# Build for DEBUG-model and RELEASE at the same time.
|
||||
#
|
||||
TARGETS := $(LIB_R) $(DLL_R) $(IMP_R) \
|
||||
$(LIB_D) $(DLL_D) $(IMP_D)
|
||||
|
||||
EXT_LIBS =
|
||||
|
||||
NGHTTP2_PDB_R := $(OBJ_DIR)/nghttp2.pdb
|
||||
NGHTTP2_PDB_D := $(OBJ_DIR)/nghttp2d.pdb
|
||||
|
||||
CC = cl
|
||||
LD := link
|
||||
AR := lib
|
||||
#CC := icl
|
||||
#LD := xilink
|
||||
#AR := xilib
|
||||
RC := rc
|
||||
CFLAGS := -I./includes -Dssize_t=long
|
||||
|
||||
CFLAGS_R := -nologo -MD -W3 -Z7 -DBUILDING_NGHTTP2
|
||||
CFLAGS_D := -nologo -MDd -W3 -Z7 -DBUILDING_NGHTTP2 \
|
||||
-Ot -D_DEBUG -GF -RTCs -RTCu # -RTCc -GS
|
||||
|
||||
LDFLAGS := -nologo -MAP -debug -incremental:no -opt:ref,icf -MANIFEST # -verbose
|
||||
|
||||
|
||||
NGHTTP2_SRC := nghttp2_pq.c \
|
||||
nghttp2_map.c \
|
||||
nghttp2_queue.c \
|
||||
nghttp2_frame.c \
|
||||
nghttp2_buf.c \
|
||||
nghttp2_stream.c \
|
||||
nghttp2_outbound_item.c \
|
||||
nghttp2_session.c \
|
||||
nghttp2_submit.c \
|
||||
nghttp2_helper.c \
|
||||
nghttp2_npn.c \
|
||||
nghttp2_hd.c \
|
||||
nghttp2_hd_huffman.c \
|
||||
nghttp2_hd_huffman_data.c \
|
||||
nghttp2_version.c \
|
||||
nghttp2_priority_spec.c \
|
||||
nghttp2_option.c \
|
||||
nghttp2_callbacks.c \
|
||||
nghttp2_mem.c \
|
||||
nghttp2_http.c \
|
||||
nghttp2_rcbuf.c \
|
||||
nghttp2_ksl.c
|
||||
|
||||
NGHTTP2_OBJ_R := $(addprefix $(OBJ_DIR)/r_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||
NGHTTP2_OBJ_D := $(addprefix $(OBJ_DIR)/d_, $(notdir $(NGHTTP2_SRC:.c=.obj)))
|
||||
|
||||
.PHONY: all intro test_ver install copy_headers_and_libs \
|
||||
install_nghttp2_pyd_0 install_nghttp2_pyd_1 \
|
||||
build_nghttp2_pyd_0 build_nghttp2_pyd_1 \
|
||||
clean_nghttp2_pyd_0 clean_nghttp2_pyd_1
|
||||
|
||||
|
||||
all: intro includes/nghttp2/nghttp2ver.h $(OBJ_DIR) $(TARGETS) build_nghttp2_pyd_$(USE_CYTHON)
|
||||
@echo 'Welcome to NgHTTP2 (release + debug).'
|
||||
@echo 'Do a "make -f Makefile.MSVC install" at own risk!'
|
||||
|
||||
intro:
|
||||
@echo 'Building NgHTTP (MSVC) ver. "$(VERSION)".'
|
||||
|
||||
test_ver:
|
||||
@echo '$$(VERSION): "$(VERSION)".'
|
||||
@echo '$$(_VERSION): "$(_VERSION)".'
|
||||
@echo '$$(VER_MAJOR): "$(VER_MAJOR)".'
|
||||
@echo '$$(VER_MINOR): "$(VER_MINOR)".'
|
||||
@echo '$$(VER_MICRO): "$(VER_MICRO)".'
|
||||
|
||||
$(OBJ_DIR):
|
||||
- mkdir $(OBJ_DIR)
|
||||
|
||||
install: includes/nghttp2/nghttp2.h includes/nghttp2/nghttp2ver.h \
|
||||
$(TARGETS) \
|
||||
copy_headers_and_libs install_nghttp2_pyd_$(USE_CYTHON)
|
||||
|
||||
#
|
||||
# This MUST be done before using the 'install_nghttp2_pyd_1' rule.
|
||||
#
|
||||
copy_headers_and_libs:
|
||||
- mkdir -p $(INSTALL_HDR)/nghttp2 $(INSTALL_BIN) $(INSTALL_LIB)
|
||||
cp --update $(addprefix includes/nghttp2/, nghttp2.h nghttp2ver.h) $(INSTALL_HDR)/nghttp2
|
||||
cp --update $(DLL_R) $(DLL_D) $(NGHTTP2_PDB_R) $(NGHTTP2_PDB_D) $(INSTALL_BIN)
|
||||
cp --update $(IMP_R) $(IMP_D) $(LIB_R) $(LIB_D) $(INSTALL_LIB)
|
||||
@echo
|
||||
|
||||
$(LIB_R): $(NGHTTP2_OBJ_R)
|
||||
$(AR) -nologo -out:$@ $^
|
||||
@echo
|
||||
|
||||
$(LIB_D): $(NGHTTP2_OBJ_D)
|
||||
$(AR) -nologo -out:$@ $^
|
||||
@echo
|
||||
|
||||
|
||||
$(IMP_R): $(DLL_R)
|
||||
|
||||
$(DLL_R): $(NGHTTP2_OBJ_R) $(OBJ_DIR)/r_nghttp2.res
|
||||
$(LD) $(LDFLAGS) -dll -out:$@ -implib:$(IMP_R) $(NGHTTP2_OBJ_R) -PDB:$(NGHTTP2_PDB_R) $(OBJ_DIR)/r_nghttp2.res $(EXT_LIBS)
|
||||
mt -nologo -manifest $@.manifest -outputresource:$@\;2
|
||||
@echo
|
||||
|
||||
$(IMP_D): $(DLL_D)
|
||||
|
||||
$(DLL_D): $(NGHTTP2_OBJ_D) $(OBJ_DIR)/d_nghttp2.res
|
||||
$(LD) $(LDFLAGS) -dll -out:$@ -implib:$(IMP_D) $(NGHTTP2_OBJ_D) -PDB:$(NGHTTP2_PDB_D) $(OBJ_DIR)/d_nghttp2.res $(EXT_LIBS)
|
||||
mt -nologo -manifest $@.manifest -outputresource:$@\;2
|
||||
@echo
|
||||
|
||||
|
||||
WIN_OBJDIR:=$(shell cygpath -w $(abspath $(OBJ_DIR)))
|
||||
WIN_OBJDIR:=$(subst \,/,$(WIN_OBJDIR))
|
||||
|
||||
../python/setup.py: ../python/setup.py.in $(THIS_MAKEFILE)
|
||||
cd ../python ; \
|
||||
echo '# $(GENERATED). DO NOT EDIT.' > setup.py ; \
|
||||
sed -e 's/@top_srcdir@/../' \
|
||||
-e 's%@top_builddir@%$(WIN_OBJDIR)%' \
|
||||
-e 's/@PACKAGE_VERSION@/$(VERSION)/' setup.py.in >> setup.py ;
|
||||
|
||||
build_nghttp2_pyd_0: ;
|
||||
|
||||
build_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx)
|
||||
cd ../python ; \
|
||||
python setup.py build_ext -i -f bdist_wininst
|
||||
|
||||
install_nghttp2_pyd_0: ;
|
||||
|
||||
install_nghttp2_pyd_1: $(addprefix ../python/, setup.py nghttp2.pyx)
|
||||
cd ../python ; \
|
||||
pip install .
|
||||
|
||||
clean_nghttp2_pyd_0: ;
|
||||
|
||||
clean_nghttp2_pyd_1:
|
||||
cd ../python ; \
|
||||
rm -fR build dist
|
||||
|
||||
$(OBJ_DIR)/r_%.obj: %.c $(THIS_MAKEFILE)
|
||||
$(CC) $(CFLAGS_R) $(CFLAGS) -Fo$@ -c $<
|
||||
@echo
|
||||
|
||||
$(OBJ_DIR)/d_%.obj: %.c $(THIS_MAKEFILE)
|
||||
$(CC) $(CFLAGS_D) $(CFLAGS) -Fo$@ -c $<
|
||||
@echo
|
||||
|
||||
$(OBJ_DIR)/r_nghttp2.res: $(OBJ_DIR)/nghttp2.rc $(THIS_MAKEFILE)
|
||||
$(RC) -D_RELEASE -Fo $@ $<
|
||||
@echo
|
||||
|
||||
$(OBJ_DIR)/d_nghttp2.res: $(OBJ_DIR)/nghttp2.rc $(THIS_MAKEFILE)
|
||||
$(RC) -D_DEBUG -Fo $@ $<
|
||||
@echo
|
||||
|
||||
includes/nghttp2/nghttp2ver.h: includes/nghttp2/nghttp2ver.h.in $(THIS_MAKEFILE)
|
||||
sed < includes/nghttp2/nghttp2ver.h.in \
|
||||
-e 's/@PACKAGE_VERSION@/$(VERSION)/g' \
|
||||
-e 's/@PACKAGE_VERSION_NUM@/$(VERSION_NUM)/g' > $@
|
||||
touch --reference=includes/nghttp2/nghttp2ver.h.in $@
|
||||
|
||||
|
||||
define RES_FILE
|
||||
#include <winver.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0
|
||||
PRODUCTVERSION $(VER_MAJOR), $(VER_MINOR), $(VER_MICRO), 0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
#ifdef _DEBUG
|
||||
#define VER_STR "$(VERSION).0 (MSVC debug)"
|
||||
#define DBG "d"
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
#define VER_STR "$(VERSION).0 (MSVC release)"
|
||||
#define DBG ""
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "http://tatsuhiro-t.github.io/nghttp2/"
|
||||
VALUE "FileDescription", "nghttp2; HTTP/2 C library"
|
||||
VALUE "FileVersion", VER_STR
|
||||
VALUE "InternalName", "nghttp2" DBG
|
||||
VALUE "LegalCopyright", "The MIT License"
|
||||
VALUE "LegalTrademarks", ""
|
||||
VALUE "OriginalFilename", "nghttp2" DBG ".dll"
|
||||
VALUE "ProductName", "NGHTTP2."
|
||||
VALUE "ProductVersion", VER_STR
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
endef
|
||||
|
||||
export RES_FILE
|
||||
|
||||
$(OBJ_DIR)/nghttp2.rc: Makefile.MSVC
|
||||
@echo 'Generating $@...'
|
||||
@echo ' /* $(GENERATED). DO NOT EDIT.' > $@
|
||||
@echo ' */' >> $@
|
||||
@echo "$$RES_FILE" >> $@
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ_DIR)/* includes/nghttp2/nghttp2ver.h
|
||||
@echo
|
||||
|
||||
vclean realclean: clean clean_nghttp2_pyd_$(USE_CYTHON)
|
||||
- rm -rf $(OBJ_DIR)
|
||||
- rm -f .depend.MSVC
|
||||
|
||||
#
|
||||
# Use gcc to generated the dependencies. No MSVC specific args please!
|
||||
#
|
||||
REPLACE_R = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/r_\1.obj: /'
|
||||
REPLACE_D = 's/\(.*\)\.o: /\n$$(OBJ_DIR)\/d_\1.obj: /'
|
||||
|
||||
depend: includes/nghttp2/nghttp2ver.h
|
||||
@echo '# $(GENERATED). DO NOT EDIT.' > .depend.MSVC
|
||||
gcc -MM $(CFLAGS) $(NGHTTP2_SRC) >> .depend.tmp
|
||||
@echo '#' >> .depend.MSVC
|
||||
@echo '# Release lib objects:' >> .depend.MSVC
|
||||
sed -e $(REPLACE_R) .depend.tmp >> .depend.MSVC
|
||||
@echo '#' >> .depend.MSVC
|
||||
@echo '# Debug lib objects:' >> .depend.MSVC
|
||||
sed -e $(REPLACE_D) .depend.tmp >> .depend.MSVC
|
||||
rm -f .depend.tmp
|
||||
|
||||
-include .depend.MSVC
|
||||
@@ -0,0 +1,4 @@
|
||||
install(FILES
|
||||
nghttp2/nghttp2.h
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/nghttp2/nghttp2ver.h"
|
||||
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/nghttp2")
|
||||
@@ -0,0 +1,26 @@
|
||||
# nghttp2 - HTTP/2 C Library
|
||||
|
||||
# Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
EXTRA_DIST = CMakeLists.txt
|
||||
|
||||
nobase_include_HEADERS = nghttp2/nghttp2.h nghttp2/nghttp2ver.h
|
||||
@@ -0,0 +1,658 @@
|
||||
# Makefile.in generated by automake 1.16.3 from Makefile.am.
|
||||
# @configure_input@
|
||||
|
||||
# Copyright (C) 1994-2020 Free Software Foundation, Inc.
|
||||
|
||||
# This Makefile.in is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
@SET_MAKE@
|
||||
|
||||
# nghttp2 - HTTP/2 C Library
|
||||
|
||||
# Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
VPATH = @srcdir@
|
||||
am__is_gnu_make = { \
|
||||
if test -z '$(MAKELEVEL)'; then \
|
||||
false; \
|
||||
elif test -n '$(MAKE_HOST)'; then \
|
||||
true; \
|
||||
elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
|
||||
true; \
|
||||
else \
|
||||
false; \
|
||||
fi; \
|
||||
}
|
||||
am__make_running_with_option = \
|
||||
case $${target_option-} in \
|
||||
?) ;; \
|
||||
*) echo "am__make_running_with_option: internal error: invalid" \
|
||||
"target option '$${target_option-}' specified" >&2; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
has_opt=no; \
|
||||
sane_makeflags=$$MAKEFLAGS; \
|
||||
if $(am__is_gnu_make); then \
|
||||
sane_makeflags=$$MFLAGS; \
|
||||
else \
|
||||
case $$MAKEFLAGS in \
|
||||
*\\[\ \ ]*) \
|
||||
bs=\\; \
|
||||
sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
|
||||
| sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
|
||||
esac; \
|
||||
fi; \
|
||||
skip_next=no; \
|
||||
strip_trailopt () \
|
||||
{ \
|
||||
flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
|
||||
}; \
|
||||
for flg in $$sane_makeflags; do \
|
||||
test $$skip_next = yes && { skip_next=no; continue; }; \
|
||||
case $$flg in \
|
||||
*=*|--*) continue;; \
|
||||
-*I) strip_trailopt 'I'; skip_next=yes;; \
|
||||
-*I?*) strip_trailopt 'I';; \
|
||||
-*O) strip_trailopt 'O'; skip_next=yes;; \
|
||||
-*O?*) strip_trailopt 'O';; \
|
||||
-*l) strip_trailopt 'l'; skip_next=yes;; \
|
||||
-*l?*) strip_trailopt 'l';; \
|
||||
-[dEDm]) skip_next=yes;; \
|
||||
-[JT]) skip_next=yes;; \
|
||||
esac; \
|
||||
case $$flg in \
|
||||
*$$target_option*) has_opt=yes; break;; \
|
||||
esac; \
|
||||
done; \
|
||||
test $$has_opt = yes
|
||||
am__make_dryrun = (target_option=n; $(am__make_running_with_option))
|
||||
am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
|
||||
pkgdatadir = $(datadir)/@PACKAGE@
|
||||
pkgincludedir = $(includedir)/@PACKAGE@
|
||||
pkglibdir = $(libdir)/@PACKAGE@
|
||||
pkglibexecdir = $(libexecdir)/@PACKAGE@
|
||||
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
|
||||
install_sh_DATA = $(install_sh) -c -m 644
|
||||
install_sh_PROGRAM = $(install_sh) -c
|
||||
install_sh_SCRIPT = $(install_sh) -c
|
||||
INSTALL_HEADER = $(INSTALL_DATA)
|
||||
transform = $(program_transform_name)
|
||||
NORMAL_INSTALL = :
|
||||
PRE_INSTALL = :
|
||||
POST_INSTALL = :
|
||||
NORMAL_UNINSTALL = :
|
||||
PRE_UNINSTALL = :
|
||||
POST_UNINSTALL = :
|
||||
build_triplet = @build@
|
||||
host_triplet = @host@
|
||||
target_triplet = @target@
|
||||
subdir = lib/includes
|
||||
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
|
||||
am__aclocal_m4_deps = $(top_srcdir)/m4/ax_boost_asio.m4 \
|
||||
$(top_srcdir)/m4/ax_boost_base.m4 \
|
||||
$(top_srcdir)/m4/ax_boost_system.m4 \
|
||||
$(top_srcdir)/m4/ax_boost_thread.m4 \
|
||||
$(top_srcdir)/m4/ax_check_compile_flag.m4 \
|
||||
$(top_srcdir)/m4/ax_cxx_compile_stdcxx.m4 \
|
||||
$(top_srcdir)/m4/ax_python_devel.m4 \
|
||||
$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
|
||||
$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
|
||||
$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
|
||||
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
|
||||
$(ACLOCAL_M4)
|
||||
DIST_COMMON = $(srcdir)/Makefile.am $(nobase_include_HEADERS) \
|
||||
$(am__DIST_COMMON)
|
||||
mkinstalldirs = $(install_sh) -d
|
||||
CONFIG_HEADER = $(top_builddir)/config.h
|
||||
CONFIG_CLEAN_FILES =
|
||||
CONFIG_CLEAN_VPATH_FILES =
|
||||
AM_V_P = $(am__v_P_@AM_V@)
|
||||
am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
|
||||
am__v_P_0 = false
|
||||
am__v_P_1 = :
|
||||
AM_V_GEN = $(am__v_GEN_@AM_V@)
|
||||
am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
|
||||
am__v_GEN_0 = @echo " GEN " $@;
|
||||
am__v_GEN_1 =
|
||||
AM_V_at = $(am__v_at_@AM_V@)
|
||||
am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
|
||||
am__v_at_0 = @
|
||||
am__v_at_1 =
|
||||
SOURCES =
|
||||
DIST_SOURCES =
|
||||
am__can_run_installinfo = \
|
||||
case $$AM_UPDATE_INFO_DIR in \
|
||||
n|no|NO) false;; \
|
||||
*) (install-info --version) >/dev/null 2>&1;; \
|
||||
esac
|
||||
am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
|
||||
am__vpath_adj = case $$p in \
|
||||
$(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
|
||||
*) f=$$p;; \
|
||||
esac;
|
||||
am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
|
||||
am__install_max = 40
|
||||
am__nobase_strip_setup = \
|
||||
srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
|
||||
am__nobase_strip = \
|
||||
for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
|
||||
am__nobase_list = $(am__nobase_strip_setup); \
|
||||
for p in $$list; do echo "$$p $$p"; done | \
|
||||
sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
|
||||
$(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
|
||||
if (++n[$$2] == $(am__install_max)) \
|
||||
{ print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
|
||||
END { for (dir in files) print dir, files[dir] }'
|
||||
am__base_list = \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
|
||||
sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
|
||||
am__uninstall_files_from_dir = { \
|
||||
test -z "$$files" \
|
||||
|| { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
|
||||
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
|
||||
$(am__cd) "$$dir" && rm -f $$files; }; \
|
||||
}
|
||||
am__installdirs = "$(DESTDIR)$(includedir)"
|
||||
HEADERS = $(nobase_include_HEADERS)
|
||||
am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
|
||||
# Read a list of newline-separated strings from the standard input,
|
||||
# and print each of them once, without duplicates. Input order is
|
||||
# *not* preserved.
|
||||
am__uniquify_input = $(AWK) '\
|
||||
BEGIN { nonempty = 0; } \
|
||||
{ items[$$0] = 1; nonempty = 1; } \
|
||||
END { if (nonempty) { for (i in items) print i; }; } \
|
||||
'
|
||||
# Make sure the list of sources is unique. This is necessary because,
|
||||
# e.g., the same source file might be shared among _SOURCES variables
|
||||
# for different programs/libraries.
|
||||
am__define_uniq_tagged_files = \
|
||||
list='$(am__tagged_files)'; \
|
||||
unique=`for i in $$list; do \
|
||||
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
|
||||
done | $(am__uniquify_input)`
|
||||
ETAGS = etags
|
||||
CTAGS = ctags
|
||||
am__DIST_COMMON = $(srcdir)/Makefile.in
|
||||
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
|
||||
ACLOCAL = @ACLOCAL@
|
||||
AMTAR = @AMTAR@
|
||||
AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
|
||||
APPLDFLAGS = @APPLDFLAGS@
|
||||
AR = @AR@
|
||||
AUTOCONF = @AUTOCONF@
|
||||
AUTOHEADER = @AUTOHEADER@
|
||||
AUTOMAKE = @AUTOMAKE@
|
||||
AWK = @AWK@
|
||||
BOOST_ASIO_LIB = @BOOST_ASIO_LIB@
|
||||
BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
|
||||
BOOST_LDFLAGS = @BOOST_LDFLAGS@
|
||||
BOOST_SYSTEM_LIB = @BOOST_SYSTEM_LIB@
|
||||
BOOST_THREAD_LIB = @BOOST_THREAD_LIB@
|
||||
CC = @CC@
|
||||
CCDEPMODE = @CCDEPMODE@
|
||||
CFLAGS = @CFLAGS@
|
||||
CPP = @CPP@
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
CUNIT_CFLAGS = @CUNIT_CFLAGS@
|
||||
CUNIT_LIBS = @CUNIT_LIBS@
|
||||
CXX = @CXX@
|
||||
CXX1XCXXFLAGS = @CXX1XCXXFLAGS@
|
||||
CXXCPP = @CXXCPP@
|
||||
CXXDEPMODE = @CXXDEPMODE@
|
||||
CXXFLAGS = @CXXFLAGS@
|
||||
CYGPATH_W = @CYGPATH_W@
|
||||
CYTHON = @CYTHON@
|
||||
DEFS = @DEFS@
|
||||
DEPDIR = @DEPDIR@
|
||||
DLLTOOL = @DLLTOOL@
|
||||
DSYMUTIL = @DSYMUTIL@
|
||||
DUMPBIN = @DUMPBIN@
|
||||
ECHO_C = @ECHO_C@
|
||||
ECHO_N = @ECHO_N@
|
||||
ECHO_T = @ECHO_T@
|
||||
EGREP = @EGREP@
|
||||
EXEEXT = @EXEEXT@
|
||||
EXTRACFLAG = @EXTRACFLAG@
|
||||
FGREP = @FGREP@
|
||||
GREP = @GREP@
|
||||
HAVE_CXX14 = @HAVE_CXX14@
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_SCRIPT = @INSTALL_SCRIPT@
|
||||
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
|
||||
JANSSON_CFLAGS = @JANSSON_CFLAGS@
|
||||
JANSSON_LIBS = @JANSSON_LIBS@
|
||||
JEMALLOC_LIBS = @JEMALLOC_LIBS@
|
||||
LD = @LD@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
LIBCARES_CFLAGS = @LIBCARES_CFLAGS@
|
||||
LIBCARES_LIBS = @LIBCARES_LIBS@
|
||||
LIBEVENT_OPENSSL_CFLAGS = @LIBEVENT_OPENSSL_CFLAGS@
|
||||
LIBEVENT_OPENSSL_LIBS = @LIBEVENT_OPENSSL_LIBS@
|
||||
LIBEV_CFLAGS = @LIBEV_CFLAGS@
|
||||
LIBEV_LIBS = @LIBEV_LIBS@
|
||||
LIBMRUBY_CFLAGS = @LIBMRUBY_CFLAGS@
|
||||
LIBMRUBY_LIBS = @LIBMRUBY_LIBS@
|
||||
LIBOBJS = @LIBOBJS@
|
||||
LIBS = @LIBS@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
LIBXML2_CFLAGS = @LIBXML2_CFLAGS@
|
||||
LIBXML2_LIBS = @LIBXML2_LIBS@
|
||||
LIPO = @LIPO@
|
||||
LN_S = @LN_S@
|
||||
LTLIBOBJS = @LTLIBOBJS@
|
||||
LT_AGE = @LT_AGE@
|
||||
LT_CURRENT = @LT_CURRENT@
|
||||
LT_REVISION = @LT_REVISION@
|
||||
LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
|
||||
MAKEINFO = @MAKEINFO@
|
||||
MANIFEST_TOOL = @MANIFEST_TOOL@
|
||||
MKDIR_P = @MKDIR_P@
|
||||
NM = @NM@
|
||||
NMEDIT = @NMEDIT@
|
||||
OBJDUMP = @OBJDUMP@
|
||||
OBJEXT = @OBJEXT@
|
||||
OPENSSL_CFLAGS = @OPENSSL_CFLAGS@
|
||||
OPENSSL_LIBS = @OPENSSL_LIBS@
|
||||
OTOOL = @OTOOL@
|
||||
OTOOL64 = @OTOOL64@
|
||||
PACKAGE = @PACKAGE@
|
||||
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
|
||||
PACKAGE_NAME = @PACKAGE_NAME@
|
||||
PACKAGE_STRING = @PACKAGE_STRING@
|
||||
PACKAGE_TARNAME = @PACKAGE_TARNAME@
|
||||
PACKAGE_URL = @PACKAGE_URL@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
PACKAGE_VERSION_NUM = @PACKAGE_VERSION_NUM@
|
||||
PATH_SEPARATOR = @PATH_SEPARATOR@
|
||||
PKG_CONFIG = @PKG_CONFIG@
|
||||
PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
|
||||
PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
|
||||
PYTHON = @PYTHON@
|
||||
PYTHON_CPPFLAGS = @PYTHON_CPPFLAGS@
|
||||
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
|
||||
PYTHON_EXTRA_LDFLAGS = @PYTHON_EXTRA_LDFLAGS@
|
||||
PYTHON_EXTRA_LIBS = @PYTHON_EXTRA_LIBS@
|
||||
PYTHON_LIBS = @PYTHON_LIBS@
|
||||
PYTHON_PLATFORM = @PYTHON_PLATFORM@
|
||||
PYTHON_PREFIX = @PYTHON_PREFIX@
|
||||
PYTHON_SITE_PKG = @PYTHON_SITE_PKG@
|
||||
PYTHON_VERSION = @PYTHON_VERSION@
|
||||
RANLIB = @RANLIB@
|
||||
SED = @SED@
|
||||
SET_MAKE = @SET_MAKE@
|
||||
SHELL = @SHELL@
|
||||
STRIP = @STRIP@
|
||||
SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
|
||||
SYSTEMD_LIBS = @SYSTEMD_LIBS@
|
||||
TESTLDADD = @TESTLDADD@
|
||||
VERSION = @VERSION@
|
||||
WARNCFLAGS = @WARNCFLAGS@
|
||||
WARNCXXFLAGS = @WARNCXXFLAGS@
|
||||
ZLIB_CFLAGS = @ZLIB_CFLAGS@
|
||||
ZLIB_LIBS = @ZLIB_LIBS@
|
||||
abs_builddir = @abs_builddir@
|
||||
abs_srcdir = @abs_srcdir@
|
||||
abs_top_builddir = @abs_top_builddir@
|
||||
abs_top_srcdir = @abs_top_srcdir@
|
||||
ac_ct_AR = @ac_ct_AR@
|
||||
ac_ct_CC = @ac_ct_CC@
|
||||
ac_ct_CXX = @ac_ct_CXX@
|
||||
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
|
||||
am__include = @am__include@
|
||||
am__leading_dot = @am__leading_dot@
|
||||
am__quote = @am__quote@
|
||||
am__tar = @am__tar@
|
||||
am__untar = @am__untar@
|
||||
bindir = @bindir@
|
||||
build = @build@
|
||||
build_alias = @build_alias@
|
||||
build_cpu = @build_cpu@
|
||||
build_os = @build_os@
|
||||
build_vendor = @build_vendor@
|
||||
builddir = @builddir@
|
||||
datadir = @datadir@
|
||||
datarootdir = @datarootdir@
|
||||
docdir = @docdir@
|
||||
dvidir = @dvidir@
|
||||
exec_prefix = @exec_prefix@
|
||||
host = @host@
|
||||
host_alias = @host_alias@
|
||||
host_cpu = @host_cpu@
|
||||
host_os = @host_os@
|
||||
host_vendor = @host_vendor@
|
||||
htmldir = @htmldir@
|
||||
includedir = @includedir@
|
||||
infodir = @infodir@
|
||||
install_sh = @install_sh@
|
||||
libdir = @libdir@
|
||||
libexecdir = @libexecdir@
|
||||
localedir = @localedir@
|
||||
localstatedir = @localstatedir@
|
||||
mandir = @mandir@
|
||||
mkdir_p = @mkdir_p@
|
||||
oldincludedir = @oldincludedir@
|
||||
pdfdir = @pdfdir@
|
||||
pkgpyexecdir = @pkgpyexecdir@
|
||||
pkgpythondir = @pkgpythondir@
|
||||
prefix = @prefix@
|
||||
program_transform_name = @program_transform_name@
|
||||
psdir = @psdir@
|
||||
pyexecdir = @pyexecdir@
|
||||
pythondir = @pythondir@
|
||||
runstatedir = @runstatedir@
|
||||
sbindir = @sbindir@
|
||||
sharedstatedir = @sharedstatedir@
|
||||
srcdir = @srcdir@
|
||||
sysconfdir = @sysconfdir@
|
||||
target = @target@
|
||||
target_alias = @target_alias@
|
||||
target_cpu = @target_cpu@
|
||||
target_os = @target_os@
|
||||
target_vendor = @target_vendor@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
EXTRA_DIST = CMakeLists.txt
|
||||
nobase_include_HEADERS = nghttp2/nghttp2.h nghttp2/nghttp2ver.h
|
||||
all: all-am
|
||||
|
||||
.SUFFIXES:
|
||||
$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
|
||||
@for dep in $?; do \
|
||||
case '$(am__configure_deps)' in \
|
||||
*$$dep*) \
|
||||
( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
|
||||
&& { if test -f $@; then exit 0; else break; fi; }; \
|
||||
exit 1;; \
|
||||
esac; \
|
||||
done; \
|
||||
echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/includes/Makefile'; \
|
||||
$(am__cd) $(top_srcdir) && \
|
||||
$(AUTOMAKE) --gnu lib/includes/Makefile
|
||||
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
|
||||
@case '$?' in \
|
||||
*config.status*) \
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
|
||||
*) \
|
||||
echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
|
||||
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
|
||||
esac;
|
||||
|
||||
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
|
||||
$(top_srcdir)/configure: $(am__configure_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(ACLOCAL_M4): $(am__aclocal_m4_deps)
|
||||
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
|
||||
$(am__aclocal_m4_deps):
|
||||
|
||||
mostlyclean-libtool:
|
||||
-rm -f *.lo
|
||||
|
||||
clean-libtool:
|
||||
-rm -rf .libs _libs
|
||||
install-nobase_includeHEADERS: $(nobase_include_HEADERS)
|
||||
@$(NORMAL_INSTALL)
|
||||
@list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \
|
||||
if test -n "$$list"; then \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
|
||||
fi; \
|
||||
$(am__nobase_list) | while read dir files; do \
|
||||
xfiles=; for file in $$files; do \
|
||||
if test -f "$$file"; then xfiles="$$xfiles $$file"; \
|
||||
else xfiles="$$xfiles $(srcdir)/$$file"; fi; done; \
|
||||
test -z "$$xfiles" || { \
|
||||
test "x$$dir" = x. || { \
|
||||
echo " $(MKDIR_P) '$(DESTDIR)$(includedir)/$$dir'"; \
|
||||
$(MKDIR_P) "$(DESTDIR)$(includedir)/$$dir"; }; \
|
||||
echo " $(INSTALL_HEADER) $$xfiles '$(DESTDIR)$(includedir)/$$dir'"; \
|
||||
$(INSTALL_HEADER) $$xfiles "$(DESTDIR)$(includedir)/$$dir" || exit $$?; }; \
|
||||
done
|
||||
|
||||
uninstall-nobase_includeHEADERS:
|
||||
@$(NORMAL_UNINSTALL)
|
||||
@list='$(nobase_include_HEADERS)'; test -n "$(includedir)" || list=; \
|
||||
$(am__nobase_strip_setup); files=`$(am__nobase_strip)`; \
|
||||
dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir)
|
||||
|
||||
ID: $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); mkid -fID $$unique
|
||||
tags: tags-am
|
||||
TAGS: tags
|
||||
|
||||
tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
set x; \
|
||||
here=`pwd`; \
|
||||
$(am__define_uniq_tagged_files); \
|
||||
shift; \
|
||||
if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
|
||||
test -n "$$unique" || unique=$$empty_fix; \
|
||||
if test $$# -gt 0; then \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
"$$@" $$unique; \
|
||||
else \
|
||||
$(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
|
||||
$$unique; \
|
||||
fi; \
|
||||
fi
|
||||
ctags: ctags-am
|
||||
|
||||
CTAGS: ctags
|
||||
ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
|
||||
$(am__define_uniq_tagged_files); \
|
||||
test -z "$(CTAGS_ARGS)$$unique" \
|
||||
|| $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
|
||||
$$unique
|
||||
|
||||
GTAGS:
|
||||
here=`$(am__cd) $(top_builddir) && pwd` \
|
||||
&& $(am__cd) $(top_srcdir) \
|
||||
&& gtags -i $(GTAGS_ARGS) "$$here"
|
||||
cscopelist: cscopelist-am
|
||||
|
||||
cscopelist-am: $(am__tagged_files)
|
||||
list='$(am__tagged_files)'; \
|
||||
case "$(srcdir)" in \
|
||||
[\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
|
||||
*) sdir=$(subdir)/$(srcdir) ;; \
|
||||
esac; \
|
||||
for i in $$list; do \
|
||||
if test -f "$$i"; then \
|
||||
echo "$(subdir)/$$i"; \
|
||||
else \
|
||||
echo "$$sdir/$$i"; \
|
||||
fi; \
|
||||
done >> $(top_builddir)/cscope.files
|
||||
|
||||
distclean-tags:
|
||||
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
|
||||
|
||||
distdir: $(BUILT_SOURCES)
|
||||
$(MAKE) $(AM_MAKEFLAGS) distdir-am
|
||||
|
||||
distdir-am: $(DISTFILES)
|
||||
@srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
|
||||
list='$(DISTFILES)'; \
|
||||
dist_files=`for file in $$list; do echo $$file; done | \
|
||||
sed -e "s|^$$srcdirstrip/||;t" \
|
||||
-e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
|
||||
case $$dist_files in \
|
||||
*/*) $(MKDIR_P) `echo "$$dist_files" | \
|
||||
sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
|
||||
sort -u` ;; \
|
||||
esac; \
|
||||
for file in $$dist_files; do \
|
||||
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
|
||||
if test -d $$d/$$file; then \
|
||||
dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
|
||||
if test -d "$(distdir)/$$file"; then \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
|
||||
cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
|
||||
find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
|
||||
fi; \
|
||||
cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
|
||||
else \
|
||||
test -f "$(distdir)/$$file" \
|
||||
|| cp -p $$d/$$file "$(distdir)/$$file" \
|
||||
|| exit 1; \
|
||||
fi; \
|
||||
done
|
||||
check-am: all-am
|
||||
check: check-am
|
||||
all-am: Makefile $(HEADERS)
|
||||
installdirs:
|
||||
for dir in "$(DESTDIR)$(includedir)"; do \
|
||||
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
|
||||
done
|
||||
install: install-am
|
||||
install-exec: install-exec-am
|
||||
install-data: install-data-am
|
||||
uninstall: uninstall-am
|
||||
|
||||
install-am: all-am
|
||||
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
|
||||
|
||||
installcheck: installcheck-am
|
||||
install-strip:
|
||||
if test -z '$(STRIP)'; then \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
install; \
|
||||
else \
|
||||
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
|
||||
install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
|
||||
"INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
|
||||
fi
|
||||
mostlyclean-generic:
|
||||
|
||||
clean-generic:
|
||||
|
||||
distclean-generic:
|
||||
-test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
|
||||
-test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
|
||||
|
||||
maintainer-clean-generic:
|
||||
@echo "This command is intended for maintainers to use"
|
||||
@echo "it deletes files that may require special tools to rebuild."
|
||||
clean: clean-am
|
||||
|
||||
clean-am: clean-generic clean-libtool mostlyclean-am
|
||||
|
||||
distclean: distclean-am
|
||||
-rm -f Makefile
|
||||
distclean-am: clean-am distclean-generic distclean-tags
|
||||
|
||||
dvi: dvi-am
|
||||
|
||||
dvi-am:
|
||||
|
||||
html: html-am
|
||||
|
||||
html-am:
|
||||
|
||||
info: info-am
|
||||
|
||||
info-am:
|
||||
|
||||
install-data-am: install-nobase_includeHEADERS
|
||||
|
||||
install-dvi: install-dvi-am
|
||||
|
||||
install-dvi-am:
|
||||
|
||||
install-exec-am:
|
||||
|
||||
install-html: install-html-am
|
||||
|
||||
install-html-am:
|
||||
|
||||
install-info: install-info-am
|
||||
|
||||
install-info-am:
|
||||
|
||||
install-man:
|
||||
|
||||
install-pdf: install-pdf-am
|
||||
|
||||
install-pdf-am:
|
||||
|
||||
install-ps: install-ps-am
|
||||
|
||||
install-ps-am:
|
||||
|
||||
installcheck-am:
|
||||
|
||||
maintainer-clean: maintainer-clean-am
|
||||
-rm -f Makefile
|
||||
maintainer-clean-am: distclean-am maintainer-clean-generic
|
||||
|
||||
mostlyclean: mostlyclean-am
|
||||
|
||||
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
|
||||
|
||||
pdf: pdf-am
|
||||
|
||||
pdf-am:
|
||||
|
||||
ps: ps-am
|
||||
|
||||
ps-am:
|
||||
|
||||
uninstall-am: uninstall-nobase_includeHEADERS
|
||||
|
||||
.MAKE: install-am install-strip
|
||||
|
||||
.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
|
||||
clean-libtool cscopelist-am ctags ctags-am distclean \
|
||||
distclean-generic distclean-libtool distclean-tags distdir dvi \
|
||||
dvi-am html html-am info info-am install install-am \
|
||||
install-data install-data-am install-dvi install-dvi-am \
|
||||
install-exec install-exec-am install-html install-html-am \
|
||||
install-info install-info-am install-man \
|
||||
install-nobase_includeHEADERS install-pdf install-pdf-am \
|
||||
install-ps install-ps-am install-strip installcheck \
|
||||
installcheck-am installdirs maintainer-clean \
|
||||
maintainer-clean-generic mostlyclean mostlyclean-generic \
|
||||
mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
|
||||
uninstall-am uninstall-nobase_includeHEADERS
|
||||
|
||||
.PRECIOUS: Makefile
|
||||
|
||||
|
||||
# Tell versions [3.59,3.63) of GNU make to not export all variables.
|
||||
# Otherwise a system limit (for SysV at least) may be exceeded.
|
||||
.NOEXPORT:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2VER_H
|
||||
#define NGHTTP2VER_H
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Version number of the nghttp2 library release
|
||||
*/
|
||||
#define NGHTTP2_VERSION "1.43.0"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Numerical representation of the version number of the nghttp2 library
|
||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||
*/
|
||||
#define NGHTTP2_VERSION_NUM 0x012b00
|
||||
|
||||
#endif /* NGHTTP2VER_H */
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2VER_H
|
||||
#define NGHTTP2VER_H
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Version number of the nghttp2 library release
|
||||
*/
|
||||
#define NGHTTP2_VERSION "@PACKAGE_VERSION@"
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Numerical representation of the version number of the nghttp2 library
|
||||
* release. This is a 24 bit number with 8 bits for major number, 8 bits
|
||||
* for minor and 8 bits for patch. Version 1.2.3 becomes 0x010203.
|
||||
*/
|
||||
#define NGHTTP2_VERSION_NUM @PACKAGE_VERSION_NUM@
|
||||
|
||||
#endif /* NGHTTP2VER_H */
|
||||
@@ -0,0 +1,33 @@
|
||||
# nghttp2 - HTTP/2 C Library
|
||||
|
||||
# Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
# a copy of this software and associated documentation files (the
|
||||
# "Software"), to deal in the Software without restriction, including
|
||||
# without limitation the rights to use, copy, modify, merge, publish,
|
||||
# distribute, sublicense, and/or sell copies of the Software, and to
|
||||
# permit persons to whom the Software is furnished to do so, subject to
|
||||
# the following conditions:
|
||||
|
||||
# The above copyright notice and this permission notice shall be
|
||||
# included in all copies or substantial portions of the Software.
|
||||
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: libnghttp2
|
||||
Description: HTTP/2 C library
|
||||
URL: https://github.com/tatsuhiro-t/nghttp2
|
||||
Version: @VERSION@
|
||||
Libs: -L${libdir} -lnghttp2
|
||||
Cflags: -I${includedir}
|
||||
@@ -0,0 +1,527 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_buf.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_debug.h"
|
||||
|
||||
void nghttp2_buf_init(nghttp2_buf *buf) {
|
||||
buf->begin = NULL;
|
||||
buf->end = NULL;
|
||||
buf->pos = NULL;
|
||||
buf->last = NULL;
|
||||
buf->mark = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem) {
|
||||
nghttp2_buf_init(buf);
|
||||
return nghttp2_buf_reserve(buf, initial, mem);
|
||||
}
|
||||
|
||||
void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem) {
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp2_mem_free(mem, buf->begin);
|
||||
buf->begin = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem) {
|
||||
uint8_t *ptr;
|
||||
size_t cap;
|
||||
|
||||
cap = nghttp2_buf_cap(buf);
|
||||
|
||||
if (cap >= new_cap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_cap = nghttp2_max(new_cap, cap * 2);
|
||||
|
||||
ptr = nghttp2_mem_realloc(mem, buf->begin, new_cap);
|
||||
if (ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
buf->pos = ptr + (buf->pos - buf->begin);
|
||||
buf->last = ptr + (buf->last - buf->begin);
|
||||
buf->mark = ptr + (buf->mark - buf->begin);
|
||||
buf->begin = ptr;
|
||||
buf->end = ptr + new_cap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_buf_reset(nghttp2_buf *buf) {
|
||||
buf->pos = buf->last = buf->mark = buf->begin;
|
||||
}
|
||||
|
||||
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
|
||||
buf->begin = buf->pos = buf->last = buf->mark = buf->end = begin;
|
||||
if (len) {
|
||||
buf->end += len;
|
||||
}
|
||||
}
|
||||
|
||||
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length,
|
||||
nghttp2_mem *mem) {
|
||||
int rv;
|
||||
|
||||
*chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
|
||||
if (*chain == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
(*chain)->next = NULL;
|
||||
|
||||
rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length, mem);
|
||||
if (rv != 0) {
|
||||
nghttp2_mem_free(mem, *chain);
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void buf_chain_del(nghttp2_buf_chain *chain, nghttp2_mem *mem) {
|
||||
nghttp2_buf_free(&chain->buf, mem);
|
||||
nghttp2_mem_free(mem, chain);
|
||||
}
|
||||
|
||||
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
|
||||
nghttp2_mem *mem) {
|
||||
return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0, mem);
|
||||
}
|
||||
|
||||
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
size_t max_chunk, size_t offset, nghttp2_mem *mem) {
|
||||
return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset,
|
||||
mem);
|
||||
}
|
||||
|
||||
int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
size_t max_chunk, size_t chunk_keep, size_t offset,
|
||||
nghttp2_mem *mem) {
|
||||
int rv;
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
rv = buf_chain_new(&chain, chunk_length, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bufs->mem = mem;
|
||||
bufs->offset = offset;
|
||||
|
||||
bufs->head = chain;
|
||||
bufs->cur = bufs->head;
|
||||
|
||||
nghttp2_buf_shift_right(&bufs->cur->buf, offset);
|
||||
|
||||
bufs->chunk_length = chunk_length;
|
||||
bufs->chunk_used = 1;
|
||||
bufs->max_chunk = max_chunk;
|
||||
bufs->chunk_keep = chunk_keep;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) {
|
||||
int rv;
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
if (chunk_length < bufs->offset) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
rv = buf_chain_new(&chain, chunk_length, bufs->mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nghttp2_bufs_free(bufs);
|
||||
|
||||
bufs->head = chain;
|
||||
bufs->cur = bufs->head;
|
||||
|
||||
nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
|
||||
|
||||
bufs->chunk_length = chunk_length;
|
||||
bufs->chunk_used = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_free(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *chain, *next_chain;
|
||||
|
||||
if (bufs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (chain = bufs->head; chain;) {
|
||||
next_chain = chain->next;
|
||||
|
||||
buf_chain_del(chain, bufs->mem);
|
||||
|
||||
chain = next_chain;
|
||||
}
|
||||
|
||||
bufs->head = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
|
||||
nghttp2_mem *mem) {
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain));
|
||||
if (chain == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
chain->next = NULL;
|
||||
|
||||
nghttp2_buf_wrap_init(&chain->buf, begin, len);
|
||||
|
||||
bufs->mem = mem;
|
||||
bufs->offset = 0;
|
||||
|
||||
bufs->head = chain;
|
||||
bufs->cur = bufs->head;
|
||||
|
||||
bufs->chunk_length = len;
|
||||
bufs->chunk_used = 1;
|
||||
bufs->max_chunk = 1;
|
||||
bufs->chunk_keep = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
|
||||
size_t veclen, nghttp2_mem *mem) {
|
||||
size_t i = 0;
|
||||
nghttp2_buf_chain *cur_chain;
|
||||
nghttp2_buf_chain *head_chain;
|
||||
nghttp2_buf_chain **dst_chain = &head_chain;
|
||||
|
||||
if (veclen == 0) {
|
||||
return nghttp2_bufs_wrap_init(bufs, NULL, 0, mem);
|
||||
}
|
||||
|
||||
head_chain = nghttp2_mem_malloc(mem, sizeof(nghttp2_buf_chain) * veclen);
|
||||
if (head_chain == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < veclen; ++i) {
|
||||
cur_chain = &head_chain[i];
|
||||
cur_chain->next = NULL;
|
||||
nghttp2_buf_wrap_init(&cur_chain->buf, vec[i].base, vec[i].len);
|
||||
|
||||
*dst_chain = cur_chain;
|
||||
dst_chain = &cur_chain->next;
|
||||
}
|
||||
|
||||
bufs->mem = mem;
|
||||
bufs->offset = 0;
|
||||
|
||||
bufs->head = head_chain;
|
||||
bufs->cur = bufs->head;
|
||||
|
||||
/* We don't use chunk_length since no allocation is expected. */
|
||||
bufs->chunk_length = 0;
|
||||
bufs->chunk_used = veclen;
|
||||
bufs->max_chunk = veclen;
|
||||
bufs->chunk_keep = veclen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
|
||||
if (bufs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (bufs->head) {
|
||||
nghttp2_mem_free(bufs->mem, bufs->head);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *ci;
|
||||
|
||||
for (ci = bufs->cur; ci; ci = ci->next) {
|
||||
if (nghttp2_buf_len(&ci->buf) == 0) {
|
||||
return;
|
||||
} else {
|
||||
bufs->cur = ci;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t nghttp2_bufs_len(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *ci;
|
||||
size_t len;
|
||||
|
||||
len = 0;
|
||||
for (ci = bufs->head; ci; ci = ci->next) {
|
||||
len += nghttp2_buf_len(&ci->buf);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int bufs_alloc_chain(nghttp2_bufs *bufs) {
|
||||
int rv;
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
if (bufs->cur->next) {
|
||||
bufs->cur = bufs->cur->next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bufs->max_chunk == bufs->chunk_used) {
|
||||
return NGHTTP2_ERR_BUFFER_ERROR;
|
||||
}
|
||||
|
||||
rv = buf_chain_new(&chain, bufs->chunk_length, bufs->mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
DEBUGF("new buffer %zu bytes allocated for bufs %p, used %zu\n",
|
||||
bufs->chunk_length, bufs, bufs->chunk_used);
|
||||
|
||||
++bufs->chunk_used;
|
||||
|
||||
bufs->cur->next = chain;
|
||||
bufs->cur = chain;
|
||||
|
||||
nghttp2_buf_shift_right(&bufs->cur->buf, bufs->offset);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) {
|
||||
int rv;
|
||||
size_t nwrite;
|
||||
nghttp2_buf *buf;
|
||||
const uint8_t *p;
|
||||
|
||||
p = data;
|
||||
|
||||
while (len) {
|
||||
buf = &bufs->cur->buf;
|
||||
|
||||
nwrite = nghttp2_min(nghttp2_buf_avail(buf), len);
|
||||
if (nwrite == 0) {
|
||||
rv = bufs_alloc_chain(bufs);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
buf->last = nghttp2_cpymem(buf->last, p, nwrite);
|
||||
p += nwrite;
|
||||
len -= nwrite;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bufs_ensure_addb(nghttp2_bufs *bufs) {
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
|
||||
buf = &bufs->cur->buf;
|
||||
|
||||
if (nghttp2_buf_avail(buf) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = bufs_alloc_chain(bufs);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*bufs->cur->buf.last++ = b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*bufs->cur->buf.last = b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*bufs->cur->buf.last++ |= b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
*bufs->cur->buf.last |= b;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
|
||||
size_t len;
|
||||
nghttp2_buf_chain *chain;
|
||||
nghttp2_buf *buf;
|
||||
uint8_t *res;
|
||||
nghttp2_buf resbuf;
|
||||
|
||||
len = 0;
|
||||
|
||||
for (chain = bufs->head; chain; chain = chain->next) {
|
||||
len += nghttp2_buf_len(&chain->buf);
|
||||
}
|
||||
|
||||
if (len == 0) {
|
||||
res = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = nghttp2_mem_malloc(bufs->mem, len);
|
||||
if (res == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_buf_wrap_init(&resbuf, res, len);
|
||||
|
||||
for (chain = bufs->head; chain; chain = chain->next) {
|
||||
buf = &chain->buf;
|
||||
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
||||
}
|
||||
|
||||
*out = res;
|
||||
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out) {
|
||||
size_t len;
|
||||
nghttp2_buf_chain *chain;
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_buf resbuf;
|
||||
|
||||
len = nghttp2_bufs_len(bufs);
|
||||
|
||||
nghttp2_buf_wrap_init(&resbuf, out, len);
|
||||
|
||||
for (chain = bufs->head; chain; chain = chain->next) {
|
||||
buf = &chain->buf;
|
||||
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *chain, *ci;
|
||||
size_t k;
|
||||
|
||||
k = bufs->chunk_keep;
|
||||
|
||||
for (ci = bufs->head; ci; ci = ci->next) {
|
||||
nghttp2_buf_reset(&ci->buf);
|
||||
nghttp2_buf_shift_right(&ci->buf, bufs->offset);
|
||||
|
||||
if (--k == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ci) {
|
||||
chain = ci->next;
|
||||
ci->next = NULL;
|
||||
|
||||
for (ci = chain; ci;) {
|
||||
chain = ci->next;
|
||||
|
||||
buf_chain_del(ci, bufs->mem);
|
||||
|
||||
ci = chain;
|
||||
}
|
||||
|
||||
bufs->chunk_used = bufs->chunk_keep;
|
||||
}
|
||||
|
||||
bufs->cur = bufs->head;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); }
|
||||
|
||||
int nghttp2_bufs_next_present(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
chain = bufs->cur->next;
|
||||
|
||||
return chain && nghttp2_buf_len(&chain->buf);
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_BUF_H
|
||||
#define NGHTTP2_BUF_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include "nghttp2_int.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
typedef struct {
|
||||
/* This points to the beginning of the buffer. The effective range
|
||||
of buffer is [begin, end). */
|
||||
uint8_t *begin;
|
||||
/* This points to the memory one byte beyond the end of the
|
||||
buffer. */
|
||||
uint8_t *end;
|
||||
/* The position indicator for effective start of the buffer. pos <=
|
||||
last must be hold. */
|
||||
uint8_t *pos;
|
||||
/* The position indicator for effective one beyond of the end of the
|
||||
buffer. last <= end must be hold. */
|
||||
uint8_t *last;
|
||||
/* Mark arbitrary position in buffer [begin, end) */
|
||||
uint8_t *mark;
|
||||
} nghttp2_buf;
|
||||
|
||||
#define nghttp2_buf_len(BUF) ((size_t)((BUF)->last - (BUF)->pos))
|
||||
#define nghttp2_buf_avail(BUF) ((size_t)((BUF)->end - (BUF)->last))
|
||||
#define nghttp2_buf_mark_avail(BUF) ((size_t)((BUF)->mark - (BUF)->last))
|
||||
#define nghttp2_buf_cap(BUF) ((size_t)((BUF)->end - (BUF)->begin))
|
||||
|
||||
#define nghttp2_buf_pos_offset(BUF) ((size_t)((BUF)->pos - (BUF)->begin))
|
||||
#define nghttp2_buf_last_offset(BUF) ((size_t)((BUF)->last - (BUF)->begin))
|
||||
|
||||
#define nghttp2_buf_shift_right(BUF, AMT) \
|
||||
do { \
|
||||
(BUF)->pos += AMT; \
|
||||
(BUF)->last += AMT; \
|
||||
} while (0)
|
||||
|
||||
#define nghttp2_buf_shift_left(BUF, AMT) \
|
||||
do { \
|
||||
(BUF)->pos -= AMT; \
|
||||
(BUF)->last -= AMT; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Initializes the |buf|. No memory is allocated in this function. Use
|
||||
* nghttp2_buf_reserve() to allocate memory.
|
||||
*/
|
||||
void nghttp2_buf_init(nghttp2_buf *buf);
|
||||
|
||||
/*
|
||||
* Initializes the |buf| and allocates at least |initial| bytes of
|
||||
* memory.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Frees buffer in |buf|.
|
||||
*/
|
||||
void nghttp2_buf_free(nghttp2_buf *buf, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Extends buffer so that nghttp2_buf_cap() returns at least
|
||||
* |new_cap|. If extensions took place, buffer pointers in |buf| will
|
||||
* change.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the followings
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Resets pos, last, mark member of |buf| to buf->begin.
|
||||
*/
|
||||
void nghttp2_buf_reset(nghttp2_buf *buf);
|
||||
|
||||
/*
|
||||
* Initializes |buf| using supplied buffer |begin| of length
|
||||
* |len|. Semantically, the application should not call *_reserve() or
|
||||
* nghttp2_free() functions for |buf|.
|
||||
*/
|
||||
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len);
|
||||
|
||||
struct nghttp2_buf_chain;
|
||||
|
||||
typedef struct nghttp2_buf_chain nghttp2_buf_chain;
|
||||
|
||||
/* Chains 2 buffers */
|
||||
struct nghttp2_buf_chain {
|
||||
/* Points to the subsequent buffer. NULL if there is no such
|
||||
buffer. */
|
||||
nghttp2_buf_chain *next;
|
||||
nghttp2_buf buf;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
/* Points to the first buffer */
|
||||
nghttp2_buf_chain *head;
|
||||
/* Buffer pointer where write occurs. */
|
||||
nghttp2_buf_chain *cur;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem *mem;
|
||||
/* The buffer capacity of each buf. This field may be 0 if
|
||||
nghttp2_bufs is initialized by nghttp2_bufs_wrap_init* family
|
||||
functions. */
|
||||
size_t chunk_length;
|
||||
/* The maximum number of nghttp2_buf_chain */
|
||||
size_t max_chunk;
|
||||
/* The number of nghttp2_buf_chain allocated */
|
||||
size_t chunk_used;
|
||||
/* The number of nghttp2_buf_chain to keep on reset */
|
||||
size_t chunk_keep;
|
||||
/* pos offset from begin in each buffers. On initialization and
|
||||
reset, buf->pos and buf->last are positioned at buf->begin +
|
||||
offset. */
|
||||
size_t offset;
|
||||
} nghttp2_bufs;
|
||||
|
||||
/*
|
||||
* This is the same as calling nghttp2_bufs_init2 with the given
|
||||
* arguments and offset = 0.
|
||||
*/
|
||||
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length, size_t max_chunk,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* This is the same as calling nghttp2_bufs_init3 with the given
|
||||
* arguments and chunk_keep = max_chunk.
|
||||
*/
|
||||
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
size_t max_chunk, size_t offset, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes |bufs|. Each buffer size is given in the
|
||||
* |chunk_length|. The maximum number of buffers is given in the
|
||||
* |max_chunk|. On reset, first |chunk_keep| buffers are kept and
|
||||
* remaining buffers are deleted. Each buffer will have bufs->pos and
|
||||
* bufs->last shifted to left by |offset| bytes on creation and reset.
|
||||
*
|
||||
* This function allocates first buffer. bufs->head and bufs->cur
|
||||
* will point to the first buffer after this call.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* chunk_keep is 0; or max_chunk < chunk_keep; or offset is too
|
||||
* long.
|
||||
*/
|
||||
int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
size_t max_chunk, size_t chunk_keep, size_t offset,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Frees any related resources to the |bufs|.
|
||||
*/
|
||||
void nghttp2_bufs_free(nghttp2_bufs *bufs);
|
||||
|
||||
/*
|
||||
* Initializes |bufs| using supplied buffer |begin| of length |len|.
|
||||
* The first buffer bufs->head uses buffer |begin|. The buffer size
|
||||
* is fixed and no extra chunk buffer is allocated. In other
|
||||
* words, max_chunk = chunk_keep = 1. To free the resource allocated
|
||||
* for |bufs|, use nghttp2_bufs_wrap_free().
|
||||
*
|
||||
* Don't use the function which performs allocation, such as
|
||||
* nghttp2_bufs_realloc().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes |bufs| using supplied |veclen| size of buf vector
|
||||
* |vec|. The number of buffers is fixed and no extra chunk buffer is
|
||||
* allocated. In other words, max_chunk = chunk_keep = |in_len|. To
|
||||
* free the resource allocated for |bufs|, use
|
||||
* nghttp2_bufs_wrap_free().
|
||||
*
|
||||
* Don't use the function which performs allocation, such as
|
||||
* nghttp2_bufs_realloc().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_bufs_wrap_init2(nghttp2_bufs *bufs, const nghttp2_vec *vec,
|
||||
size_t veclen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Frees any related resource to the |bufs|. This function does not
|
||||
* free supplied buffer provided in nghttp2_bufs_wrap_init().
|
||||
*/
|
||||
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs);
|
||||
|
||||
/*
|
||||
* Reallocates internal buffer using |chunk_length|. The max_chunk,
|
||||
* chunk_keep and offset do not change. After successful allocation
|
||||
* of new buffer, previous buffers are deallocated without copying
|
||||
* anything into new buffers. chunk_used is reset to 1.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* chunk_length < offset
|
||||
*/
|
||||
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length);
|
||||
|
||||
/*
|
||||
* Appends the |data| of length |len| to the |bufs|. The write starts
|
||||
* at bufs->cur->buf.last. A new buffers will be allocated to store
|
||||
* all data.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len);
|
||||
|
||||
/*
|
||||
* Appends a single byte |b| to the |bufs|. The write starts at
|
||||
* bufs->cur->buf.last. A new buffers will be allocated to store all
|
||||
* data.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b);
|
||||
|
||||
/*
|
||||
* Behaves like nghttp2_bufs_addb(), but this does not update
|
||||
* buf->last pointer.
|
||||
*/
|
||||
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);
|
||||
|
||||
#define nghttp2_bufs_fast_addb(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last++ = B; \
|
||||
} while (0)
|
||||
|
||||
#define nghttp2_bufs_fast_addb_hold(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last = B; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers
|
||||
* will be allocated if necessary.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b);
|
||||
|
||||
/*
|
||||
* Behaves like nghttp2_bufs_orb(), but does not update buf->last
|
||||
* pointer.
|
||||
*/
|
||||
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
|
||||
|
||||
#define nghttp2_bufs_fast_orb(BUFS, B) \
|
||||
do { \
|
||||
uint8_t **p = &(BUFS)->cur->buf.last; \
|
||||
**p = (uint8_t)(**p | (B)); \
|
||||
++(*p); \
|
||||
} while (0)
|
||||
|
||||
#define nghttp2_bufs_fast_orb_hold(BUFS, B) \
|
||||
do { \
|
||||
uint8_t *p = (BUFS)->cur->buf.last; \
|
||||
*p = (uint8_t)(*p | (B)); \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Copies all data stored in |bufs| to the contiguous buffer. This
|
||||
* function allocates the contiguous memory to store all data in
|
||||
* |bufs| and assigns it to |*out|.
|
||||
*
|
||||
* The contents of |bufs| is left unchanged.
|
||||
*
|
||||
* This function returns the length of copied data and assigns the
|
||||
* pointer to copied data to |*out| if it succeeds, or one of the
|
||||
* following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out);
|
||||
|
||||
/*
|
||||
* Copies all data stored in |bufs| to |out|. This function assumes
|
||||
* that the buffer space pointed by |out| has at least
|
||||
* nghttp2_bufs(bufs) bytes.
|
||||
*
|
||||
* The contents of |bufs| is left unchanged.
|
||||
*
|
||||
* This function returns the length of copied data.
|
||||
*/
|
||||
size_t nghttp2_bufs_remove_copy(nghttp2_bufs *bufs, uint8_t *out);
|
||||
|
||||
/*
|
||||
* Resets |bufs| and makes the buffers empty.
|
||||
*/
|
||||
void nghttp2_bufs_reset(nghttp2_bufs *bufs);
|
||||
|
||||
/*
|
||||
* Moves bufs->cur to bufs->cur->next. If resulting bufs->cur is
|
||||
* NULL, this function allocates new buffers and bufs->cur points to
|
||||
* it.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_bufs_advance(nghttp2_bufs *bufs);
|
||||
|
||||
/* Sets bufs->cur to bufs->head */
|
||||
#define nghttp2_bufs_rewind(BUFS) \
|
||||
do { \
|
||||
(BUFS)->cur = (BUFS)->head; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Move bufs->cur, from the current position, using next member, to
|
||||
* the last buf which has nghttp2_buf_len(buf) > 0 without seeing buf
|
||||
* which satisfies nghttp2_buf_len(buf) == 0. If
|
||||
* nghttp2_buf_len(&bufs->cur->buf) == 0 or bufs->cur->next is NULL,
|
||||
* bufs->cur is unchanged.
|
||||
*/
|
||||
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs);
|
||||
|
||||
/*
|
||||
* Returns nonzero if bufs->cur->next is not empty.
|
||||
*/
|
||||
int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
|
||||
|
||||
#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf)
|
||||
|
||||
/*
|
||||
* Returns the total buffer length of |bufs|.
|
||||
*/
|
||||
size_t nghttp2_bufs_len(nghttp2_bufs *bufs);
|
||||
|
||||
#endif /* NGHTTP2_BUF_H */
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_callbacks.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr) {
|
||||
*callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks));
|
||||
|
||||
if (*callbacks_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) {
|
||||
free(callbacks);
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_send_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) {
|
||||
cbs->send_callback = send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_recv_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) {
|
||||
cbs->recv_callback = recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback) {
|
||||
cbs->on_frame_recv_callback = on_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) {
|
||||
cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) {
|
||||
cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback) {
|
||||
cbs->before_frame_send_callback = before_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback) {
|
||||
cbs->on_frame_send_callback = on_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback) {
|
||||
cbs->on_frame_not_send_callback = on_frame_not_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback) {
|
||||
cbs->on_stream_close_callback = on_stream_close_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback) {
|
||||
cbs->on_begin_headers_callback = on_begin_headers_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback) {
|
||||
cbs->on_header_callback = on_header_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback2(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback2 on_header_callback2) {
|
||||
cbs->on_header_callback2 = on_header_callback2;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_header_callback on_invalid_header_callback) {
|
||||
cbs->on_invalid_header_callback = on_invalid_header_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_header_callback2(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_header_callback2 on_invalid_header_callback2) {
|
||||
cbs->on_invalid_header_callback2 = on_invalid_header_callback2;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_select_padding_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_select_padding_callback select_padding_callback) {
|
||||
cbs->select_padding_callback = select_padding_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_data_source_read_length_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback) {
|
||||
cbs->read_length_callback = data_source_read_length_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback) {
|
||||
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_send_data_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_send_data_callback send_data_callback) {
|
||||
cbs->send_data_callback = send_data_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_pack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_pack_extension_callback pack_extension_callback) {
|
||||
cbs->pack_extension_callback = pack_extension_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_unpack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_unpack_extension_callback unpack_extension_callback) {
|
||||
cbs->unpack_extension_callback = unpack_extension_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) {
|
||||
cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_error_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) {
|
||||
cbs->error_callback = error_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_error_callback2(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) {
|
||||
cbs->error_callback2 = error_callback2;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_CALLBACKS_H
|
||||
#define NGHTTP2_CALLBACKS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/*
|
||||
* Callback functions.
|
||||
*/
|
||||
struct nghttp2_session_callbacks {
|
||||
/**
|
||||
* Callback function invoked when the session wants to send data to
|
||||
* the remote peer. This callback is not necessary if the
|
||||
* application uses solely `nghttp2_session_mem_send()` to serialize
|
||||
* data to transmit.
|
||||
*/
|
||||
nghttp2_send_callback send_callback;
|
||||
/**
|
||||
* Callback function invoked when the session wants to receive data
|
||||
* from the remote peer. This callback is not necessary if the
|
||||
* application uses solely `nghttp2_session_mem_recv()` to process
|
||||
* received data.
|
||||
*/
|
||||
nghttp2_recv_callback recv_callback;
|
||||
/**
|
||||
* Callback function invoked by `nghttp2_session_recv()` when a
|
||||
* frame is received.
|
||||
*/
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback;
|
||||
/**
|
||||
* Callback function invoked by `nghttp2_session_recv()` when an
|
||||
* invalid non-DATA frame is received.
|
||||
*/
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
|
||||
/**
|
||||
* Callback function invoked when a chunk of data in DATA frame is
|
||||
* received.
|
||||
*/
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
|
||||
/**
|
||||
* Callback function invoked before a non-DATA frame is sent.
|
||||
*/
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback;
|
||||
/**
|
||||
* Callback function invoked after a frame is sent.
|
||||
*/
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback;
|
||||
/**
|
||||
* The callback function invoked when a non-DATA frame is not sent
|
||||
* because of an error.
|
||||
*/
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
|
||||
/**
|
||||
* Callback function invoked when the stream is closed.
|
||||
*/
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback;
|
||||
/**
|
||||
* Callback function invoked when the reception of header block in
|
||||
* HEADERS or PUSH_PROMISE is started.
|
||||
*/
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback;
|
||||
/**
|
||||
* Callback function invoked when a header name/value pair is
|
||||
* received.
|
||||
*/
|
||||
nghttp2_on_header_callback on_header_callback;
|
||||
nghttp2_on_header_callback2 on_header_callback2;
|
||||
/**
|
||||
* Callback function invoked when a invalid header name/value pair
|
||||
* is received which is silently ignored if these callbacks are not
|
||||
* set.
|
||||
*/
|
||||
nghttp2_on_invalid_header_callback on_invalid_header_callback;
|
||||
nghttp2_on_invalid_header_callback2 on_invalid_header_callback2;
|
||||
/**
|
||||
* Callback function invoked when the library asks application how
|
||||
* many padding bytes are required for the transmission of the given
|
||||
* frame.
|
||||
*/
|
||||
nghttp2_select_padding_callback select_padding_callback;
|
||||
/**
|
||||
* The callback function used to determine the length allowed in
|
||||
* `nghttp2_data_source_read_callback()`
|
||||
*/
|
||||
nghttp2_data_source_read_length_callback read_length_callback;
|
||||
/**
|
||||
* Sets callback function invoked when a frame header is received.
|
||||
*/
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
||||
nghttp2_send_data_callback send_data_callback;
|
||||
nghttp2_pack_extension_callback pack_extension_callback;
|
||||
nghttp2_unpack_extension_callback unpack_extension_callback;
|
||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
|
||||
nghttp2_error_callback error_callback;
|
||||
nghttp2_error_callback2 error_callback2;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_CALLBACKS_H */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
||||
static void nghttp2_default_debug_vfprintf_callback(const char *fmt,
|
||||
va_list args) {
|
||||
vfprintf(stderr, fmt, args);
|
||||
}
|
||||
|
||||
static nghttp2_debug_vprintf_callback static_debug_vprintf_callback =
|
||||
nghttp2_default_debug_vfprintf_callback;
|
||||
|
||||
void nghttp2_debug_vprintf(const char *format, ...) {
|
||||
if (static_debug_vprintf_callback) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
static_debug_vprintf_callback(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_set_debug_vprintf_callback(
|
||||
nghttp2_debug_vprintf_callback debug_vprintf_callback) {
|
||||
static_debug_vprintf_callback = debug_vprintf_callback;
|
||||
}
|
||||
|
||||
#else /* !DEBUGBUILD */
|
||||
|
||||
void nghttp2_set_debug_vprintf_callback(
|
||||
nghttp2_debug_vprintf_callback debug_vprintf_callback) {
|
||||
(void)debug_vprintf_callback;
|
||||
}
|
||||
|
||||
#endif /* !DEBUGBUILD */
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_DEBUG_H
|
||||
#define NGHTTP2_DEBUG_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
# define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__)
|
||||
void nghttp2_debug_vprintf(const char *format, ...);
|
||||
#else
|
||||
# define DEBUGF(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* NGHTTP2_DEBUG_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,624 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_FRAME_H
|
||||
#define NGHTTP2_FRAME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_buf.h"
|
||||
|
||||
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
|
||||
|
||||
/* The number of bytes of frame header. */
|
||||
#define NGHTTP2_FRAME_HDLEN 9
|
||||
|
||||
#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
|
||||
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
|
||||
|
||||
#define NGHTTP2_MAX_PAYLOADLEN 16384
|
||||
/* The one frame buffer length for tranmission. We may use several of
|
||||
them to support CONTINUATION. To account for Pad Length field, we
|
||||
allocate extra 1 byte, which saves extra large memcopying. */
|
||||
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
||||
(NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN)
|
||||
|
||||
/* The default length of DATA frame payload. */
|
||||
#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN
|
||||
|
||||
/* Maximum headers block size to send, calculated using
|
||||
nghttp2_hd_deflate_bound(). This is the default value, and can be
|
||||
overridden by nghttp2_option_set_max_send_header_block_size(). */
|
||||
#define NGHTTP2_MAX_HEADERSLEN 65536
|
||||
|
||||
/* The number of bytes for each SETTINGS entry */
|
||||
#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 6
|
||||
|
||||
/* Length of priority related fields in HEADERS/PRIORITY frames */
|
||||
#define NGHTTP2_PRIORITY_SPECLEN 5
|
||||
|
||||
/* Maximum length of padding in bytes. */
|
||||
#define NGHTTP2_MAX_PADLEN 256
|
||||
|
||||
/* Union of extension frame payload */
|
||||
typedef union {
|
||||
nghttp2_ext_altsvc altsvc;
|
||||
nghttp2_ext_origin origin;
|
||||
} nghttp2_ext_frame_payload;
|
||||
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
||||
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Initializes frame header |hd| with given parameters. Reserved bit
|
||||
* is set to 0.
|
||||
*/
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id);
|
||||
|
||||
/**
|
||||
* Returns the number of priority field depending on the |flags|. If
|
||||
* |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
|
||||
* NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0.
|
||||
*/
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags);
|
||||
|
||||
/**
|
||||
* Packs the |pri_spec| in |buf|. This function assumes |buf| has
|
||||
* enough space for serialization.
|
||||
*/
|
||||
void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
/**
|
||||
* Unpacks the priority specification from payload |payload| of length
|
||||
* |payloadlen| to |pri_spec|. The |flags| is used to determine what
|
||||
* kind of priority specification is in |payload|. This function
|
||||
* assumes the |payload| contains whole priority specification.
|
||||
*/
|
||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Returns the offset from the HEADERS frame payload where the
|
||||
* compressed header block starts. The frame payload does not include
|
||||
* frame header.
|
||||
*/
|
||||
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
|
||||
|
||||
/*
|
||||
* Packs HEADERS frame |frame| in wire format and store it in |bufs|.
|
||||
* This function expands |bufs| as necessary to store frame.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* frame->hd.length is assigned after length is determined during
|
||||
* packing process. CONTINUATION frames are also serialized in this
|
||||
* function. This function does not handle padding.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or returns one of the
|
||||
* following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* The deflate operation failed.
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
|
||||
nghttp2_hd_deflater *deflater);
|
||||
|
||||
/*
|
||||
* Unpacks HEADERS frame byte sequence into |frame|. This function
|
||||
* only unapcks bytes that come before name/value header block and
|
||||
* after possible Pad Length field.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs PRIORITY frame |frame| in wire format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
|
||||
|
||||
/*
|
||||
* Unpacks PRIORITY wire format into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs RST_STREAM frame |frame| in wire frame format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
nghttp2_rst_stream *frame);
|
||||
|
||||
/*
|
||||
* Unpacks RST_STREAM frame byte sequence into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs SETTINGS frame |frame| in wire format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or returns one of the
|
||||
* following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame);
|
||||
|
||||
/*
|
||||
* Packs the |iv|, which includes |niv| entries, in the |buf|,
|
||||
* assuming the |buf| has at least 8 * |niv| bytes.
|
||||
*
|
||||
* Returns the number of bytes written into the |buf|.
|
||||
*/
|
||||
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
|
||||
const nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Initializes payload of frame->settings. The |frame| takes
|
||||
* ownership of |iv|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
||||
nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
/*
|
||||
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
|
||||
* assigned to the |*niv_ptr|. This function allocates enough memory
|
||||
* to store the result in |*iv_ptr|. The caller is responsible to free
|
||||
* |*iv_ptr| after its use.
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
|
||||
size_t *niv_ptr,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Packs PUSH_PROMISE frame |frame| in wire format and store it in
|
||||
* |bufs|. This function expands |bufs| as necessary to store
|
||||
* frame.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* frame->hd.length is assigned after length is determined during
|
||||
* packing process. CONTINUATION frames are also serialized in this
|
||||
* function. This function does not handle padding.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or returns one of the
|
||||
* following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* The deflate operation failed.
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
||||
nghttp2_push_promise *frame,
|
||||
nghttp2_hd_deflater *deflater);
|
||||
|
||||
/*
|
||||
* Unpacks PUSH_PROMISE frame byte sequence into |frame|. This
|
||||
* function only unapcks bytes that come before name/value header
|
||||
* block and after possible Pad Length field.
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_PROTO
|
||||
* TODO END_HEADERS flag is not set
|
||||
*/
|
||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs PING frame |frame| in wire format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
|
||||
|
||||
/*
|
||||
* Unpacks PING wire format into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
|
||||
* This function expands |bufs| as necessary to store frame.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame);
|
||||
|
||||
/*
|
||||
* Unpacks GOAWAY wire format into |frame|. The |payload| of length
|
||||
* |payloadlen| contains first 8 bytes of payload. The
|
||||
* |var_gift_payload| of length |var_gift_payloadlen| contains
|
||||
* remaining payload and its buffer is gifted to the function and then
|
||||
* |frame|. The |var_gift_payloadlen| must be freed by
|
||||
* nghttp2_frame_goaway_free().
|
||||
*/
|
||||
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
||||
const uint8_t *payload,
|
||||
uint8_t *var_gift_payload,
|
||||
size_t var_gift_payloadlen);
|
||||
|
||||
/*
|
||||
* Unpacks GOAWAY wire format into |frame|. This function only exists
|
||||
* for unit test. After allocating buffer for debug data, this
|
||||
* function internally calls nghttp2_frame_unpack_goaway_payload().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
|
||||
* in |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
nghttp2_window_update *frame);
|
||||
|
||||
/*
|
||||
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs ALTSVC frame |frame| in wire frame format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
|
||||
|
||||
/*
|
||||
* Unpacks ALTSVC wire format into |frame|. The |payload| of
|
||||
* |payloadlen| bytes contains frame payload. This function assumes
|
||||
* that frame->payload points to the nghttp2_ext_altsvc object.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
size_t origin_len, uint8_t *payload,
|
||||
size_t payloadlen);
|
||||
|
||||
/*
|
||||
* Unpacks ALTSVC wire format into |frame|. This function only exists
|
||||
* for unit test. After allocating buffer for fields, this function
|
||||
* internally calls nghttp2_frame_unpack_altsvc_payload().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The payload is too small.
|
||||
*/
|
||||
int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Packs ORIGIN frame |frame| in wire frame format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext);
|
||||
|
||||
/*
|
||||
* Unpacks ORIGIN wire format into |frame|. The |payload| of length
|
||||
* |payloadlen| contains the frame payload.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The payload is too small.
|
||||
*/
|
||||
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
/*
|
||||
* Initializes HEADERS frame |frame| with given values. |frame| takes
|
||||
* ownership of |nva|, so caller must not free it. If |stream_id| is
|
||||
* not assigned yet, it must be -1.
|
||||
*/
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
|
||||
int32_t stream_id, nghttp2_headers_category cat,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem);
|
||||
|
||||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
void nghttp2_frame_priority_free(nghttp2_priority *frame);
|
||||
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
|
||||
|
||||
/*
|
||||
* Initializes PUSH_PROMISE frame |frame| with given values. |frame|
|
||||
* takes ownership of |nva|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t promised_stream_id,
|
||||
nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes SETTINGS frame |frame| with given values. |frame| takes
|
||||
* ownership of |iv|, so caller must not free it. The |flags| are
|
||||
* bitwise-OR of one or more of nghttp2_settings_flag.
|
||||
*/
|
||||
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
||||
nghttp2_settings_entry *iv, size_t niv);
|
||||
|
||||
void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes PING frame |frame| with given values. If the
|
||||
* |opqeue_data| is not NULL, it must point to 8 bytes memory region
|
||||
* of data. The data pointed by |opaque_data| is copied. It can be
|
||||
* NULL. In this case, 8 bytes NULL is used.
|
||||
*/
|
||||
void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
|
||||
const uint8_t *opque_data);
|
||||
|
||||
void nghttp2_frame_ping_free(nghttp2_ping *frame);
|
||||
|
||||
/*
|
||||
* Initializes GOAWAY frame |frame| with given values. On success,
|
||||
* this function takes ownership of |opaque_data|, so caller must not
|
||||
* free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
|
||||
*/
|
||||
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||
uint32_t error_code, uint8_t *opaque_data,
|
||||
size_t opaque_data_len);
|
||||
|
||||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem);
|
||||
|
||||
void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
int32_t window_size_increment);
|
||||
|
||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
|
||||
|
||||
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
void *payload);
|
||||
|
||||
void nghttp2_frame_extension_free(nghttp2_extension *frame);
|
||||
|
||||
/*
|
||||
* Initializes ALTSVC frame |frame| with given values. This function
|
||||
* assumes that frame->payload points to nghttp2_ext_altsvc object.
|
||||
* Also |origin| and |field_value| are allocated in single buffer,
|
||||
* starting |origin|. On success, this function takes ownership of
|
||||
* |origin|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
uint8_t *origin, size_t origin_len,
|
||||
uint8_t *field_value, size_t field_value_len);
|
||||
|
||||
/*
|
||||
* Frees up resources under |frame|. This function does not free
|
||||
* nghttp2_ext_altsvc object pointed by frame->payload. This function
|
||||
* only frees origin pointed by nghttp2_ext_altsvc.origin. Therefore,
|
||||
* other fields must be allocated in the same buffer with origin.
|
||||
*/
|
||||
void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes ORIGIN frame |frame| with given values. This function
|
||||
* assumes that frame->payload points to nghttp2_ext_origin object.
|
||||
* Also |ov| and the memory pointed by the field of its elements are
|
||||
* allocated in single buffer, starting with |ov|. On success, this
|
||||
* function takes ownership of |ov|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_origin_init(nghttp2_extension *frame,
|
||||
nghttp2_origin_entry *ov, size_t nov);
|
||||
|
||||
/*
|
||||
* Frees up resources under |frame|. This function does not free
|
||||
* nghttp2_ext_origin object pointed by frame->payload. This function
|
||||
* only frees nghttp2_ext_origin.ov. Therefore, other fields must be
|
||||
* allocated in the same buffer with ov.
|
||||
*/
|
||||
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Returns the number of padding bytes after payload. The total
|
||||
* padding length is given in the |padlen|. The returned value does
|
||||
* not include the Pad Length field. If |padlen| is 0, this function
|
||||
* returns 0, regardless of frame->hd.flags.
|
||||
*/
|
||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
|
||||
|
||||
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
|
||||
int32_t stream_id);
|
||||
|
||||
void nghttp2_frame_data_free(nghttp2_data *frame);
|
||||
|
||||
/*
|
||||
* Makes copy of |iv| and return the copy. The |niv| is the number of
|
||||
* entries in |iv|. This function returns the pointer to the copy if
|
||||
* it succeeds, or NULL.
|
||||
*/
|
||||
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||
size_t niv, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Sorts the |nva| in ascending order of name and value. If names are
|
||||
* equivalent, sort them by value.
|
||||
*/
|
||||
void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
/*
|
||||
* Copies name/value pairs from |nva|, which contains |nvlen| pairs,
|
||||
* to |*nva_ptr|, which is dynamically allocated so that all items can
|
||||
* be stored. The resultant name and value in nghttp2_nv are
|
||||
* guaranteed to be NULL-terminated even if the input is not
|
||||
* null-terminated.
|
||||
*
|
||||
* The |*nva_ptr| must be freed using nghttp2_nv_array_del().
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
||||
size_t nvlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the name/value pair |a| equals to |b|. The name
|
||||
* is compared in case-sensitive, because we ensure that this function
|
||||
* is called after the name is lower-cased.
|
||||
*/
|
||||
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b);
|
||||
|
||||
/*
|
||||
* Frees |nva|.
|
||||
*/
|
||||
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Checks that the |iv|, which includes |niv| entries, does not have
|
||||
* invalid values.
|
||||
*
|
||||
* This function returns nonzero if it succeeds, or 0.
|
||||
*/
|
||||
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
|
||||
|
||||
/*
|
||||
* Sets Pad Length field and flags and adjusts frame header position
|
||||
* of each buffers in |bufs|. The number of padding is given in the
|
||||
* |padlen| including Pad Length field. The |hd| is the frame header
|
||||
* for the serialized data. This function fills zeros padding region
|
||||
* unless framehd_only is nonzero.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the resulting frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen, int framehd_only);
|
||||
|
||||
#endif /* NGHTTP2_FRAME_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HD_H
|
||||
#define NGHTTP2_HD_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include "nghttp2_hd_huffman.h"
|
||||
#include "nghttp2_buf.h"
|
||||
#include "nghttp2_mem.h"
|
||||
#include "nghttp2_rcbuf.h"
|
||||
|
||||
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
|
||||
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
|
||||
|
||||
/* The maximum length of one name/value pair. This is the sum of the
|
||||
length of name and value. This is not specified by the spec. We
|
||||
just chose the arbitrary size */
|
||||
#define NGHTTP2_HD_MAX_NV 65536
|
||||
|
||||
/* Default size of maximum table buffer size for encoder. Even if
|
||||
remote decoder notifies larger buffer size for its decoding,
|
||||
encoder only uses the memory up to this value. */
|
||||
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
|
||||
|
||||
/* Exported for unit test */
|
||||
#define NGHTTP2_STATIC_TABLE_LENGTH 61
|
||||
|
||||
/* Generated by genlibtokenlookup.py */
|
||||
typedef enum {
|
||||
NGHTTP2_TOKEN__AUTHORITY = 0,
|
||||
NGHTTP2_TOKEN__METHOD = 1,
|
||||
NGHTTP2_TOKEN__PATH = 3,
|
||||
NGHTTP2_TOKEN__SCHEME = 5,
|
||||
NGHTTP2_TOKEN__STATUS = 7,
|
||||
NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
|
||||
NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
|
||||
NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
|
||||
NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
|
||||
NGHTTP2_TOKEN_ACCEPT = 18,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
|
||||
NGHTTP2_TOKEN_AGE = 20,
|
||||
NGHTTP2_TOKEN_ALLOW = 21,
|
||||
NGHTTP2_TOKEN_AUTHORIZATION = 22,
|
||||
NGHTTP2_TOKEN_CACHE_CONTROL = 23,
|
||||
NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
|
||||
NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
|
||||
NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
|
||||
NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
|
||||
NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
|
||||
NGHTTP2_TOKEN_CONTENT_RANGE = 29,
|
||||
NGHTTP2_TOKEN_CONTENT_TYPE = 30,
|
||||
NGHTTP2_TOKEN_COOKIE = 31,
|
||||
NGHTTP2_TOKEN_DATE = 32,
|
||||
NGHTTP2_TOKEN_ETAG = 33,
|
||||
NGHTTP2_TOKEN_EXPECT = 34,
|
||||
NGHTTP2_TOKEN_EXPIRES = 35,
|
||||
NGHTTP2_TOKEN_FROM = 36,
|
||||
NGHTTP2_TOKEN_HOST = 37,
|
||||
NGHTTP2_TOKEN_IF_MATCH = 38,
|
||||
NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
|
||||
NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
|
||||
NGHTTP2_TOKEN_IF_RANGE = 41,
|
||||
NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
|
||||
NGHTTP2_TOKEN_LAST_MODIFIED = 43,
|
||||
NGHTTP2_TOKEN_LINK = 44,
|
||||
NGHTTP2_TOKEN_LOCATION = 45,
|
||||
NGHTTP2_TOKEN_MAX_FORWARDS = 46,
|
||||
NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
|
||||
NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
|
||||
NGHTTP2_TOKEN_RANGE = 49,
|
||||
NGHTTP2_TOKEN_REFERER = 50,
|
||||
NGHTTP2_TOKEN_REFRESH = 51,
|
||||
NGHTTP2_TOKEN_RETRY_AFTER = 52,
|
||||
NGHTTP2_TOKEN_SERVER = 53,
|
||||
NGHTTP2_TOKEN_SET_COOKIE = 54,
|
||||
NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
|
||||
NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
|
||||
NGHTTP2_TOKEN_USER_AGENT = 57,
|
||||
NGHTTP2_TOKEN_VARY = 58,
|
||||
NGHTTP2_TOKEN_VIA = 59,
|
||||
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
|
||||
NGHTTP2_TOKEN_TE,
|
||||
NGHTTP2_TOKEN_CONNECTION,
|
||||
NGHTTP2_TOKEN_KEEP_ALIVE,
|
||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||
NGHTTP2_TOKEN_UPGRADE,
|
||||
NGHTTP2_TOKEN__PROTOCOL,
|
||||
} nghttp2_token;
|
||||
|
||||
struct nghttp2_hd_entry;
|
||||
typedef struct nghttp2_hd_entry nghttp2_hd_entry;
|
||||
|
||||
typedef struct {
|
||||
/* The buffer containing header field name. NULL-termination is
|
||||
guaranteed. */
|
||||
nghttp2_rcbuf *name;
|
||||
/* The buffer containing header field value. NULL-termination is
|
||||
guaranteed. */
|
||||
nghttp2_rcbuf *value;
|
||||
/* nghttp2_token value for name. It could be -1 if we have no token
|
||||
for that header field name. */
|
||||
int32_t token;
|
||||
/* Bitwise OR of one or more of nghttp2_nv_flag. */
|
||||
uint8_t flags;
|
||||
} nghttp2_hd_nv;
|
||||
|
||||
struct nghttp2_hd_entry {
|
||||
/* The header field name/value pair */
|
||||
nghttp2_hd_nv nv;
|
||||
/* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry
|
||||
APIs to keep backward compatibility. */
|
||||
nghttp2_nv cnv;
|
||||
/* The next entry which shares same bucket in hash table. */
|
||||
nghttp2_hd_entry *next;
|
||||
/* The sequence number. We will increment it by one whenever we
|
||||
store nghttp2_hd_entry to dynamic header table. */
|
||||
uint32_t seq;
|
||||
/* The hash value for header name (nv.name). */
|
||||
uint32_t hash;
|
||||
};
|
||||
|
||||
/* The entry used for static header table. */
|
||||
typedef struct {
|
||||
nghttp2_rcbuf name;
|
||||
nghttp2_rcbuf value;
|
||||
nghttp2_nv cnv;
|
||||
int32_t token;
|
||||
uint32_t hash;
|
||||
} nghttp2_hd_static_entry;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry **buffer;
|
||||
size_t mask;
|
||||
size_t first;
|
||||
size_t len;
|
||||
} nghttp2_hd_ringbuf;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_OPCODE_NONE,
|
||||
NGHTTP2_HD_OPCODE_INDEXED,
|
||||
NGHTTP2_HD_OPCODE_NEWNAME,
|
||||
NGHTTP2_HD_OPCODE_INDNAME
|
||||
} nghttp2_hd_opcode;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE,
|
||||
NGHTTP2_HD_STATE_INFLATE_START,
|
||||
NGHTTP2_HD_STATE_OPCODE,
|
||||
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
|
||||
NGHTTP2_HD_STATE_READ_INDEX,
|
||||
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
|
||||
NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
|
||||
NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF,
|
||||
NGHTTP2_HD_STATE_NEWNAME_READ_NAME,
|
||||
NGHTTP2_HD_STATE_CHECK_VALUELEN,
|
||||
NGHTTP2_HD_STATE_READ_VALUELEN,
|
||||
NGHTTP2_HD_STATE_READ_VALUEHUFF,
|
||||
NGHTTP2_HD_STATE_READ_VALUE
|
||||
} nghttp2_hd_inflate_state;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_WITH_INDEXING,
|
||||
NGHTTP2_HD_WITHOUT_INDEXING,
|
||||
NGHTTP2_HD_NEVER_INDEXING
|
||||
} nghttp2_hd_indexing_mode;
|
||||
|
||||
typedef struct {
|
||||
/* dynamic header table */
|
||||
nghttp2_hd_ringbuf hd_table;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem *mem;
|
||||
/* Abstract buffer size of hd_table as described in the spec. This
|
||||
is the sum of length of name/value in hd_table +
|
||||
NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
|
||||
size_t hd_table_bufsize;
|
||||
/* The effective header table size. */
|
||||
size_t hd_table_bufsize_max;
|
||||
/* Next sequence number for nghttp2_hd_entry */
|
||||
uint32_t next_seq;
|
||||
/* If inflate/deflate error occurred, this value is set to 1 and
|
||||
further invocation of inflate/deflate will fail with
|
||||
NGHTTP2_ERR_HEADER_COMP. */
|
||||
uint8_t bad;
|
||||
} nghttp2_hd_context;
|
||||
|
||||
#define HD_MAP_SIZE 128
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry *table[HD_MAP_SIZE];
|
||||
} nghttp2_hd_map;
|
||||
|
||||
struct nghttp2_hd_deflater {
|
||||
nghttp2_hd_context ctx;
|
||||
nghttp2_hd_map map;
|
||||
/* The upper limit of the header table size the deflater accepts. */
|
||||
size_t deflate_hd_table_bufsize_max;
|
||||
/* Minimum header table size notified in the next context update */
|
||||
size_t min_hd_table_bufsize_max;
|
||||
/* If nonzero, send header table size using encoding context update
|
||||
in the next deflate process */
|
||||
uint8_t notify_table_size_change;
|
||||
};
|
||||
|
||||
struct nghttp2_hd_inflater {
|
||||
nghttp2_hd_context ctx;
|
||||
/* Stores current state of huffman decoding */
|
||||
nghttp2_hd_huff_decode_context huff_decode_ctx;
|
||||
/* header buffer */
|
||||
nghttp2_buf namebuf, valuebuf;
|
||||
nghttp2_rcbuf *namercbuf, *valuercbuf;
|
||||
/* Pointer to the name/value pair which are used in the current
|
||||
header emission. */
|
||||
nghttp2_rcbuf *nv_name_keep, *nv_value_keep;
|
||||
/* The number of bytes to read */
|
||||
size_t left;
|
||||
/* The index in indexed repr or indexed name */
|
||||
size_t index;
|
||||
/* The maximum header table size the inflater supports. This is the
|
||||
same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
|
||||
size_t settings_hd_table_bufsize_max;
|
||||
/* Minimum header table size set by nghttp2_hd_inflate_change_table_size */
|
||||
size_t min_hd_table_bufsize_max;
|
||||
/* The number of next shift to decode integer */
|
||||
size_t shift;
|
||||
nghttp2_hd_opcode opcode;
|
||||
nghttp2_hd_inflate_state state;
|
||||
/* nonzero if string is huffman encoded */
|
||||
uint8_t huffman_encoded;
|
||||
/* nonzero if deflater requires that current entry is indexed */
|
||||
uint8_t index_required;
|
||||
/* nonzero if deflater requires that current entry must not be
|
||||
indexed */
|
||||
uint8_t no_index;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initializes the |ent| members. The reference counts of nv->name
|
||||
* and nv->value are increased by one for each.
|
||||
*/
|
||||
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv);
|
||||
|
||||
/*
|
||||
* This function decreases the reference counts of nv->name and
|
||||
* nv->value.
|
||||
*/
|
||||
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
|
||||
|
||||
/*
|
||||
* Initializes |deflater| for deflating name/values pairs.
|
||||
*
|
||||
* The encoder only uses up to
|
||||
* NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table
|
||||
* even if the larger value is specified later in
|
||||
* nghttp2_hd_change_table_size().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes |deflater| for deflating name/values pairs.
|
||||
*
|
||||
* The encoder only uses up to |max_deflate_dynamic_table_size| bytes
|
||||
* for header table even if the larger value is specified later in
|
||||
* nghttp2_hd_change_table_size().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
|
||||
size_t max_deflate_dynamic_table_size,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |deflater|.
|
||||
*/
|
||||
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
|
||||
|
||||
/*
|
||||
* Deflates the |nva|, which has the |nvlen| name/value pairs, into
|
||||
* the |bufs|.
|
||||
*
|
||||
* This function expands |bufs| as necessary to store the result. If
|
||||
* buffers is full and the process still requires more space, this
|
||||
* function fails and returns NGHTTP2_ERR_HEADER_COMP.
|
||||
*
|
||||
* After this function returns, it is safe to delete the |nva|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* Deflation process has failed.
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_bufs *bufs, const nghttp2_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
/*
|
||||
* Initializes |inflater| for inflating name/values pairs.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |inflater|.
|
||||
*/
|
||||
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
|
||||
|
||||
/*
|
||||
* Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv
|
||||
* instead of nghttp2_nv as output parameter |nv_out|. Other than
|
||||
* that return values and semantics are the same as
|
||||
* nghttp2_hd_inflate_hd().
|
||||
*/
|
||||
ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_hd_nv *nv_out, int *inflate_flags,
|
||||
const uint8_t *in, size_t inlen, int in_final);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
|
||||
nghttp2_nv *nv, int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||
int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
||||
|
||||
/* For unittesting purpose */
|
||||
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index);
|
||||
|
||||
/* For unittesting purpose */
|
||||
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
|
||||
uint32_t initial, size_t shift, uint8_t *in,
|
||||
uint8_t *last, size_t prefix);
|
||||
|
||||
/* Huffman encoding/decoding functions */
|
||||
|
||||
/*
|
||||
* Counts the required bytes to encode |src| with length |len|.
|
||||
*
|
||||
* This function returns the number of required bytes to encode given
|
||||
* data, including padding of prefix of terminal symbol code. This
|
||||
* function always succeeds.
|
||||
*/
|
||||
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
|
||||
|
||||
/*
|
||||
* Encodes the given data |src| with length |srclen| to the |bufs|.
|
||||
* This function expands extra buffers in |bufs| if necessary.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen);
|
||||
|
||||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
|
||||
|
||||
/*
|
||||
* Decodes the given data |src| with length |srclen|. The |ctx| must
|
||||
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
|
||||
* will be written to |buf|. This function assumes that |buf| has the
|
||||
* enough room to store the decoded byte string.
|
||||
*
|
||||
* The caller must set the |fin| to nonzero if the given input is the
|
||||
* final block.
|
||||
*
|
||||
* This function returns the number of read bytes from the |in|.
|
||||
*
|
||||
* If this function fails, it returns one of the following negative
|
||||
* return codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* Decoding process has failed.
|
||||
*/
|
||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
nghttp2_buf *buf, const uint8_t *src,
|
||||
size_t srclen, int fin);
|
||||
|
||||
/*
|
||||
* nghttp2_hd_huff_decode_failure_state returns nonzero if |ctx|
|
||||
* indicates that huffman decoding context is in failure state.
|
||||
*/
|
||||
int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx);
|
||||
|
||||
#endif /* NGHTTP2_HD_H */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_hd_huffman.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_net.h"
|
||||
|
||||
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
|
||||
size_t i;
|
||||
size_t nbits = 0;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
nbits += huff_sym_table[src[i]].nbits;
|
||||
}
|
||||
/* pad the prefix of EOS (256) */
|
||||
return (nbits + 7) / 8;
|
||||
}
|
||||
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen) {
|
||||
const nghttp2_huff_sym *sym;
|
||||
const uint8_t *end = src + srclen;
|
||||
uint64_t code = 0;
|
||||
uint32_t x;
|
||||
size_t nbits = 0;
|
||||
size_t avail;
|
||||
int rv;
|
||||
|
||||
avail = nghttp2_bufs_cur_avail(bufs);
|
||||
|
||||
for (; src != end;) {
|
||||
sym = &huff_sym_table[*src++];
|
||||
code |= (uint64_t)sym->code << (32 - nbits);
|
||||
nbits += sym->nbits;
|
||||
if (nbits < 32) {
|
||||
continue;
|
||||
}
|
||||
if (avail >= 4) {
|
||||
x = htonl((uint32_t)(code >> 32));
|
||||
memcpy(bufs->cur->buf.last, &x, 4);
|
||||
bufs->cur->buf.last += 4;
|
||||
avail -= 4;
|
||||
code <<= 32;
|
||||
nbits -= 32;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (; nbits >= 8;) {
|
||||
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
code <<= 8;
|
||||
nbits -= 8;
|
||||
}
|
||||
|
||||
avail = nghttp2_bufs_cur_avail(bufs);
|
||||
}
|
||||
|
||||
for (; nbits >= 8;) {
|
||||
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
code <<= 8;
|
||||
nbits -= 8;
|
||||
}
|
||||
|
||||
if (nbits) {
|
||||
rv = nghttp2_bufs_addb(
|
||||
bufs, (uint8_t)((uint8_t)(code >> 56) | ((1 << (8 - nbits)) - 1)));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
|
||||
ctx->fstate = NGHTTP2_HUFF_ACCEPTED;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
nghttp2_buf *buf, const uint8_t *src,
|
||||
size_t srclen, int final) {
|
||||
const uint8_t *end = src + srclen;
|
||||
nghttp2_huff_decode node = {ctx->fstate, 0};
|
||||
const nghttp2_huff_decode *t = &node;
|
||||
uint8_t c;
|
||||
|
||||
/* We use the decoding algorithm described in
|
||||
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
||||
for (; src != end;) {
|
||||
c = *src++;
|
||||
t = &huff_decode_table[t->fstate & 0x1ff][c >> 4];
|
||||
if (t->fstate & NGHTTP2_HUFF_SYM) {
|
||||
*buf->last++ = t->sym;
|
||||
}
|
||||
|
||||
t = &huff_decode_table[t->fstate & 0x1ff][c & 0xf];
|
||||
if (t->fstate & NGHTTP2_HUFF_SYM) {
|
||||
*buf->last++ = t->sym;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->fstate = t->fstate;
|
||||
|
||||
if (final && !(ctx->fstate & NGHTTP2_HUFF_ACCEPTED)) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
return (ssize_t)srclen;
|
||||
}
|
||||
|
||||
int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx) {
|
||||
return ctx->fstate == 0x100;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HD_HUFFMAN_H
|
||||
#define NGHTTP2_HD_HUFFMAN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
typedef enum {
|
||||
/* FSA accepts this state as the end of huffman encoding
|
||||
sequence. */
|
||||
NGHTTP2_HUFF_ACCEPTED = 1 << 14,
|
||||
/* This state emits symbol */
|
||||
NGHTTP2_HUFF_SYM = 1 << 15,
|
||||
} nghttp2_huff_decode_flag;
|
||||
|
||||
typedef struct {
|
||||
/* fstate is the current huffman decoding state, which is actually
|
||||
the node ID of internal huffman tree with
|
||||
nghttp2_huff_decode_flag OR-ed. We have 257 leaf nodes, but they
|
||||
are identical to root node other than emitting a symbol, so we
|
||||
have 256 internal nodes [1..255], inclusive. The node ID 256 is
|
||||
a special node and it is a terminal state that means decoding
|
||||
failed. */
|
||||
uint16_t fstate;
|
||||
/* symbol if NGHTTP2_HUFF_SYM flag set */
|
||||
uint8_t sym;
|
||||
} nghttp2_huff_decode;
|
||||
|
||||
typedef nghttp2_huff_decode huff_decode_table_type[16];
|
||||
|
||||
typedef struct {
|
||||
/* fstate is the current huffman decoding state. */
|
||||
uint16_t fstate;
|
||||
} nghttp2_hd_huff_decode_context;
|
||||
|
||||
typedef struct {
|
||||
/* The number of bits in this code */
|
||||
uint32_t nbits;
|
||||
/* Huffman code aligned to LSB */
|
||||
uint32_t code;
|
||||
} nghttp2_huff_sym;
|
||||
|
||||
extern const nghttp2_huff_sym huff_sym_table[];
|
||||
extern const nghttp2_huff_decode huff_decode_table[][16];
|
||||
|
||||
#endif /* NGHTTP2_HD_HUFFMAN_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,631 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nghttp2_net.h"
|
||||
|
||||
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) {
|
||||
uint16_t x = htons(n);
|
||||
memcpy(buf, &x, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) {
|
||||
uint32_t x = htonl(n);
|
||||
memcpy(buf, &x, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint16_t nghttp2_get_uint16(const uint8_t *data) {
|
||||
uint16_t n;
|
||||
memcpy(&n, data, sizeof(uint16_t));
|
||||
return ntohs(n);
|
||||
}
|
||||
|
||||
uint32_t nghttp2_get_uint32(const uint8_t *data) {
|
||||
uint32_t n;
|
||||
memcpy(&n, data, sizeof(uint32_t));
|
||||
return ntohl(n);
|
||||
}
|
||||
|
||||
/* Generated by gendowncasetbl.py */
|
||||
static const uint8_t DOWNCASE_TBL[] = {
|
||||
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
|
||||
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
|
||||
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
|
||||
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
|
||||
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
|
||||
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
|
||||
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
|
||||
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
|
||||
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
|
||||
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
|
||||
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
|
||||
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
|
||||
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
|
||||
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
|
||||
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
|
||||
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
|
||||
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
|
||||
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
|
||||
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
|
||||
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
|
||||
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
|
||||
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
|
||||
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
|
||||
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
|
||||
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
|
||||
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
|
||||
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
|
||||
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
|
||||
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
|
||||
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
|
||||
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
|
||||
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
|
||||
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
|
||||
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
|
||||
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
|
||||
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
|
||||
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
|
||||
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
|
||||
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
|
||||
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
|
||||
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
|
||||
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
|
||||
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
|
||||
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
|
||||
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
|
||||
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
|
||||
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
|
||||
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
|
||||
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
|
||||
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
|
||||
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
|
||||
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
|
||||
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
|
||||
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
|
||||
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
|
||||
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
|
||||
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
|
||||
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
|
||||
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
|
||||
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
|
||||
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
|
||||
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
|
||||
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
|
||||
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
|
||||
};
|
||||
|
||||
void nghttp2_downcase(uint8_t *s, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
s[i] = DOWNCASE_TBL[s[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* local_window_size
|
||||
* ^ *
|
||||
* | * recv_window_size
|
||||
* | * * ^
|
||||
* | * * |
|
||||
* 0+++++++++
|
||||
* | * * \
|
||||
* | * * | This rage is hidden in flow control. But it must be
|
||||
* v * * / kept in order to restore it when window size is enlarged.
|
||||
* recv_reduction
|
||||
* (+ for negative direction)
|
||||
*
|
||||
* recv_window_size could be negative if we decrease
|
||||
* local_window_size more than recv_window_size:
|
||||
*
|
||||
* local_window_size
|
||||
* ^ *
|
||||
* | *
|
||||
* | *
|
||||
* 0++++++++
|
||||
* | * ^ recv_window_size (negative)
|
||||
* | * |
|
||||
* v * *
|
||||
* recv_reduction
|
||||
*/
|
||||
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr) {
|
||||
if (*delta_ptr > 0) {
|
||||
int32_t recv_reduction_delta;
|
||||
int32_t delta;
|
||||
int32_t new_recv_window_size =
|
||||
nghttp2_max(0, *recv_window_size_ptr) - *delta_ptr;
|
||||
|
||||
if (new_recv_window_size >= 0) {
|
||||
*recv_window_size_ptr = new_recv_window_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delta = -new_recv_window_size;
|
||||
|
||||
/* The delta size is strictly more than received bytes. Increase
|
||||
local_window_size by that difference |delta|. */
|
||||
if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
*local_window_size_ptr += delta;
|
||||
/* If there is recv_reduction due to earlier window_size
|
||||
reduction, we have to adjust it too. */
|
||||
recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta);
|
||||
*recv_reduction_ptr -= recv_reduction_delta;
|
||||
if (*recv_window_size_ptr < 0) {
|
||||
*recv_window_size_ptr += recv_reduction_delta;
|
||||
} else {
|
||||
/* If *recv_window_size_ptr > 0, then those bytes are going to
|
||||
be returned to the remote peer (by WINDOW_UPDATE with the
|
||||
adjusted *delta_ptr), so it is effectively 0 now. We set to
|
||||
*recv_reduction_delta, because caller does not take into
|
||||
account it in *delta_ptr. */
|
||||
*recv_window_size_ptr = recv_reduction_delta;
|
||||
}
|
||||
/* recv_reduction_delta must be paid from *delta_ptr, since it was
|
||||
added in window size reduction (see below). */
|
||||
*delta_ptr -= recv_reduction_delta;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*local_window_size_ptr + *delta_ptr < 0 ||
|
||||
*recv_window_size_ptr < INT32_MIN - *delta_ptr ||
|
||||
*recv_reduction_ptr > INT32_MAX + *delta_ptr) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
/* Decreasing local window size. Note that we achieve this without
|
||||
noticing to the remote peer. To do this, we cut
|
||||
recv_window_size by -delta. This means that we don't send
|
||||
WINDOW_UPDATE for -delta bytes. */
|
||||
*local_window_size_ptr += *delta_ptr;
|
||||
*recv_window_size_ptr += *delta_ptr;
|
||||
*recv_reduction_ptr -= *delta_ptr;
|
||||
*delta_ptr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr) {
|
||||
int32_t recv_reduction_delta;
|
||||
int32_t delta;
|
||||
|
||||
delta = *delta_ptr;
|
||||
|
||||
assert(delta >= 0);
|
||||
|
||||
/* The delta size is strictly more than received bytes. Increase
|
||||
local_window_size by that difference |delta|. */
|
||||
if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
|
||||
*local_window_size_ptr += delta;
|
||||
/* If there is recv_reduction due to earlier window_size
|
||||
reduction, we have to adjust it too. */
|
||||
recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta);
|
||||
*recv_reduction_ptr -= recv_reduction_delta;
|
||||
|
||||
*recv_window_size_ptr += recv_reduction_delta;
|
||||
|
||||
/* recv_reduction_delta must be paid from *delta_ptr, since it was
|
||||
added in window size reduction (see below). */
|
||||
*delta_ptr -= recv_reduction_delta;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_should_send_window_update(int32_t local_window_size,
|
||||
int32_t recv_window_size) {
|
||||
return recv_window_size > 0 && recv_window_size >= local_window_size / 2;
|
||||
}
|
||||
|
||||
const char *nghttp2_strerror(int error_code) {
|
||||
switch (error_code) {
|
||||
case 0:
|
||||
return "Success";
|
||||
case NGHTTP2_ERR_INVALID_ARGUMENT:
|
||||
return "Invalid argument";
|
||||
case NGHTTP2_ERR_BUFFER_ERROR:
|
||||
return "Out of buffer space";
|
||||
case NGHTTP2_ERR_UNSUPPORTED_VERSION:
|
||||
return "Unsupported SPDY version";
|
||||
case NGHTTP2_ERR_WOULDBLOCK:
|
||||
return "Operation would block";
|
||||
case NGHTTP2_ERR_PROTO:
|
||||
return "Protocol error";
|
||||
case NGHTTP2_ERR_INVALID_FRAME:
|
||||
return "Invalid frame octets";
|
||||
case NGHTTP2_ERR_EOF:
|
||||
return "EOF";
|
||||
case NGHTTP2_ERR_DEFERRED:
|
||||
return "Data transfer deferred";
|
||||
case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE:
|
||||
return "No more Stream ID available";
|
||||
case NGHTTP2_ERR_STREAM_CLOSED:
|
||||
return "Stream was already closed or invalid";
|
||||
case NGHTTP2_ERR_STREAM_CLOSING:
|
||||
return "Stream is closing";
|
||||
case NGHTTP2_ERR_STREAM_SHUT_WR:
|
||||
return "The transmission is not allowed for this stream";
|
||||
case NGHTTP2_ERR_INVALID_STREAM_ID:
|
||||
return "Stream ID is invalid";
|
||||
case NGHTTP2_ERR_INVALID_STREAM_STATE:
|
||||
return "Invalid stream state";
|
||||
case NGHTTP2_ERR_DEFERRED_DATA_EXIST:
|
||||
return "Another DATA frame has already been deferred";
|
||||
case NGHTTP2_ERR_START_STREAM_NOT_ALLOWED:
|
||||
return "request HEADERS is not allowed";
|
||||
case NGHTTP2_ERR_GOAWAY_ALREADY_SENT:
|
||||
return "GOAWAY has already been sent";
|
||||
case NGHTTP2_ERR_INVALID_HEADER_BLOCK:
|
||||
return "Invalid header block";
|
||||
case NGHTTP2_ERR_INVALID_STATE:
|
||||
return "Invalid state";
|
||||
case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE:
|
||||
return "The user callback function failed due to the temporal error";
|
||||
case NGHTTP2_ERR_FRAME_SIZE_ERROR:
|
||||
return "The length of the frame is invalid";
|
||||
case NGHTTP2_ERR_HEADER_COMP:
|
||||
return "Header compression/decompression error";
|
||||
case NGHTTP2_ERR_FLOW_CONTROL:
|
||||
return "Flow control error";
|
||||
case NGHTTP2_ERR_INSUFF_BUFSIZE:
|
||||
return "Insufficient buffer size given to function";
|
||||
case NGHTTP2_ERR_PAUSE:
|
||||
return "Callback was paused by the application";
|
||||
case NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS:
|
||||
return "Too many inflight SETTINGS";
|
||||
case NGHTTP2_ERR_PUSH_DISABLED:
|
||||
return "Server push is disabled by peer";
|
||||
case NGHTTP2_ERR_DATA_EXIST:
|
||||
return "DATA or HEADERS frame has already been submitted for the stream";
|
||||
case NGHTTP2_ERR_SESSION_CLOSING:
|
||||
return "The current session is closing";
|
||||
case NGHTTP2_ERR_HTTP_HEADER:
|
||||
return "Invalid HTTP header field was received";
|
||||
case NGHTTP2_ERR_HTTP_MESSAGING:
|
||||
return "Violation in HTTP messaging rule";
|
||||
case NGHTTP2_ERR_REFUSED_STREAM:
|
||||
return "Stream was refused";
|
||||
case NGHTTP2_ERR_INTERNAL:
|
||||
return "Internal error";
|
||||
case NGHTTP2_ERR_CANCEL:
|
||||
return "Cancel";
|
||||
case NGHTTP2_ERR_SETTINGS_EXPECTED:
|
||||
return "When a local endpoint expects to receive SETTINGS frame, it "
|
||||
"receives an other type of frame";
|
||||
case NGHTTP2_ERR_NOMEM:
|
||||
return "Out of memory";
|
||||
case NGHTTP2_ERR_CALLBACK_FAILURE:
|
||||
return "The user callback function failed";
|
||||
case NGHTTP2_ERR_BAD_CLIENT_MAGIC:
|
||||
return "Received bad client magic byte string";
|
||||
case NGHTTP2_ERR_FLOODED:
|
||||
return "Flooding was detected in this HTTP/2 session, and it must be "
|
||||
"closed";
|
||||
case NGHTTP2_ERR_TOO_MANY_SETTINGS:
|
||||
return "SETTINGS frame contained more than the maximum allowed entries";
|
||||
default:
|
||||
return "Unknown error code";
|
||||
}
|
||||
}
|
||||
|
||||
/* Generated by gennmchartbl.py */
|
||||
static const int VALID_HD_NAME_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
|
||||
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
|
||||
0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */,
|
||||
0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */,
|
||||
0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */,
|
||||
0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
|
||||
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */,
|
||||
0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */,
|
||||
0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */,
|
||||
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_header_name(const uint8_t *name, size_t len) {
|
||||
const uint8_t *last;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (*name == ':') {
|
||||
if (len == 1) {
|
||||
return 0;
|
||||
}
|
||||
++name;
|
||||
--len;
|
||||
}
|
||||
for (last = name + len; name != last; ++name) {
|
||||
if (!VALID_HD_NAME_CHARS[*name]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generated by genvchartbl.py */
|
||||
static const int VALID_HD_VALUE_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
|
||||
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
|
||||
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
|
||||
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
|
||||
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
|
||||
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
|
||||
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
|
||||
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
|
||||
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
|
||||
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
|
||||
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
|
||||
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
|
||||
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
|
||||
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
|
||||
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
|
||||
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
|
||||
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
|
||||
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
|
||||
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
|
||||
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
|
||||
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
|
||||
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
|
||||
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
|
||||
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
|
||||
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
|
||||
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
|
||||
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
|
||||
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
|
||||
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
|
||||
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
|
||||
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
|
||||
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
|
||||
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
|
||||
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_header_value(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
for (last = value + len; value != last; ++value) {
|
||||
if (!VALID_HD_VALUE_CHARS[*value]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generated by genauthroitychartbl.py */
|
||||
static char VALID_AUTHORITY_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
|
||||
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||
0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
|
||||
0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||
0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_authority(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
for (last = value + len; value != last; ++value) {
|
||||
if (!VALID_AUTHORITY_CHARS[*value]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) {
|
||||
if (len == 0) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
memcpy(dest, src, len);
|
||||
|
||||
return dest + len;
|
||||
}
|
||||
|
||||
const char *nghttp2_http2_strerror(uint32_t error_code) {
|
||||
switch (error_code) {
|
||||
case NGHTTP2_NO_ERROR:
|
||||
return "NO_ERROR";
|
||||
case NGHTTP2_PROTOCOL_ERROR:
|
||||
return "PROTOCOL_ERROR";
|
||||
case NGHTTP2_INTERNAL_ERROR:
|
||||
return "INTERNAL_ERROR";
|
||||
case NGHTTP2_FLOW_CONTROL_ERROR:
|
||||
return "FLOW_CONTROL_ERROR";
|
||||
case NGHTTP2_SETTINGS_TIMEOUT:
|
||||
return "SETTINGS_TIMEOUT";
|
||||
case NGHTTP2_STREAM_CLOSED:
|
||||
return "STREAM_CLOSED";
|
||||
case NGHTTP2_FRAME_SIZE_ERROR:
|
||||
return "FRAME_SIZE_ERROR";
|
||||
case NGHTTP2_REFUSED_STREAM:
|
||||
return "REFUSED_STREAM";
|
||||
case NGHTTP2_CANCEL:
|
||||
return "CANCEL";
|
||||
case NGHTTP2_COMPRESSION_ERROR:
|
||||
return "COMPRESSION_ERROR";
|
||||
case NGHTTP2_CONNECT_ERROR:
|
||||
return "CONNECT_ERROR";
|
||||
case NGHTTP2_ENHANCE_YOUR_CALM:
|
||||
return "ENHANCE_YOUR_CALM";
|
||||
case NGHTTP2_INADEQUATE_SECURITY:
|
||||
return "INADEQUATE_SECURITY";
|
||||
case NGHTTP2_HTTP_1_1_REQUIRED:
|
||||
return "HTTP_1_1_REQUIRED";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HELPER_H
|
||||
#define NGHTTP2_HELPER_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
|
||||
|
||||
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
|
||||
|
||||
#define nghttp2_struct_of(ptr, type, member) \
|
||||
((type *)(void *)((char *)(ptr)-offsetof(type, member)))
|
||||
|
||||
/*
|
||||
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
||||
* network byte order.
|
||||
*/
|
||||
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n);
|
||||
|
||||
/*
|
||||
* Copies 4 byte unsigned integer |n| in host byte order to |buf| in
|
||||
* network byte order.
|
||||
*/
|
||||
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n);
|
||||
|
||||
/*
|
||||
* Retrieves 2 byte unsigned integer stored in |data| in network byte
|
||||
* order and returns it in host byte order.
|
||||
*/
|
||||
uint16_t nghttp2_get_uint16(const uint8_t *data);
|
||||
|
||||
/*
|
||||
* Retrieves 4 byte unsigned integer stored in |data| in network byte
|
||||
* order and returns it in host byte order.
|
||||
*/
|
||||
uint32_t nghttp2_get_uint32(const uint8_t *data);
|
||||
|
||||
void nghttp2_downcase(uint8_t *s, size_t len);
|
||||
|
||||
/*
|
||||
* Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|,
|
||||
* |*recv_reduction_ptr| with |*delta_ptr| which is the
|
||||
* WINDOW_UPDATE's window_size_increment sent from local side. If
|
||||
* |delta| is strictly larger than |*recv_window_size_ptr|,
|
||||
* |*local_window_size_ptr| is increased by delta -
|
||||
* *recv_window_size_ptr. If |delta| is negative,
|
||||
* |*local_window_size_ptr| is decreased by delta.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FLOW_CONTROL
|
||||
* local_window_size overflow or gets negative.
|
||||
*/
|
||||
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr);
|
||||
|
||||
/*
|
||||
* This function works like nghttp2_adjust_local_window_size(). The
|
||||
* difference is that this function assumes *delta_ptr >= 0, and
|
||||
* *recv_window_size_ptr is not decreased by *delta_ptr.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FLOW_CONTROL
|
||||
* local_window_size overflow or gets negative.
|
||||
*/
|
||||
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr);
|
||||
|
||||
/*
|
||||
* Returns non-zero if the function decided that WINDOW_UPDATE should
|
||||
* be sent.
|
||||
*/
|
||||
int nghttp2_should_send_window_update(int32_t local_window_size,
|
||||
int32_t recv_window_size);
|
||||
|
||||
/*
|
||||
* Copies the buffer |src| of length |len| to the destination pointed
|
||||
* by the |dest|, assuming that the |dest| is at lest |len| bytes long
|
||||
* . Returns dest + len.
|
||||
*/
|
||||
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
|
||||
|
||||
#endif /* NGHTTP2_HELPER_H */
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_http.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
static uint8_t downcase(uint8_t c) {
|
||||
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
|
||||
}
|
||||
|
||||
static int memieq(const void *a, const void *b, size_t n) {
|
||||
size_t i;
|
||||
const uint8_t *aa = a, *bb = b;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (downcase(aa[i]) != downcase(bb[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
|
||||
|
||||
static int64_t parse_uint(const uint8_t *s, size_t len) {
|
||||
int64_t n = 0;
|
||||
size_t i;
|
||||
if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
if ('0' <= s[i] && s[i] <= '9') {
|
||||
if (n > INT64_MAX / 10) {
|
||||
return -1;
|
||||
}
|
||||
n *= 10;
|
||||
if (n > INT64_MAX - (s[i] - '0')) {
|
||||
return -1;
|
||||
}
|
||||
n += s[i] - '0';
|
||||
continue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int lws(const uint8_t *s, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (s[i] != ' ' && s[i] != '\t') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
|
||||
int flag) {
|
||||
if (stream->http_flags & flag) {
|
||||
return 0;
|
||||
}
|
||||
if (lws(nv->value->base, nv->value->len)) {
|
||||
return 0;
|
||||
}
|
||||
stream->http_flags = (uint16_t)(stream->http_flags | flag);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int expect_response_body(nghttp2_stream *stream) {
|
||||
return (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_HEAD) == 0 &&
|
||||
stream->status_code / 100 != 1 && stream->status_code != 304 &&
|
||||
stream->status_code != 204;
|
||||
}
|
||||
|
||||
/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
|
||||
header field to represent system-wide OPTIONS request. Otherwise,
|
||||
:path header field value must start with "/". This function must
|
||||
be called after ":method" header field was received. This function
|
||||
returns nonzero if path is valid.*/
|
||||
static int check_path(nghttp2_stream *stream) {
|
||||
return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
|
||||
}
|
||||
|
||||
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
||||
int trailer, int connect_protocol) {
|
||||
if (nv->name->base[0] == ':') {
|
||||
if (trailer ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nv->token) {
|
||||
case NGHTTP2_TOKEN__AUTHORITY:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__METHOD:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
switch (nv->value->len) {
|
||||
case 4:
|
||||
if (lstreq("HEAD", nv->value->base, nv->value->len)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
switch (nv->value->base[6]) {
|
||||
case 'T':
|
||||
if (lstreq("CONNECT", nv->value->base, nv->value->len)) {
|
||||
if (stream->stream_id % 2 == 0) {
|
||||
/* we won't allow CONNECT for push */
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
if (lstreq("OPTIONS", nv->value->base, nv->value->len)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__PATH:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if (nv->value->base[0] == '/') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
|
||||
} else if (nv->value->len == 1 && nv->value->base[0] == '*') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__SCHEME:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) ||
|
||||
(nv->value->len == 5 && memieq("https", nv->value->base, 5))) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__PROTOCOL:
|
||||
if (!connect_protocol) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN_HOST:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN_CONTENT_LENGTH: {
|
||||
if (stream->content_length != -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->content_length = parse_uint(nv->value->base, nv->value->len);
|
||||
if (stream->content_length == -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* disallowed header fields */
|
||||
case NGHTTP2_TOKEN_CONNECTION:
|
||||
case NGHTTP2_TOKEN_KEEP_ALIVE:
|
||||
case NGHTTP2_TOKEN_PROXY_CONNECTION:
|
||||
case NGHTTP2_TOKEN_TRANSFER_ENCODING:
|
||||
case NGHTTP2_TOKEN_UPGRADE:
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
case NGHTTP2_TOKEN_TE:
|
||||
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
if (nv->name->base[0] != ':') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
||||
int trailer) {
|
||||
if (nv->name->base[0] == ':') {
|
||||
if (trailer ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nv->token) {
|
||||
case NGHTTP2_TOKEN__STATUS: {
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if (nv->value->len != 3) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
|
||||
if (stream->status_code == -1 || stream->status_code == 101) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_TOKEN_CONTENT_LENGTH: {
|
||||
if (stream->status_code == 204) {
|
||||
/* content-length header field in 204 response is prohibited by
|
||||
RFC 7230. But some widely used servers send content-length:
|
||||
0. Until they get fixed, we ignore it. */
|
||||
if (stream->content_length != -1) {
|
||||
/* Found multiple content-length field */
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if (!lstrieq("0", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->content_length = 0;
|
||||
return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (stream->status_code / 100 == 1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
/* https://tools.ietf.org/html/rfc7230#section-3.3.3 */
|
||||
if (stream->status_code / 100 == 2 &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
|
||||
return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (stream->content_length != -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->content_length = parse_uint(nv->value->base, nv->value->len);
|
||||
if (stream->content_length == -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* disallowed header fields */
|
||||
case NGHTTP2_TOKEN_CONNECTION:
|
||||
case NGHTTP2_TOKEN_KEEP_ALIVE:
|
||||
case NGHTTP2_TOKEN_PROXY_CONNECTION:
|
||||
case NGHTTP2_TOKEN_TRANSFER_ENCODING:
|
||||
case NGHTTP2_TOKEN_UPGRADE:
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
case NGHTTP2_TOKEN_TE:
|
||||
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
if (nv->name->base[0] != ':') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_scheme(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
last = value + len;
|
||||
++value;
|
||||
|
||||
for (; value != last; ++value) {
|
||||
if (!(('A' <= *value && *value <= 'Z') ||
|
||||
('a' <= *value && *value <= 'z') ||
|
||||
('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
|
||||
*value == '.')) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||
nghttp2_frame *frame, nghttp2_hd_nv *nv,
|
||||
int trailer) {
|
||||
int rv;
|
||||
|
||||
/* We are strict for pseudo header field. One bad character should
|
||||
lead to fail. OTOH, we should be a bit forgiving for regular
|
||||
headers, since existing public internet has so much illegal
|
||||
headers floating around and if we kill the stream because of
|
||||
this, we may disrupt many web sites and/or libraries. So we
|
||||
become conservative here, and just ignore those illegal regular
|
||||
headers. */
|
||||
if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) {
|
||||
size_t i;
|
||||
if (nv->name->len > 0 && nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
/* header field name must be lower-cased without exception */
|
||||
for (i = 0; i < nv->name->len; ++i) {
|
||||
uint8_t c = nv->name->base[i];
|
||||
if ('A' <= c && c <= 'Z') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
/* When ignoring regular headers, we set this flag so that we
|
||||
still enforce header field ordering rule for pseudo header
|
||||
fields. */
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
|
||||
nv->token == NGHTTP2_TOKEN_HOST) {
|
||||
rv = nghttp2_check_authority(nv->value->base, nv->value->len);
|
||||
} else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
|
||||
rv = check_scheme(nv->value->base, nv->value->len);
|
||||
} else {
|
||||
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
assert(nv->name->len > 0);
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
/* When ignoring regular headers, we set this flag so that we
|
||||
still enforce header field ordering rule for pseudo header
|
||||
fields. */
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||
return http_request_on_header(stream, nv, trailer,
|
||||
session->server &&
|
||||
session->pending_enable_connect_protocol);
|
||||
}
|
||||
|
||||
return http_response_on_header(stream, nv, trailer);
|
||||
}
|
||||
|
||||
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame) {
|
||||
if (!(stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
|
||||
if ((stream->http_flags &
|
||||
(NGHTTP2_HTTP_FLAG__SCHEME | NGHTTP2_HTTP_FLAG__PATH)) ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) {
|
||||
return -1;
|
||||
}
|
||||
stream->content_length = -1;
|
||||
} else {
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
|
||||
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
|
||||
(stream->http_flags &
|
||||
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) == 0 ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0)) {
|
||||
return -1;
|
||||
}
|
||||
if (!check_path(stream)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||
/* we are going to reuse data fields for upcoming response. Clear
|
||||
them now, except for method flags. */
|
||||
stream->http_flags &= NGHTTP2_HTTP_FLAG_METH_ALL;
|
||||
stream->content_length = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__STATUS) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->status_code / 100 == 1) {
|
||||
/* non-final response */
|
||||
stream->http_flags =
|
||||
(uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
|
||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
||||
stream->content_length = -1;
|
||||
stream->status_code = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->http_flags =
|
||||
(uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
||||
|
||||
if (!expect_response_body(stream)) {
|
||||
stream->content_length = 0;
|
||||
} else if (stream->http_flags & (NGHTTP2_HTTP_FLAG_METH_CONNECT |
|
||||
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)) {
|
||||
stream->content_length = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame) {
|
||||
(void)stream;
|
||||
|
||||
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream) {
|
||||
if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->content_length != -1 &&
|
||||
stream->content_length != stream->recv_content_length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n) {
|
||||
stream->recv_content_length += (int64_t)n;
|
||||
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
|
||||
(stream->content_length != -1 &&
|
||||
stream->recv_content_length > stream->content_length)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame) {
|
||||
const nghttp2_nv *nva;
|
||||
size_t nvlen;
|
||||
size_t i;
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
nva = frame->headers.nva;
|
||||
nvlen = frame->headers.nvlen;
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
nva = frame->push_promise.nva;
|
||||
nvlen = frame->push_promise.nvlen;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO we should do this strictly. */
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
const nghttp2_nv *nv = &nva[i];
|
||||
if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
|
||||
memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
|
||||
return;
|
||||
}
|
||||
if (lstreq("HEAD", nv->value, nv->valuelen)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HTTP_H
|
||||
#define NGHTTP2_HTTP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_session.h"
|
||||
#include "nghttp2_stream.h"
|
||||
|
||||
/*
|
||||
* This function is called when HTTP header field |nv| in |frame| is
|
||||
* received for |stream|. This function will validate |nv| against
|
||||
* the current state of stream.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_HTTP_HEADER
|
||||
* Invalid HTTP header field was received.
|
||||
* NGHTTP2_ERR_IGN_HTTP_HEADER
|
||||
* Invalid HTTP header field was received but it can be treated as
|
||||
* if it was not received because of compatibility reasons.
|
||||
*/
|
||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||
nghttp2_frame *frame, nghttp2_hd_nv *nv,
|
||||
int trailer);
|
||||
|
||||
/*
|
||||
* This function is called when request header is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* This function is called when response header is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_response_headers(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* This function is called trailer header (for both request and
|
||||
* response) is received. This function performs validation and
|
||||
* returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* This function is called when END_STREAM flag is seen in incoming
|
||||
* frame. This function performs validation and returns 0 if it
|
||||
* succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* This function is called when chunk of data is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
|
||||
|
||||
/*
|
||||
* This function inspects header field in |frame| and records its
|
||||
* method in stream->http_flags. If frame->hd.type is neither
|
||||
* NGHTTP2_HEADERS nor NGHTTP2_PUSH_PROMISE, this function does
|
||||
* nothing.
|
||||
*/
|
||||
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
#endif /* NGHTTP2_HTTP_H */
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_INT_H
|
||||
#define NGHTTP2_INT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/* Macros, types and constants for internal use */
|
||||
|
||||
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
|
||||
typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
|
||||
|
||||
/* Internal error code. They must be in the range [-499, -100],
|
||||
inclusive. */
|
||||
typedef enum {
|
||||
NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
|
||||
NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
|
||||
NGHTTP2_ERR_IGN_PAYLOAD = -104,
|
||||
/*
|
||||
* Invalid HTTP header field was received but it can be treated as
|
||||
* if it was not received because of compatibility reasons.
|
||||
*/
|
||||
NGHTTP2_ERR_IGN_HTTP_HEADER = -105,
|
||||
/*
|
||||
* Invalid HTTP header field was received, and it is ignored.
|
||||
* Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke
|
||||
* nghttp2_on_invalid_header_callback.
|
||||
*/
|
||||
NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106
|
||||
} nghttp2_internal_error;
|
||||
|
||||
#endif /* NGHTTP2_INT_H */
|
||||
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2020 nghttp2 contributors
|
||||
* Copyright (c) 2018 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_ksl.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
static size_t ksl_nodelen(size_t keylen) {
|
||||
return (sizeof(nghttp2_ksl_node) + keylen - sizeof(uint64_t) + 0xf) &
|
||||
(size_t)~0xf;
|
||||
}
|
||||
|
||||
static size_t ksl_blklen(size_t nodelen) {
|
||||
return sizeof(nghttp2_ksl_blk) + nodelen * NGHTTP2_KSL_MAX_NBLK -
|
||||
sizeof(uint64_t);
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_node_set_key sets |key| to |node|.
|
||||
*/
|
||||
static void ksl_node_set_key(nghttp2_ksl *ksl, nghttp2_ksl_node *node,
|
||||
const void *key) {
|
||||
memcpy(node->key, key, ksl->keylen);
|
||||
}
|
||||
|
||||
int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen,
|
||||
nghttp2_mem *mem) {
|
||||
size_t nodelen = ksl_nodelen(keylen);
|
||||
size_t blklen = ksl_blklen(nodelen);
|
||||
nghttp2_ksl_blk *head;
|
||||
|
||||
ksl->head = nghttp2_mem_malloc(mem, blklen);
|
||||
if (!ksl->head) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
ksl->front = ksl->back = ksl->head;
|
||||
ksl->compar = compar;
|
||||
ksl->keylen = keylen;
|
||||
ksl->nodelen = nodelen;
|
||||
ksl->n = 0;
|
||||
ksl->mem = mem;
|
||||
|
||||
head = ksl->head;
|
||||
head->next = head->prev = NULL;
|
||||
head->n = 0;
|
||||
head->leaf = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_free_blk frees |blk| recursively.
|
||||
*/
|
||||
static void ksl_free_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) {
|
||||
size_t i;
|
||||
|
||||
if (!blk->leaf) {
|
||||
for (i = 0; i < blk->n; ++i) {
|
||||
ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_mem_free(ksl->mem, blk);
|
||||
}
|
||||
|
||||
void nghttp2_ksl_free(nghttp2_ksl *ksl) {
|
||||
if (!ksl) {
|
||||
return;
|
||||
}
|
||||
|
||||
ksl_free_blk(ksl, ksl->head);
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_split_blk splits |blk| into 2 nghttp2_ksl_blk objects. The new
|
||||
* nghttp2_ksl_blk is always the "right" block.
|
||||
*
|
||||
* It returns the pointer to the nghttp2_ksl_blk created which is the
|
||||
* located at the right of |blk|, or NULL which indicates out of
|
||||
* memory error.
|
||||
*/
|
||||
static nghttp2_ksl_blk *ksl_split_blk(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk) {
|
||||
nghttp2_ksl_blk *rblk;
|
||||
|
||||
rblk = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
|
||||
if (rblk == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rblk->next = blk->next;
|
||||
blk->next = rblk;
|
||||
if (rblk->next) {
|
||||
rblk->next->prev = rblk;
|
||||
} else if (ksl->back == blk) {
|
||||
ksl->back = rblk;
|
||||
}
|
||||
rblk->prev = blk;
|
||||
rblk->leaf = blk->leaf;
|
||||
|
||||
rblk->n = blk->n / 2;
|
||||
|
||||
memcpy(rblk->nodes, blk->nodes + ksl->nodelen * (blk->n - rblk->n),
|
||||
ksl->nodelen * rblk->n);
|
||||
|
||||
blk->n -= rblk->n;
|
||||
|
||||
assert(blk->n >= NGHTTP2_KSL_MIN_NBLK);
|
||||
assert(rblk->n >= NGHTTP2_KSL_MIN_NBLK);
|
||||
|
||||
return rblk;
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_split_node splits a node included in |blk| at the position |i|
|
||||
* into 2 adjacent nodes. The new node is always inserted at the
|
||||
* position |i+1|.
|
||||
*
|
||||
* It returns 0 if it succeeds, or one of the following negative error
|
||||
* codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
static int ksl_split_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
|
||||
nghttp2_ksl_node *node;
|
||||
nghttp2_ksl_blk *lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk, *rblk;
|
||||
|
||||
rblk = ksl_split_blk(ksl, lblk);
|
||||
if (rblk == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
memmove(blk->nodes + (i + 2) * ksl->nodelen,
|
||||
blk->nodes + (i + 1) * ksl->nodelen,
|
||||
ksl->nodelen * (blk->n - (i + 1)));
|
||||
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i + 1);
|
||||
node->blk = rblk;
|
||||
++blk->n;
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
|
||||
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_split_head splits a head (root) block. It increases the height
|
||||
* of skip list by 1.
|
||||
*
|
||||
* It returns 0 if it succeeds, or one of the following negative error
|
||||
* codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
static int ksl_split_head(nghttp2_ksl *ksl) {
|
||||
nghttp2_ksl_blk *rblk = NULL, *lblk, *nhead = NULL;
|
||||
nghttp2_ksl_node *node;
|
||||
|
||||
rblk = ksl_split_blk(ksl, ksl->head);
|
||||
if (rblk == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
lblk = ksl->head;
|
||||
|
||||
nhead = nghttp2_mem_malloc(ksl->mem, ksl_blklen(ksl->nodelen));
|
||||
if (nhead == NULL) {
|
||||
nghttp2_mem_free(ksl->mem, rblk);
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
nhead->next = nhead->prev = NULL;
|
||||
nhead->n = 2;
|
||||
nhead->leaf = 0;
|
||||
|
||||
node = nghttp2_ksl_nth_node(ksl, nhead, 0);
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
||||
node->blk = lblk;
|
||||
|
||||
node = nghttp2_ksl_nth_node(ksl, nhead, 1);
|
||||
ksl_node_set_key(ksl, node,
|
||||
nghttp2_ksl_nth_node(ksl, rblk, rblk->n - 1)->key);
|
||||
node->blk = rblk;
|
||||
|
||||
ksl->head = nhead;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* insert_node inserts a node whose key is |key| with the associated
|
||||
* |data| at the index of |i|. This function assumes that the number
|
||||
* of nodes contained by |blk| is strictly less than
|
||||
* NGHTTP2_KSL_MAX_NBLK.
|
||||
*/
|
||||
static void ksl_insert_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i,
|
||||
const nghttp2_ksl_key *key, void *data) {
|
||||
nghttp2_ksl_node *node;
|
||||
|
||||
assert(blk->n < NGHTTP2_KSL_MAX_NBLK);
|
||||
|
||||
memmove(blk->nodes + (i + 1) * ksl->nodelen, blk->nodes + i * ksl->nodelen,
|
||||
ksl->nodelen * (blk->n - i));
|
||||
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
ksl_node_set_key(ksl, node, key);
|
||||
node->data = data;
|
||||
|
||||
++blk->n;
|
||||
}
|
||||
|
||||
static size_t ksl_bsearch(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk,
|
||||
const nghttp2_ksl_key *key,
|
||||
nghttp2_ksl_compar compar) {
|
||||
ssize_t left = -1, right = (ssize_t)blk->n, mid;
|
||||
nghttp2_ksl_node *node;
|
||||
|
||||
while (right - left > 1) {
|
||||
mid = (left + right) / 2;
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, (size_t)mid);
|
||||
if (compar((nghttp2_ksl_key *)node->key, key)) {
|
||||
left = mid;
|
||||
} else {
|
||||
right = mid;
|
||||
}
|
||||
}
|
||||
|
||||
return (size_t)right;
|
||||
}
|
||||
|
||||
int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
|
||||
const nghttp2_ksl_key *key, void *data) {
|
||||
nghttp2_ksl_blk *blk = ksl->head;
|
||||
nghttp2_ksl_node *node;
|
||||
size_t i;
|
||||
int rv;
|
||||
|
||||
if (blk->n == NGHTTP2_KSL_MAX_NBLK) {
|
||||
rv = ksl_split_head(ksl);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
blk = ksl->head;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, key, ksl->compar);
|
||||
|
||||
if (blk->leaf) {
|
||||
if (i < blk->n &&
|
||||
!ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) {
|
||||
if (it) {
|
||||
*it = nghttp2_ksl_end(ksl);
|
||||
}
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
ksl_insert_node(ksl, blk, i, key, data);
|
||||
++ksl->n;
|
||||
if (it) {
|
||||
nghttp2_ksl_it_init(it, ksl, blk, i);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (i == blk->n) {
|
||||
/* This insertion extends the largest key in this subtree. */
|
||||
for (; !blk->leaf;) {
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1);
|
||||
if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) {
|
||||
rv = ksl_split_node(ksl, blk, blk->n - 1);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1);
|
||||
}
|
||||
ksl_node_set_key(ksl, node, key);
|
||||
blk = node->blk;
|
||||
}
|
||||
ksl_insert_node(ksl, blk, blk->n, key, data);
|
||||
++ksl->n;
|
||||
if (it) {
|
||||
nghttp2_ksl_it_init(it, ksl, blk, blk->n - 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
if (node->blk->n == NGHTTP2_KSL_MAX_NBLK) {
|
||||
rv = ksl_split_node(ksl, blk, i);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
if (ksl->compar((nghttp2_ksl_key *)node->key, key)) {
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i + 1);
|
||||
if (ksl->compar((nghttp2_ksl_key *)node->key, key)) {
|
||||
ksl_node_set_key(ksl, node, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blk = node->blk;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_remove_node removes the node included in |blk| at the index of
|
||||
* |i|.
|
||||
*/
|
||||
static void ksl_remove_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
|
||||
memmove(blk->nodes + i * ksl->nodelen, blk->nodes + (i + 1) * ksl->nodelen,
|
||||
ksl->nodelen * (blk->n - (i + 1)));
|
||||
|
||||
--blk->n;
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_merge_node merges 2 nodes which are the nodes at the index of
|
||||
* |i| and |i + 1|.
|
||||
*
|
||||
* If |blk| is the direct descendant of head (root) block and the head
|
||||
* block contains just 2 nodes, the merged block becomes head block,
|
||||
* which decreases the height of |ksl| by 1.
|
||||
*
|
||||
* This function returns the pointer to the merged block.
|
||||
*/
|
||||
static nghttp2_ksl_blk *ksl_merge_node(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk,
|
||||
size_t i) {
|
||||
nghttp2_ksl_blk *lblk, *rblk;
|
||||
|
||||
assert(i + 1 < blk->n);
|
||||
|
||||
lblk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
|
||||
rblk = nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk;
|
||||
|
||||
assert(lblk->n + rblk->n < NGHTTP2_KSL_MAX_NBLK);
|
||||
|
||||
memcpy(lblk->nodes + ksl->nodelen * lblk->n, rblk->nodes,
|
||||
ksl->nodelen * rblk->n);
|
||||
|
||||
lblk->n += rblk->n;
|
||||
lblk->next = rblk->next;
|
||||
if (lblk->next) {
|
||||
lblk->next->prev = lblk;
|
||||
} else if (ksl->back == rblk) {
|
||||
ksl->back = lblk;
|
||||
}
|
||||
|
||||
nghttp2_mem_free(ksl->mem, rblk);
|
||||
|
||||
if (ksl->head == blk && blk->n == 2) {
|
||||
nghttp2_mem_free(ksl->mem, ksl->head);
|
||||
ksl->head = lblk;
|
||||
} else {
|
||||
ksl_remove_node(ksl, blk, i + 1);
|
||||
ksl_node_set_key(ksl, nghttp2_ksl_nth_node(ksl, blk, i),
|
||||
nghttp2_ksl_nth_node(ksl, lblk, lblk->n - 1)->key);
|
||||
}
|
||||
|
||||
return lblk;
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_shift_left moves the first node in blk->nodes[i]->blk->nodes to
|
||||
* blk->nodes[i - 1]->blk->nodes.
|
||||
*/
|
||||
static void ksl_shift_left(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
|
||||
nghttp2_ksl_node *lnode, *rnode, *dest, *src;
|
||||
|
||||
assert(i > 0);
|
||||
|
||||
lnode = nghttp2_ksl_nth_node(ksl, blk, i - 1);
|
||||
rnode = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
assert(lnode->blk->n < NGHTTP2_KSL_MAX_NBLK);
|
||||
assert(rnode->blk->n > NGHTTP2_KSL_MIN_NBLK);
|
||||
|
||||
dest = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n);
|
||||
src = nghttp2_ksl_nth_node(ksl, rnode->blk, 0);
|
||||
|
||||
memcpy(dest, src, ksl->nodelen);
|
||||
ksl_node_set_key(ksl, lnode, dest->key);
|
||||
++lnode->blk->n;
|
||||
|
||||
--rnode->blk->n;
|
||||
memmove(rnode->blk->nodes, rnode->blk->nodes + ksl->nodelen,
|
||||
ksl->nodelen * rnode->blk->n);
|
||||
}
|
||||
|
||||
/*
|
||||
* ksl_shift_right moves the last node in blk->nodes[i]->blk->nodes to
|
||||
* blk->nodes[i + 1]->blk->nodes.
|
||||
*/
|
||||
static void ksl_shift_right(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t i) {
|
||||
nghttp2_ksl_node *lnode, *rnode, *dest, *src;
|
||||
|
||||
assert(i < blk->n - 1);
|
||||
|
||||
lnode = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
rnode = nghttp2_ksl_nth_node(ksl, blk, i + 1);
|
||||
|
||||
assert(lnode->blk->n > NGHTTP2_KSL_MIN_NBLK);
|
||||
assert(rnode->blk->n < NGHTTP2_KSL_MAX_NBLK);
|
||||
|
||||
memmove(rnode->blk->nodes + ksl->nodelen, rnode->blk->nodes,
|
||||
ksl->nodelen * rnode->blk->n);
|
||||
++rnode->blk->n;
|
||||
|
||||
dest = nghttp2_ksl_nth_node(ksl, rnode->blk, 0);
|
||||
src = nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1);
|
||||
|
||||
memcpy(dest, src, ksl->nodelen);
|
||||
|
||||
--lnode->blk->n;
|
||||
ksl_node_set_key(
|
||||
ksl, lnode,
|
||||
nghttp2_ksl_nth_node(ksl, lnode->blk, lnode->blk->n - 1)->key);
|
||||
}
|
||||
|
||||
/*
|
||||
* key_equal returns nonzero if |lhs| and |rhs| are equal using the
|
||||
* function |compar|.
|
||||
*/
|
||||
static int key_equal(nghttp2_ksl_compar compar, const nghttp2_ksl_key *lhs,
|
||||
const nghttp2_ksl_key *rhs) {
|
||||
return !compar(lhs, rhs) && !compar(rhs, lhs);
|
||||
}
|
||||
|
||||
int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
|
||||
const nghttp2_ksl_key *key) {
|
||||
nghttp2_ksl_blk *blk = ksl->head;
|
||||
nghttp2_ksl_node *node;
|
||||
size_t i;
|
||||
|
||||
if (!blk->leaf && blk->n == 2 &&
|
||||
nghttp2_ksl_nth_node(ksl, blk, 0)->blk->n == NGHTTP2_KSL_MIN_NBLK &&
|
||||
nghttp2_ksl_nth_node(ksl, blk, 1)->blk->n == NGHTTP2_KSL_MIN_NBLK) {
|
||||
blk = ksl_merge_node(ksl, ksl->head, 0);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, key, ksl->compar);
|
||||
|
||||
if (i == blk->n) {
|
||||
if (it) {
|
||||
*it = nghttp2_ksl_end(ksl);
|
||||
}
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (blk->leaf) {
|
||||
if (ksl->compar(key, nghttp2_ksl_nth_node(ksl, blk, i)->key)) {
|
||||
if (it) {
|
||||
*it = nghttp2_ksl_end(ksl);
|
||||
}
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
ksl_remove_node(ksl, blk, i);
|
||||
--ksl->n;
|
||||
if (it) {
|
||||
if (blk->n == i && blk->next) {
|
||||
nghttp2_ksl_it_init(it, ksl, blk->next, 0);
|
||||
} else {
|
||||
nghttp2_ksl_it_init(it, ksl, blk, i);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
if (node->blk->n == NGHTTP2_KSL_MIN_NBLK) {
|
||||
if (i > 0 && nghttp2_ksl_nth_node(ksl, blk, i - 1)->blk->n >
|
||||
NGHTTP2_KSL_MIN_NBLK) {
|
||||
ksl_shift_right(ksl, blk, i - 1);
|
||||
blk = node->blk;
|
||||
} else if (i + 1 < blk->n &&
|
||||
nghttp2_ksl_nth_node(ksl, blk, i + 1)->blk->n >
|
||||
NGHTTP2_KSL_MIN_NBLK) {
|
||||
ksl_shift_left(ksl, blk, i + 1);
|
||||
blk = node->blk;
|
||||
} else if (i > 0) {
|
||||
blk = ksl_merge_node(ksl, blk, i - 1);
|
||||
} else {
|
||||
assert(i + 1 < blk->n);
|
||||
blk = ksl_merge_node(ksl, blk, i);
|
||||
}
|
||||
} else {
|
||||
blk = node->blk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl,
|
||||
const nghttp2_ksl_key *key) {
|
||||
nghttp2_ksl_blk *blk = ksl->head;
|
||||
nghttp2_ksl_it it;
|
||||
size_t i;
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, key, ksl->compar);
|
||||
|
||||
if (blk->leaf) {
|
||||
if (i == blk->n && blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
}
|
||||
nghttp2_ksl_it_init(&it, ksl, blk, i);
|
||||
return it;
|
||||
}
|
||||
|
||||
if (i == blk->n) {
|
||||
/* This happens if descendant has smaller key. Fast forward to
|
||||
find last node in this subtree. */
|
||||
for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
|
||||
;
|
||||
if (blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
} else {
|
||||
i = blk->n;
|
||||
}
|
||||
nghttp2_ksl_it_init(&it, ksl, blk, i);
|
||||
return it;
|
||||
}
|
||||
blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl,
|
||||
const nghttp2_ksl_key *key,
|
||||
nghttp2_ksl_compar compar) {
|
||||
nghttp2_ksl_blk *blk = ksl->head;
|
||||
nghttp2_ksl_it it;
|
||||
size_t i;
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, key, compar);
|
||||
|
||||
if (blk->leaf) {
|
||||
if (i == blk->n && blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
}
|
||||
nghttp2_ksl_it_init(&it, ksl, blk, i);
|
||||
return it;
|
||||
}
|
||||
|
||||
if (i == blk->n) {
|
||||
/* This happens if descendant has smaller key. Fast forward to
|
||||
find last node in this subtree. */
|
||||
for (; !blk->leaf; blk = nghttp2_ksl_nth_node(ksl, blk, blk->n - 1)->blk)
|
||||
;
|
||||
if (blk->next) {
|
||||
blk = blk->next;
|
||||
i = 0;
|
||||
} else {
|
||||
i = blk->n;
|
||||
}
|
||||
nghttp2_ksl_it_init(&it, ksl, blk, i);
|
||||
return it;
|
||||
}
|
||||
blk = nghttp2_ksl_nth_node(ksl, blk, i)->blk;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key,
|
||||
const nghttp2_ksl_key *new_key) {
|
||||
nghttp2_ksl_blk *blk = ksl->head;
|
||||
nghttp2_ksl_node *node;
|
||||
size_t i;
|
||||
|
||||
for (;;) {
|
||||
i = ksl_bsearch(ksl, blk, old_key, ksl->compar);
|
||||
|
||||
assert(i < blk->n);
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
|
||||
if (blk->leaf) {
|
||||
assert(key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key));
|
||||
ksl_node_set_key(ksl, node, new_key);
|
||||
return;
|
||||
}
|
||||
|
||||
if (key_equal(ksl->compar, (nghttp2_ksl_key *)node->key, old_key) ||
|
||||
ksl->compar((nghttp2_ksl_key *)node->key, new_key)) {
|
||||
ksl_node_set_key(ksl, node, new_key);
|
||||
}
|
||||
|
||||
blk = node->blk;
|
||||
}
|
||||
}
|
||||
|
||||
static void ksl_print(nghttp2_ksl *ksl, nghttp2_ksl_blk *blk, size_t level) {
|
||||
size_t i;
|
||||
nghttp2_ksl_node *node;
|
||||
|
||||
fprintf(stderr, "LV=%zu n=%zu\n", level, blk->n);
|
||||
|
||||
if (blk->leaf) {
|
||||
for (i = 0; i < blk->n; ++i) {
|
||||
node = nghttp2_ksl_nth_node(ksl, blk, i);
|
||||
fprintf(stderr, " %" PRId64, *(int64_t *)(void *)node->key);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < blk->n; ++i) {
|
||||
ksl_print(ksl, nghttp2_ksl_nth_node(ksl, blk, i)->blk, level + 1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t nghttp2_ksl_len(nghttp2_ksl *ksl) { return ksl->n; }
|
||||
|
||||
void nghttp2_ksl_clear(nghttp2_ksl *ksl) {
|
||||
size_t i;
|
||||
nghttp2_ksl_blk *head;
|
||||
|
||||
if (!ksl->head->leaf) {
|
||||
for (i = 0; i < ksl->head->n; ++i) {
|
||||
ksl_free_blk(ksl, nghttp2_ksl_nth_node(ksl, ksl->head, i)->blk);
|
||||
}
|
||||
}
|
||||
|
||||
ksl->front = ksl->back = ksl->head;
|
||||
ksl->n = 0;
|
||||
|
||||
head = ksl->head;
|
||||
|
||||
head->next = head->prev = NULL;
|
||||
head->n = 0;
|
||||
head->leaf = 1;
|
||||
}
|
||||
|
||||
void nghttp2_ksl_print(nghttp2_ksl *ksl) { ksl_print(ksl, ksl->head, 0); }
|
||||
|
||||
nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl) {
|
||||
nghttp2_ksl_it it;
|
||||
nghttp2_ksl_it_init(&it, ksl, ksl->front, 0);
|
||||
return it;
|
||||
}
|
||||
|
||||
nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl) {
|
||||
nghttp2_ksl_it it;
|
||||
nghttp2_ksl_it_init(&it, ksl, ksl->back, ksl->back->n);
|
||||
return it;
|
||||
}
|
||||
|
||||
void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl,
|
||||
nghttp2_ksl_blk *blk, size_t i) {
|
||||
it->ksl = ksl;
|
||||
it->blk = blk;
|
||||
it->i = i;
|
||||
}
|
||||
|
||||
void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it) {
|
||||
assert(it->i < it->blk->n);
|
||||
return nghttp2_ksl_nth_node(it->ksl, it->blk, it->i)->data;
|
||||
}
|
||||
|
||||
void nghttp2_ksl_it_prev(nghttp2_ksl_it *it) {
|
||||
assert(!nghttp2_ksl_it_begin(it));
|
||||
|
||||
if (it->i == 0) {
|
||||
it->blk = it->blk->prev;
|
||||
it->i = it->blk->n - 1;
|
||||
} else {
|
||||
--it->i;
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it) {
|
||||
return it->i == 0 && it->blk->prev == NULL;
|
||||
}
|
||||
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2020 nghttp2 contributors
|
||||
* Copyright (c) 2018 ngtcp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_KSL_H
|
||||
#define NGHTTP2_KSL_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/*
|
||||
* Skip List using single key instead of range.
|
||||
*/
|
||||
|
||||
#define NGHTTP2_KSL_DEGR 16
|
||||
/* NGHTTP2_KSL_MAX_NBLK is the maximum number of nodes which a single
|
||||
block can contain. */
|
||||
#define NGHTTP2_KSL_MAX_NBLK (2 * NGHTTP2_KSL_DEGR - 1)
|
||||
/* NGHTTP2_KSL_MIN_NBLK is the minimum number of nodes which a single
|
||||
block other than root must contains. */
|
||||
#define NGHTTP2_KSL_MIN_NBLK (NGHTTP2_KSL_DEGR - 1)
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_key represents key in nghttp2_ksl.
|
||||
*/
|
||||
typedef void nghttp2_ksl_key;
|
||||
|
||||
struct nghttp2_ksl_node;
|
||||
typedef struct nghttp2_ksl_node nghttp2_ksl_node;
|
||||
|
||||
struct nghttp2_ksl_blk;
|
||||
typedef struct nghttp2_ksl_blk nghttp2_ksl_blk;
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_node is a node which contains either nghttp2_ksl_blk or
|
||||
* opaque data. If a node is an internal node, it contains
|
||||
* nghttp2_ksl_blk. Otherwise, it has data. The key is stored at the
|
||||
* location starting at key.
|
||||
*/
|
||||
struct nghttp2_ksl_node {
|
||||
union {
|
||||
nghttp2_ksl_blk *blk;
|
||||
void *data;
|
||||
};
|
||||
union {
|
||||
uint64_t align;
|
||||
/* key is a buffer to include key associated to this node.
|
||||
Because the length of key is unknown until nghttp2_ksl_init is
|
||||
called, the actual buffer will be allocated after this
|
||||
field. */
|
||||
uint8_t key[1];
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_blk contains nghttp2_ksl_node objects.
|
||||
*/
|
||||
struct nghttp2_ksl_blk {
|
||||
/* next points to the next block if leaf field is nonzero. */
|
||||
nghttp2_ksl_blk *next;
|
||||
/* prev points to the previous block if leaf field is nonzero. */
|
||||
nghttp2_ksl_blk *prev;
|
||||
/* n is the number of nodes this object contains in nodes. */
|
||||
size_t n;
|
||||
/* leaf is nonzero if this block contains leaf nodes. */
|
||||
int leaf;
|
||||
union {
|
||||
uint64_t align;
|
||||
/* nodes is a buffer to contain NGHTTP2_KSL_MAX_NBLK
|
||||
nghttp2_ksl_node objects. Because nghttp2_ksl_node object is
|
||||
allocated along with the additional variable length key
|
||||
storage, the size of buffer is unknown until nghttp2_ksl_init is
|
||||
called. */
|
||||
uint8_t nodes[1];
|
||||
};
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_compar is a function type which returns nonzero if key
|
||||
* |lhs| should be placed before |rhs|. It returns 0 otherwise.
|
||||
*/
|
||||
typedef int (*nghttp2_ksl_compar)(const nghttp2_ksl_key *lhs,
|
||||
const nghttp2_ksl_key *rhs);
|
||||
|
||||
struct nghttp2_ksl;
|
||||
typedef struct nghttp2_ksl nghttp2_ksl;
|
||||
|
||||
struct nghttp2_ksl_it;
|
||||
typedef struct nghttp2_ksl_it nghttp2_ksl_it;
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_it is a forward iterator to iterate nodes.
|
||||
*/
|
||||
struct nghttp2_ksl_it {
|
||||
const nghttp2_ksl *ksl;
|
||||
nghttp2_ksl_blk *blk;
|
||||
size_t i;
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp2_ksl is a deterministic paged skip list.
|
||||
*/
|
||||
struct nghttp2_ksl {
|
||||
/* head points to the root block. */
|
||||
nghttp2_ksl_blk *head;
|
||||
/* front points to the first leaf block. */
|
||||
nghttp2_ksl_blk *front;
|
||||
/* back points to the last leaf block. */
|
||||
nghttp2_ksl_blk *back;
|
||||
nghttp2_ksl_compar compar;
|
||||
size_t n;
|
||||
/* keylen is the size of key */
|
||||
size_t keylen;
|
||||
/* nodelen is the actual size of nghttp2_ksl_node including key
|
||||
storage. */
|
||||
size_t nodelen;
|
||||
nghttp2_mem *mem;
|
||||
};
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_init initializes |ksl|. |compar| specifies compare
|
||||
* function. |keylen| is the length of key.
|
||||
*
|
||||
* It returns 0 if it succeeds, or one of the following negative error
|
||||
* codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_ksl_init(nghttp2_ksl *ksl, nghttp2_ksl_compar compar, size_t keylen,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_free frees resources allocated for |ksl|. If |ksl| is
|
||||
* NULL, this function does nothing. It does not free the memory
|
||||
* region pointed by |ksl| itself.
|
||||
*/
|
||||
void nghttp2_ksl_free(nghttp2_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_insert inserts |key| with its associated |data|. On
|
||||
* successful insertion, the iterator points to the inserted node is
|
||||
* stored in |*it|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* |key| already exists.
|
||||
*/
|
||||
int nghttp2_ksl_insert(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
|
||||
const nghttp2_ksl_key *key, void *data);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_remove removes the |key| from |ksl|.
|
||||
*
|
||||
* This function assigns the iterator to |*it|, which points to the
|
||||
* node which is located at the right next of the removed node if |it|
|
||||
* is not NULL. If |key| is not found, no deletion takes place and
|
||||
* the return value of nghttp2_ksl_end(ksl) is assigned to |*it|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* |key| does not exist.
|
||||
*/
|
||||
int nghttp2_ksl_remove(nghttp2_ksl *ksl, nghttp2_ksl_it *it,
|
||||
const nghttp2_ksl_key *key);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_lower_bound returns the iterator which points to the
|
||||
* first node which has the key which is equal to |key| or the last
|
||||
* node which satisfies !compar(&node->key, key). If there is no such
|
||||
* node, it returns the iterator which satisfies nghttp2_ksl_it_end(it)
|
||||
* != 0.
|
||||
*/
|
||||
nghttp2_ksl_it nghttp2_ksl_lower_bound(nghttp2_ksl *ksl,
|
||||
const nghttp2_ksl_key *key);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_lower_bound_compar works like nghttp2_ksl_lower_bound,
|
||||
* but it takes custom function |compar| to do lower bound search.
|
||||
*/
|
||||
nghttp2_ksl_it nghttp2_ksl_lower_bound_compar(nghttp2_ksl *ksl,
|
||||
const nghttp2_ksl_key *key,
|
||||
nghttp2_ksl_compar compar);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_update_key replaces the key of nodes which has |old_key|
|
||||
* with |new_key|. |new_key| must be strictly greater than the
|
||||
* previous node and strictly smaller than the next node.
|
||||
*/
|
||||
void nghttp2_ksl_update_key(nghttp2_ksl *ksl, const nghttp2_ksl_key *old_key,
|
||||
const nghttp2_ksl_key *new_key);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_begin returns the iterator which points to the first
|
||||
* node. If there is no node in |ksl|, it returns the iterator which
|
||||
* satisfies nghttp2_ksl_it_end(it) != 0.
|
||||
*/
|
||||
nghttp2_ksl_it nghttp2_ksl_begin(const nghttp2_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_end returns the iterator which points to the node
|
||||
* following the last node. The returned object satisfies
|
||||
* nghttp2_ksl_it_end(). If there is no node in |ksl|, it returns the
|
||||
* iterator which satisfies nghttp2_ksl_it_begin(it) != 0.
|
||||
*/
|
||||
nghttp2_ksl_it nghttp2_ksl_end(const nghttp2_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_len returns the number of elements stored in |ksl|.
|
||||
*/
|
||||
size_t nghttp2_ksl_len(nghttp2_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_clear removes all elements stored in |ksl|.
|
||||
*/
|
||||
void nghttp2_ksl_clear(nghttp2_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_nth_node returns the |n|th node under |blk|.
|
||||
*/
|
||||
#define nghttp2_ksl_nth_node(KSL, BLK, N) \
|
||||
((nghttp2_ksl_node *)(void *)((BLK)->nodes + (KSL)->nodelen * (N)))
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_print prints its internal state in stderr. It assumes
|
||||
* that the key is of type int64_t. This function should be used for
|
||||
* the debugging purpose only.
|
||||
*/
|
||||
void nghttp2_ksl_print(nghttp2_ksl *ksl);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_it_init initializes |it|.
|
||||
*/
|
||||
void nghttp2_ksl_it_init(nghttp2_ksl_it *it, const nghttp2_ksl *ksl,
|
||||
nghttp2_ksl_blk *blk, size_t i);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_it_get returns the data associated to the node which
|
||||
* |it| points to. It is undefined to call this function when
|
||||
* nghttp2_ksl_it_end(it) returns nonzero.
|
||||
*/
|
||||
void *nghttp2_ksl_it_get(const nghttp2_ksl_it *it);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_it_next advances the iterator by one. It is undefined
|
||||
* if this function is called when nghttp2_ksl_it_end(it) returns
|
||||
* nonzero.
|
||||
*/
|
||||
#define nghttp2_ksl_it_next(IT) \
|
||||
(++(IT)->i == (IT)->blk->n && (IT)->blk->next \
|
||||
? ((IT)->blk = (IT)->blk->next, (IT)->i = 0) \
|
||||
: 0)
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_it_prev moves backward the iterator by one. It is
|
||||
* undefined if this function is called when nghttp2_ksl_it_begin(it)
|
||||
* returns nonzero.
|
||||
*/
|
||||
void nghttp2_ksl_it_prev(nghttp2_ksl_it *it);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_it_end returns nonzero if |it| points to the beyond the
|
||||
* last node.
|
||||
*/
|
||||
#define nghttp2_ksl_it_end(IT) \
|
||||
((IT)->blk->n == (IT)->i && (IT)->blk->next == NULL)
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_it_begin returns nonzero if |it| points to the first
|
||||
* node. |it| might satisfy both nghttp2_ksl_it_begin(&it) and
|
||||
* nghttp2_ksl_it_end(&it) if the skip list has no node.
|
||||
*/
|
||||
int nghttp2_ksl_it_begin(const nghttp2_ksl_it *it);
|
||||
|
||||
/*
|
||||
* nghttp2_ksl_key returns the key of the node which |it| points to.
|
||||
* It is undefined to call this function when nghttp2_ksl_it_end(it)
|
||||
* returns nonzero.
|
||||
*/
|
||||
#define nghttp2_ksl_it_key(IT) \
|
||||
((nghttp2_ksl_key *)nghttp2_ksl_nth_node((IT)->ksl, (IT)->blk, (IT)->i)->key)
|
||||
|
||||
#endif /* NGHTTP2_KSL_H */
|
||||
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
* Copyright (c) 2012 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_map.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
#define INITIAL_TABLE_LENGTH 256
|
||||
|
||||
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem) {
|
||||
map->mem = mem;
|
||||
map->tablelen = INITIAL_TABLE_LENGTH;
|
||||
map->table =
|
||||
nghttp2_mem_calloc(mem, map->tablelen, sizeof(nghttp2_map_bucket));
|
||||
if (map->table == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
map->size = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_map_free(nghttp2_map *map) {
|
||||
size_t i;
|
||||
nghttp2_map_bucket *bkt;
|
||||
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
if (bkt->ksl) {
|
||||
nghttp2_ksl_free(bkt->ksl);
|
||||
nghttp2_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_mem_free(map->mem, map->table);
|
||||
}
|
||||
|
||||
void nghttp2_map_each_free(nghttp2_map *map,
|
||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
||||
void *ptr) {
|
||||
uint32_t i;
|
||||
nghttp2_map_bucket *bkt;
|
||||
nghttp2_ksl_it it;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
func(bkt->ptr, ptr);
|
||||
bkt->ptr = NULL;
|
||||
assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it);
|
||||
nghttp2_ksl_it_next(&it)) {
|
||||
func(nghttp2_ksl_it_get(&it), ptr);
|
||||
}
|
||||
|
||||
nghttp2_ksl_free(bkt->ksl);
|
||||
nghttp2_mem_free(map->mem, bkt->ksl);
|
||||
bkt->ksl = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_map_each(nghttp2_map *map,
|
||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
||||
void *ptr) {
|
||||
int rv;
|
||||
uint32_t i;
|
||||
nghttp2_map_bucket *bkt;
|
||||
nghttp2_ksl_it it;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = func(bkt->ptr, ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it);
|
||||
nghttp2_ksl_it_next(&it)) {
|
||||
rv = func(nghttp2_ksl_it_get(&it), ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
|
||||
entry->key = key;
|
||||
entry->next = NULL;
|
||||
}
|
||||
|
||||
/* FNV1a hash */
|
||||
static uint32_t hash(key_type key, uint32_t mod) {
|
||||
uint8_t *p, *end;
|
||||
uint32_t h = 0x811C9DC5u;
|
||||
|
||||
p = (uint8_t *)&key;
|
||||
end = p + sizeof(key_type);
|
||||
|
||||
for (; p != end;) {
|
||||
h ^= *p++;
|
||||
h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
|
||||
}
|
||||
|
||||
return h & (mod - 1);
|
||||
}
|
||||
|
||||
static int less(const nghttp2_ksl_key *lhs, const nghttp2_ksl_key *rhs) {
|
||||
return *(key_type *)lhs < *(key_type *)rhs;
|
||||
}
|
||||
|
||||
static int map_insert(nghttp2_map *map, nghttp2_map_bucket *table,
|
||||
uint32_t tablelen, nghttp2_map_entry *entry) {
|
||||
uint32_t h = hash(entry->key, tablelen);
|
||||
nghttp2_map_bucket *bkt = &table[h];
|
||||
nghttp2_mem *mem = map->mem;
|
||||
int rv;
|
||||
|
||||
if (bkt->ptr == NULL &&
|
||||
(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0)) {
|
||||
bkt->ptr = entry;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!bkt->ksl) {
|
||||
bkt->ksl = nghttp2_mem_malloc(mem, sizeof(*bkt->ksl));
|
||||
if (bkt->ksl == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
nghttp2_ksl_init(bkt->ksl, less, sizeof(key_type), mem);
|
||||
}
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = nghttp2_ksl_insert(bkt->ksl, NULL, &bkt->ptr->key, bkt->ptr);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
bkt->ptr = NULL;
|
||||
}
|
||||
|
||||
return nghttp2_ksl_insert(bkt->ksl, NULL, &entry->key, entry);
|
||||
}
|
||||
|
||||
/* new_tablelen must be power of 2 */
|
||||
static int map_resize(nghttp2_map *map, uint32_t new_tablelen) {
|
||||
uint32_t i;
|
||||
nghttp2_map_bucket *new_table;
|
||||
nghttp2_map_bucket *bkt;
|
||||
nghttp2_ksl_it it;
|
||||
int rv;
|
||||
|
||||
new_table =
|
||||
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_bucket));
|
||||
if (new_table == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
|
||||
if (bkt->ptr) {
|
||||
rv = map_insert(map, new_table, new_tablelen, bkt->ptr);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
assert(bkt->ksl == NULL || nghttp2_ksl_len(bkt->ksl) == 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
for (it = nghttp2_ksl_begin(bkt->ksl); !nghttp2_ksl_it_end(&it);
|
||||
nghttp2_ksl_it_next(&it)) {
|
||||
rv = map_insert(map, new_table, new_tablelen, nghttp2_ksl_it_get(&it));
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
if (bkt->ksl) {
|
||||
nghttp2_ksl_free(bkt->ksl);
|
||||
nghttp2_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_mem_free(map->mem, map->table);
|
||||
map->tablelen = new_tablelen;
|
||||
map->table = new_table;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
for (i = 0; i < new_tablelen; ++i) {
|
||||
bkt = &new_table[i];
|
||||
if (bkt->ksl) {
|
||||
nghttp2_ksl_free(bkt->ksl);
|
||||
nghttp2_mem_free(map->mem, bkt->ksl);
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
|
||||
int rv;
|
||||
|
||||
/* Load factor is 0.75 */
|
||||
if ((map->size + 1) * 4 > map->tablelen * 3) {
|
||||
rv = map_resize(map, map->tablelen * 2);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv = map_insert(map, map->table, map->tablelen, new_entry);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
++map->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
|
||||
nghttp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
|
||||
nghttp2_ksl_it it;
|
||||
|
||||
if (bkt->ptr) {
|
||||
if (bkt->ptr->key == key) {
|
||||
return bkt->ptr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
it = nghttp2_ksl_lower_bound(bkt->ksl, &key);
|
||||
if (nghttp2_ksl_it_end(&it) ||
|
||||
*(key_type *)nghttp2_ksl_it_key(&it) != key) {
|
||||
return NULL;
|
||||
}
|
||||
return nghttp2_ksl_it_get(&it);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nghttp2_map_remove(nghttp2_map *map, key_type key) {
|
||||
nghttp2_map_bucket *bkt = &map->table[hash(key, map->tablelen)];
|
||||
int rv;
|
||||
|
||||
if (bkt->ptr) {
|
||||
if (bkt->ptr->key == key) {
|
||||
bkt->ptr = NULL;
|
||||
--map->size;
|
||||
return 0;
|
||||
}
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (bkt->ksl) {
|
||||
rv = nghttp2_ksl_remove(bkt->ksl, NULL, &key);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
--map->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
void nghttp2_map_clear(nghttp2_map *map) {
|
||||
uint32_t i;
|
||||
nghttp2_map_bucket *bkt;
|
||||
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
bkt = &map->table[i];
|
||||
bkt->ptr = NULL;
|
||||
if (bkt->ksl) {
|
||||
nghttp2_ksl_free(bkt->ksl);
|
||||
nghttp2_mem_free(map->mem, bkt->ksl);
|
||||
bkt->ksl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
map->size = 0;
|
||||
}
|
||||
|
||||
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }
|
||||
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2017 ngtcp2 contributors
|
||||
* Copyright (c) 2012 nghttp2 contributors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_MAP_H
|
||||
#define NGHTTP2_MAP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include "nghttp2_mem.h"
|
||||
#include "nghttp2_ksl.h"
|
||||
|
||||
/* Implementation of unordered map */
|
||||
|
||||
typedef int32_t key_type;
|
||||
|
||||
typedef struct nghttp2_map_entry {
|
||||
struct nghttp2_map_entry *next;
|
||||
key_type key;
|
||||
#if SIZEOF_INT_P == 4
|
||||
/* we requires 8 bytes aligment */
|
||||
int64_t pad;
|
||||
#endif
|
||||
} nghttp2_map_entry;
|
||||
|
||||
typedef struct nghttp2_map_bucket {
|
||||
nghttp2_map_entry *ptr;
|
||||
nghttp2_ksl *ksl;
|
||||
} nghttp2_map_bucket;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_map_bucket *table;
|
||||
nghttp2_mem *mem;
|
||||
size_t size;
|
||||
uint32_t tablelen;
|
||||
} nghttp2_map;
|
||||
|
||||
/*
|
||||
* Initializes the map |map|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_map_init(nghttp2_map *map, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |map|. The stored entries
|
||||
* are not freed by this function. Use nghttp2_map_each_free() to free
|
||||
* each entries.
|
||||
*/
|
||||
void nghttp2_map_free(nghttp2_map *map);
|
||||
|
||||
/*
|
||||
* Deallocates each entries using |func| function and any resources
|
||||
* allocated for |map|. The |func| function is responsible for freeing
|
||||
* given the |entry| object. The |ptr| will be passed to the |func| as
|
||||
* send argument. The return value of the |func| will be ignored.
|
||||
*/
|
||||
void nghttp2_map_each_free(nghttp2_map *map,
|
||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
||||
void *ptr);
|
||||
|
||||
/*
|
||||
* Initializes the |entry| with the |key|. All entries to be inserted
|
||||
* to the map must be initialized with this function.
|
||||
*/
|
||||
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key);
|
||||
|
||||
/*
|
||||
* Inserts the new |entry| with the key |entry->key| to the map |map|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The item associated by |key| already exists.
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
|
||||
|
||||
/*
|
||||
* Returns the entry associated by the key |key|. If there is no such
|
||||
* entry, this function returns NULL.
|
||||
*/
|
||||
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
|
||||
|
||||
/*
|
||||
* Removes the entry associated by the key |key| from the |map|. The
|
||||
* removed entry is not freed by this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The entry associated by |key| does not exist.
|
||||
*/
|
||||
int nghttp2_map_remove(nghttp2_map *map, key_type key);
|
||||
|
||||
/*
|
||||
* Removes all entries from |map|.
|
||||
*/
|
||||
void nghttp2_map_clear(nghttp2_map *map);
|
||||
|
||||
/*
|
||||
* Returns the number of items stored in the map |map|.
|
||||
*/
|
||||
size_t nghttp2_map_size(nghttp2_map *map);
|
||||
|
||||
/*
|
||||
* Applies the function |func| to each entry in the |map| with the
|
||||
* optional user supplied pointer |ptr|.
|
||||
*
|
||||
* If the |func| returns 0, this function calls the |func| with the
|
||||
* next entry. If the |func| returns nonzero, it will not call the
|
||||
* |func| for further entries and return the return value of the
|
||||
* |func| immediately. Thus, this function returns 0 if all the
|
||||
* invocations of the |func| return 0, or nonzero value which the last
|
||||
* invocation of |func| returns.
|
||||
*
|
||||
* Don't use this function to free each entry. Use
|
||||
* nghttp2_map_each_free() instead.
|
||||
*/
|
||||
int nghttp2_map_each(nghttp2_map *map,
|
||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
||||
void *ptr);
|
||||
|
||||
#endif /* NGHTTP2_MAP_H */
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
static void *default_malloc(size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
static void default_free(void *ptr, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
static void *default_calloc(size_t nmemb, size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return calloc(nmemb, size);
|
||||
}
|
||||
|
||||
static void *default_realloc(void *ptr, size_t size, void *mem_user_data) {
|
||||
(void)mem_user_data;
|
||||
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
|
||||
static nghttp2_mem mem_default = {NULL, default_malloc, default_free,
|
||||
default_calloc, default_realloc};
|
||||
|
||||
nghttp2_mem *nghttp2_mem_default(void) { return &mem_default; }
|
||||
|
||||
void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size) {
|
||||
return mem->malloc(size, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void nghttp2_mem_free(nghttp2_mem *mem, void *ptr) {
|
||||
mem->free(ptr, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data) {
|
||||
free_func(ptr, mem_user_data);
|
||||
}
|
||||
|
||||
void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size) {
|
||||
return mem->calloc(nmemb, size, mem->mem_user_data);
|
||||
}
|
||||
|
||||
void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size) {
|
||||
return mem->realloc(ptr, size, mem->mem_user_data);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_MEM_H
|
||||
#define NGHTTP2_MEM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/* The default, system standard memory allocator */
|
||||
nghttp2_mem *nghttp2_mem_default(void);
|
||||
|
||||
/* Convenient wrapper functions to call allocator function in
|
||||
|mem|. */
|
||||
void *nghttp2_mem_malloc(nghttp2_mem *mem, size_t size);
|
||||
void nghttp2_mem_free(nghttp2_mem *mem, void *ptr);
|
||||
void nghttp2_mem_free2(nghttp2_free free_func, void *ptr, void *mem_user_data);
|
||||
void *nghttp2_mem_calloc(nghttp2_mem *mem, size_t nmemb, size_t size);
|
||||
void *nghttp2_mem_realloc(nghttp2_mem *mem, void *ptr, size_t size);
|
||||
|
||||
#endif /* NGHTTP2_MEM_H */
|
||||
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_NET_H
|
||||
#define NGHTTP2_NET_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#endif /* HAVE_ARPA_INET_H */
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#endif /* HAVE_NETINET_IN_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#if defined(WIN32)
|
||||
/* Windows requires ws2_32 library for ntonl family functions. We
|
||||
define inline functions for those function so that we don't have
|
||||
dependeny on that lib. */
|
||||
|
||||
# ifdef _MSC_VER
|
||||
# define STIN static __inline
|
||||
# else
|
||||
# define STIN static inline
|
||||
# endif
|
||||
|
||||
STIN uint32_t htonl(uint32_t hostlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostlong >> 24;
|
||||
*p++ = (hostlong >> 16) & 0xffu;
|
||||
*p++ = (hostlong >> 8) & 0xffu;
|
||||
*p = hostlong & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t htons(uint16_t hostshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&res;
|
||||
*p++ = hostshort >> 8;
|
||||
*p = hostshort & 0xffu;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint32_t ntohl(uint32_t netlong) {
|
||||
uint32_t res;
|
||||
unsigned char *p = (unsigned char *)&netlong;
|
||||
res = *p++ << 24;
|
||||
res += *p++ << 16;
|
||||
res += *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
STIN uint16_t ntohs(uint16_t netshort) {
|
||||
uint16_t res;
|
||||
unsigned char *p = (unsigned char *)&netshort;
|
||||
res = *p++ << 8;
|
||||
res += *p;
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
#endif /* NGHTTP2_NET_H */
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_npn.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static int select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
const char *key, unsigned int keylen) {
|
||||
unsigned int i;
|
||||
for (i = 0; i + keylen <= inlen; i += (unsigned int)(in[i] + 1)) {
|
||||
if (memcmp(&in[i], key, keylen) == 0) {
|
||||
*out = (unsigned char *)&in[i + 1];
|
||||
*outlen = in[i];
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
#define NGHTTP2_HTTP_1_1_ALPN "\x8http/1.1"
|
||||
#define NGHTTP2_HTTP_1_1_ALPN_LEN (sizeof(NGHTTP2_HTTP_1_1_ALPN) - 1)
|
||||
|
||||
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen) {
|
||||
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_PROTO_ALPN,
|
||||
NGHTTP2_PROTO_ALPN_LEN) == 0) {
|
||||
return 1;
|
||||
}
|
||||
if (select_next_protocol(out, outlen, in, inlen, NGHTTP2_HTTP_1_1_ALPN,
|
||||
NGHTTP2_HTTP_1_1_ALPN_LEN) == 0) {
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_NPN_H
|
||||
#define NGHTTP2_NPN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#endif /* NGHTTP2_NPN_H */
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_option.h"
|
||||
|
||||
#include "nghttp2_session.h"
|
||||
|
||||
int nghttp2_option_new(nghttp2_option **option_ptr) {
|
||||
*option_ptr = calloc(1, sizeof(nghttp2_option));
|
||||
|
||||
if (*option_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_option_del(nghttp2_option *option) { free(option); }
|
||||
|
||||
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE;
|
||||
option->no_auto_window_update = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
|
||||
uint32_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS;
|
||||
option->peer_max_concurrent_streams = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC;
|
||||
option->no_recv_client_magic = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_HTTP_MESSAGING;
|
||||
option->no_http_messaging = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
|
||||
uint32_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS;
|
||||
option->max_reserved_remote_streams = val;
|
||||
}
|
||||
|
||||
static void set_ext_type(uint8_t *ext_types, uint8_t type) {
|
||||
ext_types[type / 8] = (uint8_t)(ext_types[type / 8] | (1 << (type & 0x7)));
|
||||
}
|
||||
|
||||
void nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
|
||||
uint8_t type) {
|
||||
if (type < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
option->opt_set_mask |= NGHTTP2_OPT_USER_RECV_EXT_TYPES;
|
||||
set_ext_type(option->user_recv_ext_types, type);
|
||||
}
|
||||
|
||||
void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
|
||||
uint8_t type) {
|
||||
switch (type) {
|
||||
case NGHTTP2_ALTSVC:
|
||||
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC;
|
||||
return;
|
||||
case NGHTTP2_ORIGIN:
|
||||
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_PING_ACK;
|
||||
option->no_auto_ping_ack = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
|
||||
size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH;
|
||||
option->max_send_header_block_length = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
|
||||
size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE;
|
||||
option->max_deflate_dynamic_table_size = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_closed_streams(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_CLOSED_STREAMS;
|
||||
option->no_closed_streams = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
|
||||
option->max_outbound_ack = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_settings(nghttp2_option *option, size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_SETTINGS;
|
||||
option->max_settings = val;
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_OPTION_H
|
||||
#define NGHTTP2_OPTION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/**
|
||||
* Configuration options
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* This option prevents the library from sending WINDOW_UPDATE for a
|
||||
* connection automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for DATA until application calls
|
||||
* nghttp2_session_consume() to indicate the amount of consumed
|
||||
* DATA. By default, this option is set to zero.
|
||||
*/
|
||||
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
|
||||
/**
|
||||
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
|
||||
* remote endpoint as if it is received in SETTINGS frame. Without
|
||||
* specifying this option, before the local endpoint receives
|
||||
* SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
|
||||
* endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
|
||||
* cause problem if local endpoint submits lots of requests
|
||||
* initially and sending them at once to the remote peer may lead to
|
||||
* the rejection of some requests. Specifying this option to the
|
||||
* sensible value, say 100, may avoid this kind of issue. This value
|
||||
* will be overwritten if the local endpoint receives
|
||||
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
|
||||
*/
|
||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
||||
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
|
||||
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
|
||||
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
|
||||
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
|
||||
NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
|
||||
NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
|
||||
NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
|
||||
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
|
||||
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
|
||||
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
|
||||
NGHTTP2_OPT_MAX_SETTINGS = 1 << 12,
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
* Struct to store option values for nghttp2_session.
|
||||
*/
|
||||
struct nghttp2_option {
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
|
||||
*/
|
||||
size_t max_send_header_block_length;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE
|
||||
*/
|
||||
size_t max_deflate_dynamic_table_size;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_OUTBOUND_ACK
|
||||
*/
|
||||
size_t max_outbound_ack;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_SETTINGS
|
||||
*/
|
||||
size_t max_settings;
|
||||
/**
|
||||
* Bitwise OR of nghttp2_option_flag to determine that which fields
|
||||
* are specified.
|
||||
*/
|
||||
uint32_t opt_set_mask;
|
||||
/**
|
||||
* NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS
|
||||
*/
|
||||
uint32_t peer_max_concurrent_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS
|
||||
*/
|
||||
uint32_t max_reserved_remote_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES
|
||||
*/
|
||||
uint32_t builtin_recv_ext_types;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
|
||||
*/
|
||||
int no_auto_window_update;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC
|
||||
*/
|
||||
int no_recv_client_magic;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_HTTP_MESSAGING
|
||||
*/
|
||||
int no_http_messaging;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_PING_ACK
|
||||
*/
|
||||
int no_auto_ping_ack;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_CLOSED_STREAMS
|
||||
*/
|
||||
int no_closed_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
|
||||
*/
|
||||
uint8_t user_recv_ext_types[32];
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_OPTION_H */
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_outbound_item.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
void nghttp2_outbound_item_init(nghttp2_outbound_item *item) {
|
||||
item->cycle = 0;
|
||||
item->qnext = NULL;
|
||||
item->queued = 0;
|
||||
|
||||
memset(&item->aux_data, 0, sizeof(nghttp2_aux_data));
|
||||
}
|
||||
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
||||
nghttp2_frame *frame;
|
||||
|
||||
if (item == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
nghttp2_frame_headers_free(&frame->headers, mem);
|
||||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
break;
|
||||
case NGHTTP2_RST_STREAM:
|
||||
nghttp2_frame_rst_stream_free(&frame->rst_stream);
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
nghttp2_frame_settings_free(&frame->settings, mem);
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
nghttp2_frame_push_promise_free(&frame->push_promise, mem);
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
nghttp2_frame_ping_free(&frame->ping);
|
||||
break;
|
||||
case NGHTTP2_GOAWAY:
|
||||
nghttp2_frame_goaway_free(&frame->goaway, mem);
|
||||
break;
|
||||
case NGHTTP2_WINDOW_UPDATE:
|
||||
nghttp2_frame_window_update_free(&frame->window_update);
|
||||
break;
|
||||
default: {
|
||||
nghttp2_ext_aux_data *aux_data;
|
||||
|
||||
aux_data = &item->aux_data.ext;
|
||||
|
||||
if (aux_data->builtin == 0) {
|
||||
nghttp2_frame_extension_free(&frame->ext);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_ALTSVC:
|
||||
nghttp2_frame_altsvc_free(&frame->ext, mem);
|
||||
break;
|
||||
case NGHTTP2_ORIGIN:
|
||||
nghttp2_frame_origin_free(&frame->ext, mem);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) {
|
||||
q->head = q->tail = NULL;
|
||||
q->n = 0;
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||
nghttp2_outbound_item *item) {
|
||||
if (q->tail) {
|
||||
q->tail = q->tail->qnext = item;
|
||||
} else {
|
||||
q->head = q->tail = item;
|
||||
}
|
||||
++q->n;
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q) {
|
||||
nghttp2_outbound_item *item;
|
||||
if (!q->head) {
|
||||
return;
|
||||
}
|
||||
item = q->head;
|
||||
q->head = q->head->qnext;
|
||||
item->qnext = NULL;
|
||||
if (!q->head) {
|
||||
q->tail = NULL;
|
||||
}
|
||||
--q->n;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_OUTBOUND_ITEM_H
|
||||
#define NGHTTP2_OUTBOUND_ITEM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
/* struct used for HEADERS and PUSH_PROMISE frame */
|
||||
typedef struct {
|
||||
nghttp2_data_provider data_prd;
|
||||
void *stream_user_data;
|
||||
/* error code when request HEADERS is canceled by RST_STREAM while
|
||||
it is in queue. */
|
||||
uint32_t error_code;
|
||||
/* nonzero if request HEADERS is canceled. The error code is stored
|
||||
in |error_code|. */
|
||||
uint8_t canceled;
|
||||
} nghttp2_headers_aux_data;
|
||||
|
||||
/* struct used for DATA frame */
|
||||
typedef struct {
|
||||
/**
|
||||
* The data to be sent for this DATA frame.
|
||||
*/
|
||||
nghttp2_data_provider data_prd;
|
||||
/**
|
||||
* The flags of DATA frame. We use separate flags here and
|
||||
* nghttp2_data frame. The latter contains flags actually sent to
|
||||
* peer. This |flags| may contain NGHTTP2_FLAG_END_STREAM and only
|
||||
* when |eof| becomes nonzero, flags in nghttp2_data has
|
||||
* NGHTTP2_FLAG_END_STREAM set.
|
||||
*/
|
||||
uint8_t flags;
|
||||
/**
|
||||
* The flag to indicate whether EOF was reached or not. Initially
|
||||
* |eof| is 0. It becomes 1 after all data were read.
|
||||
*/
|
||||
uint8_t eof;
|
||||
/**
|
||||
* The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
|
||||
*/
|
||||
uint8_t no_copy;
|
||||
} nghttp2_data_aux_data;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_GOAWAY_AUX_NONE = 0x0,
|
||||
/* indicates that session should be terminated after the
|
||||
transmission of this frame. */
|
||||
NGHTTP2_GOAWAY_AUX_TERM_ON_SEND = 0x1,
|
||||
/* indicates that this GOAWAY is just a notification for graceful
|
||||
shutdown. No nghttp2_session.goaway_flags should be updated on
|
||||
the reaction to this frame. */
|
||||
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
|
||||
} nghttp2_goaway_aux_flag;
|
||||
|
||||
/* struct used for GOAWAY frame */
|
||||
typedef struct {
|
||||
/* bitwise-OR of one or more of nghttp2_goaway_aux_flag. */
|
||||
uint8_t flags;
|
||||
} nghttp2_goaway_aux_data;
|
||||
|
||||
/* struct used for extension frame */
|
||||
typedef struct {
|
||||
/* nonzero if this extension frame is serialized by library
|
||||
function, instead of user-defined callbacks. */
|
||||
uint8_t builtin;
|
||||
} nghttp2_ext_aux_data;
|
||||
|
||||
/* Additional data which cannot be stored in nghttp2_frame struct */
|
||||
typedef union {
|
||||
nghttp2_data_aux_data data;
|
||||
nghttp2_headers_aux_data headers;
|
||||
nghttp2_goaway_aux_data goaway;
|
||||
nghttp2_ext_aux_data ext;
|
||||
} nghttp2_aux_data;
|
||||
|
||||
struct nghttp2_outbound_item;
|
||||
typedef struct nghttp2_outbound_item nghttp2_outbound_item;
|
||||
|
||||
struct nghttp2_outbound_item {
|
||||
nghttp2_frame frame;
|
||||
/* Storage for extension frame payload. frame->ext.payload points
|
||||
to this structure to avoid frequent memory allocation. */
|
||||
nghttp2_ext_frame_payload ext_frame_payload;
|
||||
nghttp2_aux_data aux_data;
|
||||
/* The priority used in priority comparion. Smaller is served
|
||||
earlier. For PING, SETTINGS and non-DATA frames (excluding
|
||||
response HEADERS frame) have dedicated cycle value defined above.
|
||||
For DATA frame, cycle is computed by taking into account of
|
||||
effective weight and frame payload length previously sent, so
|
||||
that the amount of transmission is distributed across streams
|
||||
proportional to effective weight (inside a tree). */
|
||||
uint64_t cycle;
|
||||
nghttp2_outbound_item *qnext;
|
||||
/* nonzero if this object is queued, except for DATA or HEADERS
|
||||
which are attached to stream as item. */
|
||||
uint8_t queued;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initializes |item|. No memory allocation is done in this function.
|
||||
* Don't call nghttp2_outbound_item_free() until frame member is
|
||||
* initialized.
|
||||
*/
|
||||
void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Deallocates resource for |item|. If |item| is NULL, this function
|
||||
* does nothing.
|
||||
*/
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* queue for nghttp2_outbound_item.
|
||||
*/
|
||||
typedef struct {
|
||||
nghttp2_outbound_item *head, *tail;
|
||||
/* number of items in this queue. */
|
||||
size_t n;
|
||||
} nghttp2_outbound_queue;
|
||||
|
||||
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
|
||||
|
||||
/* Pushes |item| into |q| */
|
||||
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/* Pops |item| at the top from |q|. If |q| is empty, nothing
|
||||
happens. */
|
||||
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
|
||||
|
||||
/* Returns the top item. */
|
||||
#define nghttp2_outbound_queue_top(Q) ((Q)->head)
|
||||
|
||||
/* Returns the size of the queue */
|
||||
#define nghttp2_outbound_queue_size(Q) ((Q)->n)
|
||||
|
||||
#endif /* NGHTTP2_OUTBOUND_ITEM_H */
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_pq.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
|
||||
pq->mem = mem;
|
||||
pq->capacity = 0;
|
||||
pq->q = NULL;
|
||||
pq->length = 0;
|
||||
pq->less = less;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_pq_free(nghttp2_pq *pq) {
|
||||
nghttp2_mem_free(pq->mem, pq->q);
|
||||
pq->q = NULL;
|
||||
}
|
||||
|
||||
static void swap(nghttp2_pq *pq, size_t i, size_t j) {
|
||||
nghttp2_pq_entry *a = pq->q[i];
|
||||
nghttp2_pq_entry *b = pq->q[j];
|
||||
|
||||
pq->q[i] = b;
|
||||
b->index = i;
|
||||
pq->q[j] = a;
|
||||
a->index = j;
|
||||
}
|
||||
|
||||
static void bubble_up(nghttp2_pq *pq, size_t index) {
|
||||
size_t parent;
|
||||
while (index != 0) {
|
||||
parent = (index - 1) / 2;
|
||||
if (!pq->less(pq->q[index], pq->q[parent])) {
|
||||
return;
|
||||
}
|
||||
swap(pq, parent, index);
|
||||
index = parent;
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item) {
|
||||
if (pq->capacity <= pq->length) {
|
||||
void *nq;
|
||||
size_t ncapacity;
|
||||
|
||||
ncapacity = nghttp2_max(4, (pq->capacity * 2));
|
||||
|
||||
nq = nghttp2_mem_realloc(pq->mem, pq->q,
|
||||
ncapacity * sizeof(nghttp2_pq_entry *));
|
||||
if (nq == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
pq->capacity = ncapacity;
|
||||
pq->q = nq;
|
||||
}
|
||||
pq->q[pq->length] = item;
|
||||
item->index = pq->length;
|
||||
++pq->length;
|
||||
bubble_up(pq, pq->length - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq) {
|
||||
if (pq->length == 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
return pq->q[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void bubble_down(nghttp2_pq *pq, size_t index) {
|
||||
size_t i, j, minindex;
|
||||
for (;;) {
|
||||
j = index * 2 + 1;
|
||||
minindex = index;
|
||||
for (i = 0; i < 2; ++i, ++j) {
|
||||
if (j >= pq->length) {
|
||||
break;
|
||||
}
|
||||
if (pq->less(pq->q[j], pq->q[minindex])) {
|
||||
minindex = j;
|
||||
}
|
||||
}
|
||||
if (minindex == index) {
|
||||
return;
|
||||
}
|
||||
swap(pq, index, minindex);
|
||||
index = minindex;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_pq_pop(nghttp2_pq *pq) {
|
||||
if (pq->length > 0) {
|
||||
pq->q[0] = pq->q[pq->length - 1];
|
||||
pq->q[0]->index = 0;
|
||||
--pq->length;
|
||||
bubble_down(pq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item) {
|
||||
assert(pq->q[item->index] == item);
|
||||
|
||||
if (item->index == 0) {
|
||||
nghttp2_pq_pop(pq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->index == pq->length - 1) {
|
||||
--pq->length;
|
||||
return;
|
||||
}
|
||||
|
||||
pq->q[item->index] = pq->q[pq->length - 1];
|
||||
pq->q[item->index]->index = item->index;
|
||||
--pq->length;
|
||||
|
||||
if (pq->less(item, pq->q[item->index])) {
|
||||
bubble_down(pq, item->index);
|
||||
} else {
|
||||
bubble_up(pq, item->index);
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_empty(nghttp2_pq *pq) { return pq->length == 0; }
|
||||
|
||||
size_t nghttp2_pq_size(nghttp2_pq *pq) { return pq->length; }
|
||||
|
||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) {
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
if (pq->length == 0) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < pq->length; ++i) {
|
||||
rv |= (*fun)(pq->q[i], arg);
|
||||
}
|
||||
if (rv) {
|
||||
for (i = pq->length; i > 0; --i) {
|
||||
bubble_down(pq, i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) {
|
||||
size_t i;
|
||||
|
||||
if (pq->length == 0) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < pq->length; ++i) {
|
||||
if ((*fun)(pq->q[i], arg)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_PQ_H
|
||||
#define NGHTTP2_PQ_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_int.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
/* Implementation of priority queue */
|
||||
|
||||
typedef struct {
|
||||
size_t index;
|
||||
} nghttp2_pq_entry;
|
||||
|
||||
typedef struct {
|
||||
/* The pointer to the pointer to the item stored */
|
||||
nghttp2_pq_entry **q;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem *mem;
|
||||
/* The number of items stored */
|
||||
size_t length;
|
||||
/* The maximum number of items this pq can store. This is
|
||||
automatically extended when length is reached to this value. */
|
||||
size_t capacity;
|
||||
/* The less function between items */
|
||||
nghttp2_less less;
|
||||
} nghttp2_pq;
|
||||
|
||||
/*
|
||||
* Initializes priority queue |pq| with compare function |cmp|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |pq|. The stored items are
|
||||
* not freed by this function.
|
||||
*/
|
||||
void nghttp2_pq_free(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Adds |item| to the priority queue |pq|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item);
|
||||
|
||||
/*
|
||||
* Returns item at the top of the queue |pq|. If the queue is empty,
|
||||
* this function returns NULL.
|
||||
*/
|
||||
nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Pops item at the top of the queue |pq|. The popped item is not
|
||||
* freed by this function.
|
||||
*/
|
||||
void nghttp2_pq_pop(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the queue |pq| is empty.
|
||||
*/
|
||||
int nghttp2_pq_empty(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Returns the number of items in the queue |pq|.
|
||||
*/
|
||||
size_t nghttp2_pq_size(nghttp2_pq *pq);
|
||||
|
||||
typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
|
||||
|
||||
/*
|
||||
* Updates each item in |pq| using function |fun| and re-construct
|
||||
* priority queue. The |fun| must return non-zero if it modifies the
|
||||
* item in a way that it affects ordering in the priority queue. The
|
||||
* |arg| is passed to the 2nd parameter of |fun|.
|
||||
*/
|
||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
||||
|
||||
/*
|
||||
* Applys |fun| to each item in |pq|. The |arg| is passed as arg
|
||||
* parameter to callback function. This function must not change the
|
||||
* ordering key. If the return value from callback is nonzero, this
|
||||
* function returns 1 immediately without iterating remaining items.
|
||||
* Otherwise this function returns 0.
|
||||
*/
|
||||
int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
||||
|
||||
/*
|
||||
* Removes |item| from priority queue.
|
||||
*/
|
||||
void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item);
|
||||
|
||||
#endif /* NGHTTP2_PQ_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
|
||||
int32_t stream_id, int32_t weight,
|
||||
int exclusive) {
|
||||
pri_spec->stream_id = stream_id;
|
||||
pri_spec->weight = weight;
|
||||
pri_spec->exclusive = exclusive != 0;
|
||||
}
|
||||
|
||||
void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) {
|
||||
pri_spec->stream_id = 0;
|
||||
pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT;
|
||||
pri_spec->exclusive = 0;
|
||||
}
|
||||
|
||||
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) {
|
||||
return pri_spec->stream_id == 0 &&
|
||||
pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT && pri_spec->exclusive == 0;
|
||||
}
|
||||
|
||||
void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec) {
|
||||
if (pri_spec->weight < NGHTTP2_MIN_WEIGHT) {
|
||||
pri_spec->weight = NGHTTP2_MIN_WEIGHT;
|
||||
} else if (pri_spec->weight > NGHTTP2_MAX_WEIGHT) {
|
||||
pri_spec->weight = NGHTTP2_MAX_WEIGHT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_PRIORITY_SPEC_H
|
||||
#define NGHTTP2_PRIORITY_SPEC_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/*
|
||||
* This function normalizes pri_spec->weight if it is out of range.
|
||||
* If pri_spec->weight is less than NGHTTP2_MIN_WEIGHT, it is set to
|
||||
* NGHTTP2_MIN_WEIGHT. If pri_spec->weight is larger than
|
||||
* NGHTTP2_MAX_WEIGHT, it is set to NGHTTP2_MAX_WEIGHT.
|
||||
*/
|
||||
void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec);
|
||||
|
||||
#endif /* NGHTTP2_PRIORITY_SPEC_H */
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_queue.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
void nghttp2_queue_init(nghttp2_queue *queue) {
|
||||
queue->front = queue->back = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_queue_free(nghttp2_queue *queue) {
|
||||
if (!queue) {
|
||||
return;
|
||||
} else {
|
||||
nghttp2_queue_cell *p = queue->front;
|
||||
while (p) {
|
||||
nghttp2_queue_cell *next = p->next;
|
||||
free(p);
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_queue_push(nghttp2_queue *queue, void *data) {
|
||||
nghttp2_queue_cell *new_cell =
|
||||
(nghttp2_queue_cell *)malloc(sizeof(nghttp2_queue_cell));
|
||||
if (!new_cell) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
new_cell->data = data;
|
||||
new_cell->next = NULL;
|
||||
if (queue->back) {
|
||||
queue->back->next = new_cell;
|
||||
queue->back = new_cell;
|
||||
|
||||
} else {
|
||||
queue->front = queue->back = new_cell;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_queue_pop(nghttp2_queue *queue) {
|
||||
nghttp2_queue_cell *front = queue->front;
|
||||
assert(front);
|
||||
queue->front = front->next;
|
||||
if (front == queue->back) {
|
||||
queue->back = NULL;
|
||||
}
|
||||
free(front);
|
||||
}
|
||||
|
||||
void *nghttp2_queue_front(nghttp2_queue *queue) {
|
||||
assert(queue->front);
|
||||
return queue->front->data;
|
||||
}
|
||||
|
||||
void *nghttp2_queue_back(nghttp2_queue *queue) {
|
||||
assert(queue->back);
|
||||
return queue->back->data;
|
||||
}
|
||||
|
||||
int nghttp2_queue_empty(nghttp2_queue *queue) { return queue->front == NULL; }
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_QUEUE_H
|
||||
#define NGHTTP2_QUEUE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
typedef struct nghttp2_queue_cell {
|
||||
void *data;
|
||||
struct nghttp2_queue_cell *next;
|
||||
} nghttp2_queue_cell;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_queue_cell *front, *back;
|
||||
} nghttp2_queue;
|
||||
|
||||
void nghttp2_queue_init(nghttp2_queue *queue);
|
||||
void nghttp2_queue_free(nghttp2_queue *queue);
|
||||
int nghttp2_queue_push(nghttp2_queue *queue, void *data);
|
||||
void nghttp2_queue_pop(nghttp2_queue *queue);
|
||||
void *nghttp2_queue_front(nghttp2_queue *queue);
|
||||
void *nghttp2_queue_back(nghttp2_queue *queue);
|
||||
int nghttp2_queue_empty(nghttp2_queue *queue);
|
||||
|
||||
#endif /* NGHTTP2_QUEUE_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_rcbuf.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp2_mem.h"
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size,
|
||||
nghttp2_mem *mem) {
|
||||
uint8_t *p;
|
||||
|
||||
p = nghttp2_mem_malloc(mem, sizeof(nghttp2_rcbuf) + size);
|
||||
if (p == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
*rcbuf_ptr = (void *)p;
|
||||
|
||||
(*rcbuf_ptr)->mem_user_data = mem->mem_user_data;
|
||||
(*rcbuf_ptr)->free = mem->free;
|
||||
(*rcbuf_ptr)->base = p + sizeof(nghttp2_rcbuf);
|
||||
(*rcbuf_ptr)->len = size;
|
||||
(*rcbuf_ptr)->ref = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src,
|
||||
size_t srclen, nghttp2_mem *mem) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_rcbuf_new(rcbuf_ptr, srclen + 1, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
(*rcbuf_ptr)->len = srclen;
|
||||
*nghttp2_cpymem((*rcbuf_ptr)->base, src, srclen) = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees |rcbuf| itself, regardless of its reference cout.
|
||||
*/
|
||||
void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf) {
|
||||
nghttp2_mem_free2(rcbuf->free, rcbuf, rcbuf->mem_user_data);
|
||||
}
|
||||
|
||||
void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf) {
|
||||
if (rcbuf->ref == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
++rcbuf->ref;
|
||||
}
|
||||
|
||||
void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf) {
|
||||
if (rcbuf == NULL || rcbuf->ref == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(rcbuf->ref > 0);
|
||||
|
||||
if (--rcbuf->ref == 0) {
|
||||
nghttp2_rcbuf_del(rcbuf);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf) {
|
||||
nghttp2_vec res = {rcbuf->base, rcbuf->len};
|
||||
return res;
|
||||
}
|
||||
|
||||
int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf) {
|
||||
return rcbuf->ref == -1;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_RCBUF_H
|
||||
#define NGHTTP2_RCBUF_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
struct nghttp2_rcbuf {
|
||||
/* custom memory allocator belongs to the mem parameter when
|
||||
creating this object. */
|
||||
void *mem_user_data;
|
||||
nghttp2_free free;
|
||||
/* The pointer to the underlying buffer */
|
||||
uint8_t *base;
|
||||
/* Size of buffer pointed by |base|. */
|
||||
size_t len;
|
||||
/* Reference count */
|
||||
int32_t ref;
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocates nghttp2_rcbuf object with |size| as initial buffer size.
|
||||
* When the function succeeds, the reference count becomes 1.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM:
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of
|
||||
* length |srclen|. This function allocates additional byte at the
|
||||
* end and puts '\0' into it, so that the resulting buffer could be
|
||||
* used as NULL-terminated string. Still (*rcbuf_ptr)->len equals to
|
||||
* |srclen|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM:
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src,
|
||||
size_t srclen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Frees |rcbuf| itself, regardless of its reference cout.
|
||||
*/
|
||||
void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf);
|
||||
|
||||
#endif /* NGHTTP2_RCBUF_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,935 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_SESSION_H
|
||||
#define NGHTTP2_SESSION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_map.h"
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_stream.h"
|
||||
#include "nghttp2_outbound_item.h"
|
||||
#include "nghttp2_int.h"
|
||||
#include "nghttp2_buf.h"
|
||||
#include "nghttp2_callbacks.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
/* The global variable for tests where we want to disable strict
|
||||
preface handling. */
|
||||
extern int nghttp2_enable_strict_preface;
|
||||
|
||||
/*
|
||||
* Option flags.
|
||||
*/
|
||||
typedef enum {
|
||||
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
|
||||
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
|
||||
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
|
||||
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
|
||||
NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
|
||||
} nghttp2_optmask;
|
||||
|
||||
/*
|
||||
* bitmask for built-in type to enable the default handling for that
|
||||
* type of the frame.
|
||||
*/
|
||||
typedef enum {
|
||||
NGHTTP2_TYPEMASK_NONE = 0,
|
||||
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
|
||||
NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
|
||||
} nghttp2_typemask;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_OB_POP_ITEM,
|
||||
NGHTTP2_OB_SEND_DATA,
|
||||
NGHTTP2_OB_SEND_NO_COPY,
|
||||
NGHTTP2_OB_SEND_CLIENT_MAGIC
|
||||
} nghttp2_outbound_state;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_bufs framebufs;
|
||||
nghttp2_outbound_state state;
|
||||
} nghttp2_active_outbound_item;
|
||||
|
||||
/* Buffer length for inbound raw byte stream used in
|
||||
nghttp2_session_recv(). */
|
||||
#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384
|
||||
|
||||
/* The default maximum number of incoming reserved streams */
|
||||
#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
|
||||
|
||||
/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
|
||||
number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
|
||||
#define NGHTTP2_MIN_IDLE_STREAMS 16
|
||||
|
||||
/* The maximum number of items in outbound queue, which is considered
|
||||
as flooding caused by peer. All frames are not considered here.
|
||||
We only consider PING + ACK and SETTINGS + ACK. This is because
|
||||
they both are response to the frame initiated by peer and peer can
|
||||
send as many of them as they want. If peer does not read network,
|
||||
response frames are stacked up, which leads to memory exhaustion.
|
||||
The value selected here is arbitrary, but safe value and if we have
|
||||
these frames in this number, it is considered suspicious. */
|
||||
#define NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM 1000
|
||||
|
||||
/* The default value of maximum number of concurrent streams. */
|
||||
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
|
||||
|
||||
/* Internal state when receiving incoming frame */
|
||||
typedef enum {
|
||||
/* Receiving frame header */
|
||||
NGHTTP2_IB_READ_CLIENT_MAGIC,
|
||||
NGHTTP2_IB_READ_FIRST_SETTINGS,
|
||||
NGHTTP2_IB_READ_HEAD,
|
||||
NGHTTP2_IB_READ_NBYTE,
|
||||
NGHTTP2_IB_READ_HEADER_BLOCK,
|
||||
NGHTTP2_IB_IGN_HEADER_BLOCK,
|
||||
NGHTTP2_IB_IGN_PAYLOAD,
|
||||
NGHTTP2_IB_FRAME_SIZE_ERROR,
|
||||
NGHTTP2_IB_READ_SETTINGS,
|
||||
NGHTTP2_IB_READ_GOAWAY_DEBUG,
|
||||
NGHTTP2_IB_EXPECT_CONTINUATION,
|
||||
NGHTTP2_IB_IGN_CONTINUATION,
|
||||
NGHTTP2_IB_READ_PAD_DATA,
|
||||
NGHTTP2_IB_READ_DATA,
|
||||
NGHTTP2_IB_IGN_DATA,
|
||||
NGHTTP2_IB_IGN_ALL,
|
||||
NGHTTP2_IB_READ_ALTSVC_PAYLOAD,
|
||||
NGHTTP2_IB_READ_ORIGIN_PAYLOAD,
|
||||
NGHTTP2_IB_READ_EXTENSION_PAYLOAD
|
||||
} nghttp2_inbound_state;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_frame frame;
|
||||
/* Storage for extension frame payload. frame->ext.payload points
|
||||
to this structure to avoid frequent memory allocation. */
|
||||
nghttp2_ext_frame_payload ext_frame_payload;
|
||||
/* The received SETTINGS entry. For the standard settings entries,
|
||||
we only keep the last seen value. For
|
||||
SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the
|
||||
last index. */
|
||||
nghttp2_settings_entry *iv;
|
||||
/* buffer pointers to small buffer, raw_sbuf */
|
||||
nghttp2_buf sbuf;
|
||||
/* buffer pointers to large buffer, raw_lbuf */
|
||||
nghttp2_buf lbuf;
|
||||
/* Large buffer, malloced on demand */
|
||||
uint8_t *raw_lbuf;
|
||||
/* The number of entry filled in |iv| */
|
||||
size_t niv;
|
||||
/* The number of entries |iv| can store. */
|
||||
size_t max_niv;
|
||||
/* How many bytes we still need to receive for current frame */
|
||||
size_t payloadleft;
|
||||
/* padding length for the current frame */
|
||||
size_t padlen;
|
||||
nghttp2_inbound_state state;
|
||||
/* Small buffer. Currently the largest contiguous chunk to buffer
|
||||
is frame header. We buffer part of payload, but they are smaller
|
||||
than frame header. */
|
||||
uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
|
||||
} nghttp2_inbound_frame;
|
||||
|
||||
typedef struct {
|
||||
uint32_t header_table_size;
|
||||
uint32_t enable_push;
|
||||
uint32_t max_concurrent_streams;
|
||||
uint32_t initial_window_size;
|
||||
uint32_t max_frame_size;
|
||||
uint32_t max_header_list_size;
|
||||
uint32_t enable_connect_protocol;
|
||||
} nghttp2_settings_storage;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_GOAWAY_NONE = 0,
|
||||
/* Flag means that connection should be terminated after sending GOAWAY. */
|
||||
NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1,
|
||||
/* Flag means GOAWAY to terminate session has been sent */
|
||||
NGHTTP2_GOAWAY_TERM_SENT = 0x2,
|
||||
/* Flag means GOAWAY was sent */
|
||||
NGHTTP2_GOAWAY_SENT = 0x4,
|
||||
/* Flag means GOAWAY was received */
|
||||
NGHTTP2_GOAWAY_RECV = 0x8
|
||||
} nghttp2_goaway_flag;
|
||||
|
||||
/* nghttp2_inflight_settings stores the SETTINGS entries which local
|
||||
endpoint has sent to the remote endpoint, and has not received ACK
|
||||
yet. */
|
||||
struct nghttp2_inflight_settings {
|
||||
struct nghttp2_inflight_settings *next;
|
||||
nghttp2_settings_entry *iv;
|
||||
size_t niv;
|
||||
};
|
||||
|
||||
typedef struct nghttp2_inflight_settings nghttp2_inflight_settings;
|
||||
|
||||
struct nghttp2_session {
|
||||
nghttp2_map /* <nghttp2_stream*> */ streams;
|
||||
/* root of dependency tree*/
|
||||
nghttp2_stream root;
|
||||
/* Queue for outbound urgent frames (PING and SETTINGS) */
|
||||
nghttp2_outbound_queue ob_urgent;
|
||||
/* Queue for non-DATA frames */
|
||||
nghttp2_outbound_queue ob_reg;
|
||||
/* Queue for outbound stream-creating HEADERS (request or push
|
||||
response) frame, which are subject to
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
||||
nghttp2_outbound_queue ob_syn;
|
||||
nghttp2_active_outbound_item aob;
|
||||
nghttp2_inbound_frame iframe;
|
||||
nghttp2_hd_deflater hd_deflater;
|
||||
nghttp2_hd_inflater hd_inflater;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem mem;
|
||||
void *user_data;
|
||||
/* Points to the latest incoming closed stream. NULL if there is no
|
||||
closed stream. Only used when session is initialized as
|
||||
server. */
|
||||
nghttp2_stream *closed_stream_head;
|
||||
/* Points to the oldest incoming closed stream. NULL if there is no
|
||||
closed stream. Only used when session is initialized as
|
||||
server. */
|
||||
nghttp2_stream *closed_stream_tail;
|
||||
/* Points to the latest idle stream. NULL if there is no idle
|
||||
stream. Only used when session is initialized as server .*/
|
||||
nghttp2_stream *idle_stream_head;
|
||||
/* Points to the oldest idle stream. NULL if there is no idle
|
||||
stream. Only used when session is initialized as erver. */
|
||||
nghttp2_stream *idle_stream_tail;
|
||||
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
|
||||
considered as in-flight. */
|
||||
nghttp2_inflight_settings *inflight_settings_head;
|
||||
/* The number of outgoing streams. This will be capped by
|
||||
remote_settings.max_concurrent_streams. */
|
||||
size_t num_outgoing_streams;
|
||||
/* The number of incoming streams. This will be capped by
|
||||
local_settings.max_concurrent_streams. */
|
||||
size_t num_incoming_streams;
|
||||
/* The number of incoming reserved streams. This is the number of
|
||||
streams in reserved (remote) state. RFC 7540 does not limit this
|
||||
number. nghttp2 offers
|
||||
nghttp2_option_set_max_reserved_remote_streams() to achieve this.
|
||||
If it is used, num_incoming_streams is capped by
|
||||
max_incoming_reserved_streams. Client application should
|
||||
consider to set this because without that server can send
|
||||
arbitrary number of PUSH_PROMISE, and exhaust client's memory. */
|
||||
size_t num_incoming_reserved_streams;
|
||||
/* The maximum number of incoming reserved streams (reserved
|
||||
(remote) state). RST_STREAM will be sent for the pushed stream
|
||||
which exceeds this limit. */
|
||||
size_t max_incoming_reserved_streams;
|
||||
/* The number of closed streams still kept in |streams| hash. The
|
||||
closed streams can be accessed through single linked list
|
||||
|closed_stream_head|. The current implementation only keeps
|
||||
incoming streams and session is initialized as server. */
|
||||
size_t num_closed_streams;
|
||||
/* The number of idle streams kept in |streams| hash. The idle
|
||||
streams can be accessed through doubly linked list
|
||||
|idle_stream_head|. The current implementation only keeps idle
|
||||
streams if session is initialized as server. */
|
||||
size_t num_idle_streams;
|
||||
/* The number of bytes allocated for nvbuf */
|
||||
size_t nvbuflen;
|
||||
/* Counter for detecting flooding in outbound queue. If it exceeds
|
||||
max_outbound_ack, session will be closed. */
|
||||
size_t obq_flood_counter_;
|
||||
/* The maximum number of outgoing SETTINGS ACK and PING ACK in
|
||||
outbound queue. */
|
||||
size_t max_outbound_ack;
|
||||
/* The maximum length of header block to send. Calculated by the
|
||||
same way as nghttp2_hd_deflate_bound() does. */
|
||||
size_t max_send_header_block_length;
|
||||
/* The maximum number of settings accepted per SETTINGS frame. */
|
||||
size_t max_settings;
|
||||
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
||||
uint32_t next_stream_id;
|
||||
/* The last stream ID this session initiated. For client session,
|
||||
this is the last stream ID it has sent. For server session, it
|
||||
is the last promised stream ID sent in PUSH_PROMISE. */
|
||||
int32_t last_sent_stream_id;
|
||||
/* The largest stream ID received so far */
|
||||
int32_t last_recv_stream_id;
|
||||
/* The largest stream ID which has been processed in some way. This
|
||||
value will be used as last-stream-id when sending GOAWAY
|
||||
frame. */
|
||||
int32_t last_proc_stream_id;
|
||||
/* Counter of unique ID of PING. Wraps when it exceeds
|
||||
NGHTTP2_MAX_UNIQUE_ID */
|
||||
uint32_t next_unique_id;
|
||||
/* This is the last-stream-ID we have sent in GOAWAY */
|
||||
int32_t local_last_stream_id;
|
||||
/* This is the value in GOAWAY frame received from remote endpoint. */
|
||||
int32_t remote_last_stream_id;
|
||||
/* Current sender window size. This value is computed against the
|
||||
current initial window size of remote endpoint. */
|
||||
int32_t remote_window_size;
|
||||
/* Keep track of the number of bytes received without
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE. */
|
||||
int32_t recv_window_size;
|
||||
/* The number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
/* window size for local flow control. It is initially set to
|
||||
NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE and could be
|
||||
increased/decreased by submitting WINDOW_UPDATE. See
|
||||
nghttp2_submit_window_update(). */
|
||||
int32_t local_window_size;
|
||||
/* This flag is used to indicate that the local endpoint received initial
|
||||
SETTINGS frame from the remote endpoint. */
|
||||
uint8_t remote_settings_received;
|
||||
/* Settings value received from the remote endpoint. */
|
||||
nghttp2_settings_storage remote_settings;
|
||||
/* Settings value of the local endpoint. */
|
||||
nghttp2_settings_storage local_settings;
|
||||
/* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
|
||||
uint32_t opt_flags;
|
||||
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
|
||||
to refuse the incoming stream if it exceeds this value. */
|
||||
uint32_t pending_local_max_concurrent_stream;
|
||||
/* The bitwise OR of zero or more of nghttp2_typemask to indicate
|
||||
that the default handling of extension frame is enabled. */
|
||||
uint32_t builtin_recv_ext_types;
|
||||
/* Unacked local ENABLE_PUSH value. We use this to refuse
|
||||
PUSH_PROMISE before SETTINGS ACK is received. */
|
||||
uint8_t pending_enable_push;
|
||||
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
|
||||
accept :protocol header field before SETTINGS_ACK is received. */
|
||||
uint8_t pending_enable_connect_protocol;
|
||||
/* Nonzero if the session is server side. */
|
||||
uint8_t server;
|
||||
/* Flags indicating GOAWAY is sent and/or received. The flags are
|
||||
composed by bitwise OR-ing nghttp2_goaway_flag. */
|
||||
uint8_t goaway_flags;
|
||||
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
|
||||
this session. The nonzero does not necessarily mean
|
||||
WINDOW_UPDATE is not queued. */
|
||||
uint8_t window_update_queued;
|
||||
/* Bitfield of extension frame types that application is willing to
|
||||
receive. To designate the bit of given frame type i, use
|
||||
user_recv_ext_types[i / 8] & (1 << (i & 0x7)). First 10 frame
|
||||
types are standard frame types and not used in this bitfield. If
|
||||
bit is set, it indicates that incoming frame with that type is
|
||||
passed to user defined callbacks, otherwise they are ignored. */
|
||||
uint8_t user_recv_ext_types[32];
|
||||
};
|
||||
|
||||
/* Struct used when updating initial window size of each active
|
||||
stream. */
|
||||
typedef struct {
|
||||
nghttp2_session *session;
|
||||
int32_t new_window_size, old_window_size;
|
||||
} nghttp2_update_window_size_arg;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_session *session;
|
||||
/* linked list of streams to close */
|
||||
nghttp2_stream *head;
|
||||
int32_t last_stream_id;
|
||||
/* nonzero if GOAWAY is sent to peer, which means we are going to
|
||||
close incoming streams. zero if GOAWAY is received from peer and
|
||||
we are going to close outgoing streams. */
|
||||
int incoming;
|
||||
} nghttp2_close_stream_on_goaway_arg;
|
||||
|
||||
/* TODO stream timeout etc */
|
||||
|
||||
/*
|
||||
* Returns nonzero value if |stream_id| is initiated by local
|
||||
* endpoint.
|
||||
*/
|
||||
int nghttp2_session_is_my_stream_id(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* Adds |item| to the outbound queue in |session|. When this function
|
||||
* succeeds, it takes ownership of |item|. So caller must not free it
|
||||
* on success.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_STREAM_CLOSED
|
||||
* Stream already closed (DATA and PUSH_PROMISE frame only)
|
||||
*/
|
||||
int nghttp2_session_add_item(nghttp2_session *session,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Adds RST_STREAM frame for the stream |stream_id| with the error
|
||||
* code |error_code|. This is a convenient function built on top of
|
||||
* nghttp2_session_add_frame() to add RST_STREAM easily.
|
||||
*
|
||||
* This function simply returns 0 without adding RST_STREAM frame if
|
||||
* given stream is in NGHTTP2_STREAM_CLOSING state, because multiple
|
||||
* RST_STREAM for a stream is redundant.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
/*
|
||||
* Adds PING frame. This is a convenient functin built on top of
|
||||
* nghttp2_session_add_frame() to add PING easily.
|
||||
*
|
||||
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
|
||||
* region of data. The data pointed by |opaque_data| is copied. It can
|
||||
* be NULL. In this case, 8 bytes NULL is used.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue; this only happens
|
||||
* if NGHTTP2_FLAG_ACK is set in |flags|
|
||||
*/
|
||||
int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
|
||||
const uint8_t *opaque_data);
|
||||
|
||||
/*
|
||||
* Adds GOAWAY frame with the last-stream-ID |last_stream_id| and the
|
||||
* error code |error_code|. This is a convenient function built on top
|
||||
* of nghttp2_session_add_frame() to add GOAWAY easily. The
|
||||
* |aux_flags| are bitwise-OR of one or more of
|
||||
* nghttp2_goaway_aux_flag.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The |opaque_data_len| is too large.
|
||||
*/
|
||||
int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
|
||||
uint32_t error_code, const uint8_t *opaque_data,
|
||||
size_t opaque_data_len, uint8_t aux_flags);
|
||||
|
||||
/*
|
||||
* Adds WINDOW_UPDATE frame with stream ID |stream_id| and
|
||||
* window-size-increment |window_size_increment|. This is a convenient
|
||||
* function built on top of nghttp2_session_add_frame() to add
|
||||
* WINDOW_UPDATE easily.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t window_size_increment);
|
||||
|
||||
/*
|
||||
* Adds SETTINGS frame.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue; this only happens
|
||||
* if NGHTTP2_FLAG_ACK is set in |flags|
|
||||
*/
|
||||
int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_settings_entry *iv, size_t niv);
|
||||
|
||||
/*
|
||||
* Creates new stream in |session| with stream ID |stream_id|,
|
||||
* priority |pri_spec| and flags |flags|. The |flags| is bitwise OR
|
||||
* of nghttp2_stream_flag. Since this function is called when initial
|
||||
* HEADERS is sent or received, these flags are taken from it. The
|
||||
* state of stream is set to |initial_state|. The |stream_user_data|
|
||||
* is a pointer to the arbitrary user supplied data to be associated
|
||||
* to this stream.
|
||||
*
|
||||
* If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets
|
||||
* NGHTTP2_STREAM_FLAG_PUSH flag set.
|
||||
*
|
||||
* This function returns a pointer to created new stream object, or
|
||||
* NULL.
|
||||
*
|
||||
* This function adjusts neither the number of closed streams or idle
|
||||
* streams. The caller should manually call
|
||||
* nghttp2_session_adjust_closed_stream() or
|
||||
* nghttp2_session_adjust_idle_stream() respectively.
|
||||
*/
|
||||
nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
||||
int32_t stream_id, uint8_t flags,
|
||||
nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_stream_state initial_state,
|
||||
void *stream_user_data);
|
||||
|
||||
/*
|
||||
* Closes stream whose stream ID is |stream_id|. The reason of closure
|
||||
* is indicated by the |error_code|. When closing the stream,
|
||||
* on_stream_close_callback will be called.
|
||||
*
|
||||
* If the session is initialized as server and |stream| is incoming
|
||||
* stream, stream is just marked closed and this function calls
|
||||
* nghttp2_session_keep_closed_stream() with |stream|. Otherwise,
|
||||
* |stream| will be deleted from memory.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The specified stream does not exist.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
/*
|
||||
* Deletes |stream| from memory. After this function returns, stream
|
||||
* cannot be accessed.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_destroy_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Tries to keep incoming closed stream |stream|. Due to the
|
||||
* limitation of maximum number of streams in memory, |stream| is not
|
||||
* closed and just deleted from memory (see
|
||||
* nghttp2_session_destroy_stream).
|
||||
*/
|
||||
void nghttp2_session_keep_closed_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Appends |stream| to linked list |session->idle_stream_head|. We
|
||||
* apply fixed limit for list size. To fit into that limit, one or
|
||||
* more oldest streams are removed from list as necessary.
|
||||
*/
|
||||
void nghttp2_session_keep_idle_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Detaches |stream| from idle streams linked list.
|
||||
*/
|
||||
void nghttp2_session_detach_idle_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Deletes closed stream to ensure that number of incoming streams
|
||||
* including active and closed is in the maximum number of allowed
|
||||
* stream.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_adjust_closed_stream(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Deletes idle stream to ensure that number of idle streams is in
|
||||
* certain limit.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_adjust_idle_stream(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* If further receptions and transmissions over the stream |stream_id|
|
||||
* are disallowed, close the stream with error code NGHTTP2_NO_ERROR.
|
||||
*
|
||||
* This function returns 0 if it
|
||||
* succeeds, or one of the following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The specified stream does not exist.
|
||||
*/
|
||||
int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
int nghttp2_session_on_response_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Called when HEADERS is received, assuming |frame| is properly
|
||||
* initialized. This function does first validate received frame and
|
||||
* then open stream and call callback functions.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_IGN_HEADER_BLOCK
|
||||
* Frame was rejected and header block must be decoded but
|
||||
* result must be ignored.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Called when PRIORITY is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_priority_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when RST_STREAM is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when SETTINGS is received, assuming |frame| is properly
|
||||
* initialized. If |noack| is non-zero, SETTINGS with ACK will not be
|
||||
* submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS
|
||||
* with ACK will not be submitted regardless of |noack|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue, and this is most
|
||||
* likely caused by misbehaviour of peer.
|
||||
*/
|
||||
int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame, int noack);
|
||||
|
||||
/*
|
||||
* Called when PUSH_PROMISE is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_IGN_HEADER_BLOCK
|
||||
* Frame was rejected and header block must be decoded but
|
||||
* result must be ignored.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when PING is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue, and this is most
|
||||
* likely caused by misbehaviour of peer.
|
||||
*/
|
||||
int nghttp2_session_on_ping_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when GOAWAY is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_goaway_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when WINDOW_UPDATE is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_window_update_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when ALTSVC is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_altsvc_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when ORIGIN is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_origin_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when DATA is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_data_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Returns nghttp2_stream* object whose stream ID is |stream_id|. It
|
||||
* could be NULL if such stream does not exist. This function returns
|
||||
* NULL if stream is marked as closed.
|
||||
*/
|
||||
nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* This function behaves like nghttp2_session_get_stream(), but it
|
||||
* returns stream object even if it is marked as closed or in
|
||||
* NGHTTP2_STREAM_IDLE state.
|
||||
*/
|
||||
nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* Packs DATA frame |frame| in wire frame format and stores it in
|
||||
* |bufs|. Payload will be read using |aux_data->data_prd|. The
|
||||
* length of payload is at most |datamax| bytes.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_DEFERRED
|
||||
* The DATA frame is postponed.
|
||||
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||
* The read_callback failed (stream error).
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed (session error).
|
||||
*/
|
||||
int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||
size_t datamax, nghttp2_frame *frame,
|
||||
nghttp2_data_aux_data *aux_data,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Pops and returns next item to send. If there is no such item,
|
||||
* returns NULL. This function takes into account max concurrent
|
||||
* streams. That means if session->ob_syn has item and max concurrent
|
||||
* streams is reached, the even if other queues contain items, then
|
||||
* this function returns NULL.
|
||||
*/
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_session_pop_next_ob_item(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Returns next item to send. If there is no such item, this function
|
||||
* returns NULL. This function takes into account max concurrent
|
||||
* streams. That means if session->ob_syn has item and max concurrent
|
||||
* streams is reached, the even if other queues contain items, then
|
||||
* this function returns NULL.
|
||||
*/
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_session_get_next_ob_item(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Updates local settings with the |iv|. The number of elements in the
|
||||
* array pointed by the |iv| is given by the |niv|. This function
|
||||
* assumes that the all settings_id member in |iv| are in range 1 to
|
||||
* NGHTTP2_SETTINGS_MAX, inclusive.
|
||||
*
|
||||
* While updating individual stream's local window size, if the window
|
||||
* size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
|
||||
* RST_STREAM is issued against such a stream.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||
nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
/*
|
||||
* Re-prioritize |stream|. The new priority specification is
|
||||
* |pri_spec|. Caller must ensure that stream->hd.stream_id !=
|
||||
* pri_spec->stream_id.
|
||||
*
|
||||
* This function does not adjust the number of idle streams. The
|
||||
* caller should call nghttp2_session_adjust_idle_stream() later.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_reprioritize_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
/*
|
||||
* Terminates current |session| with the |error_code|. The |reason|
|
||||
* is NULL-terminated debug string.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The |reason| is too long.
|
||||
*/
|
||||
int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
|
||||
uint32_t error_code,
|
||||
const char *reason);
|
||||
|
||||
/*
|
||||
* Accumulates received bytes |delta_size| for connection-level flow
|
||||
* control and decides whether to send WINDOW_UPDATE to the
|
||||
* connection. If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set,
|
||||
* WINDOW_UPDATE will not be sent.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_session_update_recv_connection_window_size(nghttp2_session *session,
|
||||
size_t delta_size);
|
||||
|
||||
/*
|
||||
* Accumulates received bytes |delta_size| for stream-level flow
|
||||
* control and decides whether to send WINDOW_UPDATE to that stream.
|
||||
* If NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE is set, WINDOW_UPDATE will not
|
||||
* be sent.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_session_update_recv_stream_window_size(nghttp2_session *session,
|
||||
nghttp2_stream *stream,
|
||||
size_t delta_size,
|
||||
int send_window_update);
|
||||
|
||||
#endif /* NGHTTP2_SESSION_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_STREAM_H
|
||||
#define NGHTTP2_STREAM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_outbound_item.h"
|
||||
#include "nghttp2_map.h"
|
||||
#include "nghttp2_pq.h"
|
||||
#include "nghttp2_int.h"
|
||||
|
||||
/*
|
||||
* If local peer is stream initiator:
|
||||
* NGHTTP2_STREAM_OPENING : upon sending request HEADERS
|
||||
* NGHTTP2_STREAM_OPENED : upon receiving response HEADERS
|
||||
* NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
|
||||
*
|
||||
* If remote peer is stream initiator:
|
||||
* NGHTTP2_STREAM_OPENING : upon receiving request HEADERS
|
||||
* NGHTTP2_STREAM_OPENED : upon sending response HEADERS
|
||||
* NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
|
||||
*/
|
||||
typedef enum {
|
||||
/* Initial state */
|
||||
NGHTTP2_STREAM_INITIAL,
|
||||
/* For stream initiator: request HEADERS has been sent, but response
|
||||
HEADERS has not been received yet. For receiver: request HEADERS
|
||||
has been received, but it does not send response HEADERS yet. */
|
||||
NGHTTP2_STREAM_OPENING,
|
||||
/* For stream initiator: response HEADERS is received. For receiver:
|
||||
response HEADERS is sent. */
|
||||
NGHTTP2_STREAM_OPENED,
|
||||
/* RST_STREAM is received, but somehow we need to keep stream in
|
||||
memory. */
|
||||
NGHTTP2_STREAM_CLOSING,
|
||||
/* PUSH_PROMISE is received or sent */
|
||||
NGHTTP2_STREAM_RESERVED,
|
||||
/* Stream is created in this state if it is used as anchor in
|
||||
dependency tree. */
|
||||
NGHTTP2_STREAM_IDLE
|
||||
} nghttp2_stream_state;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_SHUT_NONE = 0,
|
||||
/* Indicates further receptions will be disallowed. */
|
||||
NGHTTP2_SHUT_RD = 0x01,
|
||||
/* Indicates further transmissions will be disallowed. */
|
||||
NGHTTP2_SHUT_WR = 0x02,
|
||||
/* Indicates both further receptions and transmissions will be
|
||||
disallowed. */
|
||||
NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR
|
||||
} nghttp2_shut_flag;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_STREAM_FLAG_NONE = 0,
|
||||
/* Indicates that this stream is pushed stream and not opened
|
||||
yet. */
|
||||
NGHTTP2_STREAM_FLAG_PUSH = 0x01,
|
||||
/* Indicates that this stream was closed */
|
||||
NGHTTP2_STREAM_FLAG_CLOSED = 0x02,
|
||||
/* Indicates the item is deferred due to flow control. */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04,
|
||||
/* Indicates the item is deferred by user callback */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
|
||||
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
|
||||
|
||||
} nghttp2_stream_flag;
|
||||
|
||||
/* HTTP related flags to enforce HTTP semantics */
|
||||
typedef enum {
|
||||
NGHTTP2_HTTP_FLAG_NONE = 0,
|
||||
/* header field seen so far */
|
||||
NGHTTP2_HTTP_FLAG__AUTHORITY = 1,
|
||||
NGHTTP2_HTTP_FLAG__PATH = 1 << 1,
|
||||
NGHTTP2_HTTP_FLAG__METHOD = 1 << 2,
|
||||
NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3,
|
||||
/* host is not pseudo header, but we require either host or
|
||||
:authority */
|
||||
NGHTTP2_HTTP_FLAG_HOST = 1 << 4,
|
||||
NGHTTP2_HTTP_FLAG__STATUS = 1 << 5,
|
||||
/* required header fields for HTTP request except for CONNECT
|
||||
method. */
|
||||
NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD |
|
||||
NGHTTP2_HTTP_FLAG__PATH |
|
||||
NGHTTP2_HTTP_FLAG__SCHEME,
|
||||
NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6,
|
||||
/* HTTP method flags */
|
||||
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
|
||||
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
|
||||
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
|
||||
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10,
|
||||
NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
|
||||
NGHTTP2_HTTP_FLAG_METH_HEAD |
|
||||
NGHTTP2_HTTP_FLAG_METH_OPTIONS |
|
||||
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND,
|
||||
/* :path category */
|
||||
/* path starts with "/" */
|
||||
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11,
|
||||
/* path "*" */
|
||||
NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12,
|
||||
/* scheme */
|
||||
/* "http" or "https" scheme */
|
||||
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13,
|
||||
/* set if final response is expected */
|
||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
|
||||
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
|
||||
} nghttp2_http_flag;
|
||||
|
||||
struct nghttp2_stream {
|
||||
/* Intrusive Map */
|
||||
nghttp2_map_entry map_entry;
|
||||
/* Entry for dep_prev->obq */
|
||||
nghttp2_pq_entry pq_entry;
|
||||
/* Priority Queue storing direct descendant (nghttp2_stream). Only
|
||||
streams which itself has some data to send, or has a descendant
|
||||
which has some data to sent. */
|
||||
nghttp2_pq obq;
|
||||
/* Content-Length of request/response body. -1 if unknown. */
|
||||
int64_t content_length;
|
||||
/* Received body so far */
|
||||
int64_t recv_content_length;
|
||||
/* Base last_cycle for direct descendent streams. */
|
||||
uint64_t descendant_last_cycle;
|
||||
/* Next scheduled time to sent item */
|
||||
uint64_t cycle;
|
||||
/* Next seq used for direct descendant streams */
|
||||
uint64_t descendant_next_seq;
|
||||
/* Secondary key for prioritization to break a tie for cycle. This
|
||||
value is monotonically increased for single parent stream. */
|
||||
uint64_t seq;
|
||||
/* pointers to form dependency tree. If multiple streams depend on
|
||||
a stream, only one stream (left most) has non-NULL dep_prev which
|
||||
points to the stream it depends on. The remaining streams are
|
||||
linked using sib_prev and sib_next. The stream which has
|
||||
non-NULL dep_prev always NULL sib_prev. The right most stream
|
||||
has NULL sib_next. If this stream is a root of dependency tree,
|
||||
dep_prev and sib_prev are NULL. */
|
||||
nghttp2_stream *dep_prev, *dep_next;
|
||||
nghttp2_stream *sib_prev, *sib_next;
|
||||
/* When stream is kept after closure, it may be kept in doubly
|
||||
linked list pointed by nghttp2_session closed_stream_head.
|
||||
closed_next points to the next stream object if it is the element
|
||||
of the list. */
|
||||
nghttp2_stream *closed_prev, *closed_next;
|
||||
/* The arbitrary data provided by user for this stream. */
|
||||
void *stream_user_data;
|
||||
/* Item to send */
|
||||
nghttp2_outbound_item *item;
|
||||
/* Last written length of frame payload */
|
||||
size_t last_writelen;
|
||||
/* stream ID */
|
||||
int32_t stream_id;
|
||||
/* Current remote window size. This value is computed against the
|
||||
current initial window size of remote endpoint. */
|
||||
int32_t remote_window_size;
|
||||
/* Keep track of the number of bytes received without
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_window_size;
|
||||
/* The number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
/* window size for local flow control. It is initially set to
|
||||
NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by
|
||||
submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */
|
||||
int32_t local_window_size;
|
||||
/* weight of this stream */
|
||||
int32_t weight;
|
||||
/* This is unpaid penalty (offset) when calculating cycle. */
|
||||
uint32_t pending_penalty;
|
||||
/* sum of weight of direct descendants */
|
||||
int32_t sum_dep_weight;
|
||||
nghttp2_stream_state state;
|
||||
/* status code from remote server */
|
||||
int16_t status_code;
|
||||
/* Bitwise OR of zero or more nghttp2_http_flag values */
|
||||
uint16_t http_flags;
|
||||
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
|
||||
uint8_t flags;
|
||||
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
||||
uint8_t shut_flags;
|
||||
/* Nonzero if this stream has been queued to stream pointed by
|
||||
dep_prev. We maintain the invariant that if a stream is queued,
|
||||
then its ancestors, except for root, are also queued. This
|
||||
invariant may break in fatal error condition. */
|
||||
uint8_t queued;
|
||||
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
|
||||
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
|
||||
is not queued. */
|
||||
uint8_t window_update_queued;
|
||||
};
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
uint8_t flags, nghttp2_stream_state initial_state,
|
||||
int32_t weight, int32_t remote_initial_window_size,
|
||||
int32_t local_initial_window_size,
|
||||
void *stream_user_data, nghttp2_mem *mem);
|
||||
|
||||
void nghttp2_stream_free(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Disallow either further receptions or transmissions, or both.
|
||||
* |flag| is bitwise OR of one or more of nghttp2_shut_flag.
|
||||
*/
|
||||
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
|
||||
|
||||
/*
|
||||
* Defer |stream->item|. We won't call this function in the situation
|
||||
* where |stream->item| == NULL. The |flags| is bitwise OR of zero or
|
||||
* more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates
|
||||
* the reason of this action.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
|
||||
|
||||
/*
|
||||
* Put back deferred data in this stream to active state. The |flags|
|
||||
* are one or more of bitwise OR of the following values:
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_USER and
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
|
||||
* cleared if they are set. So even if this function is called, if
|
||||
* one of flag is still set, data does not become active.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags);
|
||||
|
||||
/*
|
||||
* Returns nonzero if item is deferred by whatever reason.
|
||||
*/
|
||||
int nghttp2_stream_check_deferred_item(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if item is deferred by flow control.
|
||||
*/
|
||||
int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Updates the remote window size with the new value
|
||||
* |new_initial_window_size|. The |old_initial_window_size| is used to
|
||||
* calculate the current window size.
|
||||
*
|
||||
* This function returns 0 if it succeeds or -1. The failure is due to
|
||||
* overflow.
|
||||
*/
|
||||
int nghttp2_stream_update_remote_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
|
||||
/*
|
||||
* Updates the local window size with the new value
|
||||
* |new_initial_window_size|. The |old_initial_window_size| is used to
|
||||
* calculate the current window size.
|
||||
*
|
||||
* This function returns 0 if it succeeds or -1. The failure is due to
|
||||
* overflow.
|
||||
*/
|
||||
int nghttp2_stream_update_local_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
|
||||
/*
|
||||
* Call this function if promised stream |stream| is replied with
|
||||
* HEADERS. This function makes the state of the |stream| to
|
||||
* NGHTTP2_STREAM_OPENED.
|
||||
*/
|
||||
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |target| is an ancestor of |stream|.
|
||||
*/
|
||||
int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
|
||||
nghttp2_stream *target);
|
||||
|
||||
/*
|
||||
* Computes distributed weight of a stream of the |weight| under the
|
||||
* |stream| if |stream| is removed from a dependency tree.
|
||||
*/
|
||||
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
|
||||
int32_t weight);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* exclusive. All existing direct descendants of |dep_stream| become
|
||||
* the descendants of the |stream|. This function assumes
|
||||
* |stream->item| is NULL.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* not exclusive. This function assumes |stream->item| is NULL.
|
||||
*/
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Removes the |stream| from the current dependency tree. This
|
||||
* function assumes |stream->item| is NULL.
|
||||
*/
|
||||
int nghttp2_stream_dep_remove(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Attaches |item| to |stream|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Detaches |stream->item|. This function does not free
|
||||
* |stream->item|. The caller must free it.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_detach_item(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* exclusive.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* not exclusive.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Removes subtree whose root stream is |stream|. The
|
||||
* effective_weight of streams in removed subtree is not updated.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |stream| is in any dependency tree.
|
||||
*/
|
||||
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Schedules transmission of |stream|'s item, assuming stream->item is
|
||||
* attached, and stream->last_writelen was updated.
|
||||
*/
|
||||
void nghttp2_stream_reschedule(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Changes |stream|'s weight to |weight|. If |stream| is queued, it
|
||||
* will be rescheduled based on new weight.
|
||||
*/
|
||||
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight);
|
||||
|
||||
/*
|
||||
* Returns a stream which has highest priority, updating
|
||||
* descendant_last_cycle of selected stream's ancestors.
|
||||
*/
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_stream_next_outbound_item(nghttp2_stream *stream);
|
||||
|
||||
#endif /* NGHTTP2_STREAM */
|
||||
@@ -0,0 +1,824 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_submit.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp2_session.h"
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
/*
|
||||
* Detects the dependency error, that is stream attempted to depend on
|
||||
* itself. If |stream_id| is -1, we use session->next_stream_id as
|
||||
* stream ID.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* Stream attempted to depend on itself.
|
||||
*/
|
||||
static int detect_self_dependency(nghttp2_session *session, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec) {
|
||||
assert(pri_spec);
|
||||
|
||||
if (stream_id == -1) {
|
||||
if ((int32_t)session->next_stream_id == pri_spec->stream_id) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (stream_id == pri_spec->stream_id) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This function takes ownership of |nva_copy|. Regardless of the
|
||||
return value, the caller must not free |nva_copy| after this
|
||||
function returns. */
|
||||
static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva_copy, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data) {
|
||||
int rv;
|
||||
uint8_t flags_copy;
|
||||
nghttp2_outbound_item *item = NULL;
|
||||
nghttp2_frame *frame = NULL;
|
||||
nghttp2_headers_category hcat;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
if (data_prd != NULL && data_prd->read_callback != NULL) {
|
||||
item->aux_data.headers.data_prd = *data_prd;
|
||||
}
|
||||
|
||||
item->aux_data.headers.stream_user_data = stream_user_data;
|
||||
|
||||
flags_copy =
|
||||
(uint8_t)((flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
|
||||
NGHTTP2_FLAG_END_HEADERS);
|
||||
|
||||
if (stream_id == -1) {
|
||||
if (session->next_stream_id > INT32_MAX) {
|
||||
rv = NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
stream_id = (int32_t)session->next_stream_id;
|
||||
session->next_stream_id += 2;
|
||||
|
||||
hcat = NGHTTP2_HCAT_REQUEST;
|
||||
} else {
|
||||
/* More specific categorization will be done later. */
|
||||
hcat = NGHTTP2_HCAT_HEADERS;
|
||||
}
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat,
|
||||
pri_spec, nva_copy, nvlen);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_headers_free(&frame->headers, mem);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if (hcat == NGHTTP2_HCAT_REQUEST) {
|
||||
return stream_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
/* nghttp2_frame_headers_init() takes ownership of nva_copy. */
|
||||
nghttp2_nv_array_del(nva_copy, mem);
|
||||
fail2:
|
||||
nghttp2_mem_free(mem, item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int32_t submit_headers_shared_nva(nghttp2_session *session,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data) {
|
||||
int rv;
|
||||
nghttp2_nv *nva_copy;
|
||||
nghttp2_priority_spec copy_pri_spec;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (pri_spec) {
|
||||
copy_pri_spec = *pri_spec;
|
||||
nghttp2_priority_spec_normalize_weight(©_pri_spec);
|
||||
} else {
|
||||
nghttp2_priority_spec_default_init(©_pri_spec);
|
||||
}
|
||||
|
||||
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem);
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return submit_headers_shared(session, flags, stream_id, ©_pri_spec,
|
||||
nva_copy, nvlen, data_prd, stream_user_data);
|
||||
}
|
||||
|
||||
int nghttp2_submit_trailer(nghttp2_session *session, int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen) {
|
||||
if (stream_id <= 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return (int)submit_headers_shared_nva(session, NGHTTP2_FLAG_END_STREAM,
|
||||
stream_id, NULL, nva, nvlen, NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
void *stream_user_data) {
|
||||
int rv;
|
||||
|
||||
if (stream_id == -1) {
|
||||
if (session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
} else if (stream_id <= 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
flags &= NGHTTP2_FLAG_END_STREAM;
|
||||
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
rv = detect_self_dependency(session, stream_id, pri_spec);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
} else {
|
||||
pri_spec = NULL;
|
||||
}
|
||||
|
||||
return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva,
|
||||
nvlen, NULL, stream_user_data);
|
||||
}
|
||||
|
||||
int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
|
||||
const uint8_t *opaque_data) {
|
||||
flags &= NGHTTP2_FLAG_ACK;
|
||||
return nghttp2_session_add_ping(session, flags, opaque_data);
|
||||
}
|
||||
|
||||
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_priority_spec copy_pri_spec;
|
||||
nghttp2_mem *mem;
|
||||
(void)flags;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (stream_id == 0 || pri_spec == NULL) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (stream_id == pri_spec->stream_id) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
copy_pri_spec = *pri_spec;
|
||||
|
||||
nghttp2_priority_spec_normalize_weight(©_pri_spec);
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
nghttp2_frame_priority_init(&frame->priority, stream_id, ©_pri_spec);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
nghttp2_mem_free(mem, item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, uint32_t error_code) {
|
||||
(void)flags;
|
||||
|
||||
if (stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
return nghttp2_session_add_rst_stream(session, stream_id, error_code);
|
||||
}
|
||||
|
||||
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
|
||||
int32_t last_stream_id, uint32_t error_code,
|
||||
const uint8_t *opaque_data, size_t opaque_data_len) {
|
||||
(void)flags;
|
||||
|
||||
if (session->goaway_flags & NGHTTP2_GOAWAY_TERM_ON_SEND) {
|
||||
return 0;
|
||||
}
|
||||
return nghttp2_session_add_goaway(session, last_stream_id, error_code,
|
||||
opaque_data, opaque_data_len,
|
||||
NGHTTP2_GOAWAY_AUX_NONE);
|
||||
}
|
||||
|
||||
int nghttp2_submit_shutdown_notice(nghttp2_session *session) {
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
if (session->goaway_flags) {
|
||||
return 0;
|
||||
}
|
||||
return nghttp2_session_add_goaway(session, (1u << 31) - 1, NGHTTP2_NO_ERROR,
|
||||
NULL, 0,
|
||||
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE);
|
||||
}
|
||||
|
||||
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_settings_entry *iv, size_t niv) {
|
||||
(void)flags;
|
||||
return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
|
||||
}
|
||||
|
||||
int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const nghttp2_nv *nva,
|
||||
size_t nvlen,
|
||||
void *promised_stream_user_data) {
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_nv *nva_copy;
|
||||
uint8_t flags_copy;
|
||||
int32_t promised_stream_id;
|
||||
int rv;
|
||||
nghttp2_mem *mem;
|
||||
(void)flags;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (stream_id <= 0 || nghttp2_session_is_my_stream_id(session, stream_id)) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
/* All 32bit signed stream IDs are spent. */
|
||||
if (session->next_stream_id > INT32_MAX) {
|
||||
return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
item->aux_data.headers.stream_user_data = promised_stream_user_data;
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen, mem);
|
||||
if (rv < 0) {
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
|
||||
flags_copy = NGHTTP2_FLAG_END_HEADERS;
|
||||
|
||||
promised_stream_id = (int32_t)session->next_stream_id;
|
||||
session->next_stream_id += 2;
|
||||
|
||||
nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy, stream_id,
|
||||
promised_stream_id, nva_copy, nvlen);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_push_promise_free(&frame->push_promise, mem);
|
||||
nghttp2_mem_free(mem, item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return promised_stream_id;
|
||||
}
|
||||
|
||||
int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t window_size_increment) {
|
||||
int rv;
|
||||
nghttp2_stream *stream = 0;
|
||||
(void)flags;
|
||||
|
||||
if (window_size_increment == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (stream_id == 0) {
|
||||
rv = nghttp2_adjust_local_window_size(
|
||||
&session->local_window_size, &session->recv_window_size,
|
||||
&session->recv_reduction, &window_size_increment);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
stream = nghttp2_session_get_stream(session, stream_id);
|
||||
if (!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = nghttp2_adjust_local_window_size(
|
||||
&stream->local_window_size, &stream->recv_window_size,
|
||||
&stream->recv_reduction, &window_size_increment);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if (window_size_increment > 0) {
|
||||
if (stream_id == 0) {
|
||||
session->consumed_size =
|
||||
nghttp2_max(0, session->consumed_size - window_size_increment);
|
||||
} else {
|
||||
stream->consumed_size =
|
||||
nghttp2_max(0, stream->consumed_size - window_size_increment);
|
||||
}
|
||||
|
||||
return nghttp2_session_add_window_update(session, 0, stream_id,
|
||||
window_size_increment);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_session_set_local_window_size(nghttp2_session *session,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
int32_t window_size) {
|
||||
int32_t window_size_increment;
|
||||
nghttp2_stream *stream;
|
||||
int rv;
|
||||
(void)flags;
|
||||
|
||||
if (window_size < 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (stream_id == 0) {
|
||||
window_size_increment = window_size - session->local_window_size;
|
||||
|
||||
if (window_size_increment == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (window_size_increment < 0) {
|
||||
return nghttp2_adjust_local_window_size(
|
||||
&session->local_window_size, &session->recv_window_size,
|
||||
&session->recv_reduction, &window_size_increment);
|
||||
}
|
||||
|
||||
rv = nghttp2_increase_local_window_size(
|
||||
&session->local_window_size, &session->recv_window_size,
|
||||
&session->recv_reduction, &window_size_increment);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (window_size_increment > 0) {
|
||||
return nghttp2_session_add_window_update(session, 0, stream_id,
|
||||
window_size_increment);
|
||||
}
|
||||
|
||||
return nghttp2_session_update_recv_connection_window_size(session, 0);
|
||||
} else {
|
||||
stream = nghttp2_session_get_stream(session, stream_id);
|
||||
|
||||
if (stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
window_size_increment = window_size - stream->local_window_size;
|
||||
|
||||
if (window_size_increment == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (window_size_increment < 0) {
|
||||
return nghttp2_adjust_local_window_size(
|
||||
&stream->local_window_size, &stream->recv_window_size,
|
||||
&stream->recv_reduction, &window_size_increment);
|
||||
}
|
||||
|
||||
rv = nghttp2_increase_local_window_size(
|
||||
&stream->local_window_size, &stream->recv_window_size,
|
||||
&stream->recv_reduction, &window_size_increment);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (window_size_increment > 0) {
|
||||
return nghttp2_session_add_window_update(session, 0, stream_id,
|
||||
window_size_increment);
|
||||
}
|
||||
|
||||
return nghttp2_session_update_recv_stream_window_size(session, stream, 0,
|
||||
1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *origin,
|
||||
size_t origin_len, const uint8_t *field_value,
|
||||
size_t field_value_len) {
|
||||
nghttp2_mem *mem;
|
||||
uint8_t *buf, *p;
|
||||
uint8_t *origin_copy;
|
||||
uint8_t *field_value_copy;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
int rv;
|
||||
(void)flags;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (2 + origin_len + field_value_len > NGHTTP2_MAX_PAYLOADLEN) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (stream_id == 0) {
|
||||
if (origin_len == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
} else if (origin_len != 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
buf = nghttp2_mem_malloc(mem, origin_len + field_value_len + 2);
|
||||
if (buf == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
p = buf;
|
||||
|
||||
origin_copy = p;
|
||||
if (origin_len) {
|
||||
p = nghttp2_cpymem(p, origin, origin_len);
|
||||
}
|
||||
*p++ = '\0';
|
||||
|
||||
field_value_copy = p;
|
||||
if (field_value_len) {
|
||||
p = nghttp2_cpymem(p, field_value, field_value_len);
|
||||
}
|
||||
*p++ = '\0';
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail_item_malloc;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
item->aux_data.ext.builtin = 1;
|
||||
|
||||
altsvc = &item->ext_frame_payload.altsvc;
|
||||
|
||||
frame = &item->frame;
|
||||
frame->ext.payload = altsvc;
|
||||
|
||||
nghttp2_frame_altsvc_init(&frame->ext, stream_id, origin_copy, origin_len,
|
||||
field_value_copy, field_value_len);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_altsvc_free(&frame->ext, mem);
|
||||
nghttp2_mem_free(mem, item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_item_malloc:
|
||||
free(buf);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_origin_entry *ov, size_t nov) {
|
||||
nghttp2_mem *mem;
|
||||
uint8_t *p;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_ext_origin *origin;
|
||||
nghttp2_origin_entry *ov_copy;
|
||||
size_t len = 0;
|
||||
size_t i;
|
||||
int rv;
|
||||
(void)flags;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (nov) {
|
||||
for (i = 0; i < nov; ++i) {
|
||||
len += ov[i].origin_len;
|
||||
}
|
||||
|
||||
if (2 * nov + len > NGHTTP2_MAX_PAYLOADLEN) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* The last nov is added for terminal NULL character. */
|
||||
ov_copy =
|
||||
nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov);
|
||||
if (ov_copy == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
p = (uint8_t *)ov_copy + nov * sizeof(nghttp2_origin_entry);
|
||||
|
||||
for (i = 0; i < nov; ++i) {
|
||||
ov_copy[i].origin = p;
|
||||
ov_copy[i].origin_len = ov[i].origin_len;
|
||||
p = nghttp2_cpymem(p, ov[i].origin, ov[i].origin_len);
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
assert((size_t)(p - (uint8_t *)ov_copy) ==
|
||||
nov * sizeof(nghttp2_origin_entry) + len + nov);
|
||||
} else {
|
||||
ov_copy = NULL;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail_item_malloc;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
item->aux_data.ext.builtin = 1;
|
||||
|
||||
origin = &item->ext_frame_payload.origin;
|
||||
|
||||
frame = &item->frame;
|
||||
frame->ext.payload = origin;
|
||||
|
||||
nghttp2_frame_origin_init(&frame->ext, ov_copy, nov);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_origin_free(&frame->ext, mem);
|
||||
nghttp2_mem_free(mem, item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_item_malloc:
|
||||
free(ov_copy);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||
if (data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
flags |= NGHTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
|
||||
if (pri_spec) {
|
||||
flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
int32_t nghttp2_submit_request(nghttp2_session *session,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data) {
|
||||
uint8_t flags;
|
||||
int rv;
|
||||
|
||||
if (session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
rv = detect_self_dependency(session, -1, pri_spec);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
pri_spec = NULL;
|
||||
}
|
||||
|
||||
flags = set_request_flags(pri_spec, data_prd);
|
||||
|
||||
return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen,
|
||||
data_prd, stream_user_data);
|
||||
}
|
||||
|
||||
static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||
if (data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
flags |= NGHTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags;
|
||||
|
||||
if (stream_id <= 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
flags = set_response_flags(data_prd);
|
||||
return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
|
||||
data_prd, NULL);
|
||||
}
|
||||
|
||||
int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_data_aux_data *aux_data;
|
||||
uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
aux_data = &item->aux_data.data;
|
||||
aux_data->data_prd = *data_prd;
|
||||
aux_data->eof = 0;
|
||||
aux_data->flags = nflags;
|
||||
|
||||
/* flags are sent on transmission */
|
||||
nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
|
||||
const nghttp2_settings_entry *iv,
|
||||
size_t niv) {
|
||||
if (!nghttp2_iv_check(iv, niv)) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) {
|
||||
return NGHTTP2_ERR_INSUFF_BUFSIZE;
|
||||
}
|
||||
|
||||
return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv);
|
||||
}
|
||||
|
||||
int nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id, void *payload) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (type <= NGHTTP2_CONTINUATION) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!session->callbacks.pack_extension_callback) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_extension_free(&frame->ext);
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_SUBMIT_H
|
||||
#define NGHTTP2_SUBMIT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#endif /* NGHTTP2_SUBMIT_H */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
static nghttp2_info version = {NGHTTP2_VERSION_AGE, NGHTTP2_VERSION_NUM,
|
||||
NGHTTP2_VERSION, NGHTTP2_PROTO_VERSION_ID};
|
||||
|
||||
nghttp2_info *nghttp2_version(int least_version) {
|
||||
if (least_version > NGHTTP2_VERSION_NUM)
|
||||
return NULL;
|
||||
return &version;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#include <winver.h>
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
|
||||
FILEVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0
|
||||
PRODUCTVERSION @PROJECT_VERSION_MAJOR@, @PROJECT_VERSION_MINOR@, @PROJECT_VERSION_PATCH@, 0
|
||||
FILEFLAGSMASK 0x3fL
|
||||
FILEOS 0x40004L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
#ifdef _DEBUG
|
||||
#define VER_STR "@[email protected] (MSVC debug)"
|
||||
#define DBG "d"
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
#define VER_STR "@[email protected] (MSVC release)"
|
||||
#define DBG ""
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "https://nghttp2.org/"
|
||||
VALUE "FileDescription", "nghttp2; HTTP/2 C library"
|
||||
VALUE "FileVersion", VER_STR
|
||||
VALUE "InternalName", "nghttp2" DBG
|
||||
VALUE "LegalCopyright", "The MIT License"
|
||||
VALUE "LegalTrademarks", ""
|
||||
VALUE "OriginalFilename", "nghttp2" DBG ".dll"
|
||||
VALUE "ProductName", "NGHTTP2."
|
||||
VALUE "ProductVersion", VER_STR
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
||||
Reference in New Issue
Block a user