mirror of https://github.com/lukechilds/node.git
Browse Source
PR-URL: https://github.com/nodejs/node/pull/14239 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>v6
James M Snell
8 years ago
55 changed files with 30847 additions and 0 deletions
@ -0,0 +1,63 @@ |
|||
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 |
|||
) |
|||
|
|||
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 |
|||
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 |
|||
) |
|||
|
|||
if(HAVE_CUNIT) |
|||
# 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 |
|||
) |
|||
target_compile_definitions(nghttp2_static PUBLIC "-DNGHTTP2_STATICLIB") |
|||
endif() |
|||
|
|||
install(TARGETS nghttp2 |
|||
DESTINATION "${CMAKE_INSTALL_LIBDIR}") |
|||
|
|||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libnghttp2.pc" |
|||
DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") |
@ -0,0 +1,72 @@ |
|||
# 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 |
|||
|
|||
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 |
|||
|
|||
libnghttp2_la_SOURCES = $(HFILES) $(OBJECTS) |
|||
libnghttp2_la_LDFLAGS = -no-undefined \
|
|||
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) |
@ -0,0 +1,286 @@ |
|||
#
|
|||
# GNU Makefile for nghttp2 / MSVC.
|
|||
#
|
|||
# By G. Vanem <gvanem@yahoo.no> 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_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,80 @@ |
|||
/* Hint to the compiler that a function never returns */ |
|||
#define NGHTTP2_NORETURN |
|||
|
|||
/* Define to `int' if <sys/types.h> does not define. */ |
|||
#define ssize_t int |
|||
|
|||
/* Define to 1 if you have the `std::map::emplace`. */ |
|||
#define HAVE_STD_MAP_EMPLACE 1 |
|||
|
|||
/* Define to 1 if you have `libjansson` library. */ |
|||
/* #undef HAVE_JANSSON */ |
|||
|
|||
/* Define to 1 if you have `libxml2` library. */ |
|||
/* #undef HAVE_LIBXML2 */ |
|||
|
|||
/* Define to 1 if you have `spdylay` library. */ |
|||
/* #undef HAVE_SPDYLAY */ |
|||
|
|||
/* Define to 1 if you have `mruby` library. */ |
|||
/* #undef HAVE_MRUBY */ |
|||
|
|||
/* Define to 1 if you have `neverbleed` library. */ |
|||
/* #undef HAVE_NEVERBLEED */ |
|||
|
|||
/* sizeof(int *) */ |
|||
#define SIZEOF_INT_P 4 |
|||
|
|||
/* sizeof(time_t) */ |
|||
#define SIZEOF_TIME_T 8 |
|||
|
|||
/* Define to 1 if you have the `_Exit` function. */ |
|||
#define HAVE__EXIT 1 |
|||
|
|||
/* Define to 1 if you have the `accept4` function. */ |
|||
/* #undef HAVE_ACCEPT4 */ |
|||
|
|||
/* Define to 1 if you have the `initgroups` function. */ |
|||
#define HAVE_DECL_INITGROUPS 0 |
|||
|
|||
/* Define to 1 to enable debug output. */ |
|||
/* #undef DEBUGBUILD */ |
|||
|
|||
/* Define to 1 if you want to disable threads. */ |
|||
/* #undef NOTHREADS */ |
|||
|
|||
/* Define to 1 if you have the <arpa/inet.h> header file. */ |
|||
/* #undef HAVE_ARPA_INET_H */ |
|||
|
|||
/* Define to 1 if you have the <fcntl.h> header file. */ |
|||
#define HAVE_FCNTL_H 1 |
|||
|
|||
/* Define to 1 if you have the <inttypes.h> header file. */ |
|||
#define HAVE_INTTYPES_H 1 |
|||
|
|||
/* Define to 1 if you have the <limits.h> header file. */ |
|||
#define HAVE_LIMITS_H 1 |
|||
|
|||
/* Define to 1 if you have the <netdb.h> header file. */ |
|||
/* #undef HAVE_NETDB_H */ |
|||
|
|||
/* Define to 1 if you have the <netinet/in.h> header file. */ |
|||
/* #undef HAVE_NETINET_IN_H */ |
|||
|
|||
/* Define to 1 if you have the <pwd.h> header file. */ |
|||
/* #undef HAVE_PWD_H */ |
|||
|
|||
/* Define to 1 if you have the <sys/socket.h> header file. */ |
|||
/* #undef HAVE_SYS_SOCKET_H */ |
|||
|
|||
/* Define to 1 if you have the <sys/time.h> header file. */ |
|||
/* #undef HAVE_SYS_TIME_H */ |
|||
|
|||
/* Define to 1 if you have the <syslog.h> header file. */ |
|||
/* #undef HAVE_SYSLOG_H */ |
|||
|
|||
/* Define to 1 if you have the <time.h> header file. */ |
|||
#define HAVE_TIME_H 1 |
|||
|
|||
/* Define to 1 if you have the <unistd.h> header file. */ |
|||
/* #undef HAVE_UNISTD_H */ |
File diff suppressed because it is too large
@ -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.22.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 0x011600 |
|||
|
|||
#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,525 @@ |
|||
/*
|
|||
* 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 = begin; |
|||
buf->end = begin + 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 emtpy. |
|||
*/ |
|||
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,170 @@ |
|||
/*
|
|||
* 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; |
|||
} |
@ -0,0 +1,124 @@ |
|||
/*
|
|||
* 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; |
|||
}; |
|||
|
|||
#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 */ |
@ -0,0 +1,993 @@ |
|||
/*
|
|||
* 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_frame.h" |
|||
|
|||
#include <string.h> |
|||
#include <assert.h> |
|||
#include <stdio.h> |
|||
#include <errno.h> |
|||
|
|||
#include "nghttp2_helper.h" |
|||
#include "nghttp2_net.h" |
|||
#include "nghttp2_priority_spec.h" |
|||
#include "nghttp2_debug.h" |
|||
|
|||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd) { |
|||
nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8)); |
|||
buf[3] = hd->type; |
|||
buf[4] = hd->flags; |
|||
nghttp2_put_uint32be(&buf[5], (uint32_t)hd->stream_id); |
|||
/* ignore hd->reserved for now */ |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf) { |
|||
hd->length = nghttp2_get_uint32(&buf[0]) >> 8; |
|||
hd->type = buf[3]; |
|||
hd->flags = buf[4]; |
|||
hd->stream_id = nghttp2_get_uint32(&buf[5]) & NGHTTP2_STREAM_ID_MASK; |
|||
hd->reserved = 0; |
|||
} |
|||
|
|||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type, |
|||
uint8_t flags, int32_t stream_id) { |
|||
hd->length = length; |
|||
hd->type = type; |
|||
hd->flags = flags; |
|||
hd->stream_id = stream_id; |
|||
hd->reserved = 0; |
|||
} |
|||
|
|||
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) { |
|||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id); |
|||
frame->padlen = 0; |
|||
frame->nva = nva; |
|||
frame->nvlen = nvlen; |
|||
frame->cat = cat; |
|||
|
|||
if (pri_spec) { |
|||
frame->pri_spec = *pri_spec; |
|||
} else { |
|||
nghttp2_priority_spec_default_init(&frame->pri_spec); |
|||
} |
|||
} |
|||
|
|||
void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem) { |
|||
nghttp2_nv_array_del(frame->nva, mem); |
|||
} |
|||
|
|||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id, |
|||
const nghttp2_priority_spec *pri_spec) { |
|||
nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY, |
|||
NGHTTP2_FLAG_NONE, stream_id); |
|||
frame->pri_spec = *pri_spec; |
|||
} |
|||
|
|||
void nghttp2_frame_priority_free(nghttp2_priority *frame) { (void)frame; } |
|||
|
|||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id, |
|||
uint32_t error_code) { |
|||
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE, |
|||
stream_id); |
|||
frame->error_code = error_code; |
|||
} |
|||
|
|||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame) { (void)frame; } |
|||
|
|||
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags, |
|||
nghttp2_settings_entry *iv, size_t niv) { |
|||
nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH, |
|||
NGHTTP2_SETTINGS, flags, 0); |
|||
frame->niv = niv; |
|||
frame->iv = iv; |
|||
} |
|||
|
|||
void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem) { |
|||
nghttp2_mem_free(mem, frame->iv); |
|||
} |
|||
|
|||
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) { |
|||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id); |
|||
frame->padlen = 0; |
|||
frame->nva = nva; |
|||
frame->nvlen = nvlen; |
|||
frame->promised_stream_id = promised_stream_id; |
|||
frame->reserved = 0; |
|||
} |
|||
|
|||
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame, |
|||
nghttp2_mem *mem) { |
|||
nghttp2_nv_array_del(frame->nva, mem); |
|||
} |
|||
|
|||
void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags, |
|||
const uint8_t *opaque_data) { |
|||
nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0); |
|||
if (opaque_data) { |
|||
memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data)); |
|||
} else { |
|||
memset(frame->opaque_data, 0, sizeof(frame->opaque_data)); |
|||
} |
|||
} |
|||
|
|||
void nghttp2_frame_ping_free(nghttp2_ping *frame) { (void)frame; } |
|||
|
|||
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) { |
|||
nghttp2_frame_hd_init(&frame->hd, 8 + opaque_data_len, NGHTTP2_GOAWAY, |
|||
NGHTTP2_FLAG_NONE, 0); |
|||
frame->last_stream_id = last_stream_id; |
|||
frame->error_code = error_code; |
|||
frame->opaque_data = opaque_data; |
|||
frame->opaque_data_len = opaque_data_len; |
|||
frame->reserved = 0; |
|||
} |
|||
|
|||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem) { |
|||
nghttp2_mem_free(mem, frame->opaque_data); |
|||
} |
|||
|
|||
void nghttp2_frame_window_update_init(nghttp2_window_update *frame, |
|||
uint8_t flags, int32_t stream_id, |
|||
int32_t window_size_increment) { |
|||
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id); |
|||
frame->window_size_increment = window_size_increment; |
|||
frame->reserved = 0; |
|||
} |
|||
|
|||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame) { |
|||
(void)frame; |
|||
} |
|||
|
|||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) { |
|||
/* We have iframe->padlen == 0, but iframe->frame.hd.flags may have
|
|||
NGHTTP2_FLAG_PADDED set. This happens when receiving |
|||
CONTINUATION frame, since we don't reset flags after HEADERS was |
|||
received. */ |
|||
if (padlen == 0) { |
|||
return 0; |
|||
} |
|||
return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0); |
|||
} |
|||
|
|||
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags, |
|||
int32_t stream_id) { |
|||
/* At this moment, the length of DATA frame is unknown */ |
|||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id); |
|||
frame->padlen = 0; |
|||
} |
|||
|
|||
void nghttp2_frame_data_free(nghttp2_data *frame) { (void)frame; } |
|||
|
|||
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type, |
|||
uint8_t flags, int32_t stream_id, |
|||
void *payload) { |
|||
nghttp2_frame_hd_init(&frame->hd, 0, type, flags, stream_id); |
|||
frame->payload = payload; |
|||
} |
|||
|
|||
void nghttp2_frame_extension_free(nghttp2_extension *frame) { (void)frame; } |
|||
|
|||
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) { |
|||
nghttp2_ext_altsvc *altsvc; |
|||
|
|||
nghttp2_frame_hd_init(&frame->hd, 2 + origin_len + field_value_len, |
|||
NGHTTP2_ALTSVC, NGHTTP2_FLAG_NONE, stream_id); |
|||
|
|||
altsvc = frame->payload; |
|||
altsvc->origin = origin; |
|||
altsvc->origin_len = origin_len; |
|||
altsvc->field_value = field_value; |
|||
altsvc->field_value_len = field_value_len; |
|||
} |
|||
|
|||
void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem) { |
|||
nghttp2_ext_altsvc *altsvc; |
|||
|
|||
altsvc = frame->payload; |
|||
/* We use the same buffer for altsvc->origin and
|
|||
altsvc->field_value. */ |
|||
nghttp2_mem_free(mem, altsvc->origin); |
|||
} |
|||
|
|||
size_t nghttp2_frame_priority_len(uint8_t flags) { |
|||
if (flags & NGHTTP2_FLAG_PRIORITY) { |
|||
return NGHTTP2_PRIORITY_SPECLEN; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) { |
|||
return nghttp2_frame_priority_len(frame->hd.flags); |
|||
} |
|||
|
|||
/*
|
|||
* Call this function after payload was serialized, but not before |
|||
* changing buf->pos and serializing frame header. |
|||
* |
|||
* This function assumes bufs->cur points to the last buf chain of the |
|||
* frame(s). |
|||
* |
|||
* This function serializes frame header for HEADERS/PUSH_PROMISE and |
|||
* handles their successive CONTINUATION frames. |
|||
* |
|||
* We don't process any padding here. |
|||
*/ |
|||
static int frame_pack_headers_shared(nghttp2_bufs *bufs, |
|||
nghttp2_frame_hd *frame_hd) { |
|||
nghttp2_buf *buf; |
|||
nghttp2_buf_chain *ci, *ce; |
|||
nghttp2_frame_hd hd; |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
hd = *frame_hd; |
|||
hd.length = nghttp2_buf_len(buf); |
|||
|
|||
DEBUGF("send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length); |
|||
|
|||
/* We have multiple frame buffers, which means one or more
|
|||
CONTINUATION frame is involved. Remove END_HEADERS flag from the |
|||
first frame. */ |
|||
if (bufs->head != bufs->cur) { |
|||
hd.flags = (uint8_t)(hd.flags & ~NGHTTP2_FLAG_END_HEADERS); |
|||
} |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
nghttp2_frame_pack_frame_hd(buf->pos, &hd); |
|||
|
|||
if (bufs->head != bufs->cur) { |
|||
/* 2nd and later frames are CONTINUATION frames. */ |
|||
hd.type = NGHTTP2_CONTINUATION; |
|||
/* We don't have no flags except for last CONTINUATION */ |
|||
hd.flags = NGHTTP2_FLAG_NONE; |
|||
|
|||
ce = bufs->cur; |
|||
|
|||
for (ci = bufs->head->next; ci != ce; ci = ci->next) { |
|||
buf = &ci->buf; |
|||
|
|||
hd.length = nghttp2_buf_len(buf); |
|||
|
|||
DEBUGF("send: int CONTINUATION, payloadlen=%zu\n", hd.length); |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
nghttp2_frame_pack_frame_hd(buf->pos, &hd); |
|||
} |
|||
|
|||
buf = &ci->buf; |
|||
hd.length = nghttp2_buf_len(buf); |
|||
/* Set END_HEADERS flag for last CONTINUATION */ |
|||
hd.flags = NGHTTP2_FLAG_END_HEADERS; |
|||
|
|||
DEBUGF("send: last CONTINUATION, payloadlen=%zu\n", hd.length); |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
nghttp2_frame_pack_frame_hd(buf->pos, &hd); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame, |
|||
nghttp2_hd_deflater *deflater) { |
|||
size_t nv_offset; |
|||
int rv; |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
nv_offset = nghttp2_frame_headers_payload_nv_offset(frame); |
|||
|
|||
buf = &bufs->cur->buf; |
|||
|
|||
buf->pos += nv_offset; |
|||
buf->last = buf->pos; |
|||
|
|||
/* This call will adjust buf->last to the correct position */ |
|||
rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); |
|||
|
|||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) { |
|||
rv = NGHTTP2_ERR_HEADER_COMP; |
|||
} |
|||
|
|||
buf->pos -= nv_offset; |
|||
|
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
|
|||
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { |
|||
nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec); |
|||
} |
|||
|
|||
frame->padlen = 0; |
|||
frame->hd.length = nghttp2_bufs_len(bufs); |
|||
|
|||
return frame_pack_headers_shared(bufs, &frame->hd); |
|||
} |
|||
|
|||
void nghttp2_frame_pack_priority_spec(uint8_t *buf, |
|||
const nghttp2_priority_spec *pri_spec) { |
|||
nghttp2_put_uint32be(buf, (uint32_t)pri_spec->stream_id); |
|||
if (pri_spec->exclusive) { |
|||
buf[0] |= 0x80; |
|||
} |
|||
buf[4] = (uint8_t)(pri_spec->weight - 1); |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec, |
|||
const uint8_t *payload) { |
|||
int32_t dep_stream_id; |
|||
uint8_t exclusive; |
|||
int32_t weight; |
|||
|
|||
dep_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; |
|||
exclusive = (payload[0] & 0x80) > 0; |
|||
weight = payload[4] + 1; |
|||
|
|||
nghttp2_priority_spec_init(pri_spec, dep_stream_id, weight, exclusive); |
|||
} |
|||
|
|||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame, |
|||
const uint8_t *payload) { |
|||
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) { |
|||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); |
|||
} else { |
|||
nghttp2_priority_spec_default_init(&frame->pri_spec); |
|||
} |
|||
|
|||
frame->nva = NULL; |
|||
frame->nvlen = 0; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) { |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
assert(nghttp2_buf_avail(buf) >= NGHTTP2_PRIORITY_SPECLEN); |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
|
|||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); |
|||
|
|||
nghttp2_frame_pack_priority_spec(buf->last, &frame->pri_spec); |
|||
|
|||
buf->last += NGHTTP2_PRIORITY_SPECLEN; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame, |
|||
const uint8_t *payload) { |
|||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, payload); |
|||
} |
|||
|
|||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs, |
|||
nghttp2_rst_stream *frame) { |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
assert(nghttp2_buf_avail(buf) >= 4); |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
|
|||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); |
|||
|
|||
nghttp2_put_uint32be(buf->last, frame->error_code); |
|||
buf->last += 4; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame, |
|||
const uint8_t *payload) { |
|||
frame->error_code = nghttp2_get_uint32(payload); |
|||
} |
|||
|
|||
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame) { |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
if (nghttp2_buf_avail(buf) < frame->hd.length) { |
|||
return NGHTTP2_ERR_FRAME_SIZE_ERROR; |
|||
} |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
|
|||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); |
|||
|
|||
buf->last += |
|||
nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf, |
|||
const nghttp2_settings_entry *iv, |
|||
size_t niv) { |
|||
size_t i; |
|||
for (i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) { |
|||
nghttp2_put_uint16be(buf, (uint16_t)iv[i].settings_id); |
|||
nghttp2_put_uint32be(buf + 2, iv[i].value); |
|||
} |
|||
return NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH * niv; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame, |
|||
nghttp2_settings_entry *iv, |
|||
size_t niv) { |
|||
frame->iv = iv; |
|||
frame->niv = niv; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv, |
|||
const uint8_t *payload) { |
|||
iv->settings_id = nghttp2_get_uint16(&payload[0]); |
|||
iv->value = nghttp2_get_uint32(&payload[2]); |
|||
} |
|||
|
|||
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) { |
|||
size_t i; |
|||
|
|||
*niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; |
|||
|
|||
if (*niv_ptr == 0) { |
|||
*iv_ptr = NULL; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
*iv_ptr = |
|||
nghttp2_mem_malloc(mem, (*niv_ptr) * sizeof(nghttp2_settings_entry)); |
|||
|
|||
if (*iv_ptr == NULL) { |
|||
return NGHTTP2_ERR_NOMEM; |
|||
} |
|||
|
|||
for (i = 0; i < *niv_ptr; ++i) { |
|||
size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH; |
|||
nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs, |
|||
nghttp2_push_promise *frame, |
|||
nghttp2_hd_deflater *deflater) { |
|||
size_t nv_offset = 4; |
|||
int rv; |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
buf = &bufs->cur->buf; |
|||
|
|||
buf->pos += nv_offset; |
|||
buf->last = buf->pos; |
|||
|
|||
/* This call will adjust buf->last to the correct position */ |
|||
rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen); |
|||
|
|||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) { |
|||
rv = NGHTTP2_ERR_HEADER_COMP; |
|||
} |
|||
|
|||
buf->pos -= nv_offset; |
|||
|
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
|
|||
nghttp2_put_uint32be(buf->pos, (uint32_t)frame->promised_stream_id); |
|||
|
|||
frame->padlen = 0; |
|||
frame->hd.length = nghttp2_bufs_len(bufs); |
|||
|
|||
return frame_pack_headers_shared(bufs, &frame->hd); |
|||
} |
|||
|
|||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame, |
|||
const uint8_t *payload) { |
|||
frame->promised_stream_id = |
|||
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; |
|||
frame->nva = NULL; |
|||
frame->nvlen = 0; |
|||
return 0; |
|||
} |
|||
|
|||
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) { |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
assert(nghttp2_buf_avail(buf) >= 8); |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
|
|||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); |
|||
|
|||
buf->last = |
|||
nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data)); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame, |
|||
const uint8_t *payload) { |
|||
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data)); |
|||
} |
|||
|
|||
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame) { |
|||
int rv; |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
|
|||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); |
|||
|
|||
nghttp2_put_uint32be(buf->last, (uint32_t)frame->last_stream_id); |
|||
buf->last += 4; |
|||
|
|||
nghttp2_put_uint32be(buf->last, frame->error_code); |
|||
buf->last += 4; |
|||
|
|||
rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len); |
|||
|
|||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) { |
|||
return NGHTTP2_ERR_FRAME_SIZE_ERROR; |
|||
} |
|||
|
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame, |
|||
const uint8_t *payload, |
|||
uint8_t *var_gift_payload, |
|||
size_t var_gift_payloadlen) { |
|||
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK; |
|||
frame->error_code = nghttp2_get_uint32(payload + 4); |
|||
|
|||
frame->opaque_data = var_gift_payload; |
|||
frame->opaque_data_len = var_gift_payloadlen; |
|||
} |
|||
|
|||
int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame, |
|||
const uint8_t *payload, |
|||
size_t payloadlen, nghttp2_mem *mem) { |
|||
uint8_t *var_gift_payload; |
|||
size_t var_gift_payloadlen; |
|||
|
|||
if (payloadlen > 8) { |
|||
var_gift_payloadlen = payloadlen - 8; |
|||
} else { |
|||
var_gift_payloadlen = 0; |
|||
} |
|||
|
|||
payloadlen -= var_gift_payloadlen; |
|||
|
|||
if (!var_gift_payloadlen) { |
|||
var_gift_payload = NULL; |
|||
} else { |
|||
var_gift_payload = nghttp2_mem_malloc(mem, var_gift_payloadlen); |
|||
|
|||
if (var_gift_payload == NULL) { |
|||
return NGHTTP2_ERR_NOMEM; |
|||
} |
|||
|
|||
memcpy(var_gift_payload, payload + 8, var_gift_payloadlen); |
|||
} |
|||
|
|||
nghttp2_frame_unpack_goaway_payload(frame, payload, var_gift_payload, |
|||
var_gift_payloadlen); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs, |
|||
nghttp2_window_update *frame) { |
|||
nghttp2_buf *buf; |
|||
|
|||
assert(bufs->head == bufs->cur); |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
assert(nghttp2_buf_avail(buf) >= 4); |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
|
|||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); |
|||
|
|||
nghttp2_put_uint32be(buf->last, (uint32_t)frame->window_size_increment); |
|||
buf->last += 4; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame, |
|||
const uint8_t *payload) { |
|||
frame->window_size_increment = |
|||
nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK; |
|||
} |
|||
|
|||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) { |
|||
int rv; |
|||
nghttp2_buf *buf; |
|||
nghttp2_ext_altsvc *altsvc; |
|||
|
|||
altsvc = frame->payload; |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
assert(nghttp2_buf_avail(buf) >= |
|||
2 + altsvc->origin_len + altsvc->field_value_len); |
|||
|
|||
buf->pos -= NGHTTP2_FRAME_HDLEN; |
|||
|
|||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd); |
|||
|
|||
nghttp2_put_uint16be(buf->last, (uint16_t)altsvc->origin_len); |
|||
buf->last += 2; |
|||
|
|||
rv = nghttp2_bufs_add(bufs, altsvc->origin, altsvc->origin_len); |
|||
|
|||
assert(rv == 0); |
|||
|
|||
rv = nghttp2_bufs_add(bufs, altsvc->field_value, altsvc->field_value_len); |
|||
|
|||
assert(rv == 0); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame, |
|||
size_t origin_len, uint8_t *payload, |
|||
size_t payloadlen) { |
|||
nghttp2_ext_altsvc *altsvc; |
|||
uint8_t *p; |
|||
|
|||
altsvc = frame->payload; |
|||
p = payload; |
|||
|
|||
altsvc->origin = p; |
|||
|
|||
p += origin_len; |
|||
|
|||
altsvc->origin_len = origin_len; |
|||
|
|||
altsvc->field_value = p; |
|||
altsvc->field_value_len = (size_t)(payload + payloadlen - p); |
|||
} |
|||
|
|||
int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame, |
|||
const uint8_t *payload, |
|||
size_t payloadlen, nghttp2_mem *mem) { |
|||
uint8_t *buf; |
|||
size_t origin_len; |
|||
|
|||
if (payloadlen < 2) { |
|||
return NGHTTP2_FRAME_SIZE_ERROR; |
|||
} |
|||
|
|||
origin_len = nghttp2_get_uint16(payload); |
|||
|
|||
buf = nghttp2_mem_malloc(mem, payloadlen - 2); |
|||
if (!buf) { |
|||
return NGHTTP2_ERR_NOMEM; |
|||
} |
|||
|
|||
nghttp2_cpymem(buf, payload + 2, payloadlen - 2); |
|||
|
|||
nghttp2_frame_unpack_altsvc_payload(frame, origin_len, buf, payloadlen - 2); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv, |
|||
size_t niv, nghttp2_mem *mem) { |
|||
nghttp2_settings_entry *iv_copy; |
|||
size_t len = niv * sizeof(nghttp2_settings_entry); |
|||
|
|||
if (len == 0) { |
|||
return NULL; |
|||
} |
|||
|
|||
iv_copy = nghttp2_mem_malloc(mem, len); |
|||
|
|||
if (iv_copy == NULL) { |
|||
return NULL; |
|||
} |
|||
|
|||
memcpy(iv_copy, iv, len); |
|||
|
|||
return iv_copy; |
|||
} |
|||
|
|||
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) { |
|||
return a->namelen == b->namelen && a->valuelen == b->valuelen && |
|||
memcmp(a->name, b->name, a->namelen) == 0 && |
|||
memcmp(a->value, b->value, a->valuelen) == 0; |
|||
} |
|||
|
|||
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem) { |
|||
nghttp2_mem_free(mem, nva); |
|||
} |
|||
|
|||
static int bytes_compar(const uint8_t *a, size_t alen, const uint8_t *b, |
|||
size_t blen) { |
|||
int rv; |
|||
|
|||
if (alen == blen) { |
|||
return memcmp(a, b, alen); |
|||
} |
|||
|
|||
if (alen < blen) { |
|||
rv = memcmp(a, b, alen); |
|||
|
|||
if (rv == 0) { |
|||
return -1; |
|||
} |
|||
|
|||
return rv; |
|||
} |
|||
|
|||
rv = memcmp(a, b, blen); |
|||
|
|||
if (rv == 0) { |
|||
return 1; |
|||
} |
|||
|
|||
return rv; |
|||
} |
|||
|
|||
int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs) { |
|||
return bytes_compar(lhs->name, lhs->namelen, rhs->name, rhs->namelen); |
|||
} |
|||
|
|||
static int nv_compar(const void *lhs, const void *rhs) { |
|||
const nghttp2_nv *a = (const nghttp2_nv *)lhs; |
|||
const nghttp2_nv *b = (const nghttp2_nv *)rhs; |
|||
int rv; |
|||
|
|||
rv = bytes_compar(a->name, a->namelen, b->name, b->namelen); |
|||
|
|||
if (rv == 0) { |
|||
return bytes_compar(a->value, a->valuelen, b->value, b->valuelen); |
|||
} |
|||
|
|||
return rv; |
|||
} |
|||
|
|||
void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) { |
|||
qsort(nva, nvlen, sizeof(nghttp2_nv), nv_compar); |
|||
} |
|||
|
|||
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva, |
|||
size_t nvlen, nghttp2_mem *mem) { |
|||
size_t i; |
|||
uint8_t *data = NULL; |
|||
size_t buflen = 0; |
|||
nghttp2_nv *p; |
|||
|
|||
if (nvlen == 0) { |
|||
*nva_ptr = NULL; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
for (i = 0; i < nvlen; ++i) { |
|||
/* + 1 for null-termination */ |
|||
if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) == 0) { |
|||
buflen += nva[i].namelen + 1; |
|||
} |
|||
if ((nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) == 0) { |
|||
buflen += nva[i].valuelen + 1; |
|||
} |
|||
} |
|||
|
|||
buflen += sizeof(nghttp2_nv) * nvlen; |
|||
|
|||
*nva_ptr = nghttp2_mem_malloc(mem, buflen); |
|||
|
|||
if (*nva_ptr == NULL) { |
|||
return NGHTTP2_ERR_NOMEM; |
|||
} |
|||
|
|||
p = *nva_ptr; |
|||
data = (uint8_t *)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen; |
|||
|
|||
for (i = 0; i < nvlen; ++i) { |
|||
p->flags = nva[i].flags; |
|||
|
|||
if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_NAME) { |
|||
p->name = nva[i].name; |
|||
p->namelen = nva[i].namelen; |
|||
} else { |
|||
if (nva[i].namelen) { |
|||
memcpy(data, nva[i].name, nva[i].namelen); |
|||
} |
|||
p->name = data; |
|||
p->namelen = nva[i].namelen; |
|||
data[p->namelen] = '\0'; |
|||
nghttp2_downcase(p->name, p->namelen); |
|||
data += nva[i].namelen + 1; |
|||
} |
|||
|
|||
if (nva[i].flags & NGHTTP2_NV_FLAG_NO_COPY_VALUE) { |
|||
p->value = nva[i].value; |
|||
p->valuelen = nva[i].valuelen; |
|||
} else { |
|||
if (nva[i].valuelen) { |
|||
memcpy(data, nva[i].value, nva[i].valuelen); |
|||
} |
|||
p->value = data; |
|||
p->valuelen = nva[i].valuelen; |
|||
data[p->valuelen] = '\0'; |
|||
data += nva[i].valuelen + 1; |
|||
} |
|||
|
|||
++p; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) { |
|||
size_t i; |
|||
for (i = 0; i < niv; ++i) { |
|||
switch (iv[i].settings_id) { |
|||
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE: |
|||
break; |
|||
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS: |
|||
break; |
|||
case NGHTTP2_SETTINGS_ENABLE_PUSH: |
|||
if (iv[i].value != 0 && iv[i].value != 1) { |
|||
return 0; |
|||
} |
|||
break; |
|||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE: |
|||
if (iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) { |
|||
return 0; |
|||
} |
|||
break; |
|||
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE: |
|||
if (iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN || |
|||
iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) { |
|||
return 0; |
|||
} |
|||
break; |
|||
case NGHTTP2_SETTINGS_MAX_HEADER_LIST_SIZE: |
|||
break; |
|||
} |
|||
} |
|||
return 1; |
|||
} |
|||
|
|||
static void frame_set_pad(nghttp2_buf *buf, size_t padlen, int framehd_only) { |
|||
size_t trail_padlen; |
|||
size_t newlen; |
|||
|
|||
DEBUGF("send: padlen=%zu, shift left 1 bytes\n", padlen); |
|||
|
|||
memmove(buf->pos - 1, buf->pos, NGHTTP2_FRAME_HDLEN); |
|||
|
|||
--buf->pos; |
|||
|
|||
buf->pos[4] |= NGHTTP2_FLAG_PADDED; |
|||
|
|||
newlen = (nghttp2_get_uint32(buf->pos) >> 8) + padlen; |
|||
nghttp2_put_uint32be(buf->pos, (uint32_t)((newlen << 8) + buf->pos[3])); |
|||
|
|||
if (framehd_only) { |
|||
return; |
|||
} |
|||
|
|||
trail_padlen = padlen - 1; |
|||
buf->pos[NGHTTP2_FRAME_HDLEN] = (uint8_t)trail_padlen; |
|||
|
|||
/* zero out padding */ |
|||
memset(buf->last, 0, trail_padlen); |
|||
/* extend buffers trail_padlen bytes, since we ate previous padlen -
|
|||
trail_padlen byte(s) */ |
|||
buf->last += trail_padlen; |
|||
} |
|||
|
|||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd, |
|||
size_t padlen, int framehd_only) { |
|||
nghttp2_buf *buf; |
|||
|
|||
if (padlen == 0) { |
|||
DEBUGF("send: padlen = 0, nothing to do\n"); |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
/*
|
|||
* We have arranged bufs like this: |
|||
* |
|||
* 0 1 2 3 |
|||
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
|||
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
|||
* | |Frame header | Frame payload... : |
|||
* +-+-----------------+-------------------------------------------+ |
|||
* | |Frame header | Frame payload... : |
|||
* +-+-----------------+-------------------------------------------+ |
|||
* | |Frame header | Frame payload... : |
|||
* +-+-----------------+-------------------------------------------+ |
|||
* |
|||
* We arranged padding so that it is included in the first frame |
|||
* completely. For padded frame, we are going to adjust buf->pos of |
|||
* frame which includes padding and serialize (memmove) frame header |
|||
* in the correct position. Also extends buf->last to include |
|||
* padding. |
|||
*/ |
|||
|
|||
buf = &bufs->head->buf; |
|||
|
|||
assert(nghttp2_buf_avail(buf) >= padlen - 1); |
|||
|
|||
frame_set_pad(buf, padlen, framehd_only); |
|||
|
|||
hd->length += padlen; |
|||
hd->flags |= NGHTTP2_FLAG_PADDED; |
|||
|
|||
DEBUGF("send: final payloadlen=%zu, padlen=%zu\n", hd->length, padlen); |
|||
|
|||
return 0; |
|||
} |
@ -0,0 +1,573 @@ |
|||
/*
|
|||
* 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_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); |
|||
|
|||
/*
|
|||
* 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); |
|||
|
|||
/*
|
|||
* 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
@ -0,0 +1,430 @@ |
|||
/*
|
|||
* 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; |
|||
|
|||
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 |
|||
* funtion 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); |
|||
|
|||
#endif /* NGHTTP2_HD_H */ |
@ -0,0 +1,231 @@ |
|||
/*
|
|||
* 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" |
|||
|
|||
/*
|
|||
* Encodes huffman code |sym| into |*dest_ptr|, whose least |rembits| |
|||
* bits are not filled yet. The |rembits| must be in range [1, 8], |
|||
* inclusive. At the end of the process, the |*dest_ptr| is updated |
|||
* and points where next output should be placed. The number of |
|||
* unfilled bits in the pointed location is returned. |
|||
*/ |
|||
static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr, |
|||
size_t rembits, const nghttp2_huff_sym *sym) { |
|||
int rv; |
|||
size_t nbits = sym->nbits; |
|||
uint32_t code = sym->code; |
|||
|
|||
/* We assume that sym->nbits <= 32 */ |
|||
if (rembits > nbits) { |
|||
nghttp2_bufs_fast_orb_hold(bufs, (uint8_t)(code << (rembits - nbits))); |
|||
return (ssize_t)(rembits - nbits); |
|||
} |
|||
|
|||
if (rembits == nbits) { |
|||
nghttp2_bufs_fast_orb(bufs, (uint8_t)code); |
|||
--*avail_ptr; |
|||
return 8; |
|||
} |
|||
|
|||
nghttp2_bufs_fast_orb(bufs, (uint8_t)(code >> (nbits - rembits))); |
|||
--*avail_ptr; |
|||
|
|||
nbits -= rembits; |
|||
if (nbits & 0x7) { |
|||
/* align code to MSB byte boundary */ |
|||
code <<= 8 - (nbits & 0x7); |
|||
} |
|||
|
|||
if (*avail_ptr < (nbits + 7) / 8) { |
|||
/* slow path */ |
|||
if (nbits > 24) { |
|||
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 24)); |
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
nbits -= 8; |
|||
} |
|||
if (nbits > 16) { |
|||
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 16)); |
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
nbits -= 8; |
|||
} |
|||
if (nbits > 8) { |
|||
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 8)); |
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
nbits -= 8; |
|||
} |
|||
if (nbits == 8) { |
|||
rv = nghttp2_bufs_addb(bufs, (uint8_t)code); |
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
*avail_ptr = nghttp2_bufs_cur_avail(bufs); |
|||
return 8; |
|||
} |
|||
|
|||
rv = nghttp2_bufs_addb_hold(bufs, (uint8_t)code); |
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
*avail_ptr = nghttp2_bufs_cur_avail(bufs); |
|||
return (ssize_t)(8 - nbits); |
|||
} |
|||
|
|||
/* fast path, since most code is less than 8 */ |
|||
if (nbits < 8) { |
|||
nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code); |
|||
*avail_ptr = nghttp2_bufs_cur_avail(bufs); |
|||
return (ssize_t)(8 - nbits); |
|||
} |
|||
|
|||
/* handle longer code path */ |
|||
if (nbits > 24) { |
|||
nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 24)); |
|||
nbits -= 8; |
|||
} |
|||
|
|||
if (nbits > 16) { |
|||
nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 16)); |
|||
nbits -= 8; |
|||
} |
|||
|
|||
if (nbits > 8) { |
|||
nghttp2_bufs_fast_addb(bufs, (uint8_t)(code >> 8)); |
|||
nbits -= 8; |
|||
} |
|||
|
|||
if (nbits == 8) { |
|||
nghttp2_bufs_fast_addb(bufs, (uint8_t)code); |
|||
*avail_ptr = nghttp2_bufs_cur_avail(bufs); |
|||
return 8; |
|||
} |
|||
|
|||
nghttp2_bufs_fast_addb_hold(bufs, (uint8_t)code); |
|||
*avail_ptr = nghttp2_bufs_cur_avail(bufs); |
|||
return (ssize_t)(8 - nbits); |
|||
} |
|||
|
|||
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) { |
|||
int rv; |
|||
ssize_t rembits = 8; |
|||
size_t i; |
|||
size_t avail; |
|||
|
|||
avail = nghttp2_bufs_cur_avail(bufs); |
|||
|
|||
for (i = 0; i < srclen; ++i) { |
|||
const nghttp2_huff_sym *sym = &huff_sym_table[src[i]]; |
|||
if (rembits == 8) { |
|||
if (avail) { |
|||
nghttp2_bufs_fast_addb_hold(bufs, 0); |
|||
} else { |
|||
rv = nghttp2_bufs_addb_hold(bufs, 0); |
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
avail = nghttp2_bufs_cur_avail(bufs); |
|||
} |
|||
} |
|||
rembits = huff_encode_sym(bufs, &avail, (size_t)rembits, sym); |
|||
if (rembits < 0) { |
|||
return (int)rembits; |
|||
} |
|||
} |
|||
/* 256 is special terminal symbol, pad with its prefix */ |
|||
if (rembits < 8) { |
|||
/* if rembits < 8, we should have at least 1 buffer space
|
|||
available */ |
|||
const nghttp2_huff_sym *sym = &huff_sym_table[256]; |
|||
assert(avail); |
|||
/* Caution we no longer adjust avail here */ |
|||
nghttp2_bufs_fast_orb( |
|||
bufs, (uint8_t)(sym->code >> (sym->nbits - (size_t)rembits))); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) { |
|||
ctx->state = 0; |
|||
ctx->accept = 1; |
|||
} |
|||
|
|||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx, |
|||
nghttp2_buf *buf, const uint8_t *src, |
|||
size_t srclen, int final) { |
|||
size_t i; |
|||
|
|||
/* We use the decoding algorithm described in
|
|||
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
|||
for (i = 0; i < srclen; ++i) { |
|||
const nghttp2_huff_decode *t; |
|||
|
|||
t = &huff_decode_table[ctx->state][src[i] >> 4]; |
|||
if (t->flags & NGHTTP2_HUFF_FAIL) { |
|||
return NGHTTP2_ERR_HEADER_COMP; |
|||
} |
|||
if (t->flags & NGHTTP2_HUFF_SYM) { |
|||
*buf->last++ = t->sym; |
|||
} |
|||
|
|||
t = &huff_decode_table[t->state][src[i] & 0xf]; |
|||
if (t->flags & NGHTTP2_HUFF_FAIL) { |
|||
return NGHTTP2_ERR_HEADER_COMP; |
|||
} |
|||
if (t->flags & NGHTTP2_HUFF_SYM) { |
|||
*buf->last++ = t->sym; |
|||
} |
|||
|
|||
ctx->state = t->state; |
|||
ctx->accept = (t->flags & NGHTTP2_HUFF_ACCEPTED) != 0; |
|||
} |
|||
if (final && !ctx->accept) { |
|||
return NGHTTP2_ERR_HEADER_COMP; |
|||
} |
|||
return (ssize_t)i; |
|||
} |
@ -0,0 +1,77 @@ |
|||
/*
|
|||
* 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, |
|||
/* This state emits symbol */ |
|||
NGHTTP2_HUFF_SYM = (1 << 1), |
|||
/* If state machine reaches this state, decoding fails. */ |
|||
NGHTTP2_HUFF_FAIL = (1 << 2) |
|||
} nghttp2_huff_decode_flag; |
|||
|
|||
typedef struct { |
|||
/* huffman decoding state, which is actually the node ID of internal
|
|||
huffman tree. 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. */ |
|||
uint8_t state; |
|||
/* bitwise OR of zero or more of the nghttp2_huff_decode_flag */ |
|||
uint8_t flags; |
|||
/* symbol if NGHTTP2_HUFF_SYM flag set */ |
|||
uint8_t sym; |
|||
} nghttp2_huff_decode; |
|||
|
|||
typedef nghttp2_huff_decode huff_decode_table_type[16]; |
|||
|
|||
typedef struct { |
|||
/* Current huffman decoding state. We stripped leaf nodes, so the
|
|||
value range is [0..255], inclusive. */ |
|||
uint8_t state; |
|||
/* nonzero if we can say that the decoding process succeeds at this
|
|||
state */ |
|||
uint8_t accept; |
|||
} 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
@ -0,0 +1,548 @@ |
|||
/*
|
|||
* 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_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"; |
|||
default: |
|||
return "Unknown error code"; |
|||
} |
|||
} |
|||
|
|||
/* Generated by gennmchartbl.py */ |
|||
static 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 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; |
|||
} |
|||
|
|||
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,596 @@ |
|||
/*
|
|||
* 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) { |
|||
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; |
|||
if (stream->http_flags & |
|||
(NGHTTP2_HTTP_FLAG__PATH | NGHTTP2_HTTP_FLAG__SCHEME)) { |
|||
return NGHTTP2_ERR_HTTP_HEADER; |
|||
} |
|||
} |
|||
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 (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { |
|||
return NGHTTP2_ERR_HTTP_HEADER; |
|||
} |
|||
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 (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) { |
|||
return NGHTTP2_ERR_HTTP_HEADER; |
|||
} |
|||
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_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) { |
|||
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 || |
|||
(stream->status_code == 200 && |
|||
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT))) { |
|||
return NGHTTP2_ERR_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; |
|||
} |
|||
|
|||
/* 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 */ |
|||
}; |
|||
|
|||
static int 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; |
|||
} |
|||
|
|||
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 = 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); |
|||
} |
|||
|
|||
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_METH_CONNECT) { |
|||
if ((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 (!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,189 @@ |
|||
/*
|
|||
* 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_map.h" |
|||
|
|||
#include <string.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_entry *)); |
|||
if (map->table == NULL) { |
|||
return NGHTTP2_ERR_NOMEM; |
|||
} |
|||
|
|||
map->size = 0; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
void nghttp2_map_free(nghttp2_map *map) { |
|||
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; |
|||
for (i = 0; i < map->tablelen; ++i) { |
|||
nghttp2_map_entry *entry; |
|||
for (entry = map->table[i]; entry;) { |
|||
nghttp2_map_entry *next = entry->next; |
|||
func(entry, ptr); |
|||
entry = next; |
|||
} |
|||
map->table[i] = NULL; |
|||
} |
|||
} |
|||
|
|||
int nghttp2_map_each(nghttp2_map *map, |
|||
int (*func)(nghttp2_map_entry *entry, void *ptr), |
|||
void *ptr) { |
|||
int rv; |
|||
uint32_t i; |
|||
for (i = 0; i < map->tablelen; ++i) { |
|||
nghttp2_map_entry *entry; |
|||
for (entry = map->table[i]; entry; entry = entry->next) { |
|||
rv = func(entry, 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; |
|||
} |
|||
|
|||
/* Same hash function in android HashMap source code. */ |
|||
/* The |mod| must be power of 2 */ |
|||
static uint32_t hash(int32_t key, uint32_t mod) { |
|||
uint32_t h = (uint32_t)key; |
|||
h ^= (h >> 20) ^ (h >> 12); |
|||
h ^= (h >> 7) ^ (h >> 4); |
|||
return h & (mod - 1); |
|||
} |
|||
|
|||
static int insert(nghttp2_map_entry **table, uint32_t tablelen, |
|||
nghttp2_map_entry *entry) { |
|||
uint32_t h = hash(entry->key, tablelen); |
|||
if (table[h] == NULL) { |
|||
table[h] = entry; |
|||
} else { |
|||
nghttp2_map_entry *p; |
|||
/* We won't allow duplicated key, so check it out. */ |
|||
for (p = table[h]; p; p = p->next) { |
|||
if (p->key == entry->key) { |
|||
return NGHTTP2_ERR_INVALID_ARGUMENT; |
|||
} |
|||
} |
|||
entry->next = table[h]; |
|||
table[h] = entry; |
|||
} |
|||
return 0; |
|||
} |
|||
|
|||
/* new_tablelen must be power of 2 */ |
|||
static int resize(nghttp2_map *map, uint32_t new_tablelen) { |
|||
uint32_t i; |
|||
nghttp2_map_entry **new_table; |
|||
|
|||
new_table = |
|||
nghttp2_mem_calloc(map->mem, new_tablelen, sizeof(nghttp2_map_entry *)); |
|||
if (new_table == NULL) { |
|||
return NGHTTP2_ERR_NOMEM; |
|||
} |
|||
|
|||
for (i = 0; i < map->tablelen; ++i) { |
|||
nghttp2_map_entry *entry; |
|||
for (entry = map->table[i]; entry;) { |
|||
nghttp2_map_entry *next = entry->next; |
|||
entry->next = NULL; |
|||
/* This function must succeed */ |
|||
insert(new_table, new_tablelen, entry); |
|||
entry = next; |
|||
} |
|||
} |
|||
nghttp2_mem_free(map->mem, map->table); |
|||
map->tablelen = new_tablelen; |
|||
map->table = new_table; |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
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 = resize(map, map->tablelen * 2); |
|||
if (rv != 0) { |
|||
return rv; |
|||
} |
|||
} |
|||
rv = insert(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) { |
|||
uint32_t h; |
|||
nghttp2_map_entry *entry; |
|||
h = hash(key, map->tablelen); |
|||
for (entry = map->table[h]; entry; entry = entry->next) { |
|||
if (entry->key == key) { |
|||
return entry; |
|||
} |
|||
} |
|||
return NULL; |
|||
} |
|||
|
|||
int nghttp2_map_remove(nghttp2_map *map, key_type key) { |
|||
uint32_t h; |
|||
nghttp2_map_entry **dst; |
|||
|
|||
h = hash(key, map->tablelen); |
|||
|
|||
for (dst = &map->table[h]; *dst; dst = &(*dst)->next) { |
|||
if ((*dst)->key != key) { |
|||
continue; |
|||
} |
|||
|
|||
*dst = (*dst)->next; |
|||
--map->size; |
|||
return 0; |
|||
} |
|||
return NGHTTP2_ERR_INVALID_ARGUMENT; |
|||
} |
|||
|
|||
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; } |
@ -0,0 +1,144 @@ |
|||
/*
|
|||
* 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_MAP_H |
|||
#define NGHTTP2_MAP_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 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_entry **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); |
|||
|
|||
/*
|
|||
* 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,114 @@ |
|||
/*
|
|||
* 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; |
|||
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; |
|||
} |
@ -0,0 +1,126 @@ |
|||
/*
|
|||
* 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_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; |
|||
/**
|
|||
* 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,124 @@ |
|||
/*
|
|||
* 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; |
|||
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
|
|||
ealier. 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,128 @@ |
|||
/*
|
|||
* 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 sotred */ |
|||
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 succeds, 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,49 @@ |
|||
/*
|
|||
* 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,98 @@ |
|||
/*
|
|||
* 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; |
|||
} |
@ -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
@ -0,0 +1,879 @@ |
|||
/*
|
|||
* 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; |
|||
|
|||
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_MAX_OBQ_FLOOD_ITEM 10000 |
|||
|
|||
/* 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_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; |
|||
} 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; |
|||
/* Base value when we schedule next DATA frame write. This is
|
|||
updated when one frame was written. */ |
|||
uint64_t last_cycle; |
|||
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 */ |
|||
size_t obq_flood_counter_; |
|||
/* 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; |
|||
/* 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; |
|||
/* Settings value received from the remote endpoint. We just use ID
|
|||
as index. The index = 0 is unused. */ |
|||
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 bitwose 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; |
|||
/* Nonzero if the session is server side. */ |
|||
uint8_t server; |
|||
/* Flags indicating GOAWAY is sent and/or recieved. 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 recieved, 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 recieved, 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 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); |
|||
|
|||
#endif /* NGHTTP2_SESSION_H */ |
File diff suppressed because it is too large
@ -0,0 +1,436 @@ |
|||
/*
|
|||
* 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; |
|||
|
|||
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. */ |
|||
uint32_t descendant_last_cycle; |
|||
/* Next scheduled time to sent item */ |
|||
uint32_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,731 @@ |
|||
/*
|
|||
* 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; |
|||
} |
|||
} 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 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; |
|||
} |
|||
|
|||
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 "@PROJECT_VERSION@.0 (MSVC debug)" |
|||
#define DBG "d" |
|||
FILEFLAGS 0x1L |
|||
#else |
|||
#define VER_STR "@PROJECT_VERSION@.0 (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 |
@ -0,0 +1,59 @@ |
|||
{ |
|||
'target_defaults': { |
|||
'defines': [ |
|||
'_U_=' |
|||
] |
|||
}, |
|||
'targets': [ |
|||
{ |
|||
'target_name': 'nghttp2', |
|||
'type': 'static_library', |
|||
'include_dirs': ['lib/includes'], |
|||
'conditions': [ |
|||
['OS=="win"', { |
|||
'defines': [ |
|||
'WIN32', |
|||
'_WINDOWS', |
|||
'HAVE_CONFIG_H', |
|||
'NGHTTP2_STATICLIB', |
|||
], |
|||
'msvs_settings': { |
|||
'VCCLCompilerTool': { |
|||
'CompileAs': '1' |
|||
}, |
|||
}, |
|||
}], |
|||
['debug_nghttp2 == 1', { |
|||
'defines': [ 'DEBUGBUILD=1' ] |
|||
}] |
|||
], |
|||
'direct_dependent_settings': { |
|||
'include_dirs': [ 'lib/includes' ] |
|||
}, |
|||
'sources': [ |
|||
'lib/nghttp2_buf.c', |
|||
'lib/nghttp2_callbacks.c', |
|||
'lib/nghttp2_debug.c', |
|||
'lib/nghttp2_frame.c', |
|||
'lib/nghttp2_hd.c', |
|||
'lib/nghttp2_hd_huffman.c', |
|||
'lib/nghttp2_hd_huffman_data.c', |
|||
'lib/nghttp2_helper.c', |
|||
'lib/nghttp2_http.c', |
|||
'lib/nghttp2_map.c', |
|||
'lib/nghttp2_mem.c', |
|||
'lib/nghttp2_npn.c', |
|||
'lib/nghttp2_option.c', |
|||
'lib/nghttp2_outbound_item.c', |
|||
'lib/nghttp2_pq.c', |
|||
'lib/nghttp2_priority_spec.c', |
|||
'lib/nghttp2_queue.c', |
|||
'lib/nghttp2_rcbuf.c', |
|||
'lib/nghttp2_session.c', |
|||
'lib/nghttp2_stream.c', |
|||
'lib/nghttp2_submit.c', |
|||
'lib/nghttp2_version.c' |
|||
] |
|||
} |
|||
] |
|||
} |
Loading…
Reference in new issue