mirror of
https://gitlab.kitware.com/cmake/cmake.git
synced 2026-09-28 04:09:35 +03:00
nghttp2 2019-11-15 (cc05c5fe)
Code extracted from:
https://github.com/nghttp2/nghttp2.git
at commit cc05c5fe8cfc8287ddc4930fa9684af878d9e631 (v1.40.0).
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* -whitespace
|
||||
@@ -0,0 +1,23 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2012, 2014, 2015, 2016 Tatsuhiro Tsujikawa
|
||||
Copyright (c) 2012, 2014, 2015, 2016 nghttp2 contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2VER_H
|
||||
#define NGHTTP2VER_H
|
||||
|
||||
/**
|
||||
* @macro
|
||||
* Version number of the nghttp2 library release
|
||||
*/
|
||||
#define NGHTTP2_VERSION "1.40.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 0x012800
|
||||
|
||||
#endif /* NGHTTP2VER_H */
|
||||
@@ -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 empty.
|
||||
*/
|
||||
int nghttp2_bufs_next_present(nghttp2_bufs *bufs);
|
||||
|
||||
#define nghttp2_bufs_cur_avail(BUFS) nghttp2_buf_avail(&(BUFS)->cur->buf)
|
||||
|
||||
/*
|
||||
* Returns the total buffer length of |bufs|.
|
||||
*/
|
||||
size_t nghttp2_bufs_len(nghttp2_bufs *bufs);
|
||||
|
||||
#endif /* NGHTTP2_BUF_H */
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_callbacks.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr) {
|
||||
*callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks));
|
||||
|
||||
if (*callbacks_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) {
|
||||
free(callbacks);
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_send_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) {
|
||||
cbs->send_callback = send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_recv_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) {
|
||||
cbs->recv_callback = recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback) {
|
||||
cbs->on_frame_recv_callback = on_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) {
|
||||
cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) {
|
||||
cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback) {
|
||||
cbs->before_frame_send_callback = before_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback) {
|
||||
cbs->on_frame_send_callback = on_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback) {
|
||||
cbs->on_frame_not_send_callback = on_frame_not_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback) {
|
||||
cbs->on_stream_close_callback = on_stream_close_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback) {
|
||||
cbs->on_begin_headers_callback = on_begin_headers_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback) {
|
||||
cbs->on_header_callback = on_header_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback2(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback2 on_header_callback2) {
|
||||
cbs->on_header_callback2 = on_header_callback2;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_header_callback on_invalid_header_callback) {
|
||||
cbs->on_invalid_header_callback = on_invalid_header_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_header_callback2(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_header_callback2 on_invalid_header_callback2) {
|
||||
cbs->on_invalid_header_callback2 = on_invalid_header_callback2;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_select_padding_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_select_padding_callback select_padding_callback) {
|
||||
cbs->select_padding_callback = select_padding_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_data_source_read_length_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback) {
|
||||
cbs->read_length_callback = data_source_read_length_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback) {
|
||||
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_send_data_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_send_data_callback send_data_callback) {
|
||||
cbs->send_data_callback = send_data_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_pack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_pack_extension_callback pack_extension_callback) {
|
||||
cbs->pack_extension_callback = pack_extension_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_unpack_extension_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_unpack_extension_callback unpack_extension_callback) {
|
||||
cbs->unpack_extension_callback = unpack_extension_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_extension_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback) {
|
||||
cbs->on_extension_chunk_recv_callback = on_extension_chunk_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_error_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_error_callback error_callback) {
|
||||
cbs->error_callback = error_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_error_callback2(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_error_callback2 error_callback2) {
|
||||
cbs->error_callback2 = error_callback2;
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_CALLBACKS_H
|
||||
#define NGHTTP2_CALLBACKS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/*
|
||||
* Callback functions.
|
||||
*/
|
||||
struct nghttp2_session_callbacks {
|
||||
/**
|
||||
* Callback function invoked when the session wants to send data to
|
||||
* the remote peer. This callback is not necessary if the
|
||||
* application uses solely `nghttp2_session_mem_send()` to serialize
|
||||
* data to transmit.
|
||||
*/
|
||||
nghttp2_send_callback send_callback;
|
||||
/**
|
||||
* Callback function invoked when the session wants to receive data
|
||||
* from the remote peer. This callback is not necessary if the
|
||||
* application uses solely `nghttp2_session_mem_recv()` to process
|
||||
* received data.
|
||||
*/
|
||||
nghttp2_recv_callback recv_callback;
|
||||
/**
|
||||
* Callback function invoked by `nghttp2_session_recv()` when a
|
||||
* frame is received.
|
||||
*/
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback;
|
||||
/**
|
||||
* Callback function invoked by `nghttp2_session_recv()` when an
|
||||
* invalid non-DATA frame is received.
|
||||
*/
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback;
|
||||
/**
|
||||
* Callback function invoked when a chunk of data in DATA frame is
|
||||
* received.
|
||||
*/
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback;
|
||||
/**
|
||||
* Callback function invoked before a non-DATA frame is sent.
|
||||
*/
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback;
|
||||
/**
|
||||
* Callback function invoked after a frame is sent.
|
||||
*/
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback;
|
||||
/**
|
||||
* The callback function invoked when a non-DATA frame is not sent
|
||||
* because of an error.
|
||||
*/
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback;
|
||||
/**
|
||||
* Callback function invoked when the stream is closed.
|
||||
*/
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback;
|
||||
/**
|
||||
* Callback function invoked when the reception of header block in
|
||||
* HEADERS or PUSH_PROMISE is started.
|
||||
*/
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback;
|
||||
/**
|
||||
* Callback function invoked when a header name/value pair is
|
||||
* received.
|
||||
*/
|
||||
nghttp2_on_header_callback on_header_callback;
|
||||
nghttp2_on_header_callback2 on_header_callback2;
|
||||
/**
|
||||
* Callback function invoked when a invalid header name/value pair
|
||||
* is received which is silently ignored if these callbacks are not
|
||||
* set.
|
||||
*/
|
||||
nghttp2_on_invalid_header_callback on_invalid_header_callback;
|
||||
nghttp2_on_invalid_header_callback2 on_invalid_header_callback2;
|
||||
/**
|
||||
* Callback function invoked when the library asks application how
|
||||
* many padding bytes are required for the transmission of the given
|
||||
* frame.
|
||||
*/
|
||||
nghttp2_select_padding_callback select_padding_callback;
|
||||
/**
|
||||
* The callback function used to determine the length allowed in
|
||||
* `nghttp2_data_source_read_callback()`
|
||||
*/
|
||||
nghttp2_data_source_read_length_callback read_length_callback;
|
||||
/**
|
||||
* Sets callback function invoked when a frame header is received.
|
||||
*/
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback;
|
||||
nghttp2_send_data_callback send_data_callback;
|
||||
nghttp2_pack_extension_callback pack_extension_callback;
|
||||
nghttp2_unpack_extension_callback unpack_extension_callback;
|
||||
nghttp2_on_extension_chunk_recv_callback on_extension_chunk_recv_callback;
|
||||
nghttp2_error_callback error_callback;
|
||||
nghttp2_error_callback2 error_callback2;
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_CALLBACKS_H */
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_debug.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
|
||||
static void nghttp2_default_debug_vfprintf_callback(const char *fmt,
|
||||
va_list args) {
|
||||
vfprintf(stderr, fmt, args);
|
||||
}
|
||||
|
||||
static nghttp2_debug_vprintf_callback static_debug_vprintf_callback =
|
||||
nghttp2_default_debug_vfprintf_callback;
|
||||
|
||||
void nghttp2_debug_vprintf(const char *format, ...) {
|
||||
if (static_debug_vprintf_callback) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
static_debug_vprintf_callback(format, args);
|
||||
va_end(args);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_set_debug_vprintf_callback(
|
||||
nghttp2_debug_vprintf_callback debug_vprintf_callback) {
|
||||
static_debug_vprintf_callback = debug_vprintf_callback;
|
||||
}
|
||||
|
||||
#else /* !DEBUGBUILD */
|
||||
|
||||
void nghttp2_set_debug_vprintf_callback(
|
||||
nghttp2_debug_vprintf_callback debug_vprintf_callback) {
|
||||
(void)debug_vprintf_callback;
|
||||
}
|
||||
|
||||
#endif /* !DEBUGBUILD */
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_DEBUG_H
|
||||
#define NGHTTP2_DEBUG_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
# define DEBUGF(...) nghttp2_debug_vprintf(__VA_ARGS__)
|
||||
void nghttp2_debug_vprintf(const char *format, ...);
|
||||
#else
|
||||
# define DEBUGF(...) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#endif /* NGHTTP2_DEBUG_H */
|
||||
+1134
@@ -0,0 +1,1134 @@
|
||||
/*
|
||||
* 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;
|
||||
if (altsvc == NULL) {
|
||||
return;
|
||||
}
|
||||
/* We use the same buffer for altsvc->origin and
|
||||
altsvc->field_value. */
|
||||
nghttp2_mem_free(mem, altsvc->origin);
|
||||
}
|
||||
|
||||
void nghttp2_frame_origin_init(nghttp2_extension *frame,
|
||||
nghttp2_origin_entry *ov, size_t nov) {
|
||||
nghttp2_ext_origin *origin;
|
||||
size_t payloadlen = 0;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nov; ++i) {
|
||||
payloadlen += 2 + ov[i].origin_len;
|
||||
}
|
||||
|
||||
nghttp2_frame_hd_init(&frame->hd, payloadlen, NGHTTP2_ORIGIN,
|
||||
NGHTTP2_FLAG_NONE, 0);
|
||||
|
||||
origin = frame->payload;
|
||||
origin->ov = ov;
|
||||
origin->nov = nov;
|
||||
}
|
||||
|
||||
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem) {
|
||||
nghttp2_ext_origin *origin;
|
||||
|
||||
origin = frame->payload;
|
||||
if (origin == NULL) {
|
||||
return;
|
||||
}
|
||||
/* We use the same buffer for all resources pointed by the field of
|
||||
origin directly or indirectly. */
|
||||
nghttp2_mem_free(mem, origin->ov);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
/* This is required with --disable-assert. */
|
||||
(void)rv;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *frame) {
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_ext_origin *origin;
|
||||
nghttp2_origin_entry *orig;
|
||||
size_t i;
|
||||
|
||||
origin = frame->payload;
|
||||
|
||||
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);
|
||||
|
||||
for (i = 0; i < origin->nov; ++i) {
|
||||
orig = &origin->ov[i];
|
||||
nghttp2_put_uint16be(buf->last, (uint16_t)orig->origin_len);
|
||||
buf->last += 2;
|
||||
buf->last = nghttp2_cpymem(buf->last, orig->origin, orig->origin_len);
|
||||
}
|
||||
|
||||
assert(nghttp2_buf_len(buf) == NGHTTP2_FRAME_HDLEN + frame->hd.length);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem) {
|
||||
nghttp2_ext_origin *origin;
|
||||
const uint8_t *p, *end;
|
||||
uint8_t *dst;
|
||||
size_t originlen;
|
||||
nghttp2_origin_entry *ov;
|
||||
size_t nov = 0;
|
||||
size_t len = 0;
|
||||
|
||||
origin = frame->payload;
|
||||
p = payload;
|
||||
end = p + payloadlen;
|
||||
|
||||
for (; p != end;) {
|
||||
if (end - p < 2) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
originlen = nghttp2_get_uint16(p);
|
||||
p += 2;
|
||||
if (originlen == 0) {
|
||||
continue;
|
||||
}
|
||||
if (originlen > (size_t)(end - p)) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
p += originlen;
|
||||
/* 1 for terminal NULL */
|
||||
len += originlen + 1;
|
||||
++nov;
|
||||
}
|
||||
|
||||
if (nov == 0) {
|
||||
origin->ov = NULL;
|
||||
origin->nov = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
len += nov * sizeof(nghttp2_origin_entry);
|
||||
|
||||
ov = nghttp2_mem_malloc(mem, len);
|
||||
if (ov == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
origin->ov = ov;
|
||||
origin->nov = nov;
|
||||
|
||||
dst = (uint8_t *)ov + nov * sizeof(nghttp2_origin_entry);
|
||||
p = payload;
|
||||
|
||||
for (; p != end;) {
|
||||
originlen = nghttp2_get_uint16(p);
|
||||
p += 2;
|
||||
if (originlen == 0) {
|
||||
continue;
|
||||
}
|
||||
ov->origin = dst;
|
||||
ov->origin_len = originlen;
|
||||
dst = nghttp2_cpymem(dst, p, originlen);
|
||||
*dst++ = '\0';
|
||||
p += originlen;
|
||||
++ov;
|
||||
}
|
||||
|
||||
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;
|
||||
case NGHTTP2_SETTINGS_ENABLE_CONNECT_PROTOCOL:
|
||||
if (iv[i].value != 0 && iv[i].value != 1) {
|
||||
return 0;
|
||||
}
|
||||
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,624 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_FRAME_H
|
||||
#define NGHTTP2_FRAME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_buf.h"
|
||||
|
||||
#define NGHTTP2_STREAM_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRI_GROUP_ID_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_PRIORITY_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_WINDOW_SIZE_INCREMENT_MASK ((1u << 31) - 1)
|
||||
#define NGHTTP2_SETTINGS_ID_MASK ((1 << 24) - 1)
|
||||
|
||||
/* The number of bytes of frame header. */
|
||||
#define NGHTTP2_FRAME_HDLEN 9
|
||||
|
||||
#define NGHTTP2_MAX_FRAME_SIZE_MAX ((1 << 24) - 1)
|
||||
#define NGHTTP2_MAX_FRAME_SIZE_MIN (1 << 14)
|
||||
|
||||
#define NGHTTP2_MAX_PAYLOADLEN 16384
|
||||
/* The one frame buffer length for tranmission. We may use several of
|
||||
them to support CONTINUATION. To account for Pad Length field, we
|
||||
allocate extra 1 byte, which saves extra large memcopying. */
|
||||
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
||||
(NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN)
|
||||
|
||||
/* The default length of DATA frame payload. */
|
||||
#define NGHTTP2_DATA_PAYLOADLEN NGHTTP2_MAX_FRAME_SIZE_MIN
|
||||
|
||||
/* Maximum headers block size to send, calculated using
|
||||
nghttp2_hd_deflate_bound(). This is the default value, and can be
|
||||
overridden by nghttp2_option_set_max_send_header_block_size(). */
|
||||
#define NGHTTP2_MAX_HEADERSLEN 65536
|
||||
|
||||
/* The number of bytes for each SETTINGS entry */
|
||||
#define NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH 6
|
||||
|
||||
/* Length of priority related fields in HEADERS/PRIORITY frames */
|
||||
#define NGHTTP2_PRIORITY_SPECLEN 5
|
||||
|
||||
/* Maximum length of padding in bytes. */
|
||||
#define NGHTTP2_MAX_PADLEN 256
|
||||
|
||||
/* Union of extension frame payload */
|
||||
typedef union {
|
||||
nghttp2_ext_altsvc altsvc;
|
||||
nghttp2_ext_origin origin;
|
||||
} nghttp2_ext_frame_payload;
|
||||
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
||||
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Initializes frame header |hd| with given parameters. Reserved bit
|
||||
* is set to 0.
|
||||
*/
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id);
|
||||
|
||||
/**
|
||||
* Returns the number of priority field depending on the |flags|. If
|
||||
* |flags| has neither NGHTTP2_FLAG_PRIORITY_GROUP nor
|
||||
* NGHTTP2_FLAG_PRIORITY_DEPENDENCY set, return 0.
|
||||
*/
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags);
|
||||
|
||||
/**
|
||||
* Packs the |pri_spec| in |buf|. This function assumes |buf| has
|
||||
* enough space for serialization.
|
||||
*/
|
||||
void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
/**
|
||||
* Unpacks the priority specification from payload |payload| of length
|
||||
* |payloadlen| to |pri_spec|. The |flags| is used to determine what
|
||||
* kind of priority specification is in |payload|. This function
|
||||
* assumes the |payload| contains whole priority specification.
|
||||
*/
|
||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Returns the offset from the HEADERS frame payload where the
|
||||
* compressed header block starts. The frame payload does not include
|
||||
* frame header.
|
||||
*/
|
||||
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
|
||||
|
||||
/*
|
||||
* Packs HEADERS frame |frame| in wire format and store it in |bufs|.
|
||||
* This function expands |bufs| as necessary to store frame.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* frame->hd.length is assigned after length is determined during
|
||||
* packing process. CONTINUATION frames are also serialized in this
|
||||
* function. This function does not handle padding.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or returns one of the
|
||||
* following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* The deflate operation failed.
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
|
||||
nghttp2_hd_deflater *deflater);
|
||||
|
||||
/*
|
||||
* Unpacks HEADERS frame byte sequence into |frame|. This function
|
||||
* only unapcks bytes that come before name/value header block and
|
||||
* after possible Pad Length field.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs PRIORITY frame |frame| in wire format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
|
||||
|
||||
/*
|
||||
* Unpacks PRIORITY wire format into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs RST_STREAM frame |frame| in wire frame format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
nghttp2_rst_stream *frame);
|
||||
|
||||
/*
|
||||
* Unpacks RST_STREAM frame byte sequence into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs SETTINGS frame |frame| in wire format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or returns one of the
|
||||
* following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame);
|
||||
|
||||
/*
|
||||
* Packs the |iv|, which includes |niv| entries, in the |buf|,
|
||||
* assuming the |buf| has at least 8 * |niv| bytes.
|
||||
*
|
||||
* Returns the number of bytes written into the |buf|.
|
||||
*/
|
||||
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
|
||||
const nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Initializes payload of frame->settings. The |frame| takes
|
||||
* ownership of |iv|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
||||
nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
/*
|
||||
* Unpacks SETTINGS payload into |*iv_ptr|. The number of entries are
|
||||
* assigned to the |*niv_ptr|. This function allocates enough memory
|
||||
* to store the result in |*iv_ptr|. The caller is responsible to free
|
||||
* |*iv_ptr| after its use.
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
|
||||
size_t *niv_ptr,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Packs PUSH_PROMISE frame |frame| in wire format and store it in
|
||||
* |bufs|. This function expands |bufs| as necessary to store
|
||||
* frame.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* frame->hd.length is assigned after length is determined during
|
||||
* packing process. CONTINUATION frames are also serialized in this
|
||||
* function. This function does not handle padding.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or returns one of the
|
||||
* following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* The deflate operation failed.
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
||||
nghttp2_push_promise *frame,
|
||||
nghttp2_hd_deflater *deflater);
|
||||
|
||||
/*
|
||||
* Unpacks PUSH_PROMISE frame byte sequence into |frame|. This
|
||||
* function only unapcks bytes that come before name/value header
|
||||
* block and after possible Pad Length field.
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_PROTO
|
||||
* TODO END_HEADERS flag is not set
|
||||
*/
|
||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs PING frame |frame| in wire format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame);
|
||||
|
||||
/*
|
||||
* Unpacks PING wire format into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs GOAWAY frame |frame| in wire format and store it in |bufs|.
|
||||
* This function expands |bufs| as necessary to store frame.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame);
|
||||
|
||||
/*
|
||||
* Unpacks GOAWAY wire format into |frame|. The |payload| of length
|
||||
* |payloadlen| contains first 8 bytes of payload. The
|
||||
* |var_gift_payload| of length |var_gift_payloadlen| contains
|
||||
* remaining payload and its buffer is gifted to the function and then
|
||||
* |frame|. The |var_gift_payloadlen| must be freed by
|
||||
* nghttp2_frame_goaway_free().
|
||||
*/
|
||||
void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
||||
const uint8_t *payload,
|
||||
uint8_t *var_gift_payload,
|
||||
size_t var_gift_payloadlen);
|
||||
|
||||
/*
|
||||
* Unpacks GOAWAY wire format into |frame|. This function only exists
|
||||
* for unit test. After allocating buffer for debug data, this
|
||||
* function internally calls nghttp2_frame_unpack_goaway_payload().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Packs WINDOW_UPDATE frame |frame| in wire frame format and store it
|
||||
* in |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
nghttp2_window_update *frame);
|
||||
|
||||
/*
|
||||
* Unpacks WINDOW_UPDATE frame byte sequence into |frame|.
|
||||
*/
|
||||
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||
const uint8_t *payload);
|
||||
|
||||
/*
|
||||
* Packs ALTSVC frame |frame| in wire frame format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *ext);
|
||||
|
||||
/*
|
||||
* Unpacks ALTSVC wire format into |frame|. The |payload| of
|
||||
* |payloadlen| bytes contains frame payload. This function assumes
|
||||
* that frame->payload points to the nghttp2_ext_altsvc object.
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
void nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
size_t origin_len, uint8_t *payload,
|
||||
size_t payloadlen);
|
||||
|
||||
/*
|
||||
* Unpacks ALTSVC wire format into |frame|. This function only exists
|
||||
* for unit test. After allocating buffer for fields, this function
|
||||
* internally calls nghttp2_frame_unpack_altsvc_payload().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The payload is too small.
|
||||
*/
|
||||
int nghttp2_frame_unpack_altsvc_payload2(nghttp2_extension *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Packs ORIGIN frame |frame| in wire frame format and store it in
|
||||
* |bufs|.
|
||||
*
|
||||
* The caller must make sure that nghttp2_bufs_reset(bufs) is called
|
||||
* before calling this function.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_pack_origin(nghttp2_bufs *bufs, nghttp2_extension *ext);
|
||||
|
||||
/*
|
||||
* Unpacks ORIGIN wire format into |frame|. The |payload| of length
|
||||
* |payloadlen| contains the frame payload.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The payload is too small.
|
||||
*/
|
||||
int nghttp2_frame_unpack_origin_payload(nghttp2_extension *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen, nghttp2_mem *mem);
|
||||
/*
|
||||
* Initializes HEADERS frame |frame| with given values. |frame| takes
|
||||
* ownership of |nva|, so caller must not free it. If |stream_id| is
|
||||
* not assigned yet, it must be -1.
|
||||
*/
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
|
||||
int32_t stream_id, nghttp2_headers_category cat,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
void nghttp2_frame_headers_free(nghttp2_headers *frame, nghttp2_mem *mem);
|
||||
|
||||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
void nghttp2_frame_priority_free(nghttp2_priority *frame);
|
||||
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
|
||||
|
||||
/*
|
||||
* Initializes PUSH_PROMISE frame |frame| with given values. |frame|
|
||||
* takes ownership of |nva|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t promised_stream_id,
|
||||
nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes SETTINGS frame |frame| with given values. |frame| takes
|
||||
* ownership of |iv|, so caller must not free it. The |flags| are
|
||||
* bitwise-OR of one or more of nghttp2_settings_flag.
|
||||
*/
|
||||
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
||||
nghttp2_settings_entry *iv, size_t niv);
|
||||
|
||||
void nghttp2_frame_settings_free(nghttp2_settings *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes PING frame |frame| with given values. If the
|
||||
* |opqeue_data| is not NULL, it must point to 8 bytes memory region
|
||||
* of data. The data pointed by |opaque_data| is copied. It can be
|
||||
* NULL. In this case, 8 bytes NULL is used.
|
||||
*/
|
||||
void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
|
||||
const uint8_t *opque_data);
|
||||
|
||||
void nghttp2_frame_ping_free(nghttp2_ping *frame);
|
||||
|
||||
/*
|
||||
* Initializes GOAWAY frame |frame| with given values. On success,
|
||||
* this function takes ownership of |opaque_data|, so caller must not
|
||||
* free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
|
||||
*/
|
||||
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||
uint32_t error_code, uint8_t *opaque_data,
|
||||
size_t opaque_data_len);
|
||||
|
||||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame, nghttp2_mem *mem);
|
||||
|
||||
void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
int32_t window_size_increment);
|
||||
|
||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
|
||||
|
||||
void nghttp2_frame_extension_init(nghttp2_extension *frame, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
void *payload);
|
||||
|
||||
void nghttp2_frame_extension_free(nghttp2_extension *frame);
|
||||
|
||||
/*
|
||||
* Initializes ALTSVC frame |frame| with given values. This function
|
||||
* assumes that frame->payload points to nghttp2_ext_altsvc object.
|
||||
* Also |origin| and |field_value| are allocated in single buffer,
|
||||
* starting |origin|. On success, this function takes ownership of
|
||||
* |origin|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
uint8_t *origin, size_t origin_len,
|
||||
uint8_t *field_value, size_t field_value_len);
|
||||
|
||||
/*
|
||||
* Frees up resources under |frame|. This function does not free
|
||||
* nghttp2_ext_altsvc object pointed by frame->payload. This function
|
||||
* only frees origin pointed by nghttp2_ext_altsvc.origin. Therefore,
|
||||
* other fields must be allocated in the same buffer with origin.
|
||||
*/
|
||||
void nghttp2_frame_altsvc_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes ORIGIN frame |frame| with given values. This function
|
||||
* assumes that frame->payload points to nghttp2_ext_origin object.
|
||||
* Also |ov| and the memory pointed by the field of its elements are
|
||||
* allocated in single buffer, starting with |ov|. On success, this
|
||||
* function takes ownership of |ov|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_origin_init(nghttp2_extension *frame,
|
||||
nghttp2_origin_entry *ov, size_t nov);
|
||||
|
||||
/*
|
||||
* Frees up resources under |frame|. This function does not free
|
||||
* nghttp2_ext_origin object pointed by frame->payload. This function
|
||||
* only frees nghttp2_ext_origin.ov. Therefore, other fields must be
|
||||
* allocated in the same buffer with ov.
|
||||
*/
|
||||
void nghttp2_frame_origin_free(nghttp2_extension *frame, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Returns the number of padding bytes after payload. The total
|
||||
* padding length is given in the |padlen|. The returned value does
|
||||
* not include the Pad Length field. If |padlen| is 0, this function
|
||||
* returns 0, regardless of frame->hd.flags.
|
||||
*/
|
||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen);
|
||||
|
||||
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
|
||||
int32_t stream_id);
|
||||
|
||||
void nghttp2_frame_data_free(nghttp2_data *frame);
|
||||
|
||||
/*
|
||||
* Makes copy of |iv| and return the copy. The |niv| is the number of
|
||||
* entries in |iv|. This function returns the pointer to the copy if
|
||||
* it succeeds, or NULL.
|
||||
*/
|
||||
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||
size_t niv, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Sorts the |nva| in ascending order of name and value. If names are
|
||||
* equivalent, sort them by value.
|
||||
*/
|
||||
void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
/*
|
||||
* Copies name/value pairs from |nva|, which contains |nvlen| pairs,
|
||||
* to |*nva_ptr|, which is dynamically allocated so that all items can
|
||||
* be stored. The resultant name and value in nghttp2_nv are
|
||||
* guaranteed to be NULL-terminated even if the input is not
|
||||
* null-terminated.
|
||||
*
|
||||
* The |*nva_ptr| must be freed using nghttp2_nv_array_del().
|
||||
*
|
||||
* This function returns 0 if it succeeds or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
||||
size_t nvlen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the name/value pair |a| equals to |b|. The name
|
||||
* is compared in case-sensitive, because we ensure that this function
|
||||
* is called after the name is lower-cased.
|
||||
*/
|
||||
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b);
|
||||
|
||||
/*
|
||||
* Frees |nva|.
|
||||
*/
|
||||
void nghttp2_nv_array_del(nghttp2_nv *nva, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Checks that the |iv|, which includes |niv| entries, does not have
|
||||
* invalid values.
|
||||
*
|
||||
* This function returns nonzero if it succeeds, or 0.
|
||||
*/
|
||||
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv);
|
||||
|
||||
/*
|
||||
* Sets Pad Length field and flags and adjusts frame header position
|
||||
* of each buffers in |bufs|. The number of padding is given in the
|
||||
* |padlen| including Pad Length field. The |hd| is the frame header
|
||||
* for the serialized data. This function fills zeros padding region
|
||||
* unless framehd_only is nonzero.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FRAME_SIZE_ERROR
|
||||
* The length of the resulting frame is too large.
|
||||
*/
|
||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen, int framehd_only);
|
||||
|
||||
#endif /* NGHTTP2_FRAME_H */
|
||||
+2351
@@ -0,0 +1,2351 @@
|
||||
/*
|
||||
* 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.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_int.h"
|
||||
#include "nghttp2_debug.h"
|
||||
|
||||
/* Make scalar initialization form of nghttp2_hd_entry */
|
||||
#define MAKE_STATIC_ENT(N, V, T, H) \
|
||||
{ \
|
||||
{NULL, NULL, (uint8_t *)(N), sizeof((N)) - 1, -1}, \
|
||||
{NULL, NULL, (uint8_t *)(V), sizeof((V)) - 1, -1}, \
|
||||
{(uint8_t *)(N), (uint8_t *)(V), sizeof((N)) - 1, sizeof((V)) - 1, 0}, \
|
||||
T, H \
|
||||
}
|
||||
|
||||
/* Generated by mkstatictbl.py */
|
||||
/* 3rd parameter is nghttp2_token value for header field name. We use
|
||||
first enum value if same header names are repeated (e.g.,
|
||||
:status). */
|
||||
static const nghttp2_hd_static_entry static_table[] = {
|
||||
MAKE_STATIC_ENT(":authority", "", 0, 3153725150u),
|
||||
MAKE_STATIC_ENT(":method", "GET", 1, 695666056u),
|
||||
MAKE_STATIC_ENT(":method", "POST", 1, 695666056u),
|
||||
MAKE_STATIC_ENT(":path", "/", 3, 3292848686u),
|
||||
MAKE_STATIC_ENT(":path", "/index.html", 3, 3292848686u),
|
||||
MAKE_STATIC_ENT(":scheme", "http", 5, 2510477674u),
|
||||
MAKE_STATIC_ENT(":scheme", "https", 5, 2510477674u),
|
||||
MAKE_STATIC_ENT(":status", "200", 7, 4000288983u),
|
||||
MAKE_STATIC_ENT(":status", "204", 7, 4000288983u),
|
||||
MAKE_STATIC_ENT(":status", "206", 7, 4000288983u),
|
||||
MAKE_STATIC_ENT(":status", "304", 7, 4000288983u),
|
||||
MAKE_STATIC_ENT(":status", "400", 7, 4000288983u),
|
||||
MAKE_STATIC_ENT(":status", "404", 7, 4000288983u),
|
||||
MAKE_STATIC_ENT(":status", "500", 7, 4000288983u),
|
||||
MAKE_STATIC_ENT("accept-charset", "", 14, 3664010344u),
|
||||
MAKE_STATIC_ENT("accept-encoding", "gzip, deflate", 15, 3379649177u),
|
||||
MAKE_STATIC_ENT("accept-language", "", 16, 1979086614u),
|
||||
MAKE_STATIC_ENT("accept-ranges", "", 17, 1713753958u),
|
||||
MAKE_STATIC_ENT("accept", "", 18, 136609321u),
|
||||
MAKE_STATIC_ENT("access-control-allow-origin", "", 19, 2710797292u),
|
||||
MAKE_STATIC_ENT("age", "", 20, 742476188u),
|
||||
MAKE_STATIC_ENT("allow", "", 21, 2930878514u),
|
||||
MAKE_STATIC_ENT("authorization", "", 22, 2436257726u),
|
||||
MAKE_STATIC_ENT("cache-control", "", 23, 1355326669u),
|
||||
MAKE_STATIC_ENT("content-disposition", "", 24, 3889184348u),
|
||||
MAKE_STATIC_ENT("content-encoding", "", 25, 65203592u),
|
||||
MAKE_STATIC_ENT("content-language", "", 26, 24973587u),
|
||||
MAKE_STATIC_ENT("content-length", "", 27, 1308181789u),
|
||||
MAKE_STATIC_ENT("content-location", "", 28, 2302364718u),
|
||||
MAKE_STATIC_ENT("content-range", "", 29, 3555523146u),
|
||||
MAKE_STATIC_ENT("content-type", "", 30, 4244048277u),
|
||||
MAKE_STATIC_ENT("cookie", "", 31, 2007449791u),
|
||||
MAKE_STATIC_ENT("date", "", 32, 3564297305u),
|
||||
MAKE_STATIC_ENT("etag", "", 33, 113792960u),
|
||||
MAKE_STATIC_ENT("expect", "", 34, 2530896728u),
|
||||
MAKE_STATIC_ENT("expires", "", 35, 1049544579u),
|
||||
MAKE_STATIC_ENT("from", "", 36, 2513272949u),
|
||||
MAKE_STATIC_ENT("host", "", 37, 2952701295u),
|
||||
MAKE_STATIC_ENT("if-match", "", 38, 3597694698u),
|
||||
MAKE_STATIC_ENT("if-modified-since", "", 39, 2213050793u),
|
||||
MAKE_STATIC_ENT("if-none-match", "", 40, 2536202615u),
|
||||
MAKE_STATIC_ENT("if-range", "", 41, 2340978238u),
|
||||
MAKE_STATIC_ENT("if-unmodified-since", "", 42, 3794814858u),
|
||||
MAKE_STATIC_ENT("last-modified", "", 43, 3226950251u),
|
||||
MAKE_STATIC_ENT("link", "", 44, 232457833u),
|
||||
MAKE_STATIC_ENT("location", "", 45, 200649126u),
|
||||
MAKE_STATIC_ENT("max-forwards", "", 46, 1826162134u),
|
||||
MAKE_STATIC_ENT("proxy-authenticate", "", 47, 2709445359u),
|
||||
MAKE_STATIC_ENT("proxy-authorization", "", 48, 2686392507u),
|
||||
MAKE_STATIC_ENT("range", "", 49, 4208725202u),
|
||||
MAKE_STATIC_ENT("referer", "", 50, 3969579366u),
|
||||
MAKE_STATIC_ENT("refresh", "", 51, 3572655668u),
|
||||
MAKE_STATIC_ENT("retry-after", "", 52, 3336180598u),
|
||||
MAKE_STATIC_ENT("server", "", 53, 1085029842u),
|
||||
MAKE_STATIC_ENT("set-cookie", "", 54, 1848371000u),
|
||||
MAKE_STATIC_ENT("strict-transport-security", "", 55, 4138147361u),
|
||||
MAKE_STATIC_ENT("transfer-encoding", "", 56, 3719590988u),
|
||||
MAKE_STATIC_ENT("user-agent", "", 57, 606444526u),
|
||||
MAKE_STATIC_ENT("vary", "", 58, 1085005381u),
|
||||
MAKE_STATIC_ENT("via", "", 59, 1762798611u),
|
||||
MAKE_STATIC_ENT("www-authenticate", "", 60, 779865858u),
|
||||
};
|
||||
|
||||
static int memeq(const void *s1, const void *s2, size_t n) {
|
||||
return memcmp(s1, s2, n) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function was generated by genlibtokenlookup.py. Inspired by
|
||||
* h2o header lookup. https://github.com/h2o/h2o
|
||||
*/
|
||||
static int32_t lookup_token(const uint8_t *name, size_t namelen) {
|
||||
switch (namelen) {
|
||||
case 2:
|
||||
switch (name[1]) {
|
||||
case 'e':
|
||||
if (memeq("t", name, 1)) {
|
||||
return NGHTTP2_TOKEN_TE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
switch (name[2]) {
|
||||
case 'a':
|
||||
if (memeq("vi", name, 2)) {
|
||||
return NGHTTP2_TOKEN_VIA;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (memeq("ag", name, 2)) {
|
||||
return NGHTTP2_TOKEN_AGE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (name[3]) {
|
||||
case 'e':
|
||||
if (memeq("dat", name, 3)) {
|
||||
return NGHTTP2_TOKEN_DATE;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (memeq("eta", name, 3)) {
|
||||
return NGHTTP2_TOKEN_ETAG;
|
||||
}
|
||||
break;
|
||||
case 'k':
|
||||
if (memeq("lin", name, 3)) {
|
||||
return NGHTTP2_TOKEN_LINK;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (memeq("fro", name, 3)) {
|
||||
return NGHTTP2_TOKEN_FROM;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (memeq("hos", name, 3)) {
|
||||
return NGHTTP2_TOKEN_HOST;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (memeq("var", name, 3)) {
|
||||
return NGHTTP2_TOKEN_VARY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
switch (name[4]) {
|
||||
case 'e':
|
||||
if (memeq("rang", name, 4)) {
|
||||
return NGHTTP2_TOKEN_RANGE;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (memeq(":pat", name, 4)) {
|
||||
return NGHTTP2_TOKEN__PATH;
|
||||
}
|
||||
break;
|
||||
case 'w':
|
||||
if (memeq("allo", name, 4)) {
|
||||
return NGHTTP2_TOKEN_ALLOW;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
switch (name[5]) {
|
||||
case 'e':
|
||||
if (memeq("cooki", name, 5)) {
|
||||
return NGHTTP2_TOKEN_COOKIE;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (memeq("serve", name, 5)) {
|
||||
return NGHTTP2_TOKEN_SERVER;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (memeq("accep", name, 5)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT;
|
||||
}
|
||||
if (memeq("expec", name, 5)) {
|
||||
return NGHTTP2_TOKEN_EXPECT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
switch (name[6]) {
|
||||
case 'd':
|
||||
if (memeq(":metho", name, 6)) {
|
||||
return NGHTTP2_TOKEN__METHOD;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (memeq(":schem", name, 6)) {
|
||||
return NGHTTP2_TOKEN__SCHEME;
|
||||
}
|
||||
if (memeq("upgrad", name, 6)) {
|
||||
return NGHTTP2_TOKEN_UPGRADE;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (memeq("refres", name, 6)) {
|
||||
return NGHTTP2_TOKEN_REFRESH;
|
||||
}
|
||||
break;
|
||||
case 'r':
|
||||
if (memeq("refere", name, 6)) {
|
||||
return NGHTTP2_TOKEN_REFERER;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (memeq(":statu", name, 6)) {
|
||||
return NGHTTP2_TOKEN__STATUS;
|
||||
}
|
||||
if (memeq("expire", name, 6)) {
|
||||
return NGHTTP2_TOKEN_EXPIRES;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
switch (name[7]) {
|
||||
case 'e':
|
||||
if (memeq("if-rang", name, 7)) {
|
||||
return NGHTTP2_TOKEN_IF_RANGE;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (memeq("if-matc", name, 7)) {
|
||||
return NGHTTP2_TOKEN_IF_MATCH;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (memeq("locatio", name, 7)) {
|
||||
return NGHTTP2_TOKEN_LOCATION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
switch (name[8]) {
|
||||
case 'l':
|
||||
if (memeq(":protoco", name, 8)) {
|
||||
return NGHTTP2_TOKEN__PROTOCOL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
switch (name[9]) {
|
||||
case 'e':
|
||||
if (memeq("keep-aliv", name, 9)) {
|
||||
return NGHTTP2_TOKEN_KEEP_ALIVE;
|
||||
}
|
||||
if (memeq("set-cooki", name, 9)) {
|
||||
return NGHTTP2_TOKEN_SET_COOKIE;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (memeq("connectio", name, 9)) {
|
||||
return NGHTTP2_TOKEN_CONNECTION;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (memeq("user-agen", name, 9)) {
|
||||
return NGHTTP2_TOKEN_USER_AGENT;
|
||||
}
|
||||
break;
|
||||
case 'y':
|
||||
if (memeq(":authorit", name, 9)) {
|
||||
return NGHTTP2_TOKEN__AUTHORITY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
switch (name[10]) {
|
||||
case 'r':
|
||||
if (memeq("retry-afte", name, 10)) {
|
||||
return NGHTTP2_TOKEN_RETRY_AFTER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 12:
|
||||
switch (name[11]) {
|
||||
case 'e':
|
||||
if (memeq("content-typ", name, 11)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_TYPE;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (memeq("max-forward", name, 11)) {
|
||||
return NGHTTP2_TOKEN_MAX_FORWARDS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 13:
|
||||
switch (name[12]) {
|
||||
case 'd':
|
||||
if (memeq("last-modifie", name, 12)) {
|
||||
return NGHTTP2_TOKEN_LAST_MODIFIED;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
if (memeq("content-rang", name, 12)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_RANGE;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
if (memeq("if-none-matc", name, 12)) {
|
||||
return NGHTTP2_TOKEN_IF_NONE_MATCH;
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
if (memeq("cache-contro", name, 12)) {
|
||||
return NGHTTP2_TOKEN_CACHE_CONTROL;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (memeq("authorizatio", name, 12)) {
|
||||
return NGHTTP2_TOKEN_AUTHORIZATION;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (memeq("accept-range", name, 12)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_RANGES;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 14:
|
||||
switch (name[13]) {
|
||||
case 'h':
|
||||
if (memeq("content-lengt", name, 13)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_LENGTH;
|
||||
}
|
||||
break;
|
||||
case 't':
|
||||
if (memeq("accept-charse", name, 13)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_CHARSET;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 15:
|
||||
switch (name[14]) {
|
||||
case 'e':
|
||||
if (memeq("accept-languag", name, 14)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_LANGUAGE;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (memeq("accept-encodin", name, 14)) {
|
||||
return NGHTTP2_TOKEN_ACCEPT_ENCODING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 16:
|
||||
switch (name[15]) {
|
||||
case 'e':
|
||||
if (memeq("content-languag", name, 15)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_LANGUAGE;
|
||||
}
|
||||
if (memeq("www-authenticat", name, 15)) {
|
||||
return NGHTTP2_TOKEN_WWW_AUTHENTICATE;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (memeq("content-encodin", name, 15)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_ENCODING;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (memeq("content-locatio", name, 15)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_LOCATION;
|
||||
}
|
||||
if (memeq("proxy-connectio", name, 15)) {
|
||||
return NGHTTP2_TOKEN_PROXY_CONNECTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 17:
|
||||
switch (name[16]) {
|
||||
case 'e':
|
||||
if (memeq("if-modified-sinc", name, 16)) {
|
||||
return NGHTTP2_TOKEN_IF_MODIFIED_SINCE;
|
||||
}
|
||||
break;
|
||||
case 'g':
|
||||
if (memeq("transfer-encodin", name, 16)) {
|
||||
return NGHTTP2_TOKEN_TRANSFER_ENCODING;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 18:
|
||||
switch (name[17]) {
|
||||
case 'e':
|
||||
if (memeq("proxy-authenticat", name, 17)) {
|
||||
return NGHTTP2_TOKEN_PROXY_AUTHENTICATE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 19:
|
||||
switch (name[18]) {
|
||||
case 'e':
|
||||
if (memeq("if-unmodified-sinc", name, 18)) {
|
||||
return NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (memeq("content-dispositio", name, 18)) {
|
||||
return NGHTTP2_TOKEN_CONTENT_DISPOSITION;
|
||||
}
|
||||
if (memeq("proxy-authorizatio", name, 18)) {
|
||||
return NGHTTP2_TOKEN_PROXY_AUTHORIZATION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 25:
|
||||
switch (name[24]) {
|
||||
case 'y':
|
||||
if (memeq("strict-transport-securit", name, 24)) {
|
||||
return NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 27:
|
||||
switch (name[26]) {
|
||||
case 'n':
|
||||
if (memeq("access-control-allow-origi", name, 26)) {
|
||||
return NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv) {
|
||||
ent->nv = *nv;
|
||||
ent->cnv.name = nv->name->base;
|
||||
ent->cnv.namelen = nv->name->len;
|
||||
ent->cnv.value = nv->value->base;
|
||||
ent->cnv.valuelen = nv->value->len;
|
||||
ent->cnv.flags = nv->flags;
|
||||
ent->next = NULL;
|
||||
ent->hash = 0;
|
||||
|
||||
nghttp2_rcbuf_incref(ent->nv.name);
|
||||
nghttp2_rcbuf_incref(ent->nv.value);
|
||||
}
|
||||
|
||||
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent) {
|
||||
nghttp2_rcbuf_decref(ent->nv.value);
|
||||
nghttp2_rcbuf_decref(ent->nv.name);
|
||||
}
|
||||
|
||||
static int name_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) {
|
||||
return a->name->len == b->namelen &&
|
||||
memeq(a->name->base, b->name, b->namelen);
|
||||
}
|
||||
|
||||
static int value_eq(const nghttp2_hd_nv *a, const nghttp2_nv *b) {
|
||||
return a->value->len == b->valuelen &&
|
||||
memeq(a->value->base, b->value, b->valuelen);
|
||||
}
|
||||
|
||||
static uint32_t name_hash(const nghttp2_nv *nv) {
|
||||
/* 32 bit FNV-1a: http://isthe.com/chongo/tech/comp/fnv/ */
|
||||
uint32_t h = 2166136261u;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < nv->namelen; ++i) {
|
||||
h ^= nv->name[i];
|
||||
h += (h << 1) + (h << 4) + (h << 7) + (h << 8) + (h << 24);
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static void hd_map_init(nghttp2_hd_map *map) {
|
||||
memset(map, 0, sizeof(nghttp2_hd_map));
|
||||
}
|
||||
|
||||
static void hd_map_insert(nghttp2_hd_map *map, nghttp2_hd_entry *ent) {
|
||||
nghttp2_hd_entry **bucket;
|
||||
|
||||
bucket = &map->table[ent->hash & (HD_MAP_SIZE - 1)];
|
||||
|
||||
if (*bucket == NULL) {
|
||||
*bucket = ent;
|
||||
return;
|
||||
}
|
||||
|
||||
/* lower index is linked near the root */
|
||||
ent->next = *bucket;
|
||||
*bucket = ent;
|
||||
}
|
||||
|
||||
static nghttp2_hd_entry *hd_map_find(nghttp2_hd_map *map, int *exact_match,
|
||||
const nghttp2_nv *nv, int32_t token,
|
||||
uint32_t hash, int name_only) {
|
||||
nghttp2_hd_entry *p;
|
||||
nghttp2_hd_entry *res = NULL;
|
||||
|
||||
*exact_match = 0;
|
||||
|
||||
for (p = map->table[hash & (HD_MAP_SIZE - 1)]; p; p = p->next) {
|
||||
if (token != p->nv.token ||
|
||||
(token == -1 && (hash != p->hash || !name_eq(&p->nv, nv)))) {
|
||||
continue;
|
||||
}
|
||||
if (!res) {
|
||||
res = p;
|
||||
if (name_only) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value_eq(&p->nv, nv)) {
|
||||
res = p;
|
||||
*exact_match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void hd_map_remove(nghttp2_hd_map *map, nghttp2_hd_entry *ent) {
|
||||
nghttp2_hd_entry **dst;
|
||||
|
||||
dst = &map->table[ent->hash & (HD_MAP_SIZE - 1)];
|
||||
|
||||
for (; *dst; dst = &(*dst)->next) {
|
||||
if (*dst != ent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*dst = ent->next;
|
||||
ent->next = NULL;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static int hd_ringbuf_init(nghttp2_hd_ringbuf *ringbuf, size_t bufsize,
|
||||
nghttp2_mem *mem) {
|
||||
size_t size;
|
||||
for (size = 1; size < bufsize; size <<= 1)
|
||||
;
|
||||
ringbuf->buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size);
|
||||
if (ringbuf->buffer == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
ringbuf->mask = size - 1;
|
||||
ringbuf->first = 0;
|
||||
ringbuf->len = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static nghttp2_hd_entry *hd_ringbuf_get(nghttp2_hd_ringbuf *ringbuf,
|
||||
size_t idx) {
|
||||
assert(idx < ringbuf->len);
|
||||
return ringbuf->buffer[(ringbuf->first + idx) & ringbuf->mask];
|
||||
}
|
||||
|
||||
static int hd_ringbuf_reserve(nghttp2_hd_ringbuf *ringbuf, size_t bufsize,
|
||||
nghttp2_mem *mem) {
|
||||
size_t i;
|
||||
size_t size;
|
||||
nghttp2_hd_entry **buffer;
|
||||
|
||||
if (ringbuf->mask + 1 >= bufsize) {
|
||||
return 0;
|
||||
}
|
||||
for (size = 1; size < bufsize; size <<= 1)
|
||||
;
|
||||
buffer = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry *) * size);
|
||||
if (buffer == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
for (i = 0; i < ringbuf->len; ++i) {
|
||||
buffer[i] = hd_ringbuf_get(ringbuf, i);
|
||||
}
|
||||
nghttp2_mem_free(mem, ringbuf->buffer);
|
||||
ringbuf->buffer = buffer;
|
||||
ringbuf->mask = size - 1;
|
||||
ringbuf->first = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hd_ringbuf_free(nghttp2_hd_ringbuf *ringbuf, nghttp2_mem *mem) {
|
||||
size_t i;
|
||||
if (ringbuf == NULL) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < ringbuf->len; ++i) {
|
||||
nghttp2_hd_entry *ent = hd_ringbuf_get(ringbuf, i);
|
||||
|
||||
nghttp2_hd_entry_free(ent);
|
||||
nghttp2_mem_free(mem, ent);
|
||||
}
|
||||
nghttp2_mem_free(mem, ringbuf->buffer);
|
||||
}
|
||||
|
||||
static int hd_ringbuf_push_front(nghttp2_hd_ringbuf *ringbuf,
|
||||
nghttp2_hd_entry *ent, nghttp2_mem *mem) {
|
||||
int rv;
|
||||
|
||||
rv = hd_ringbuf_reserve(ringbuf, ringbuf->len + 1, mem);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
ringbuf->buffer[--ringbuf->first & ringbuf->mask] = ent;
|
||||
++ringbuf->len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hd_ringbuf_pop_back(nghttp2_hd_ringbuf *ringbuf) {
|
||||
assert(ringbuf->len > 0);
|
||||
--ringbuf->len;
|
||||
}
|
||||
|
||||
static int hd_context_init(nghttp2_hd_context *context, nghttp2_mem *mem) {
|
||||
int rv;
|
||||
context->mem = mem;
|
||||
context->bad = 0;
|
||||
context->hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
||||
rv = hd_ringbuf_init(
|
||||
&context->hd_table,
|
||||
context->hd_table_bufsize_max / NGHTTP2_HD_ENTRY_OVERHEAD, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
context->hd_table_bufsize = 0;
|
||||
context->next_seq = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void hd_context_free(nghttp2_hd_context *context) {
|
||||
hd_ringbuf_free(&context->hd_table, context->mem);
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem) {
|
||||
return nghttp2_hd_deflate_init2(
|
||||
deflater, NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE, mem);
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
|
||||
size_t max_deflate_dynamic_table_size,
|
||||
nghttp2_mem *mem) {
|
||||
int rv;
|
||||
rv = hd_context_init(&deflater->ctx, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
hd_map_init(&deflater->map);
|
||||
|
||||
if (max_deflate_dynamic_table_size < NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE) {
|
||||
deflater->notify_table_size_change = 1;
|
||||
deflater->ctx.hd_table_bufsize_max = max_deflate_dynamic_table_size;
|
||||
} else {
|
||||
deflater->notify_table_size_change = 0;
|
||||
}
|
||||
|
||||
deflater->deflate_hd_table_bufsize_max = max_deflate_dynamic_table_size;
|
||||
deflater->min_hd_table_bufsize_max = UINT32_MAX;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem) {
|
||||
int rv;
|
||||
|
||||
rv = hd_context_init(&inflater->ctx, mem);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
inflater->settings_hd_table_bufsize_max = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
||||
inflater->min_hd_table_bufsize_max = UINT32_MAX;
|
||||
|
||||
inflater->nv_name_keep = NULL;
|
||||
inflater->nv_value_keep = NULL;
|
||||
|
||||
inflater->opcode = NGHTTP2_HD_OPCODE_NONE;
|
||||
inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
|
||||
|
||||
nghttp2_buf_init(&inflater->namebuf);
|
||||
nghttp2_buf_init(&inflater->valuebuf);
|
||||
|
||||
inflater->namercbuf = NULL;
|
||||
inflater->valuercbuf = NULL;
|
||||
|
||||
inflater->huffman_encoded = 0;
|
||||
inflater->index = 0;
|
||||
inflater->left = 0;
|
||||
inflater->shift = 0;
|
||||
inflater->index_required = 0;
|
||||
inflater->no_index = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void hd_inflate_keep_free(nghttp2_hd_inflater *inflater) {
|
||||
nghttp2_rcbuf_decref(inflater->nv_value_keep);
|
||||
nghttp2_rcbuf_decref(inflater->nv_name_keep);
|
||||
|
||||
inflater->nv_value_keep = NULL;
|
||||
inflater->nv_name_keep = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater) {
|
||||
hd_context_free(&deflater->ctx);
|
||||
}
|
||||
|
||||
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater) {
|
||||
hd_inflate_keep_free(inflater);
|
||||
|
||||
nghttp2_rcbuf_decref(inflater->valuercbuf);
|
||||
nghttp2_rcbuf_decref(inflater->namercbuf);
|
||||
|
||||
hd_context_free(&inflater->ctx);
|
||||
}
|
||||
|
||||
static size_t entry_room(size_t namelen, size_t valuelen) {
|
||||
return NGHTTP2_HD_ENTRY_OVERHEAD + namelen + valuelen;
|
||||
}
|
||||
|
||||
static void emit_header(nghttp2_hd_nv *nv_out, nghttp2_hd_nv *nv) {
|
||||
DEBUGF("inflatehd: header emission: %s: %s\n", nv->name->base,
|
||||
nv->value->base);
|
||||
/* ent->ref may be 0. This happens if the encoder emits literal
|
||||
block larger than header table capacity with indexing. */
|
||||
*nv_out = *nv;
|
||||
}
|
||||
|
||||
static size_t count_encoded_length(size_t n, size_t prefix) {
|
||||
size_t k = (size_t)((1 << prefix) - 1);
|
||||
size_t len = 0;
|
||||
|
||||
if (n < k) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
n -= k;
|
||||
++len;
|
||||
|
||||
for (; n >= 128; n >>= 7, ++len)
|
||||
;
|
||||
|
||||
return len + 1;
|
||||
}
|
||||
|
||||
static size_t encode_length(uint8_t *buf, size_t n, size_t prefix) {
|
||||
size_t k = (size_t)((1 << prefix) - 1);
|
||||
uint8_t *begin = buf;
|
||||
|
||||
*buf = (uint8_t)(*buf & ~k);
|
||||
|
||||
if (n < k) {
|
||||
*buf = (uint8_t)(*buf | n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
*buf = (uint8_t)(*buf | k);
|
||||
++buf;
|
||||
|
||||
n -= k;
|
||||
|
||||
for (; n >= 128; n >>= 7) {
|
||||
*buf++ = (uint8_t)((1 << 7) | (n & 0x7f));
|
||||
}
|
||||
|
||||
*buf++ = (uint8_t)n;
|
||||
|
||||
return (size_t)(buf - begin);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes |prefix| prefixed integer stored from |in|. The |last|
|
||||
* represents the 1 beyond the last of the valid contiguous memory
|
||||
* region from |in|. The decoded integer must be less than or equal
|
||||
* to UINT32_MAX.
|
||||
*
|
||||
* If the |initial| is nonzero, it is used as a initial value, this
|
||||
* function assumes the |in| starts with intermediate data.
|
||||
*
|
||||
* An entire integer is decoded successfully, decoded, the |*fin| is
|
||||
* set to nonzero.
|
||||
*
|
||||
* This function stores the decoded integer in |*res| if it succeed,
|
||||
* including partial decoding (in this case, number of shift to make
|
||||
* in the next call will be stored in |*shift_ptr|) and returns number
|
||||
* of bytes processed, or returns -1, indicating decoding error.
|
||||
*/
|
||||
static ssize_t decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
|
||||
uint32_t initial, size_t shift, const uint8_t *in,
|
||||
const uint8_t *last, size_t prefix) {
|
||||
uint32_t k = (uint8_t)((1 << prefix) - 1);
|
||||
uint32_t n = initial;
|
||||
const uint8_t *start = in;
|
||||
|
||||
*shift_ptr = 0;
|
||||
*fin = 0;
|
||||
|
||||
if (n == 0) {
|
||||
if ((*in & k) != k) {
|
||||
*res = (*in) & k;
|
||||
*fin = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
n = k;
|
||||
|
||||
if (++in == last) {
|
||||
*res = n;
|
||||
return (ssize_t)(in - start);
|
||||
}
|
||||
}
|
||||
|
||||
for (; in != last; ++in, shift += 7) {
|
||||
uint32_t add = *in & 0x7f;
|
||||
|
||||
if (shift >= 32) {
|
||||
DEBUGF("inflate: shift exponent overflow\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((UINT32_MAX >> shift) < add) {
|
||||
DEBUGF("inflate: integer overflow on shift\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
add <<= shift;
|
||||
|
||||
if (UINT32_MAX - add < n) {
|
||||
DEBUGF("inflate: integer overflow on addition\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
n += add;
|
||||
|
||||
if ((*in & (1 << 7)) == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*shift_ptr = shift;
|
||||
|
||||
if (in == last) {
|
||||
*res = n;
|
||||
return (ssize_t)(in - start);
|
||||
}
|
||||
|
||||
*res = n;
|
||||
*fin = 1;
|
||||
return (ssize_t)(in + 1 - start);
|
||||
}
|
||||
|
||||
static int emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
|
||||
int rv;
|
||||
uint8_t *bufp;
|
||||
size_t blocklen;
|
||||
uint8_t sb[16];
|
||||
|
||||
DEBUGF("deflatehd: emit table_size=%zu\n", table_size);
|
||||
|
||||
blocklen = count_encoded_length(table_size, 5);
|
||||
|
||||
if (sizeof(sb) < blocklen) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
bufp = sb;
|
||||
|
||||
*bufp = 0x20u;
|
||||
|
||||
encode_length(bufp, table_size, 5);
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, sb, blocklen);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_indexed_block(nghttp2_bufs *bufs, size_t idx) {
|
||||
int rv;
|
||||
size_t blocklen;
|
||||
uint8_t sb[16];
|
||||
uint8_t *bufp;
|
||||
|
||||
blocklen = count_encoded_length(idx + 1, 7);
|
||||
|
||||
DEBUGF("deflatehd: emit indexed index=%zu, %zu bytes\n", idx, blocklen);
|
||||
|
||||
if (sizeof(sb) < blocklen) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
bufp = sb;
|
||||
*bufp = 0x80u;
|
||||
encode_length(bufp, idx + 1, 7);
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, sb, blocklen);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_string(nghttp2_bufs *bufs, const uint8_t *str, size_t len) {
|
||||
int rv;
|
||||
uint8_t sb[16];
|
||||
uint8_t *bufp;
|
||||
size_t blocklen;
|
||||
size_t enclen;
|
||||
int huffman = 0;
|
||||
|
||||
enclen = nghttp2_hd_huff_encode_count(str, len);
|
||||
|
||||
if (enclen < len) {
|
||||
huffman = 1;
|
||||
} else {
|
||||
enclen = len;
|
||||
}
|
||||
|
||||
blocklen = count_encoded_length(enclen, 7);
|
||||
|
||||
DEBUGF("deflatehd: emit string str=%.*s, length=%zu, huffman=%d, "
|
||||
"encoded_length=%zu\n",
|
||||
(int)len, (const char *)str, len, huffman, enclen);
|
||||
|
||||
if (sizeof(sb) < blocklen) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
bufp = sb;
|
||||
*bufp = huffman ? 1 << 7 : 0;
|
||||
encode_length(bufp, enclen, 7);
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, sb, blocklen);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (huffman) {
|
||||
rv = nghttp2_hd_huff_encode(bufs, str, len);
|
||||
} else {
|
||||
assert(enclen == len);
|
||||
rv = nghttp2_bufs_add(bufs, str, len);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static uint8_t pack_first_byte(int indexing_mode) {
|
||||
switch (indexing_mode) {
|
||||
case NGHTTP2_HD_WITH_INDEXING:
|
||||
return 0x40u;
|
||||
case NGHTTP2_HD_WITHOUT_INDEXING:
|
||||
return 0;
|
||||
case NGHTTP2_HD_NEVER_INDEXING:
|
||||
return 0x10u;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
/* This is required to compile with android NDK r10d +
|
||||
--enable-werror */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_indname_block(nghttp2_bufs *bufs, size_t idx,
|
||||
const nghttp2_nv *nv, int indexing_mode) {
|
||||
int rv;
|
||||
uint8_t *bufp;
|
||||
size_t blocklen;
|
||||
uint8_t sb[16];
|
||||
size_t prefixlen;
|
||||
|
||||
if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
|
||||
prefixlen = 6;
|
||||
} else {
|
||||
prefixlen = 4;
|
||||
}
|
||||
|
||||
DEBUGF("deflatehd: emit indname index=%zu, valuelen=%zu, indexing_mode=%d\n",
|
||||
idx, nv->valuelen, indexing_mode);
|
||||
|
||||
blocklen = count_encoded_length(idx + 1, prefixlen);
|
||||
|
||||
if (sizeof(sb) < blocklen) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
bufp = sb;
|
||||
|
||||
*bufp = pack_first_byte(indexing_mode);
|
||||
|
||||
encode_length(bufp, idx + 1, prefixlen);
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, sb, blocklen);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = emit_string(bufs, nv->value, nv->valuelen);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int emit_newname_block(nghttp2_bufs *bufs, const nghttp2_nv *nv,
|
||||
int indexing_mode) {
|
||||
int rv;
|
||||
|
||||
DEBUGF(
|
||||
"deflatehd: emit newname namelen=%zu, valuelen=%zu, indexing_mode=%d\n",
|
||||
nv->namelen, nv->valuelen, indexing_mode);
|
||||
|
||||
rv = nghttp2_bufs_addb(bufs, pack_first_byte(indexing_mode));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = emit_string(bufs, nv->name, nv->namelen);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = emit_string(bufs, nv->value, nv->valuelen);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int add_hd_table_incremental(nghttp2_hd_context *context,
|
||||
nghttp2_hd_nv *nv, nghttp2_hd_map *map,
|
||||
uint32_t hash) {
|
||||
int rv;
|
||||
nghttp2_hd_entry *new_ent;
|
||||
size_t room;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = context->mem;
|
||||
room = entry_room(nv->name->len, nv->value->len);
|
||||
|
||||
while (context->hd_table_bufsize + room > context->hd_table_bufsize_max &&
|
||||
context->hd_table.len > 0) {
|
||||
|
||||
size_t idx = context->hd_table.len - 1;
|
||||
nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
|
||||
|
||||
context->hd_table_bufsize -=
|
||||
entry_room(ent->nv.name->len, ent->nv.value->len);
|
||||
|
||||
DEBUGF("hpack: remove item from header table: %s: %s\n",
|
||||
(char *)ent->nv.name->base, (char *)ent->nv.value->base);
|
||||
|
||||
hd_ringbuf_pop_back(&context->hd_table);
|
||||
if (map) {
|
||||
hd_map_remove(map, ent);
|
||||
}
|
||||
|
||||
nghttp2_hd_entry_free(ent);
|
||||
nghttp2_mem_free(mem, ent);
|
||||
}
|
||||
|
||||
if (room > context->hd_table_bufsize_max) {
|
||||
/* The entry taking more than NGHTTP2_HD_MAX_BUFFER_SIZE is
|
||||
immediately evicted. So we don't allocate memory for it. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_ent = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_entry));
|
||||
if (new_ent == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_hd_entry_init(new_ent, nv);
|
||||
|
||||
rv = hd_ringbuf_push_front(&context->hd_table, new_ent, mem);
|
||||
|
||||
if (rv != 0) {
|
||||
nghttp2_hd_entry_free(new_ent);
|
||||
nghttp2_mem_free(mem, new_ent);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
new_ent->seq = context->next_seq++;
|
||||
new_ent->hash = hash;
|
||||
|
||||
if (map) {
|
||||
hd_map_insert(map, new_ent);
|
||||
}
|
||||
|
||||
context->hd_table_bufsize += room;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
ssize_t index;
|
||||
/* Nonzero if both name and value are matched. */
|
||||
int name_value_match;
|
||||
} search_result;
|
||||
|
||||
static search_result search_static_table(const nghttp2_nv *nv, int32_t token,
|
||||
int name_only) {
|
||||
search_result res = {token, 0};
|
||||
int i;
|
||||
const nghttp2_hd_static_entry *ent;
|
||||
|
||||
if (name_only) {
|
||||
return res;
|
||||
}
|
||||
|
||||
for (i = token;
|
||||
i <= NGHTTP2_TOKEN_WWW_AUTHENTICATE && static_table[i].token == token;
|
||||
++i) {
|
||||
ent = &static_table[i];
|
||||
if (ent->value.len == nv->valuelen &&
|
||||
memcmp(ent->value.base, nv->value, nv->valuelen) == 0) {
|
||||
res.index = i;
|
||||
res.name_value_match = 1;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static search_result search_hd_table(nghttp2_hd_context *context,
|
||||
const nghttp2_nv *nv, int32_t token,
|
||||
int indexing_mode, nghttp2_hd_map *map,
|
||||
uint32_t hash) {
|
||||
search_result res = {-1, 0};
|
||||
const nghttp2_hd_entry *ent;
|
||||
int exact_match;
|
||||
int name_only = indexing_mode == NGHTTP2_HD_NEVER_INDEXING;
|
||||
|
||||
exact_match = 0;
|
||||
ent = hd_map_find(map, &exact_match, nv, token, hash, name_only);
|
||||
|
||||
if (!exact_match && token >= 0 && token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
|
||||
return search_static_table(nv, token, name_only);
|
||||
}
|
||||
|
||||
if (ent == NULL) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res.index =
|
||||
(ssize_t)(context->next_seq - 1 - ent->seq + NGHTTP2_STATIC_TABLE_LENGTH);
|
||||
res.name_value_match = exact_match;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void hd_context_shrink_table_size(nghttp2_hd_context *context,
|
||||
nghttp2_hd_map *map) {
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = context->mem;
|
||||
|
||||
while (context->hd_table_bufsize > context->hd_table_bufsize_max &&
|
||||
context->hd_table.len > 0) {
|
||||
size_t idx = context->hd_table.len - 1;
|
||||
nghttp2_hd_entry *ent = hd_ringbuf_get(&context->hd_table, idx);
|
||||
context->hd_table_bufsize -=
|
||||
entry_room(ent->nv.name->len, ent->nv.value->len);
|
||||
hd_ringbuf_pop_back(&context->hd_table);
|
||||
if (map) {
|
||||
hd_map_remove(map, ent);
|
||||
}
|
||||
|
||||
nghttp2_hd_entry_free(ent);
|
||||
nghttp2_mem_free(mem, ent);
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_change_table_size(
|
||||
nghttp2_hd_deflater *deflater, size_t settings_max_dynamic_table_size) {
|
||||
size_t next_bufsize = nghttp2_min(settings_max_dynamic_table_size,
|
||||
deflater->deflate_hd_table_bufsize_max);
|
||||
|
||||
deflater->ctx.hd_table_bufsize_max = next_bufsize;
|
||||
|
||||
deflater->min_hd_table_bufsize_max =
|
||||
nghttp2_min(deflater->min_hd_table_bufsize_max, next_bufsize);
|
||||
|
||||
deflater->notify_table_size_change = 1;
|
||||
|
||||
hd_context_shrink_table_size(&deflater->ctx, &deflater->map);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_hd_inflate_change_table_size(
|
||||
nghttp2_hd_inflater *inflater, size_t settings_max_dynamic_table_size) {
|
||||
switch (inflater->state) {
|
||||
case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE:
|
||||
case NGHTTP2_HD_STATE_INFLATE_START:
|
||||
break;
|
||||
default:
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
/* It seems that encoder is not required to send dynamic table size
|
||||
update if the table size is not changed after applying
|
||||
SETTINGS_HEADER_TABLE_SIZE. RFC 7541 is ambiguous here, but this
|
||||
is the intention of the editor. If new maximum table size is
|
||||
strictly smaller than the current negotiated maximum size,
|
||||
encoder must send dynamic table size update. In other cases, we
|
||||
cannot expect it to do so. */
|
||||
if (inflater->ctx.hd_table_bufsize_max > settings_max_dynamic_table_size) {
|
||||
inflater->state = NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE;
|
||||
/* Remember minimum value, and validate that encoder sends the
|
||||
value less than or equal to this. */
|
||||
inflater->min_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||
}
|
||||
|
||||
inflater->settings_hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||
|
||||
inflater->ctx.hd_table_bufsize_max = settings_max_dynamic_table_size;
|
||||
|
||||
hd_context_shrink_table_size(&inflater->ctx, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define INDEX_RANGE_VALID(context, idx) \
|
||||
((idx) < (context)->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH)
|
||||
|
||||
static size_t get_max_index(nghttp2_hd_context *context) {
|
||||
return context->hd_table.len + NGHTTP2_STATIC_TABLE_LENGTH;
|
||||
}
|
||||
|
||||
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t idx) {
|
||||
assert(INDEX_RANGE_VALID(context, idx));
|
||||
if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) {
|
||||
return hd_ringbuf_get(&context->hd_table, idx - NGHTTP2_STATIC_TABLE_LENGTH)
|
||||
->nv;
|
||||
} else {
|
||||
const nghttp2_hd_static_entry *ent = &static_table[idx];
|
||||
nghttp2_hd_nv nv = {(nghttp2_rcbuf *)&ent->name,
|
||||
(nghttp2_rcbuf *)&ent->value, ent->token,
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
return nv;
|
||||
}
|
||||
}
|
||||
|
||||
static const nghttp2_nv *nghttp2_hd_table_get2(nghttp2_hd_context *context,
|
||||
size_t idx) {
|
||||
assert(INDEX_RANGE_VALID(context, idx));
|
||||
if (idx >= NGHTTP2_STATIC_TABLE_LENGTH) {
|
||||
return &hd_ringbuf_get(&context->hd_table,
|
||||
idx - NGHTTP2_STATIC_TABLE_LENGTH)
|
||||
->cnv;
|
||||
}
|
||||
|
||||
return &static_table[idx].cnv;
|
||||
}
|
||||
|
||||
static int hd_deflate_decide_indexing(nghttp2_hd_deflater *deflater,
|
||||
const nghttp2_nv *nv, int32_t token) {
|
||||
if (token == NGHTTP2_TOKEN__PATH || token == NGHTTP2_TOKEN_AGE ||
|
||||
token == NGHTTP2_TOKEN_CONTENT_LENGTH || token == NGHTTP2_TOKEN_ETAG ||
|
||||
token == NGHTTP2_TOKEN_IF_MODIFIED_SINCE ||
|
||||
token == NGHTTP2_TOKEN_IF_NONE_MATCH || token == NGHTTP2_TOKEN_LOCATION ||
|
||||
token == NGHTTP2_TOKEN_SET_COOKIE ||
|
||||
entry_room(nv->namelen, nv->valuelen) >
|
||||
deflater->ctx.hd_table_bufsize_max * 3 / 4) {
|
||||
return NGHTTP2_HD_WITHOUT_INDEXING;
|
||||
}
|
||||
|
||||
return NGHTTP2_HD_WITH_INDEXING;
|
||||
}
|
||||
|
||||
static int deflate_nv(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
||||
const nghttp2_nv *nv) {
|
||||
int rv;
|
||||
search_result res;
|
||||
ssize_t idx;
|
||||
int indexing_mode;
|
||||
int32_t token;
|
||||
nghttp2_mem *mem;
|
||||
uint32_t hash = 0;
|
||||
|
||||
DEBUGF("deflatehd: deflating %.*s: %.*s\n", (int)nv->namelen, nv->name,
|
||||
(int)nv->valuelen, nv->value);
|
||||
|
||||
mem = deflater->ctx.mem;
|
||||
|
||||
token = lookup_token(nv->name, nv->namelen);
|
||||
if (token == -1) {
|
||||
hash = name_hash(nv);
|
||||
} else if (token <= NGHTTP2_TOKEN_WWW_AUTHENTICATE) {
|
||||
hash = static_table[token].hash;
|
||||
}
|
||||
|
||||
/* Don't index authorization header field since it may contain low
|
||||
entropy secret data (e.g., id/password). Also cookie header
|
||||
field with less than 20 bytes value is also never indexed. This
|
||||
is the same criteria used in Firefox codebase. */
|
||||
indexing_mode =
|
||||
token == NGHTTP2_TOKEN_AUTHORIZATION ||
|
||||
(token == NGHTTP2_TOKEN_COOKIE && nv->valuelen < 20) ||
|
||||
(nv->flags & NGHTTP2_NV_FLAG_NO_INDEX)
|
||||
? NGHTTP2_HD_NEVER_INDEXING
|
||||
: hd_deflate_decide_indexing(deflater, nv, token);
|
||||
|
||||
res = search_hd_table(&deflater->ctx, nv, token, indexing_mode,
|
||||
&deflater->map, hash);
|
||||
|
||||
idx = res.index;
|
||||
|
||||
if (res.name_value_match) {
|
||||
|
||||
DEBUGF("deflatehd: name/value match index=%zd\n", idx);
|
||||
|
||||
rv = emit_indexed_block(bufs, (size_t)idx);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (res.index != -1) {
|
||||
DEBUGF("deflatehd: name match index=%zd\n", res.index);
|
||||
}
|
||||
|
||||
if (indexing_mode == NGHTTP2_HD_WITH_INDEXING) {
|
||||
nghttp2_hd_nv hd_nv;
|
||||
|
||||
if (idx != -1) {
|
||||
hd_nv.name = nghttp2_hd_table_get(&deflater->ctx, (size_t)idx).name;
|
||||
nghttp2_rcbuf_incref(hd_nv.name);
|
||||
} else {
|
||||
rv = nghttp2_rcbuf_new2(&hd_nv.name, nv->name, nv->namelen, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
rv = nghttp2_rcbuf_new2(&hd_nv.value, nv->value, nv->valuelen, mem);
|
||||
|
||||
if (rv != 0) {
|
||||
nghttp2_rcbuf_decref(hd_nv.name);
|
||||
return rv;
|
||||
}
|
||||
|
||||
hd_nv.token = token;
|
||||
hd_nv.flags = NGHTTP2_NV_FLAG_NONE;
|
||||
|
||||
rv = add_hd_table_incremental(&deflater->ctx, &hd_nv, &deflater->map, hash);
|
||||
|
||||
nghttp2_rcbuf_decref(hd_nv.value);
|
||||
nghttp2_rcbuf_decref(hd_nv.name);
|
||||
|
||||
if (rv != 0) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
}
|
||||
if (idx == -1) {
|
||||
rv = emit_newname_block(bufs, nv, indexing_mode);
|
||||
} else {
|
||||
rv = emit_indname_block(bufs, (size_t)idx, nv, indexing_mode);
|
||||
}
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_bufs *bufs, const nghttp2_nv *nv,
|
||||
size_t nvlen) {
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
|
||||
if (deflater->ctx.bad) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
if (deflater->notify_table_size_change) {
|
||||
size_t min_hd_table_bufsize_max;
|
||||
|
||||
min_hd_table_bufsize_max = deflater->min_hd_table_bufsize_max;
|
||||
|
||||
deflater->notify_table_size_change = 0;
|
||||
deflater->min_hd_table_bufsize_max = UINT32_MAX;
|
||||
|
||||
if (deflater->ctx.hd_table_bufsize_max > min_hd_table_bufsize_max) {
|
||||
|
||||
rv = emit_table_size(bufs, min_hd_table_bufsize_max);
|
||||
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rv = emit_table_size(bufs, deflater->ctx.hd_table_bufsize_max);
|
||||
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
rv = deflate_nv(deflater, bufs, &nv[i]);
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
DEBUGF("deflatehd: all input name/value pairs were deflated\n");
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
DEBUGF("deflatehd: error return %d\n", rv);
|
||||
|
||||
deflater->ctx.bad = 1;
|
||||
return rv;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
|
||||
size_t buflen, const nghttp2_nv *nv,
|
||||
size_t nvlen) {
|
||||
nghttp2_bufs bufs;
|
||||
int rv;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = deflater->ctx.mem;
|
||||
|
||||
rv = nghttp2_bufs_wrap_init(&bufs, buf, buflen, mem);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen);
|
||||
|
||||
buflen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
nghttp2_bufs_wrap_free(&bufs);
|
||||
|
||||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
return NGHTTP2_ERR_INSUFF_BUFSIZE;
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return (ssize_t)buflen;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_hd_deflate_hd_vec(nghttp2_hd_deflater *deflater,
|
||||
const nghttp2_vec *vec, size_t veclen,
|
||||
const nghttp2_nv *nv, size_t nvlen) {
|
||||
nghttp2_bufs bufs;
|
||||
int rv;
|
||||
nghttp2_mem *mem;
|
||||
size_t buflen;
|
||||
|
||||
mem = deflater->ctx.mem;
|
||||
|
||||
rv = nghttp2_bufs_wrap_init2(&bufs, vec, veclen, mem);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, nv, nvlen);
|
||||
|
||||
buflen = nghttp2_bufs_len(&bufs);
|
||||
|
||||
nghttp2_bufs_wrap_free(&bufs);
|
||||
|
||||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
return NGHTTP2_ERR_INSUFF_BUFSIZE;
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return (ssize_t)buflen;
|
||||
}
|
||||
|
||||
size_t nghttp2_hd_deflate_bound(nghttp2_hd_deflater *deflater,
|
||||
const nghttp2_nv *nva, size_t nvlen) {
|
||||
size_t n = 0;
|
||||
size_t i;
|
||||
(void)deflater;
|
||||
|
||||
/* Possible Maximum Header Table Size Change. Encoding (1u << 31) -
|
||||
1 using 4 bit prefix requires 6 bytes. We may emit this at most
|
||||
twice. */
|
||||
n += 12;
|
||||
|
||||
/* Use Literal Header Field without indexing - New Name, since it is
|
||||
most space consuming format. Also we choose the less one between
|
||||
non-huffman and huffman, so using literal byte count is
|
||||
sufficient for upper bound.
|
||||
|
||||
Encoding (1u << 31) - 1 using 7 bit prefix requires 6 bytes. We
|
||||
need 2 of this for |nvlen| header fields. */
|
||||
n += 6 * 2 * nvlen;
|
||||
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
n += nva[i].namelen + nva[i].valuelen;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_new(nghttp2_hd_deflater **deflater_ptr,
|
||||
size_t deflate_hd_table_bufsize_max) {
|
||||
return nghttp2_hd_deflate_new2(deflater_ptr, deflate_hd_table_bufsize_max,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int nghttp2_hd_deflate_new2(nghttp2_hd_deflater **deflater_ptr,
|
||||
size_t deflate_hd_table_bufsize_max,
|
||||
nghttp2_mem *mem) {
|
||||
int rv;
|
||||
nghttp2_hd_deflater *deflater;
|
||||
|
||||
if (mem == NULL) {
|
||||
mem = nghttp2_mem_default();
|
||||
}
|
||||
|
||||
deflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_deflater));
|
||||
|
||||
if (deflater == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
rv = nghttp2_hd_deflate_init2(deflater, deflate_hd_table_bufsize_max, mem);
|
||||
|
||||
if (rv != 0) {
|
||||
nghttp2_mem_free(mem, deflater);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
*deflater_ptr = deflater;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_hd_deflate_del(nghttp2_hd_deflater *deflater) {
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = deflater->ctx.mem;
|
||||
|
||||
nghttp2_hd_deflate_free(deflater);
|
||||
|
||||
nghttp2_mem_free(mem, deflater);
|
||||
}
|
||||
|
||||
static void hd_inflate_set_huffman_encoded(nghttp2_hd_inflater *inflater,
|
||||
const uint8_t *in) {
|
||||
inflater->huffman_encoded = (*in & (1 << 7)) != 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Decodes the integer from the range [in, last). The result is
|
||||
* assigned to |inflater->left|. If the |inflater->left| is 0, then
|
||||
* it performs variable integer decoding from scratch. Otherwise, it
|
||||
* uses the |inflater->left| as the initial value and continues to
|
||||
* decode assuming that [in, last) begins with intermediary sequence.
|
||||
*
|
||||
* This function returns the number of bytes read if it succeeds, or
|
||||
* one of the following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* Integer decoding failed
|
||||
*/
|
||||
static ssize_t hd_inflate_read_len(nghttp2_hd_inflater *inflater, int *rfin,
|
||||
const uint8_t *in, const uint8_t *last,
|
||||
size_t prefix, size_t maxlen) {
|
||||
ssize_t rv;
|
||||
uint32_t out;
|
||||
|
||||
*rfin = 0;
|
||||
|
||||
rv = decode_length(&out, &inflater->shift, rfin, (uint32_t)inflater->left,
|
||||
inflater->shift, in, last, prefix);
|
||||
|
||||
if (rv == -1) {
|
||||
DEBUGF("inflatehd: integer decoding failed\n");
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
if (out > maxlen) {
|
||||
DEBUGF("inflatehd: integer exceeded the maximum value %zu\n", maxlen);
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
inflater->left = out;
|
||||
|
||||
DEBUGF("inflatehd: decoded integer is %u\n", out);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads |inflater->left| bytes from the range [in, last) and performs
|
||||
* huffman decoding against them and pushes the result into the
|
||||
* |buffer|.
|
||||
*
|
||||
* This function returns the number of bytes read if it succeeds, or
|
||||
* one of the following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* Huffman decoding failed
|
||||
*/
|
||||
static ssize_t hd_inflate_read_huff(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_buf *buf, const uint8_t *in,
|
||||
const uint8_t *last) {
|
||||
ssize_t readlen;
|
||||
int fin = 0;
|
||||
if ((size_t)(last - in) >= inflater->left) {
|
||||
last = in + inflater->left;
|
||||
fin = 1;
|
||||
}
|
||||
readlen = nghttp2_hd_huff_decode(&inflater->huff_decode_ctx, buf, in,
|
||||
(size_t)(last - in), fin);
|
||||
|
||||
if (readlen < 0) {
|
||||
DEBUGF("inflatehd: huffman decoding failed\n");
|
||||
return readlen;
|
||||
}
|
||||
if (nghttp2_hd_huff_decode_failure_state(&inflater->huff_decode_ctx)) {
|
||||
DEBUGF("inflatehd: huffman decoding failed\n");
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
inflater->left -= (size_t)readlen;
|
||||
return readlen;
|
||||
}
|
||||
|
||||
/*
|
||||
* Reads |inflater->left| bytes from the range [in, last) and copies
|
||||
* them into the |buffer|.
|
||||
*
|
||||
* This function returns the number of bytes read if it succeeds, or
|
||||
* one of the following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* Header decompression failed
|
||||
*/
|
||||
static ssize_t hd_inflate_read(nghttp2_hd_inflater *inflater, nghttp2_buf *buf,
|
||||
const uint8_t *in, const uint8_t *last) {
|
||||
size_t len = nghttp2_min((size_t)(last - in), inflater->left);
|
||||
|
||||
buf->last = nghttp2_cpymem(buf->last, in, len);
|
||||
|
||||
inflater->left -= len;
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize indexed header representation reception. The referenced
|
||||
* header is always emitted, and |*nv_out| is filled with that value.
|
||||
*/
|
||||
static void hd_inflate_commit_indexed(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_hd_nv *nv_out) {
|
||||
nghttp2_hd_nv nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
|
||||
|
||||
emit_header(nv_out, &nv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize literal header representation - new name- reception. If
|
||||
* header is emitted, |*nv_out| is filled with that value and 0 is
|
||||
* returned.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
static int hd_inflate_commit_newname(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_hd_nv *nv_out) {
|
||||
nghttp2_hd_nv nv;
|
||||
int rv;
|
||||
|
||||
if (inflater->no_index) {
|
||||
nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
|
||||
} else {
|
||||
nv.flags = NGHTTP2_NV_FLAG_NONE;
|
||||
}
|
||||
|
||||
nv.name = inflater->namercbuf;
|
||||
nv.value = inflater->valuercbuf;
|
||||
nv.token = lookup_token(inflater->namercbuf->base, inflater->namercbuf->len);
|
||||
|
||||
if (inflater->index_required) {
|
||||
rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0);
|
||||
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
emit_header(nv_out, &nv);
|
||||
|
||||
inflater->nv_name_keep = nv.name;
|
||||
inflater->nv_value_keep = nv.value;
|
||||
|
||||
inflater->namercbuf = NULL;
|
||||
inflater->valuercbuf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Finalize literal header representation - indexed name-
|
||||
* reception. If header is emitted, |*nv_out| is filled with that
|
||||
* value and 0 is returned.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
static int hd_inflate_commit_indname(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_hd_nv *nv_out) {
|
||||
nghttp2_hd_nv nv;
|
||||
int rv;
|
||||
|
||||
nv = nghttp2_hd_table_get(&inflater->ctx, inflater->index);
|
||||
|
||||
if (inflater->no_index) {
|
||||
nv.flags = NGHTTP2_NV_FLAG_NO_INDEX;
|
||||
} else {
|
||||
nv.flags = NGHTTP2_NV_FLAG_NONE;
|
||||
}
|
||||
|
||||
nghttp2_rcbuf_incref(nv.name);
|
||||
|
||||
nv.value = inflater->valuercbuf;
|
||||
|
||||
if (inflater->index_required) {
|
||||
rv = add_hd_table_incremental(&inflater->ctx, &nv, NULL, 0);
|
||||
if (rv != 0) {
|
||||
nghttp2_rcbuf_decref(nv.name);
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
emit_header(nv_out, &nv);
|
||||
|
||||
inflater->nv_name_keep = nv.name;
|
||||
inflater->nv_value_keep = nv.value;
|
||||
|
||||
inflater->valuercbuf = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
|
||||
int *inflate_flags, uint8_t *in, size_t inlen,
|
||||
int in_final) {
|
||||
return nghttp2_hd_inflate_hd2(inflater, nv_out, inflate_flags, in, inlen,
|
||||
in_final);
|
||||
}
|
||||
|
||||
ssize_t nghttp2_hd_inflate_hd2(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_nv *nv_out, int *inflate_flags,
|
||||
const uint8_t *in, size_t inlen, int in_final) {
|
||||
ssize_t rv;
|
||||
nghttp2_hd_nv hd_nv;
|
||||
|
||||
rv = nghttp2_hd_inflate_hd_nv(inflater, &hd_nv, inflate_flags, in, inlen,
|
||||
in_final);
|
||||
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (*inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
|
||||
nv_out->name = hd_nv.name->base;
|
||||
nv_out->namelen = hd_nv.name->len;
|
||||
|
||||
nv_out->value = hd_nv.value->base;
|
||||
nv_out->valuelen = hd_nv.value->len;
|
||||
|
||||
nv_out->flags = hd_nv.flags;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
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) {
|
||||
ssize_t rv = 0;
|
||||
const uint8_t *first = in;
|
||||
const uint8_t *last = in + inlen;
|
||||
int rfin = 0;
|
||||
int busy = 0;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = inflater->ctx.mem;
|
||||
|
||||
if (inflater->ctx.bad) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
DEBUGF("inflatehd: start state=%d\n", inflater->state);
|
||||
hd_inflate_keep_free(inflater);
|
||||
*inflate_flags = NGHTTP2_HD_INFLATE_NONE;
|
||||
for (; in != last || busy;) {
|
||||
busy = 0;
|
||||
switch (inflater->state) {
|
||||
case NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE:
|
||||
if ((*in & 0xe0u) != 0x20u) {
|
||||
DEBUGF("inflatehd: header table size change was expected, but saw "
|
||||
"0x%02x as first byte",
|
||||
*in);
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
goto fail;
|
||||
}
|
||||
/* fall through */
|
||||
case NGHTTP2_HD_STATE_INFLATE_START:
|
||||
case NGHTTP2_HD_STATE_OPCODE:
|
||||
if ((*in & 0xe0u) == 0x20u) {
|
||||
DEBUGF("inflatehd: header table size change\n");
|
||||
if (inflater->state == NGHTTP2_HD_STATE_OPCODE) {
|
||||
DEBUGF("inflatehd: header table size change must appear at the head "
|
||||
"of header block\n");
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
goto fail;
|
||||
}
|
||||
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_TABLE_SIZE;
|
||||
} else if (*in & 0x80u) {
|
||||
DEBUGF("inflatehd: indexed repr\n");
|
||||
inflater->opcode = NGHTTP2_HD_OPCODE_INDEXED;
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
|
||||
} else {
|
||||
if (*in == 0x40u || *in == 0 || *in == 0x10u) {
|
||||
DEBUGF("inflatehd: literal header repr - new name\n");
|
||||
inflater->opcode = NGHTTP2_HD_OPCODE_NEWNAME;
|
||||
inflater->state = NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN;
|
||||
} else {
|
||||
DEBUGF("inflatehd: literal header repr - indexed name\n");
|
||||
inflater->opcode = NGHTTP2_HD_OPCODE_INDNAME;
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_INDEX;
|
||||
}
|
||||
inflater->index_required = (*in & 0x40) != 0;
|
||||
inflater->no_index = (*in & 0xf0u) == 0x10u;
|
||||
DEBUGF("inflatehd: indexing required=%d, no_index=%d\n",
|
||||
inflater->index_required, inflater->no_index);
|
||||
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
|
||||
++in;
|
||||
}
|
||||
}
|
||||
inflater->left = 0;
|
||||
inflater->shift = 0;
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_READ_TABLE_SIZE:
|
||||
rfin = 0;
|
||||
rv = hd_inflate_read_len(
|
||||
inflater, &rfin, in, last, 5,
|
||||
nghttp2_min(inflater->min_hd_table_bufsize_max,
|
||||
inflater->settings_hd_table_bufsize_max));
|
||||
if (rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
in += rv;
|
||||
if (!rfin) {
|
||||
goto almost_ok;
|
||||
}
|
||||
DEBUGF("inflatehd: table_size=%zu\n", inflater->left);
|
||||
inflater->min_hd_table_bufsize_max = UINT32_MAX;
|
||||
inflater->ctx.hd_table_bufsize_max = inflater->left;
|
||||
hd_context_shrink_table_size(&inflater->ctx, NULL);
|
||||
inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_READ_INDEX: {
|
||||
size_t prefixlen;
|
||||
|
||||
if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
|
||||
prefixlen = 7;
|
||||
} else if (inflater->index_required) {
|
||||
prefixlen = 6;
|
||||
} else {
|
||||
prefixlen = 4;
|
||||
}
|
||||
|
||||
rfin = 0;
|
||||
rv = hd_inflate_read_len(inflater, &rfin, in, last, prefixlen,
|
||||
get_max_index(&inflater->ctx));
|
||||
if (rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
in += rv;
|
||||
|
||||
if (!rfin) {
|
||||
goto almost_ok;
|
||||
}
|
||||
|
||||
if (inflater->left == 0) {
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
DEBUGF("inflatehd: index=%zu\n", inflater->left);
|
||||
if (inflater->opcode == NGHTTP2_HD_OPCODE_INDEXED) {
|
||||
inflater->index = inflater->left;
|
||||
--inflater->index;
|
||||
|
||||
hd_inflate_commit_indexed(inflater, nv_out);
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_OPCODE;
|
||||
*inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
|
||||
return (ssize_t)(in - first);
|
||||
} else {
|
||||
inflater->index = inflater->left;
|
||||
--inflater->index;
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN:
|
||||
hd_inflate_set_huffman_encoded(inflater, in);
|
||||
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN;
|
||||
inflater->left = 0;
|
||||
inflater->shift = 0;
|
||||
DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0);
|
||||
/* Fall through */
|
||||
case NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN:
|
||||
rfin = 0;
|
||||
rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV);
|
||||
if (rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
in += rv;
|
||||
if (!rfin) {
|
||||
DEBUGF("inflatehd: integer not fully decoded. current=%zu\n",
|
||||
inflater->left);
|
||||
|
||||
goto almost_ok;
|
||||
}
|
||||
|
||||
if (inflater->huffman_encoded) {
|
||||
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF;
|
||||
|
||||
rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left * 2 + 1,
|
||||
mem);
|
||||
} else {
|
||||
inflater->state = NGHTTP2_HD_STATE_NEWNAME_READ_NAME;
|
||||
rv = nghttp2_rcbuf_new(&inflater->namercbuf, inflater->left + 1, mem);
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nghttp2_buf_wrap_init(&inflater->namebuf, inflater->namercbuf->base,
|
||||
inflater->namercbuf->len);
|
||||
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF:
|
||||
rv = hd_inflate_read_huff(inflater, &inflater->namebuf, in, last);
|
||||
if (rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
in += rv;
|
||||
|
||||
DEBUGF("inflatehd: %zd bytes read\n", rv);
|
||||
|
||||
if (inflater->left) {
|
||||
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
|
||||
|
||||
goto almost_ok;
|
||||
}
|
||||
|
||||
*inflater->namebuf.last = '\0';
|
||||
inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf);
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
|
||||
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_NEWNAME_READ_NAME:
|
||||
rv = hd_inflate_read(inflater, &inflater->namebuf, in, last);
|
||||
if (rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
in += rv;
|
||||
|
||||
DEBUGF("inflatehd: %zd bytes read\n", rv);
|
||||
if (inflater->left) {
|
||||
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
|
||||
|
||||
goto almost_ok;
|
||||
}
|
||||
|
||||
*inflater->namebuf.last = '\0';
|
||||
inflater->namercbuf->len = nghttp2_buf_len(&inflater->namebuf);
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_CHECK_VALUELEN;
|
||||
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_CHECK_VALUELEN:
|
||||
hd_inflate_set_huffman_encoded(inflater, in);
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_VALUELEN;
|
||||
inflater->left = 0;
|
||||
inflater->shift = 0;
|
||||
DEBUGF("inflatehd: huffman encoded=%d\n", inflater->huffman_encoded != 0);
|
||||
/* Fall through */
|
||||
case NGHTTP2_HD_STATE_READ_VALUELEN:
|
||||
rfin = 0;
|
||||
rv = hd_inflate_read_len(inflater, &rfin, in, last, 7, NGHTTP2_HD_MAX_NV);
|
||||
if (rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
in += rv;
|
||||
|
||||
if (!rfin) {
|
||||
goto almost_ok;
|
||||
}
|
||||
|
||||
DEBUGF("inflatehd: valuelen=%zu\n", inflater->left);
|
||||
|
||||
if (inflater->huffman_encoded) {
|
||||
nghttp2_hd_huff_decode_context_init(&inflater->huff_decode_ctx);
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_VALUEHUFF;
|
||||
|
||||
rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left * 2 + 1,
|
||||
mem);
|
||||
} else {
|
||||
inflater->state = NGHTTP2_HD_STATE_READ_VALUE;
|
||||
|
||||
rv = nghttp2_rcbuf_new(&inflater->valuercbuf, inflater->left + 1, mem);
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nghttp2_buf_wrap_init(&inflater->valuebuf, inflater->valuercbuf->base,
|
||||
inflater->valuercbuf->len);
|
||||
|
||||
busy = 1;
|
||||
|
||||
break;
|
||||
case NGHTTP2_HD_STATE_READ_VALUEHUFF:
|
||||
rv = hd_inflate_read_huff(inflater, &inflater->valuebuf, in, last);
|
||||
if (rv < 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
in += rv;
|
||||
|
||||
DEBUGF("inflatehd: %zd bytes read\n", rv);
|
||||
|
||||
if (inflater->left) {
|
||||
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
|
||||
|
||||
goto almost_ok;
|
||||
}
|
||||
|
||||
*inflater->valuebuf.last = '\0';
|
||||
inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf);
|
||||
|
||||
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
|
||||
rv = hd_inflate_commit_newname(inflater, nv_out);
|
||||
} else {
|
||||
rv = hd_inflate_commit_indname(inflater, nv_out);
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_OPCODE;
|
||||
*inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
|
||||
|
||||
return (ssize_t)(in - first);
|
||||
case NGHTTP2_HD_STATE_READ_VALUE:
|
||||
rv = hd_inflate_read(inflater, &inflater->valuebuf, in, last);
|
||||
if (rv < 0) {
|
||||
DEBUGF("inflatehd: value read failure %zd: %s\n", rv,
|
||||
nghttp2_strerror((int)rv));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
in += rv;
|
||||
|
||||
DEBUGF("inflatehd: %zd bytes read\n", rv);
|
||||
|
||||
if (inflater->left) {
|
||||
DEBUGF("inflatehd: still %zu bytes to go\n", inflater->left);
|
||||
goto almost_ok;
|
||||
}
|
||||
|
||||
*inflater->valuebuf.last = '\0';
|
||||
inflater->valuercbuf->len = nghttp2_buf_len(&inflater->valuebuf);
|
||||
|
||||
if (inflater->opcode == NGHTTP2_HD_OPCODE_NEWNAME) {
|
||||
rv = hd_inflate_commit_newname(inflater, nv_out);
|
||||
} else {
|
||||
rv = hd_inflate_commit_indname(inflater, nv_out);
|
||||
}
|
||||
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
inflater->state = NGHTTP2_HD_STATE_OPCODE;
|
||||
*inflate_flags |= NGHTTP2_HD_INFLATE_EMIT;
|
||||
|
||||
return (ssize_t)(in - first);
|
||||
}
|
||||
}
|
||||
|
||||
assert(in == last);
|
||||
|
||||
DEBUGF("inflatehd: all input bytes were processed\n");
|
||||
|
||||
if (in_final) {
|
||||
DEBUGF("inflatehd: in_final set\n");
|
||||
|
||||
if (inflater->state != NGHTTP2_HD_STATE_OPCODE &&
|
||||
inflater->state != NGHTTP2_HD_STATE_INFLATE_START) {
|
||||
DEBUGF("inflatehd: unacceptable state=%d\n", inflater->state);
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
*inflate_flags |= NGHTTP2_HD_INFLATE_FINAL;
|
||||
}
|
||||
return (ssize_t)(in - first);
|
||||
|
||||
almost_ok:
|
||||
if (in_final) {
|
||||
DEBUGF("inflatehd: input ended prematurely\n");
|
||||
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
return (ssize_t)(in - first);
|
||||
|
||||
fail:
|
||||
DEBUGF("inflatehd: error return %zd\n", rv);
|
||||
|
||||
inflater->ctx.bad = 1;
|
||||
return rv;
|
||||
}
|
||||
|
||||
int nghttp2_hd_inflate_end_headers(nghttp2_hd_inflater *inflater) {
|
||||
hd_inflate_keep_free(inflater);
|
||||
inflater->state = NGHTTP2_HD_STATE_INFLATE_START;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_hd_inflate_new(nghttp2_hd_inflater **inflater_ptr) {
|
||||
return nghttp2_hd_inflate_new2(inflater_ptr, NULL);
|
||||
}
|
||||
|
||||
int nghttp2_hd_inflate_new2(nghttp2_hd_inflater **inflater_ptr,
|
||||
nghttp2_mem *mem) {
|
||||
int rv;
|
||||
nghttp2_hd_inflater *inflater;
|
||||
|
||||
if (mem == NULL) {
|
||||
mem = nghttp2_mem_default();
|
||||
}
|
||||
|
||||
inflater = nghttp2_mem_malloc(mem, sizeof(nghttp2_hd_inflater));
|
||||
|
||||
if (inflater == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
rv = nghttp2_hd_inflate_init(inflater, mem);
|
||||
|
||||
if (rv != 0) {
|
||||
nghttp2_mem_free(mem, inflater);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
*inflater_ptr = inflater;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_hd_inflate_del(nghttp2_hd_inflater *inflater) {
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = inflater->ctx.mem;
|
||||
nghttp2_hd_inflate_free(inflater);
|
||||
|
||||
nghttp2_mem_free(mem, inflater);
|
||||
}
|
||||
|
||||
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t idx,
|
||||
nghttp2_nv *nv, int indexing_mode) {
|
||||
|
||||
return emit_indname_block(bufs, idx, nv, indexing_mode);
|
||||
}
|
||||
|
||||
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||
int indexing_mode) {
|
||||
return emit_newname_block(bufs, nv, indexing_mode);
|
||||
}
|
||||
|
||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size) {
|
||||
return emit_table_size(bufs, table_size);
|
||||
}
|
||||
|
||||
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) {
|
||||
return decode_length(res, shift_ptr, fin, initial, shift, in, last, prefix);
|
||||
}
|
||||
|
||||
static const nghttp2_nv *hd_get_table_entry(nghttp2_hd_context *context,
|
||||
size_t idx) {
|
||||
if (idx == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
--idx;
|
||||
|
||||
if (!INDEX_RANGE_VALID(context, idx)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return nghttp2_hd_table_get2(context, idx);
|
||||
}
|
||||
|
||||
size_t nghttp2_hd_deflate_get_num_table_entries(nghttp2_hd_deflater *deflater) {
|
||||
return get_max_index(&deflater->ctx);
|
||||
}
|
||||
|
||||
const nghttp2_nv *
|
||||
nghttp2_hd_deflate_get_table_entry(nghttp2_hd_deflater *deflater, size_t idx) {
|
||||
return hd_get_table_entry(&deflater->ctx, idx);
|
||||
}
|
||||
|
||||
size_t
|
||||
nghttp2_hd_deflate_get_dynamic_table_size(nghttp2_hd_deflater *deflater) {
|
||||
return deflater->ctx.hd_table_bufsize;
|
||||
}
|
||||
|
||||
size_t
|
||||
nghttp2_hd_deflate_get_max_dynamic_table_size(nghttp2_hd_deflater *deflater) {
|
||||
return deflater->ctx.hd_table_bufsize_max;
|
||||
}
|
||||
|
||||
size_t nghttp2_hd_inflate_get_num_table_entries(nghttp2_hd_inflater *inflater) {
|
||||
return get_max_index(&inflater->ctx);
|
||||
}
|
||||
|
||||
const nghttp2_nv *
|
||||
nghttp2_hd_inflate_get_table_entry(nghttp2_hd_inflater *inflater, size_t idx) {
|
||||
return hd_get_table_entry(&inflater->ctx, idx);
|
||||
}
|
||||
|
||||
size_t
|
||||
nghttp2_hd_inflate_get_dynamic_table_size(nghttp2_hd_inflater *inflater) {
|
||||
return inflater->ctx.hd_table_bufsize;
|
||||
}
|
||||
|
||||
size_t
|
||||
nghttp2_hd_inflate_get_max_dynamic_table_size(nghttp2_hd_inflater *inflater) {
|
||||
return inflater->ctx.hd_table_bufsize_max;
|
||||
}
|
||||
@@ -0,0 +1,439 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HD_H
|
||||
#define NGHTTP2_HD_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#include "nghttp2_hd_huffman.h"
|
||||
#include "nghttp2_buf.h"
|
||||
#include "nghttp2_mem.h"
|
||||
#include "nghttp2_rcbuf.h"
|
||||
|
||||
#define NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE NGHTTP2_DEFAULT_HEADER_TABLE_SIZE
|
||||
#define NGHTTP2_HD_ENTRY_OVERHEAD 32
|
||||
|
||||
/* The maximum length of one name/value pair. This is the sum of the
|
||||
length of name and value. This is not specified by the spec. We
|
||||
just chose the arbitrary size */
|
||||
#define NGHTTP2_HD_MAX_NV 65536
|
||||
|
||||
/* Default size of maximum table buffer size for encoder. Even if
|
||||
remote decoder notifies larger buffer size for its decoding,
|
||||
encoder only uses the memory up to this value. */
|
||||
#define NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE (1 << 12)
|
||||
|
||||
/* Exported for unit test */
|
||||
#define NGHTTP2_STATIC_TABLE_LENGTH 61
|
||||
|
||||
/* Generated by genlibtokenlookup.py */
|
||||
typedef enum {
|
||||
NGHTTP2_TOKEN__AUTHORITY = 0,
|
||||
NGHTTP2_TOKEN__METHOD = 1,
|
||||
NGHTTP2_TOKEN__PATH = 3,
|
||||
NGHTTP2_TOKEN__SCHEME = 5,
|
||||
NGHTTP2_TOKEN__STATUS = 7,
|
||||
NGHTTP2_TOKEN_ACCEPT_CHARSET = 14,
|
||||
NGHTTP2_TOKEN_ACCEPT_ENCODING = 15,
|
||||
NGHTTP2_TOKEN_ACCEPT_LANGUAGE = 16,
|
||||
NGHTTP2_TOKEN_ACCEPT_RANGES = 17,
|
||||
NGHTTP2_TOKEN_ACCEPT = 18,
|
||||
NGHTTP2_TOKEN_ACCESS_CONTROL_ALLOW_ORIGIN = 19,
|
||||
NGHTTP2_TOKEN_AGE = 20,
|
||||
NGHTTP2_TOKEN_ALLOW = 21,
|
||||
NGHTTP2_TOKEN_AUTHORIZATION = 22,
|
||||
NGHTTP2_TOKEN_CACHE_CONTROL = 23,
|
||||
NGHTTP2_TOKEN_CONTENT_DISPOSITION = 24,
|
||||
NGHTTP2_TOKEN_CONTENT_ENCODING = 25,
|
||||
NGHTTP2_TOKEN_CONTENT_LANGUAGE = 26,
|
||||
NGHTTP2_TOKEN_CONTENT_LENGTH = 27,
|
||||
NGHTTP2_TOKEN_CONTENT_LOCATION = 28,
|
||||
NGHTTP2_TOKEN_CONTENT_RANGE = 29,
|
||||
NGHTTP2_TOKEN_CONTENT_TYPE = 30,
|
||||
NGHTTP2_TOKEN_COOKIE = 31,
|
||||
NGHTTP2_TOKEN_DATE = 32,
|
||||
NGHTTP2_TOKEN_ETAG = 33,
|
||||
NGHTTP2_TOKEN_EXPECT = 34,
|
||||
NGHTTP2_TOKEN_EXPIRES = 35,
|
||||
NGHTTP2_TOKEN_FROM = 36,
|
||||
NGHTTP2_TOKEN_HOST = 37,
|
||||
NGHTTP2_TOKEN_IF_MATCH = 38,
|
||||
NGHTTP2_TOKEN_IF_MODIFIED_SINCE = 39,
|
||||
NGHTTP2_TOKEN_IF_NONE_MATCH = 40,
|
||||
NGHTTP2_TOKEN_IF_RANGE = 41,
|
||||
NGHTTP2_TOKEN_IF_UNMODIFIED_SINCE = 42,
|
||||
NGHTTP2_TOKEN_LAST_MODIFIED = 43,
|
||||
NGHTTP2_TOKEN_LINK = 44,
|
||||
NGHTTP2_TOKEN_LOCATION = 45,
|
||||
NGHTTP2_TOKEN_MAX_FORWARDS = 46,
|
||||
NGHTTP2_TOKEN_PROXY_AUTHENTICATE = 47,
|
||||
NGHTTP2_TOKEN_PROXY_AUTHORIZATION = 48,
|
||||
NGHTTP2_TOKEN_RANGE = 49,
|
||||
NGHTTP2_TOKEN_REFERER = 50,
|
||||
NGHTTP2_TOKEN_REFRESH = 51,
|
||||
NGHTTP2_TOKEN_RETRY_AFTER = 52,
|
||||
NGHTTP2_TOKEN_SERVER = 53,
|
||||
NGHTTP2_TOKEN_SET_COOKIE = 54,
|
||||
NGHTTP2_TOKEN_STRICT_TRANSPORT_SECURITY = 55,
|
||||
NGHTTP2_TOKEN_TRANSFER_ENCODING = 56,
|
||||
NGHTTP2_TOKEN_USER_AGENT = 57,
|
||||
NGHTTP2_TOKEN_VARY = 58,
|
||||
NGHTTP2_TOKEN_VIA = 59,
|
||||
NGHTTP2_TOKEN_WWW_AUTHENTICATE = 60,
|
||||
NGHTTP2_TOKEN_TE,
|
||||
NGHTTP2_TOKEN_CONNECTION,
|
||||
NGHTTP2_TOKEN_KEEP_ALIVE,
|
||||
NGHTTP2_TOKEN_PROXY_CONNECTION,
|
||||
NGHTTP2_TOKEN_UPGRADE,
|
||||
NGHTTP2_TOKEN__PROTOCOL,
|
||||
} nghttp2_token;
|
||||
|
||||
struct nghttp2_hd_entry;
|
||||
typedef struct nghttp2_hd_entry nghttp2_hd_entry;
|
||||
|
||||
typedef struct {
|
||||
/* The buffer containing header field name. NULL-termination is
|
||||
guaranteed. */
|
||||
nghttp2_rcbuf *name;
|
||||
/* The buffer containing header field value. NULL-termination is
|
||||
guaranteed. */
|
||||
nghttp2_rcbuf *value;
|
||||
/* nghttp2_token value for name. It could be -1 if we have no token
|
||||
for that header field name. */
|
||||
int32_t token;
|
||||
/* Bitwise OR of one or more of nghttp2_nv_flag. */
|
||||
uint8_t flags;
|
||||
} nghttp2_hd_nv;
|
||||
|
||||
struct nghttp2_hd_entry {
|
||||
/* The header field name/value pair */
|
||||
nghttp2_hd_nv nv;
|
||||
/* This is solely for nghttp2_hd_{deflate,inflate}_get_table_entry
|
||||
APIs to keep backward compatibility. */
|
||||
nghttp2_nv cnv;
|
||||
/* The next entry which shares same bucket in hash table. */
|
||||
nghttp2_hd_entry *next;
|
||||
/* The sequence number. We will increment it by one whenever we
|
||||
store nghttp2_hd_entry to dynamic header table. */
|
||||
uint32_t seq;
|
||||
/* The hash value for header name (nv.name). */
|
||||
uint32_t hash;
|
||||
};
|
||||
|
||||
/* The entry used for static header table. */
|
||||
typedef struct {
|
||||
nghttp2_rcbuf name;
|
||||
nghttp2_rcbuf value;
|
||||
nghttp2_nv cnv;
|
||||
int32_t token;
|
||||
uint32_t hash;
|
||||
} nghttp2_hd_static_entry;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry **buffer;
|
||||
size_t mask;
|
||||
size_t first;
|
||||
size_t len;
|
||||
} nghttp2_hd_ringbuf;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_OPCODE_NONE,
|
||||
NGHTTP2_HD_OPCODE_INDEXED,
|
||||
NGHTTP2_HD_OPCODE_NEWNAME,
|
||||
NGHTTP2_HD_OPCODE_INDNAME
|
||||
} nghttp2_hd_opcode;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_STATE_EXPECT_TABLE_SIZE,
|
||||
NGHTTP2_HD_STATE_INFLATE_START,
|
||||
NGHTTP2_HD_STATE_OPCODE,
|
||||
NGHTTP2_HD_STATE_READ_TABLE_SIZE,
|
||||
NGHTTP2_HD_STATE_READ_INDEX,
|
||||
NGHTTP2_HD_STATE_NEWNAME_CHECK_NAMELEN,
|
||||
NGHTTP2_HD_STATE_NEWNAME_READ_NAMELEN,
|
||||
NGHTTP2_HD_STATE_NEWNAME_READ_NAMEHUFF,
|
||||
NGHTTP2_HD_STATE_NEWNAME_READ_NAME,
|
||||
NGHTTP2_HD_STATE_CHECK_VALUELEN,
|
||||
NGHTTP2_HD_STATE_READ_VALUELEN,
|
||||
NGHTTP2_HD_STATE_READ_VALUEHUFF,
|
||||
NGHTTP2_HD_STATE_READ_VALUE
|
||||
} nghttp2_hd_inflate_state;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_HD_WITH_INDEXING,
|
||||
NGHTTP2_HD_WITHOUT_INDEXING,
|
||||
NGHTTP2_HD_NEVER_INDEXING
|
||||
} nghttp2_hd_indexing_mode;
|
||||
|
||||
typedef struct {
|
||||
/* dynamic header table */
|
||||
nghttp2_hd_ringbuf hd_table;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem *mem;
|
||||
/* Abstract buffer size of hd_table as described in the spec. This
|
||||
is the sum of length of name/value in hd_table +
|
||||
NGHTTP2_HD_ENTRY_OVERHEAD bytes overhead per each entry. */
|
||||
size_t hd_table_bufsize;
|
||||
/* The effective header table size. */
|
||||
size_t hd_table_bufsize_max;
|
||||
/* Next sequence number for nghttp2_hd_entry */
|
||||
uint32_t next_seq;
|
||||
/* If inflate/deflate error occurred, this value is set to 1 and
|
||||
further invocation of inflate/deflate will fail with
|
||||
NGHTTP2_ERR_HEADER_COMP. */
|
||||
uint8_t bad;
|
||||
} nghttp2_hd_context;
|
||||
|
||||
#define HD_MAP_SIZE 128
|
||||
|
||||
typedef struct {
|
||||
nghttp2_hd_entry *table[HD_MAP_SIZE];
|
||||
} nghttp2_hd_map;
|
||||
|
||||
struct nghttp2_hd_deflater {
|
||||
nghttp2_hd_context ctx;
|
||||
nghttp2_hd_map map;
|
||||
/* The upper limit of the header table size the deflater accepts. */
|
||||
size_t deflate_hd_table_bufsize_max;
|
||||
/* Minimum header table size notified in the next context update */
|
||||
size_t min_hd_table_bufsize_max;
|
||||
/* If nonzero, send header table size using encoding context update
|
||||
in the next deflate process */
|
||||
uint8_t notify_table_size_change;
|
||||
};
|
||||
|
||||
struct nghttp2_hd_inflater {
|
||||
nghttp2_hd_context ctx;
|
||||
/* Stores current state of huffman decoding */
|
||||
nghttp2_hd_huff_decode_context huff_decode_ctx;
|
||||
/* header buffer */
|
||||
nghttp2_buf namebuf, valuebuf;
|
||||
nghttp2_rcbuf *namercbuf, *valuercbuf;
|
||||
/* Pointer to the name/value pair which are used in the current
|
||||
header emission. */
|
||||
nghttp2_rcbuf *nv_name_keep, *nv_value_keep;
|
||||
/* The number of bytes to read */
|
||||
size_t left;
|
||||
/* The index in indexed repr or indexed name */
|
||||
size_t index;
|
||||
/* The maximum header table size the inflater supports. This is the
|
||||
same value transmitted in SETTINGS_HEADER_TABLE_SIZE */
|
||||
size_t settings_hd_table_bufsize_max;
|
||||
/* Minimum header table size set by nghttp2_hd_inflate_change_table_size */
|
||||
size_t min_hd_table_bufsize_max;
|
||||
/* The number of next shift to decode integer */
|
||||
size_t shift;
|
||||
nghttp2_hd_opcode opcode;
|
||||
nghttp2_hd_inflate_state state;
|
||||
/* nonzero if string is huffman encoded */
|
||||
uint8_t huffman_encoded;
|
||||
/* nonzero if deflater requires that current entry is indexed */
|
||||
uint8_t index_required;
|
||||
/* nonzero if deflater requires that current entry must not be
|
||||
indexed */
|
||||
uint8_t no_index;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initializes the |ent| members. The reference counts of nv->name
|
||||
* and nv->value are increased by one for each.
|
||||
*/
|
||||
void nghttp2_hd_entry_init(nghttp2_hd_entry *ent, nghttp2_hd_nv *nv);
|
||||
|
||||
/*
|
||||
* This function decreases the reference counts of nv->name and
|
||||
* nv->value.
|
||||
*/
|
||||
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
|
||||
|
||||
/*
|
||||
* Initializes |deflater| for deflating name/values pairs.
|
||||
*
|
||||
* The encoder only uses up to
|
||||
* NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE bytes for header table
|
||||
* even if the larger value is specified later in
|
||||
* nghttp2_hd_change_table_size().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_hd_deflate_init(nghttp2_hd_deflater *deflater, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Initializes |deflater| for deflating name/values pairs.
|
||||
*
|
||||
* The encoder only uses up to |max_deflate_dynamic_table_size| bytes
|
||||
* for header table even if the larger value is specified later in
|
||||
* nghttp2_hd_change_table_size().
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_hd_deflate_init2(nghttp2_hd_deflater *deflater,
|
||||
size_t max_deflate_dynamic_table_size,
|
||||
nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |deflater|.
|
||||
*/
|
||||
void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
|
||||
|
||||
/*
|
||||
* Deflates the |nva|, which has the |nvlen| name/value pairs, into
|
||||
* the |bufs|.
|
||||
*
|
||||
* This function expands |bufs| as necessary to store the result. If
|
||||
* buffers is full and the process still requires more space, this
|
||||
* function fails and returns NGHTTP2_ERR_HEADER_COMP.
|
||||
*
|
||||
* After this function returns, it is safe to delete the |nva|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* Deflation process has failed.
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_bufs *bufs, const nghttp2_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
/*
|
||||
* Initializes |inflater| for inflating name/values pairs.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* :enum:`NGHTTP2_ERR_NOMEM`
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_hd_inflate_init(nghttp2_hd_inflater *inflater, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |inflater|.
|
||||
*/
|
||||
void nghttp2_hd_inflate_free(nghttp2_hd_inflater *inflater);
|
||||
|
||||
/*
|
||||
* Similar to nghttp2_hd_inflate_hd(), but this takes nghttp2_hd_nv
|
||||
* instead of nghttp2_nv as output parameter |nv_out|. Other than
|
||||
* that return values and semantics are the same as
|
||||
* nghttp2_hd_inflate_hd().
|
||||
*/
|
||||
ssize_t nghttp2_hd_inflate_hd_nv(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_hd_nv *nv_out, int *inflate_flags,
|
||||
const uint8_t *in, size_t inlen, int in_final);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_indname_block(nghttp2_bufs *bufs, size_t index,
|
||||
nghttp2_nv *nv, int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||
int indexing_mode);
|
||||
|
||||
/* For unittesting purpose */
|
||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
||||
|
||||
/* For unittesting purpose */
|
||||
nghttp2_hd_nv nghttp2_hd_table_get(nghttp2_hd_context *context, size_t index);
|
||||
|
||||
/* For unittesting purpose */
|
||||
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *fin,
|
||||
uint32_t initial, size_t shift, uint8_t *in,
|
||||
uint8_t *last, size_t prefix);
|
||||
|
||||
/* Huffman encoding/decoding functions */
|
||||
|
||||
/*
|
||||
* Counts the required bytes to encode |src| with length |len|.
|
||||
*
|
||||
* This function returns the number of required bytes to encode given
|
||||
* data, including padding of prefix of terminal symbol code. This
|
||||
* function always succeeds.
|
||||
*/
|
||||
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
|
||||
|
||||
/*
|
||||
* Encodes the given data |src| with length |srclen| to the |bufs|.
|
||||
* This function expands extra buffers in |bufs| if necessary.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen);
|
||||
|
||||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
|
||||
|
||||
/*
|
||||
* Decodes the given data |src| with length |srclen|. The |ctx| must
|
||||
* be initialized by nghttp2_hd_huff_decode_context_init(). The result
|
||||
* will be written to |buf|. This function assumes that |buf| has the
|
||||
* enough room to store the decoded byte string.
|
||||
*
|
||||
* The caller must set the |fin| to nonzero if the given input is the
|
||||
* final block.
|
||||
*
|
||||
* This function returns the number of read bytes from the |in|.
|
||||
*
|
||||
* If this function fails, it returns one of the following negative
|
||||
* return codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_HEADER_COMP
|
||||
* Decoding process has failed.
|
||||
*/
|
||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
nghttp2_buf *buf, const uint8_t *src,
|
||||
size_t srclen, int fin);
|
||||
|
||||
/*
|
||||
* nghttp2_hd_huff_decode_failure_state returns nonzero if |ctx|
|
||||
* indicates that huffman decoding context is in failure state.
|
||||
*/
|
||||
int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx);
|
||||
|
||||
#endif /* NGHTTP2_HD_H */
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_hd_huffman.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_net.h"
|
||||
|
||||
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
|
||||
size_t i;
|
||||
size_t nbits = 0;
|
||||
|
||||
for (i = 0; i < len; ++i) {
|
||||
nbits += huff_sym_table[src[i]].nbits;
|
||||
}
|
||||
/* pad the prefix of EOS (256) */
|
||||
return (nbits + 7) / 8;
|
||||
}
|
||||
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen) {
|
||||
const nghttp2_huff_sym *sym;
|
||||
const uint8_t *end = src + srclen;
|
||||
uint64_t code = 0;
|
||||
uint32_t x;
|
||||
size_t nbits = 0;
|
||||
size_t avail;
|
||||
int rv;
|
||||
|
||||
avail = nghttp2_bufs_cur_avail(bufs);
|
||||
|
||||
for (; src != end;) {
|
||||
sym = &huff_sym_table[*src++];
|
||||
code |= (uint64_t)sym->code << (32 - nbits);
|
||||
nbits += sym->nbits;
|
||||
if (nbits < 32) {
|
||||
continue;
|
||||
}
|
||||
if (avail >= 4) {
|
||||
x = htonl((uint32_t)(code >> 32));
|
||||
memcpy(bufs->cur->buf.last, &x, 4);
|
||||
bufs->cur->buf.last += 4;
|
||||
avail -= 4;
|
||||
code <<= 32;
|
||||
nbits -= 32;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (; nbits >= 8;) {
|
||||
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
code <<= 8;
|
||||
nbits -= 8;
|
||||
}
|
||||
|
||||
avail = nghttp2_bufs_cur_avail(bufs);
|
||||
}
|
||||
|
||||
for (; nbits >= 8;) {
|
||||
rv = nghttp2_bufs_addb(bufs, (uint8_t)(code >> 56));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
code <<= 8;
|
||||
nbits -= 8;
|
||||
}
|
||||
|
||||
if (nbits) {
|
||||
rv = nghttp2_bufs_addb(
|
||||
bufs, (uint8_t)((uint8_t)(code >> 56) | ((1 << (8 - nbits)) - 1)));
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
|
||||
ctx->fstate = NGHTTP2_HUFF_ACCEPTED;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
nghttp2_buf *buf, const uint8_t *src,
|
||||
size_t srclen, int final) {
|
||||
const uint8_t *end = src + srclen;
|
||||
nghttp2_huff_decode node = {ctx->fstate, 0};
|
||||
const nghttp2_huff_decode *t = &node;
|
||||
uint8_t c;
|
||||
|
||||
/* We use the decoding algorithm described in
|
||||
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
||||
for (; src != end;) {
|
||||
c = *src++;
|
||||
t = &huff_decode_table[t->fstate & 0x1ff][c >> 4];
|
||||
if (t->fstate & NGHTTP2_HUFF_SYM) {
|
||||
*buf->last++ = t->sym;
|
||||
}
|
||||
|
||||
t = &huff_decode_table[t->fstate & 0x1ff][c & 0xf];
|
||||
if (t->fstate & NGHTTP2_HUFF_SYM) {
|
||||
*buf->last++ = t->sym;
|
||||
}
|
||||
}
|
||||
|
||||
ctx->fstate = t->fstate;
|
||||
|
||||
if (final && !(ctx->fstate & NGHTTP2_HUFF_ACCEPTED)) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
return (ssize_t)srclen;
|
||||
}
|
||||
|
||||
int nghttp2_hd_huff_decode_failure_state(nghttp2_hd_huff_decode_context *ctx) {
|
||||
return ctx->fstate == 0x100;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HD_HUFFMAN_H
|
||||
#define NGHTTP2_HD_HUFFMAN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
typedef enum {
|
||||
/* FSA accepts this state as the end of huffman encoding
|
||||
sequence. */
|
||||
NGHTTP2_HUFF_ACCEPTED = 1 << 14,
|
||||
/* This state emits symbol */
|
||||
NGHTTP2_HUFF_SYM = 1 << 15,
|
||||
} nghttp2_huff_decode_flag;
|
||||
|
||||
typedef struct {
|
||||
/* fstate is the current huffman decoding state, which is actually
|
||||
the node ID of internal huffman tree with
|
||||
nghttp2_huff_decode_flag OR-ed. We have 257 leaf nodes, but they
|
||||
are identical to root node other than emitting a symbol, so we
|
||||
have 256 internal nodes [1..255], inclusive. The node ID 256 is
|
||||
a special node and it is a terminal state that means decoding
|
||||
failed. */
|
||||
uint16_t fstate;
|
||||
/* symbol if NGHTTP2_HUFF_SYM flag set */
|
||||
uint8_t sym;
|
||||
} nghttp2_huff_decode;
|
||||
|
||||
typedef nghttp2_huff_decode huff_decode_table_type[16];
|
||||
|
||||
typedef struct {
|
||||
/* fstate is the current huffman decoding state. */
|
||||
uint16_t fstate;
|
||||
} nghttp2_hd_huff_decode_context;
|
||||
|
||||
typedef struct {
|
||||
/* The number of bits in this code */
|
||||
uint32_t nbits;
|
||||
/* Huffman code aligned to LSB */
|
||||
uint32_t code;
|
||||
} nghttp2_huff_sym;
|
||||
|
||||
extern const nghttp2_huff_sym huff_sym_table[];
|
||||
extern const nghttp2_huff_decode huff_decode_table[][16];
|
||||
|
||||
#endif /* NGHTTP2_HD_HUFFMAN_H */
|
||||
@@ -0,0 +1,4980 @@
|
||||
/*
|
||||
* 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"
|
||||
|
||||
/* Generated by mkhufftbl.py */
|
||||
|
||||
const nghttp2_huff_sym huff_sym_table[] = {
|
||||
{13, 0xffc00000u}, {23, 0xffffb000u}, {28, 0xfffffe20u}, {28, 0xfffffe30u},
|
||||
{28, 0xfffffe40u}, {28, 0xfffffe50u}, {28, 0xfffffe60u}, {28, 0xfffffe70u},
|
||||
{28, 0xfffffe80u}, {24, 0xffffea00u}, {30, 0xfffffff0u}, {28, 0xfffffe90u},
|
||||
{28, 0xfffffea0u}, {30, 0xfffffff4u}, {28, 0xfffffeb0u}, {28, 0xfffffec0u},
|
||||
{28, 0xfffffed0u}, {28, 0xfffffee0u}, {28, 0xfffffef0u}, {28, 0xffffff00u},
|
||||
{28, 0xffffff10u}, {28, 0xffffff20u}, {30, 0xfffffff8u}, {28, 0xffffff30u},
|
||||
{28, 0xffffff40u}, {28, 0xffffff50u}, {28, 0xffffff60u}, {28, 0xffffff70u},
|
||||
{28, 0xffffff80u}, {28, 0xffffff90u}, {28, 0xffffffa0u}, {28, 0xffffffb0u},
|
||||
{6, 0x50000000u}, {10, 0xfe000000u}, {10, 0xfe400000u}, {12, 0xffa00000u},
|
||||
{13, 0xffc80000u}, {6, 0x54000000u}, {8, 0xf8000000u}, {11, 0xff400000u},
|
||||
{10, 0xfe800000u}, {10, 0xfec00000u}, {8, 0xf9000000u}, {11, 0xff600000u},
|
||||
{8, 0xfa000000u}, {6, 0x58000000u}, {6, 0x5c000000u}, {6, 0x60000000u},
|
||||
{5, 0x0u}, {5, 0x8000000u}, {5, 0x10000000u}, {6, 0x64000000u},
|
||||
{6, 0x68000000u}, {6, 0x6c000000u}, {6, 0x70000000u}, {6, 0x74000000u},
|
||||
{6, 0x78000000u}, {6, 0x7c000000u}, {7, 0xb8000000u}, {8, 0xfb000000u},
|
||||
{15, 0xfff80000u}, {6, 0x80000000u}, {12, 0xffb00000u}, {10, 0xff000000u},
|
||||
{13, 0xffd00000u}, {6, 0x84000000u}, {7, 0xba000000u}, {7, 0xbc000000u},
|
||||
{7, 0xbe000000u}, {7, 0xc0000000u}, {7, 0xc2000000u}, {7, 0xc4000000u},
|
||||
{7, 0xc6000000u}, {7, 0xc8000000u}, {7, 0xca000000u}, {7, 0xcc000000u},
|
||||
{7, 0xce000000u}, {7, 0xd0000000u}, {7, 0xd2000000u}, {7, 0xd4000000u},
|
||||
{7, 0xd6000000u}, {7, 0xd8000000u}, {7, 0xda000000u}, {7, 0xdc000000u},
|
||||
{7, 0xde000000u}, {7, 0xe0000000u}, {7, 0xe2000000u}, {7, 0xe4000000u},
|
||||
{8, 0xfc000000u}, {7, 0xe6000000u}, {8, 0xfd000000u}, {13, 0xffd80000u},
|
||||
{19, 0xfffe0000u}, {13, 0xffe00000u}, {14, 0xfff00000u}, {6, 0x88000000u},
|
||||
{15, 0xfffa0000u}, {5, 0x18000000u}, {6, 0x8c000000u}, {5, 0x20000000u},
|
||||
{6, 0x90000000u}, {5, 0x28000000u}, {6, 0x94000000u}, {6, 0x98000000u},
|
||||
{6, 0x9c000000u}, {5, 0x30000000u}, {7, 0xe8000000u}, {7, 0xea000000u},
|
||||
{6, 0xa0000000u}, {6, 0xa4000000u}, {6, 0xa8000000u}, {5, 0x38000000u},
|
||||
{6, 0xac000000u}, {7, 0xec000000u}, {6, 0xb0000000u}, {5, 0x40000000u},
|
||||
{5, 0x48000000u}, {6, 0xb4000000u}, {7, 0xee000000u}, {7, 0xf0000000u},
|
||||
{7, 0xf2000000u}, {7, 0xf4000000u}, {7, 0xf6000000u}, {15, 0xfffc0000u},
|
||||
{11, 0xff800000u}, {14, 0xfff40000u}, {13, 0xffe80000u}, {28, 0xffffffc0u},
|
||||
{20, 0xfffe6000u}, {22, 0xffff4800u}, {20, 0xfffe7000u}, {20, 0xfffe8000u},
|
||||
{22, 0xffff4c00u}, {22, 0xffff5000u}, {22, 0xffff5400u}, {23, 0xffffb200u},
|
||||
{22, 0xffff5800u}, {23, 0xffffb400u}, {23, 0xffffb600u}, {23, 0xffffb800u},
|
||||
{23, 0xffffba00u}, {23, 0xffffbc00u}, {24, 0xffffeb00u}, {23, 0xffffbe00u},
|
||||
{24, 0xffffec00u}, {24, 0xffffed00u}, {22, 0xffff5c00u}, {23, 0xffffc000u},
|
||||
{24, 0xffffee00u}, {23, 0xffffc200u}, {23, 0xffffc400u}, {23, 0xffffc600u},
|
||||
{23, 0xffffc800u}, {21, 0xfffee000u}, {22, 0xffff6000u}, {23, 0xffffca00u},
|
||||
{22, 0xffff6400u}, {23, 0xffffcc00u}, {23, 0xffffce00u}, {24, 0xffffef00u},
|
||||
{22, 0xffff6800u}, {21, 0xfffee800u}, {20, 0xfffe9000u}, {22, 0xffff6c00u},
|
||||
{22, 0xffff7000u}, {23, 0xffffd000u}, {23, 0xffffd200u}, {21, 0xfffef000u},
|
||||
{23, 0xffffd400u}, {22, 0xffff7400u}, {22, 0xffff7800u}, {24, 0xfffff000u},
|
||||
{21, 0xfffef800u}, {22, 0xffff7c00u}, {23, 0xffffd600u}, {23, 0xffffd800u},
|
||||
{21, 0xffff0000u}, {21, 0xffff0800u}, {22, 0xffff8000u}, {21, 0xffff1000u},
|
||||
{23, 0xffffda00u}, {22, 0xffff8400u}, {23, 0xffffdc00u}, {23, 0xffffde00u},
|
||||
{20, 0xfffea000u}, {22, 0xffff8800u}, {22, 0xffff8c00u}, {22, 0xffff9000u},
|
||||
{23, 0xffffe000u}, {22, 0xffff9400u}, {22, 0xffff9800u}, {23, 0xffffe200u},
|
||||
{26, 0xfffff800u}, {26, 0xfffff840u}, {20, 0xfffeb000u}, {19, 0xfffe2000u},
|
||||
{22, 0xffff9c00u}, {23, 0xffffe400u}, {22, 0xffffa000u}, {25, 0xfffff600u},
|
||||
{26, 0xfffff880u}, {26, 0xfffff8c0u}, {26, 0xfffff900u}, {27, 0xfffffbc0u},
|
||||
{27, 0xfffffbe0u}, {26, 0xfffff940u}, {24, 0xfffff100u}, {25, 0xfffff680u},
|
||||
{19, 0xfffe4000u}, {21, 0xffff1800u}, {26, 0xfffff980u}, {27, 0xfffffc00u},
|
||||
{27, 0xfffffc20u}, {26, 0xfffff9c0u}, {27, 0xfffffc40u}, {24, 0xfffff200u},
|
||||
{21, 0xffff2000u}, {21, 0xffff2800u}, {26, 0xfffffa00u}, {26, 0xfffffa40u},
|
||||
{28, 0xffffffd0u}, {27, 0xfffffc60u}, {27, 0xfffffc80u}, {27, 0xfffffca0u},
|
||||
{20, 0xfffec000u}, {24, 0xfffff300u}, {20, 0xfffed000u}, {21, 0xffff3000u},
|
||||
{22, 0xffffa400u}, {21, 0xffff3800u}, {21, 0xffff4000u}, {23, 0xffffe600u},
|
||||
{22, 0xffffa800u}, {22, 0xffffac00u}, {25, 0xfffff700u}, {25, 0xfffff780u},
|
||||
{24, 0xfffff400u}, {24, 0xfffff500u}, {26, 0xfffffa80u}, {23, 0xffffe800u},
|
||||
{26, 0xfffffac0u}, {27, 0xfffffcc0u}, {26, 0xfffffb00u}, {26, 0xfffffb40u},
|
||||
{27, 0xfffffce0u}, {27, 0xfffffd00u}, {27, 0xfffffd20u}, {27, 0xfffffd40u},
|
||||
{27, 0xfffffd60u}, {28, 0xffffffe0u}, {27, 0xfffffd80u}, {27, 0xfffffda0u},
|
||||
{27, 0xfffffdc0u}, {27, 0xfffffde0u}, {27, 0xfffffe00u}, {26, 0xfffffb80u},
|
||||
{30, 0xfffffffcu}};
|
||||
|
||||
const nghttp2_huff_decode huff_decode_table[][16] = {
|
||||
/* 0 */
|
||||
{
|
||||
{0x04, 0},
|
||||
{0x05, 0},
|
||||
{0x07, 0},
|
||||
{0x08, 0},
|
||||
{0x0b, 0},
|
||||
{0x0c, 0},
|
||||
{0x10, 0},
|
||||
{0x13, 0},
|
||||
{0x19, 0},
|
||||
{0x1c, 0},
|
||||
{0x20, 0},
|
||||
{0x23, 0},
|
||||
{0x2a, 0},
|
||||
{0x31, 0},
|
||||
{0x39, 0},
|
||||
{0x4040, 0},
|
||||
},
|
||||
/* 1 */
|
||||
{
|
||||
{0xc000, 48},
|
||||
{0xc000, 49},
|
||||
{0xc000, 50},
|
||||
{0xc000, 97},
|
||||
{0xc000, 99},
|
||||
{0xc000, 101},
|
||||
{0xc000, 105},
|
||||
{0xc000, 111},
|
||||
{0xc000, 115},
|
||||
{0xc000, 116},
|
||||
{0x0d, 0},
|
||||
{0x0e, 0},
|
||||
{0x11, 0},
|
||||
{0x12, 0},
|
||||
{0x14, 0},
|
||||
{0x15, 0},
|
||||
},
|
||||
/* 2 */
|
||||
{
|
||||
{0x8001, 48},
|
||||
{0xc016, 48},
|
||||
{0x8001, 49},
|
||||
{0xc016, 49},
|
||||
{0x8001, 50},
|
||||
{0xc016, 50},
|
||||
{0x8001, 97},
|
||||
{0xc016, 97},
|
||||
{0x8001, 99},
|
||||
{0xc016, 99},
|
||||
{0x8001, 101},
|
||||
{0xc016, 101},
|
||||
{0x8001, 105},
|
||||
{0xc016, 105},
|
||||
{0x8001, 111},
|
||||
{0xc016, 111},
|
||||
},
|
||||
/* 3 */
|
||||
{
|
||||
{0x8002, 48},
|
||||
{0x8009, 48},
|
||||
{0x8017, 48},
|
||||
{0xc028, 48},
|
||||
{0x8002, 49},
|
||||
{0x8009, 49},
|
||||
{0x8017, 49},
|
||||
{0xc028, 49},
|
||||
{0x8002, 50},
|
||||
{0x8009, 50},
|
||||
{0x8017, 50},
|
||||
{0xc028, 50},
|
||||
{0x8002, 97},
|
||||
{0x8009, 97},
|
||||
{0x8017, 97},
|
||||
{0xc028, 97},
|
||||
},
|
||||
/* 4 */
|
||||
{
|
||||
{0x8003, 48},
|
||||
{0x8006, 48},
|
||||
{0x800a, 48},
|
||||
{0x800f, 48},
|
||||
{0x8018, 48},
|
||||
{0x801f, 48},
|
||||
{0x8029, 48},
|
||||
{0xc038, 48},
|
||||
{0x8003, 49},
|
||||
{0x8006, 49},
|
||||
{0x800a, 49},
|
||||
{0x800f, 49},
|
||||
{0x8018, 49},
|
||||
{0x801f, 49},
|
||||
{0x8029, 49},
|
||||
{0xc038, 49},
|
||||
},
|
||||
/* 5 */
|
||||
{
|
||||
{0x8003, 50},
|
||||
{0x8006, 50},
|
||||
{0x800a, 50},
|
||||
{0x800f, 50},
|
||||
{0x8018, 50},
|
||||
{0x801f, 50},
|
||||
{0x8029, 50},
|
||||
{0xc038, 50},
|
||||
{0x8003, 97},
|
||||
{0x8006, 97},
|
||||
{0x800a, 97},
|
||||
{0x800f, 97},
|
||||
{0x8018, 97},
|
||||
{0x801f, 97},
|
||||
{0x8029, 97},
|
||||
{0xc038, 97},
|
||||
},
|
||||
/* 6 */
|
||||
{
|
||||
{0x8002, 99},
|
||||
{0x8009, 99},
|
||||
{0x8017, 99},
|
||||
{0xc028, 99},
|
||||
{0x8002, 101},
|
||||
{0x8009, 101},
|
||||
{0x8017, 101},
|
||||
{0xc028, 101},
|
||||
{0x8002, 105},
|
||||
{0x8009, 105},
|
||||
{0x8017, 105},
|
||||
{0xc028, 105},
|
||||
{0x8002, 111},
|
||||
{0x8009, 111},
|
||||
{0x8017, 111},
|
||||
{0xc028, 111},
|
||||
},
|
||||
/* 7 */
|
||||
{
|
||||
{0x8003, 99},
|
||||
{0x8006, 99},
|
||||
{0x800a, 99},
|
||||
{0x800f, 99},
|
||||
{0x8018, 99},
|
||||
{0x801f, 99},
|
||||
{0x8029, 99},
|
||||
{0xc038, 99},
|
||||
{0x8003, 101},
|
||||
{0x8006, 101},
|
||||
{0x800a, 101},
|
||||
{0x800f, 101},
|
||||
{0x8018, 101},
|
||||
{0x801f, 101},
|
||||
{0x8029, 101},
|
||||
{0xc038, 101},
|
||||
},
|
||||
/* 8 */
|
||||
{
|
||||
{0x8003, 105},
|
||||
{0x8006, 105},
|
||||
{0x800a, 105},
|
||||
{0x800f, 105},
|
||||
{0x8018, 105},
|
||||
{0x801f, 105},
|
||||
{0x8029, 105},
|
||||
{0xc038, 105},
|
||||
{0x8003, 111},
|
||||
{0x8006, 111},
|
||||
{0x800a, 111},
|
||||
{0x800f, 111},
|
||||
{0x8018, 111},
|
||||
{0x801f, 111},
|
||||
{0x8029, 111},
|
||||
{0xc038, 111},
|
||||
},
|
||||
/* 9 */
|
||||
{
|
||||
{0x8001, 115},
|
||||
{0xc016, 115},
|
||||
{0x8001, 116},
|
||||
{0xc016, 116},
|
||||
{0xc000, 32},
|
||||
{0xc000, 37},
|
||||
{0xc000, 45},
|
||||
{0xc000, 46},
|
||||
{0xc000, 47},
|
||||
{0xc000, 51},
|
||||
{0xc000, 52},
|
||||
{0xc000, 53},
|
||||
{0xc000, 54},
|
||||
{0xc000, 55},
|
||||
{0xc000, 56},
|
||||
{0xc000, 57},
|
||||
},
|
||||
/* 10 */
|
||||
{
|
||||
{0x8002, 115},
|
||||
{0x8009, 115},
|
||||
{0x8017, 115},
|
||||
{0xc028, 115},
|
||||
{0x8002, 116},
|
||||
{0x8009, 116},
|
||||
{0x8017, 116},
|
||||
{0xc028, 116},
|
||||
{0x8001, 32},
|
||||
{0xc016, 32},
|
||||
{0x8001, 37},
|
||||
{0xc016, 37},
|
||||
{0x8001, 45},
|
||||
{0xc016, 45},
|
||||
{0x8001, 46},
|
||||
{0xc016, 46},
|
||||
},
|
||||
/* 11 */
|
||||
{
|
||||
{0x8003, 115},
|
||||
{0x8006, 115},
|
||||
{0x800a, 115},
|
||||
{0x800f, 115},
|
||||
{0x8018, 115},
|
||||
{0x801f, 115},
|
||||
{0x8029, 115},
|
||||
{0xc038, 115},
|
||||
{0x8003, 116},
|
||||
{0x8006, 116},
|
||||
{0x800a, 116},
|
||||
{0x800f, 116},
|
||||
{0x8018, 116},
|
||||
{0x801f, 116},
|
||||
{0x8029, 116},
|
||||
{0xc038, 116},
|
||||
},
|
||||
/* 12 */
|
||||
{
|
||||
{0x8002, 32},
|
||||
{0x8009, 32},
|
||||
{0x8017, 32},
|
||||
{0xc028, 32},
|
||||
{0x8002, 37},
|
||||
{0x8009, 37},
|
||||
{0x8017, 37},
|
||||
{0xc028, 37},
|
||||
{0x8002, 45},
|
||||
{0x8009, 45},
|
||||
{0x8017, 45},
|
||||
{0xc028, 45},
|
||||
{0x8002, 46},
|
||||
{0x8009, 46},
|
||||
{0x8017, 46},
|
||||
{0xc028, 46},
|
||||
},
|
||||
/* 13 */
|
||||
{
|
||||
{0x8003, 32},
|
||||
{0x8006, 32},
|
||||
{0x800a, 32},
|
||||
{0x800f, 32},
|
||||
{0x8018, 32},
|
||||
{0x801f, 32},
|
||||
{0x8029, 32},
|
||||
{0xc038, 32},
|
||||
{0x8003, 37},
|
||||
{0x8006, 37},
|
||||
{0x800a, 37},
|
||||
{0x800f, 37},
|
||||
{0x8018, 37},
|
||||
{0x801f, 37},
|
||||
{0x8029, 37},
|
||||
{0xc038, 37},
|
||||
},
|
||||
/* 14 */
|
||||
{
|
||||
{0x8003, 45},
|
||||
{0x8006, 45},
|
||||
{0x800a, 45},
|
||||
{0x800f, 45},
|
||||
{0x8018, 45},
|
||||
{0x801f, 45},
|
||||
{0x8029, 45},
|
||||
{0xc038, 45},
|
||||
{0x8003, 46},
|
||||
{0x8006, 46},
|
||||
{0x800a, 46},
|
||||
{0x800f, 46},
|
||||
{0x8018, 46},
|
||||
{0x801f, 46},
|
||||
{0x8029, 46},
|
||||
{0xc038, 46},
|
||||
},
|
||||
/* 15 */
|
||||
{
|
||||
{0x8001, 47},
|
||||
{0xc016, 47},
|
||||
{0x8001, 51},
|
||||
{0xc016, 51},
|
||||
{0x8001, 52},
|
||||
{0xc016, 52},
|
||||
{0x8001, 53},
|
||||
{0xc016, 53},
|
||||
{0x8001, 54},
|
||||
{0xc016, 54},
|
||||
{0x8001, 55},
|
||||
{0xc016, 55},
|
||||
{0x8001, 56},
|
||||
{0xc016, 56},
|
||||
{0x8001, 57},
|
||||
{0xc016, 57},
|
||||
},
|
||||
/* 16 */
|
||||
{
|
||||
{0x8002, 47},
|
||||
{0x8009, 47},
|
||||
{0x8017, 47},
|
||||
{0xc028, 47},
|
||||
{0x8002, 51},
|
||||
{0x8009, 51},
|
||||
{0x8017, 51},
|
||||
{0xc028, 51},
|
||||
{0x8002, 52},
|
||||
{0x8009, 52},
|
||||
{0x8017, 52},
|
||||
{0xc028, 52},
|
||||
{0x8002, 53},
|
||||
{0x8009, 53},
|
||||
{0x8017, 53},
|
||||
{0xc028, 53},
|
||||
},
|
||||
/* 17 */
|
||||
{
|
||||
{0x8003, 47},
|
||||
{0x8006, 47},
|
||||
{0x800a, 47},
|
||||
{0x800f, 47},
|
||||
{0x8018, 47},
|
||||
{0x801f, 47},
|
||||
{0x8029, 47},
|
||||
{0xc038, 47},
|
||||
{0x8003, 51},
|
||||
{0x8006, 51},
|
||||
{0x800a, 51},
|
||||
{0x800f, 51},
|
||||
{0x8018, 51},
|
||||
{0x801f, 51},
|
||||
{0x8029, 51},
|
||||
{0xc038, 51},
|
||||
},
|
||||
/* 18 */
|
||||
{
|
||||
{0x8003, 52},
|
||||
{0x8006, 52},
|
||||
{0x800a, 52},
|
||||
{0x800f, 52},
|
||||
{0x8018, 52},
|
||||
{0x801f, 52},
|
||||
{0x8029, 52},
|
||||
{0xc038, 52},
|
||||
{0x8003, 53},
|
||||
{0x8006, 53},
|
||||
{0x800a, 53},
|
||||
{0x800f, 53},
|
||||
{0x8018, 53},
|
||||
{0x801f, 53},
|
||||
{0x8029, 53},
|
||||
{0xc038, 53},
|
||||
},
|
||||
/* 19 */
|
||||
{
|
||||
{0x8002, 54},
|
||||
{0x8009, 54},
|
||||
{0x8017, 54},
|
||||
{0xc028, 54},
|
||||
{0x8002, 55},
|
||||
{0x8009, 55},
|
||||
{0x8017, 55},
|
||||
{0xc028, 55},
|
||||
{0x8002, 56},
|
||||
{0x8009, 56},
|
||||
{0x8017, 56},
|
||||
{0xc028, 56},
|
||||
{0x8002, 57},
|
||||
{0x8009, 57},
|
||||
{0x8017, 57},
|
||||
{0xc028, 57},
|
||||
},
|
||||
/* 20 */
|
||||
{
|
||||
{0x8003, 54},
|
||||
{0x8006, 54},
|
||||
{0x800a, 54},
|
||||
{0x800f, 54},
|
||||
{0x8018, 54},
|
||||
{0x801f, 54},
|
||||
{0x8029, 54},
|
||||
{0xc038, 54},
|
||||
{0x8003, 55},
|
||||
{0x8006, 55},
|
||||
{0x800a, 55},
|
||||
{0x800f, 55},
|
||||
{0x8018, 55},
|
||||
{0x801f, 55},
|
||||
{0x8029, 55},
|
||||
{0xc038, 55},
|
||||
},
|
||||
/* 21 */
|
||||
{
|
||||
{0x8003, 56},
|
||||
{0x8006, 56},
|
||||
{0x800a, 56},
|
||||
{0x800f, 56},
|
||||
{0x8018, 56},
|
||||
{0x801f, 56},
|
||||
{0x8029, 56},
|
||||
{0xc038, 56},
|
||||
{0x8003, 57},
|
||||
{0x8006, 57},
|
||||
{0x800a, 57},
|
||||
{0x800f, 57},
|
||||
{0x8018, 57},
|
||||
{0x801f, 57},
|
||||
{0x8029, 57},
|
||||
{0xc038, 57},
|
||||
},
|
||||
/* 22 */
|
||||
{
|
||||
{0x1a, 0},
|
||||
{0x1b, 0},
|
||||
{0x1d, 0},
|
||||
{0x1e, 0},
|
||||
{0x21, 0},
|
||||
{0x22, 0},
|
||||
{0x24, 0},
|
||||
{0x25, 0},
|
||||
{0x2b, 0},
|
||||
{0x2e, 0},
|
||||
{0x32, 0},
|
||||
{0x35, 0},
|
||||
{0x3a, 0},
|
||||
{0x3d, 0},
|
||||
{0x41, 0},
|
||||
{0x4044, 0},
|
||||
},
|
||||
/* 23 */
|
||||
{
|
||||
{0xc000, 61},
|
||||
{0xc000, 65},
|
||||
{0xc000, 95},
|
||||
{0xc000, 98},
|
||||
{0xc000, 100},
|
||||
{0xc000, 102},
|
||||
{0xc000, 103},
|
||||
{0xc000, 104},
|
||||
{0xc000, 108},
|
||||
{0xc000, 109},
|
||||
{0xc000, 110},
|
||||
{0xc000, 112},
|
||||
{0xc000, 114},
|
||||
{0xc000, 117},
|
||||
{0x26, 0},
|
||||
{0x27, 0},
|
||||
},
|
||||
/* 24 */
|
||||
{
|
||||
{0x8001, 61},
|
||||
{0xc016, 61},
|
||||
{0x8001, 65},
|
||||
{0xc016, 65},
|
||||
{0x8001, 95},
|
||||
{0xc016, 95},
|
||||
{0x8001, 98},
|
||||
{0xc016, 98},
|
||||
{0x8001, 100},
|
||||
{0xc016, 100},
|
||||
{0x8001, 102},
|
||||
{0xc016, 102},
|
||||
{0x8001, 103},
|
||||
{0xc016, 103},
|
||||
{0x8001, 104},
|
||||
{0xc016, 104},
|
||||
},
|
||||
/* 25 */
|
||||
{
|
||||
{0x8002, 61},
|
||||
{0x8009, 61},
|
||||
{0x8017, 61},
|
||||
{0xc028, 61},
|
||||
{0x8002, 65},
|
||||
{0x8009, 65},
|
||||
{0x8017, 65},
|
||||
{0xc028, 65},
|
||||
{0x8002, 95},
|
||||
{0x8009, 95},
|
||||
{0x8017, 95},
|
||||
{0xc028, 95},
|
||||
{0x8002, 98},
|
||||
{0x8009, 98},
|
||||
{0x8017, 98},
|
||||
{0xc028, 98},
|
||||
},
|
||||
/* 26 */
|
||||
{
|
||||
{0x8003, 61},
|
||||
{0x8006, 61},
|
||||
{0x800a, 61},
|
||||
{0x800f, 61},
|
||||
{0x8018, 61},
|
||||
{0x801f, 61},
|
||||
{0x8029, 61},
|
||||
{0xc038, 61},
|
||||
{0x8003, 65},
|
||||
{0x8006, 65},
|
||||
{0x800a, 65},
|
||||
{0x800f, 65},
|
||||
{0x8018, 65},
|
||||
{0x801f, 65},
|
||||
{0x8029, 65},
|
||||
{0xc038, 65},
|
||||
},
|
||||
/* 27 */
|
||||
{
|
||||
{0x8003, 95},
|
||||
{0x8006, 95},
|
||||
{0x800a, 95},
|
||||
{0x800f, 95},
|
||||
{0x8018, 95},
|
||||
{0x801f, 95},
|
||||
{0x8029, 95},
|
||||
{0xc038, 95},
|
||||
{0x8003, 98},
|
||||
{0x8006, 98},
|
||||
{0x800a, 98},
|
||||
{0x800f, 98},
|
||||
{0x8018, 98},
|
||||
{0x801f, 98},
|
||||
{0x8029, 98},
|
||||
{0xc038, 98},
|
||||
},
|
||||
/* 28 */
|
||||
{
|
||||
{0x8002, 100},
|
||||
{0x8009, 100},
|
||||
{0x8017, 100},
|
||||
{0xc028, 100},
|
||||
{0x8002, 102},
|
||||
{0x8009, 102},
|
||||
{0x8017, 102},
|
||||
{0xc028, 102},
|
||||
{0x8002, 103},
|
||||
{0x8009, 103},
|
||||
{0x8017, 103},
|
||||
{0xc028, 103},
|
||||
{0x8002, 104},
|
||||
{0x8009, 104},
|
||||
{0x8017, 104},
|
||||
{0xc028, 104},
|
||||
},
|
||||
/* 29 */
|
||||
{
|
||||
{0x8003, 100},
|
||||
{0x8006, 100},
|
||||
{0x800a, 100},
|
||||
{0x800f, 100},
|
||||
{0x8018, 100},
|
||||
{0x801f, 100},
|
||||
{0x8029, 100},
|
||||
{0xc038, 100},
|
||||
{0x8003, 102},
|
||||
{0x8006, 102},
|
||||
{0x800a, 102},
|
||||
{0x800f, 102},
|
||||
{0x8018, 102},
|
||||
{0x801f, 102},
|
||||
{0x8029, 102},
|
||||
{0xc038, 102},
|
||||
},
|
||||
/* 30 */
|
||||
{
|
||||
{0x8003, 103},
|
||||
{0x8006, 103},
|
||||
{0x800a, 103},
|
||||
{0x800f, 103},
|
||||
{0x8018, 103},
|
||||
{0x801f, 103},
|
||||
{0x8029, 103},
|
||||
{0xc038, 103},
|
||||
{0x8003, 104},
|
||||
{0x8006, 104},
|
||||
{0x800a, 104},
|
||||
{0x800f, 104},
|
||||
{0x8018, 104},
|
||||
{0x801f, 104},
|
||||
{0x8029, 104},
|
||||
{0xc038, 104},
|
||||
},
|
||||
/* 31 */
|
||||
{
|
||||
{0x8001, 108},
|
||||
{0xc016, 108},
|
||||
{0x8001, 109},
|
||||
{0xc016, 109},
|
||||
{0x8001, 110},
|
||||
{0xc016, 110},
|
||||
{0x8001, 112},
|
||||
{0xc016, 112},
|
||||
{0x8001, 114},
|
||||
{0xc016, 114},
|
||||
{0x8001, 117},
|
||||
{0xc016, 117},
|
||||
{0xc000, 58},
|
||||
{0xc000, 66},
|
||||
{0xc000, 67},
|
||||
{0xc000, 68},
|
||||
},
|
||||
/* 32 */
|
||||
{
|
||||
{0x8002, 108},
|
||||
{0x8009, 108},
|
||||
{0x8017, 108},
|
||||
{0xc028, 108},
|
||||
{0x8002, 109},
|
||||
{0x8009, 109},
|
||||
{0x8017, 109},
|
||||
{0xc028, 109},
|
||||
{0x8002, 110},
|
||||
{0x8009, 110},
|
||||
{0x8017, 110},
|
||||
{0xc028, 110},
|
||||
{0x8002, 112},
|
||||
{0x8009, 112},
|
||||
{0x8017, 112},
|
||||
{0xc028, 112},
|
||||
},
|
||||
/* 33 */
|
||||
{
|
||||
{0x8003, 108},
|
||||
{0x8006, 108},
|
||||
{0x800a, 108},
|
||||
{0x800f, 108},
|
||||
{0x8018, 108},
|
||||
{0x801f, 108},
|
||||
{0x8029, 108},
|
||||
{0xc038, 108},
|
||||
{0x8003, 109},
|
||||
{0x8006, 109},
|
||||
{0x800a, 109},
|
||||
{0x800f, 109},
|
||||
{0x8018, 109},
|
||||
{0x801f, 109},
|
||||
{0x8029, 109},
|
||||
{0xc038, 109},
|
||||
},
|
||||
/* 34 */
|
||||
{
|
||||
{0x8003, 110},
|
||||
{0x8006, 110},
|
||||
{0x800a, 110},
|
||||
{0x800f, 110},
|
||||
{0x8018, 110},
|
||||
{0x801f, 110},
|
||||
{0x8029, 110},
|
||||
{0xc038, 110},
|
||||
{0x8003, 112},
|
||||
{0x8006, 112},
|
||||
{0x800a, 112},
|
||||
{0x800f, 112},
|
||||
{0x8018, 112},
|
||||
{0x801f, 112},
|
||||
{0x8029, 112},
|
||||
{0xc038, 112},
|
||||
},
|
||||
/* 35 */
|
||||
{
|
||||
{0x8002, 114},
|
||||
{0x8009, 114},
|
||||
{0x8017, 114},
|
||||
{0xc028, 114},
|
||||
{0x8002, 117},
|
||||
{0x8009, 117},
|
||||
{0x8017, 117},
|
||||
{0xc028, 117},
|
||||
{0x8001, 58},
|
||||
{0xc016, 58},
|
||||
{0x8001, 66},
|
||||
{0xc016, 66},
|
||||
{0x8001, 67},
|
||||
{0xc016, 67},
|
||||
{0x8001, 68},
|
||||
{0xc016, 68},
|
||||
},
|
||||
/* 36 */
|
||||
{
|
||||
{0x8003, 114},
|
||||
{0x8006, 114},
|
||||
{0x800a, 114},
|
||||
{0x800f, 114},
|
||||
{0x8018, 114},
|
||||
{0x801f, 114},
|
||||
{0x8029, 114},
|
||||
{0xc038, 114},
|
||||
{0x8003, 117},
|
||||
{0x8006, 117},
|
||||
{0x800a, 117},
|
||||
{0x800f, 117},
|
||||
{0x8018, 117},
|
||||
{0x801f, 117},
|
||||
{0x8029, 117},
|
||||
{0xc038, 117},
|
||||
},
|
||||
/* 37 */
|
||||
{
|
||||
{0x8002, 58},
|
||||
{0x8009, 58},
|
||||
{0x8017, 58},
|
||||
{0xc028, 58},
|
||||
{0x8002, 66},
|
||||
{0x8009, 66},
|
||||
{0x8017, 66},
|
||||
{0xc028, 66},
|
||||
{0x8002, 67},
|
||||
{0x8009, 67},
|
||||
{0x8017, 67},
|
||||
{0xc028, 67},
|
||||
{0x8002, 68},
|
||||
{0x8009, 68},
|
||||
{0x8017, 68},
|
||||
{0xc028, 68},
|
||||
},
|
||||
/* 38 */
|
||||
{
|
||||
{0x8003, 58},
|
||||
{0x8006, 58},
|
||||
{0x800a, 58},
|
||||
{0x800f, 58},
|
||||
{0x8018, 58},
|
||||
{0x801f, 58},
|
||||
{0x8029, 58},
|
||||
{0xc038, 58},
|
||||
{0x8003, 66},
|
||||
{0x8006, 66},
|
||||
{0x800a, 66},
|
||||
{0x800f, 66},
|
||||
{0x8018, 66},
|
||||
{0x801f, 66},
|
||||
{0x8029, 66},
|
||||
{0xc038, 66},
|
||||
},
|
||||
/* 39 */
|
||||
{
|
||||
{0x8003, 67},
|
||||
{0x8006, 67},
|
||||
{0x800a, 67},
|
||||
{0x800f, 67},
|
||||
{0x8018, 67},
|
||||
{0x801f, 67},
|
||||
{0x8029, 67},
|
||||
{0xc038, 67},
|
||||
{0x8003, 68},
|
||||
{0x8006, 68},
|
||||
{0x800a, 68},
|
||||
{0x800f, 68},
|
||||
{0x8018, 68},
|
||||
{0x801f, 68},
|
||||
{0x8029, 68},
|
||||
{0xc038, 68},
|
||||
},
|
||||
/* 40 */
|
||||
{
|
||||
{0x2c, 0},
|
||||
{0x2d, 0},
|
||||
{0x2f, 0},
|
||||
{0x30, 0},
|
||||
{0x33, 0},
|
||||
{0x34, 0},
|
||||
{0x36, 0},
|
||||
{0x37, 0},
|
||||
{0x3b, 0},
|
||||
{0x3c, 0},
|
||||
{0x3e, 0},
|
||||
{0x3f, 0},
|
||||
{0x42, 0},
|
||||
{0x43, 0},
|
||||
{0x45, 0},
|
||||
{0x4048, 0},
|
||||
},
|
||||
/* 41 */
|
||||
{
|
||||
{0xc000, 69},
|
||||
{0xc000, 70},
|
||||
{0xc000, 71},
|
||||
{0xc000, 72},
|
||||
{0xc000, 73},
|
||||
{0xc000, 74},
|
||||
{0xc000, 75},
|
||||
{0xc000, 76},
|
||||
{0xc000, 77},
|
||||
{0xc000, 78},
|
||||
{0xc000, 79},
|
||||
{0xc000, 80},
|
||||
{0xc000, 81},
|
||||
{0xc000, 82},
|
||||
{0xc000, 83},
|
||||
{0xc000, 84},
|
||||
},
|
||||
/* 42 */
|
||||
{
|
||||
{0x8001, 69},
|
||||
{0xc016, 69},
|
||||
{0x8001, 70},
|
||||
{0xc016, 70},
|
||||
{0x8001, 71},
|
||||
{0xc016, 71},
|
||||
{0x8001, 72},
|
||||
{0xc016, 72},
|
||||
{0x8001, 73},
|
||||
{0xc016, 73},
|
||||
{0x8001, 74},
|
||||
{0xc016, 74},
|
||||
{0x8001, 75},
|
||||
{0xc016, 75},
|
||||
{0x8001, 76},
|
||||
{0xc016, 76},
|
||||
},
|
||||
/* 43 */
|
||||
{
|
||||
{0x8002, 69},
|
||||
{0x8009, 69},
|
||||
{0x8017, 69},
|
||||
{0xc028, 69},
|
||||
{0x8002, 70},
|
||||
{0x8009, 70},
|
||||
{0x8017, 70},
|
||||
{0xc028, 70},
|
||||
{0x8002, 71},
|
||||
{0x8009, 71},
|
||||
{0x8017, 71},
|
||||
{0xc028, 71},
|
||||
{0x8002, 72},
|
||||
{0x8009, 72},
|
||||
{0x8017, 72},
|
||||
{0xc028, 72},
|
||||
},
|
||||
/* 44 */
|
||||
{
|
||||
{0x8003, 69},
|
||||
{0x8006, 69},
|
||||
{0x800a, 69},
|
||||
{0x800f, 69},
|
||||
{0x8018, 69},
|
||||
{0x801f, 69},
|
||||
{0x8029, 69},
|
||||
{0xc038, 69},
|
||||
{0x8003, 70},
|
||||
{0x8006, 70},
|
||||
{0x800a, 70},
|
||||
{0x800f, 70},
|
||||
{0x8018, 70},
|
||||
{0x801f, 70},
|
||||
{0x8029, 70},
|
||||
{0xc038, 70},
|
||||
},
|
||||
/* 45 */
|
||||
{
|
||||
{0x8003, 71},
|
||||
{0x8006, 71},
|
||||
{0x800a, 71},
|
||||
{0x800f, 71},
|
||||
{0x8018, 71},
|
||||
{0x801f, 71},
|
||||
{0x8029, 71},
|
||||
{0xc038, 71},
|
||||
{0x8003, 72},
|
||||
{0x8006, 72},
|
||||
{0x800a, 72},
|
||||
{0x800f, 72},
|
||||
{0x8018, 72},
|
||||
{0x801f, 72},
|
||||
{0x8029, 72},
|
||||
{0xc038, 72},
|
||||
},
|
||||
/* 46 */
|
||||
{
|
||||
{0x8002, 73},
|
||||
{0x8009, 73},
|
||||
{0x8017, 73},
|
||||
{0xc028, 73},
|
||||
{0x8002, 74},
|
||||
{0x8009, 74},
|
||||
{0x8017, 74},
|
||||
{0xc028, 74},
|
||||
{0x8002, 75},
|
||||
{0x8009, 75},
|
||||
{0x8017, 75},
|
||||
{0xc028, 75},
|
||||
{0x8002, 76},
|
||||
{0x8009, 76},
|
||||
{0x8017, 76},
|
||||
{0xc028, 76},
|
||||
},
|
||||
/* 47 */
|
||||
{
|
||||
{0x8003, 73},
|
||||
{0x8006, 73},
|
||||
{0x800a, 73},
|
||||
{0x800f, 73},
|
||||
{0x8018, 73},
|
||||
{0x801f, 73},
|
||||
{0x8029, 73},
|
||||
{0xc038, 73},
|
||||
{0x8003, 74},
|
||||
{0x8006, 74},
|
||||
{0x800a, 74},
|
||||
{0x800f, 74},
|
||||
{0x8018, 74},
|
||||
{0x801f, 74},
|
||||
{0x8029, 74},
|
||||
{0xc038, 74},
|
||||
},
|
||||
/* 48 */
|
||||
{
|
||||
{0x8003, 75},
|
||||
{0x8006, 75},
|
||||
{0x800a, 75},
|
||||
{0x800f, 75},
|
||||
{0x8018, 75},
|
||||
{0x801f, 75},
|
||||
{0x8029, 75},
|
||||
{0xc038, 75},
|
||||
{0x8003, 76},
|
||||
{0x8006, 76},
|
||||
{0x800a, 76},
|
||||
{0x800f, 76},
|
||||
{0x8018, 76},
|
||||
{0x801f, 76},
|
||||
{0x8029, 76},
|
||||
{0xc038, 76},
|
||||
},
|
||||
/* 49 */
|
||||
{
|
||||
{0x8001, 77},
|
||||
{0xc016, 77},
|
||||
{0x8001, 78},
|
||||
{0xc016, 78},
|
||||
{0x8001, 79},
|
||||
{0xc016, 79},
|
||||
{0x8001, 80},
|
||||
{0xc016, 80},
|
||||
{0x8001, 81},
|
||||
{0xc016, 81},
|
||||
{0x8001, 82},
|
||||
{0xc016, 82},
|
||||
{0x8001, 83},
|
||||
{0xc016, 83},
|
||||
{0x8001, 84},
|
||||
{0xc016, 84},
|
||||
},
|
||||
/* 50 */
|
||||
{
|
||||
{0x8002, 77},
|
||||
{0x8009, 77},
|
||||
{0x8017, 77},
|
||||
{0xc028, 77},
|
||||
{0x8002, 78},
|
||||
{0x8009, 78},
|
||||
{0x8017, 78},
|
||||
{0xc028, 78},
|
||||
{0x8002, 79},
|
||||
{0x8009, 79},
|
||||
{0x8017, 79},
|
||||
{0xc028, 79},
|
||||
{0x8002, 80},
|
||||
{0x8009, 80},
|
||||
{0x8017, 80},
|
||||
{0xc028, 80},
|
||||
},
|
||||
/* 51 */
|
||||
{
|
||||
{0x8003, 77},
|
||||
{0x8006, 77},
|
||||
{0x800a, 77},
|
||||
{0x800f, 77},
|
||||
{0x8018, 77},
|
||||
{0x801f, 77},
|
||||
{0x8029, 77},
|
||||
{0xc038, 77},
|
||||
{0x8003, 78},
|
||||
{0x8006, 78},
|
||||
{0x800a, 78},
|
||||
{0x800f, 78},
|
||||
{0x8018, 78},
|
||||
{0x801f, 78},
|
||||
{0x8029, 78},
|
||||
{0xc038, 78},
|
||||
},
|
||||
/* 52 */
|
||||
{
|
||||
{0x8003, 79},
|
||||
{0x8006, 79},
|
||||
{0x800a, 79},
|
||||
{0x800f, 79},
|
||||
{0x8018, 79},
|
||||
{0x801f, 79},
|
||||
{0x8029, 79},
|
||||
{0xc038, 79},
|
||||
{0x8003, 80},
|
||||
{0x8006, 80},
|
||||
{0x800a, 80},
|
||||
{0x800f, 80},
|
||||
{0x8018, 80},
|
||||
{0x801f, 80},
|
||||
{0x8029, 80},
|
||||
{0xc038, 80},
|
||||
},
|
||||
/* 53 */
|
||||
{
|
||||
{0x8002, 81},
|
||||
{0x8009, 81},
|
||||
{0x8017, 81},
|
||||
{0xc028, 81},
|
||||
{0x8002, 82},
|
||||
{0x8009, 82},
|
||||
{0x8017, 82},
|
||||
{0xc028, 82},
|
||||
{0x8002, 83},
|
||||
{0x8009, 83},
|
||||
{0x8017, 83},
|
||||
{0xc028, 83},
|
||||
{0x8002, 84},
|
||||
{0x8009, 84},
|
||||
{0x8017, 84},
|
||||
{0xc028, 84},
|
||||
},
|
||||
/* 54 */
|
||||
{
|
||||
{0x8003, 81},
|
||||
{0x8006, 81},
|
||||
{0x800a, 81},
|
||||
{0x800f, 81},
|
||||
{0x8018, 81},
|
||||
{0x801f, 81},
|
||||
{0x8029, 81},
|
||||
{0xc038, 81},
|
||||
{0x8003, 82},
|
||||
{0x8006, 82},
|
||||
{0x800a, 82},
|
||||
{0x800f, 82},
|
||||
{0x8018, 82},
|
||||
{0x801f, 82},
|
||||
{0x8029, 82},
|
||||
{0xc038, 82},
|
||||
},
|
||||
/* 55 */
|
||||
{
|
||||
{0x8003, 83},
|
||||
{0x8006, 83},
|
||||
{0x800a, 83},
|
||||
{0x800f, 83},
|
||||
{0x8018, 83},
|
||||
{0x801f, 83},
|
||||
{0x8029, 83},
|
||||
{0xc038, 83},
|
||||
{0x8003, 84},
|
||||
{0x8006, 84},
|
||||
{0x800a, 84},
|
||||
{0x800f, 84},
|
||||
{0x8018, 84},
|
||||
{0x801f, 84},
|
||||
{0x8029, 84},
|
||||
{0xc038, 84},
|
||||
},
|
||||
/* 56 */
|
||||
{
|
||||
{0xc000, 85},
|
||||
{0xc000, 86},
|
||||
{0xc000, 87},
|
||||
{0xc000, 89},
|
||||
{0xc000, 106},
|
||||
{0xc000, 107},
|
||||
{0xc000, 113},
|
||||
{0xc000, 118},
|
||||
{0xc000, 119},
|
||||
{0xc000, 120},
|
||||
{0xc000, 121},
|
||||
{0xc000, 122},
|
||||
{0x46, 0},
|
||||
{0x47, 0},
|
||||
{0x49, 0},
|
||||
{0x404a, 0},
|
||||
},
|
||||
/* 57 */
|
||||
{
|
||||
{0x8001, 85},
|
||||
{0xc016, 85},
|
||||
{0x8001, 86},
|
||||
{0xc016, 86},
|
||||
{0x8001, 87},
|
||||
{0xc016, 87},
|
||||
{0x8001, 89},
|
||||
{0xc016, 89},
|
||||
{0x8001, 106},
|
||||
{0xc016, 106},
|
||||
{0x8001, 107},
|
||||
{0xc016, 107},
|
||||
{0x8001, 113},
|
||||
{0xc016, 113},
|
||||
{0x8001, 118},
|
||||
{0xc016, 118},
|
||||
},
|
||||
/* 58 */
|
||||
{
|
||||
{0x8002, 85},
|
||||
{0x8009, 85},
|
||||
{0x8017, 85},
|
||||
{0xc028, 85},
|
||||
{0x8002, 86},
|
||||
{0x8009, 86},
|
||||
{0x8017, 86},
|
||||
{0xc028, 86},
|
||||
{0x8002, 87},
|
||||
{0x8009, 87},
|
||||
{0x8017, 87},
|
||||
{0xc028, 87},
|
||||
{0x8002, 89},
|
||||
{0x8009, 89},
|
||||
{0x8017, 89},
|
||||
{0xc028, 89},
|
||||
},
|
||||
/* 59 */
|
||||
{
|
||||
{0x8003, 85},
|
||||
{0x8006, 85},
|
||||
{0x800a, 85},
|
||||
{0x800f, 85},
|
||||
{0x8018, 85},
|
||||
{0x801f, 85},
|
||||
{0x8029, 85},
|
||||
{0xc038, 85},
|
||||
{0x8003, 86},
|
||||
{0x8006, 86},
|
||||
{0x800a, 86},
|
||||
{0x800f, 86},
|
||||
{0x8018, 86},
|
||||
{0x801f, 86},
|
||||
{0x8029, 86},
|
||||
{0xc038, 86},
|
||||
},
|
||||
/* 60 */
|
||||
{
|
||||
{0x8003, 87},
|
||||
{0x8006, 87},
|
||||
{0x800a, 87},
|
||||
{0x800f, 87},
|
||||
{0x8018, 87},
|
||||
{0x801f, 87},
|
||||
{0x8029, 87},
|
||||
{0xc038, 87},
|
||||
{0x8003, 89},
|
||||
{0x8006, 89},
|
||||
{0x800a, 89},
|
||||
{0x800f, 89},
|
||||
{0x8018, 89},
|
||||
{0x801f, 89},
|
||||
{0x8029, 89},
|
||||
{0xc038, 89},
|
||||
},
|
||||
/* 61 */
|
||||
{
|
||||
{0x8002, 106},
|
||||
{0x8009, 106},
|
||||
{0x8017, 106},
|
||||
{0xc028, 106},
|
||||
{0x8002, 107},
|
||||
{0x8009, 107},
|
||||
{0x8017, 107},
|
||||
{0xc028, 107},
|
||||
{0x8002, 113},
|
||||
{0x8009, 113},
|
||||
{0x8017, 113},
|
||||
{0xc028, 113},
|
||||
{0x8002, 118},
|
||||
{0x8009, 118},
|
||||
{0x8017, 118},
|
||||
{0xc028, 118},
|
||||
},
|
||||
/* 62 */
|
||||
{
|
||||
{0x8003, 106},
|
||||
{0x8006, 106},
|
||||
{0x800a, 106},
|
||||
{0x800f, 106},
|
||||
{0x8018, 106},
|
||||
{0x801f, 106},
|
||||
{0x8029, 106},
|
||||
{0xc038, 106},
|
||||
{0x8003, 107},
|
||||
{0x8006, 107},
|
||||
{0x800a, 107},
|
||||
{0x800f, 107},
|
||||
{0x8018, 107},
|
||||
{0x801f, 107},
|
||||
{0x8029, 107},
|
||||
{0xc038, 107},
|
||||
},
|
||||
/* 63 */
|
||||
{
|
||||
{0x8003, 113},
|
||||
{0x8006, 113},
|
||||
{0x800a, 113},
|
||||
{0x800f, 113},
|
||||
{0x8018, 113},
|
||||
{0x801f, 113},
|
||||
{0x8029, 113},
|
||||
{0xc038, 113},
|
||||
{0x8003, 118},
|
||||
{0x8006, 118},
|
||||
{0x800a, 118},
|
||||
{0x800f, 118},
|
||||
{0x8018, 118},
|
||||
{0x801f, 118},
|
||||
{0x8029, 118},
|
||||
{0xc038, 118},
|
||||
},
|
||||
/* 64 */
|
||||
{
|
||||
{0x8001, 119},
|
||||
{0xc016, 119},
|
||||
{0x8001, 120},
|
||||
{0xc016, 120},
|
||||
{0x8001, 121},
|
||||
{0xc016, 121},
|
||||
{0x8001, 122},
|
||||
{0xc016, 122},
|
||||
{0xc000, 38},
|
||||
{0xc000, 42},
|
||||
{0xc000, 44},
|
||||
{0xc000, 59},
|
||||
{0xc000, 88},
|
||||
{0xc000, 90},
|
||||
{0x4b, 0},
|
||||
{0x4e, 0},
|
||||
},
|
||||
/* 65 */
|
||||
{
|
||||
{0x8002, 119},
|
||||
{0x8009, 119},
|
||||
{0x8017, 119},
|
||||
{0xc028, 119},
|
||||
{0x8002, 120},
|
||||
{0x8009, 120},
|
||||
{0x8017, 120},
|
||||
{0xc028, 120},
|
||||
{0x8002, 121},
|
||||
{0x8009, 121},
|
||||
{0x8017, 121},
|
||||
{0xc028, 121},
|
||||
{0x8002, 122},
|
||||
{0x8009, 122},
|
||||
{0x8017, 122},
|
||||
{0xc028, 122},
|
||||
},
|
||||
/* 66 */
|
||||
{
|
||||
{0x8003, 119},
|
||||
{0x8006, 119},
|
||||
{0x800a, 119},
|
||||
{0x800f, 119},
|
||||
{0x8018, 119},
|
||||
{0x801f, 119},
|
||||
{0x8029, 119},
|
||||
{0xc038, 119},
|
||||
{0x8003, 120},
|
||||
{0x8006, 120},
|
||||
{0x800a, 120},
|
||||
{0x800f, 120},
|
||||
{0x8018, 120},
|
||||
{0x801f, 120},
|
||||
{0x8029, 120},
|
||||
{0xc038, 120},
|
||||
},
|
||||
/* 67 */
|
||||
{
|
||||
{0x8003, 121},
|
||||
{0x8006, 121},
|
||||
{0x800a, 121},
|
||||
{0x800f, 121},
|
||||
{0x8018, 121},
|
||||
{0x801f, 121},
|
||||
{0x8029, 121},
|
||||
{0xc038, 121},
|
||||
{0x8003, 122},
|
||||
{0x8006, 122},
|
||||
{0x800a, 122},
|
||||
{0x800f, 122},
|
||||
{0x8018, 122},
|
||||
{0x801f, 122},
|
||||
{0x8029, 122},
|
||||
{0xc038, 122},
|
||||
},
|
||||
/* 68 */
|
||||
{
|
||||
{0x8001, 38},
|
||||
{0xc016, 38},
|
||||
{0x8001, 42},
|
||||
{0xc016, 42},
|
||||
{0x8001, 44},
|
||||
{0xc016, 44},
|
||||
{0x8001, 59},
|
||||
{0xc016, 59},
|
||||
{0x8001, 88},
|
||||
{0xc016, 88},
|
||||
{0x8001, 90},
|
||||
{0xc016, 90},
|
||||
{0x4c, 0},
|
||||
{0x4d, 0},
|
||||
{0x4f, 0},
|
||||
{0x51, 0},
|
||||
},
|
||||
/* 69 */
|
||||
{
|
||||
{0x8002, 38},
|
||||
{0x8009, 38},
|
||||
{0x8017, 38},
|
||||
{0xc028, 38},
|
||||
{0x8002, 42},
|
||||
{0x8009, 42},
|
||||
{0x8017, 42},
|
||||
{0xc028, 42},
|
||||
{0x8002, 44},
|
||||
{0x8009, 44},
|
||||
{0x8017, 44},
|
||||
{0xc028, 44},
|
||||
{0x8002, 59},
|
||||
{0x8009, 59},
|
||||
{0x8017, 59},
|
||||
{0xc028, 59},
|
||||
},
|
||||
/* 70 */
|
||||
{
|
||||
{0x8003, 38},
|
||||
{0x8006, 38},
|
||||
{0x800a, 38},
|
||||
{0x800f, 38},
|
||||
{0x8018, 38},
|
||||
{0x801f, 38},
|
||||
{0x8029, 38},
|
||||
{0xc038, 38},
|
||||
{0x8003, 42},
|
||||
{0x8006, 42},
|
||||
{0x800a, 42},
|
||||
{0x800f, 42},
|
||||
{0x8018, 42},
|
||||
{0x801f, 42},
|
||||
{0x8029, 42},
|
||||
{0xc038, 42},
|
||||
},
|
||||
/* 71 */
|
||||
{
|
||||
{0x8003, 44},
|
||||
{0x8006, 44},
|
||||
{0x800a, 44},
|
||||
{0x800f, 44},
|
||||
{0x8018, 44},
|
||||
{0x801f, 44},
|
||||
{0x8029, 44},
|
||||
{0xc038, 44},
|
||||
{0x8003, 59},
|
||||
{0x8006, 59},
|
||||
{0x800a, 59},
|
||||
{0x800f, 59},
|
||||
{0x8018, 59},
|
||||
{0x801f, 59},
|
||||
{0x8029, 59},
|
||||
{0xc038, 59},
|
||||
},
|
||||
/* 72 */
|
||||
{
|
||||
{0x8002, 88},
|
||||
{0x8009, 88},
|
||||
{0x8017, 88},
|
||||
{0xc028, 88},
|
||||
{0x8002, 90},
|
||||
{0x8009, 90},
|
||||
{0x8017, 90},
|
||||
{0xc028, 90},
|
||||
{0xc000, 33},
|
||||
{0xc000, 34},
|
||||
{0xc000, 40},
|
||||
{0xc000, 41},
|
||||
{0xc000, 63},
|
||||
{0x50, 0},
|
||||
{0x52, 0},
|
||||
{0x54, 0},
|
||||
},
|
||||
/* 73 */
|
||||
{
|
||||
{0x8003, 88},
|
||||
{0x8006, 88},
|
||||
{0x800a, 88},
|
||||
{0x800f, 88},
|
||||
{0x8018, 88},
|
||||
{0x801f, 88},
|
||||
{0x8029, 88},
|
||||
{0xc038, 88},
|
||||
{0x8003, 90},
|
||||
{0x8006, 90},
|
||||
{0x800a, 90},
|
||||
{0x800f, 90},
|
||||
{0x8018, 90},
|
||||
{0x801f, 90},
|
||||
{0x8029, 90},
|
||||
{0xc038, 90},
|
||||
},
|
||||
/* 74 */
|
||||
{
|
||||
{0x8001, 33},
|
||||
{0xc016, 33},
|
||||
{0x8001, 34},
|
||||
{0xc016, 34},
|
||||
{0x8001, 40},
|
||||
{0xc016, 40},
|
||||
{0x8001, 41},
|
||||
{0xc016, 41},
|
||||
{0x8001, 63},
|
||||
{0xc016, 63},
|
||||
{0xc000, 39},
|
||||
{0xc000, 43},
|
||||
{0xc000, 124},
|
||||
{0x53, 0},
|
||||
{0x55, 0},
|
||||
{0x58, 0},
|
||||
},
|
||||
/* 75 */
|
||||
{
|
||||
{0x8002, 33},
|
||||
{0x8009, 33},
|
||||
{0x8017, 33},
|
||||
{0xc028, 33},
|
||||
{0x8002, 34},
|
||||
{0x8009, 34},
|
||||
{0x8017, 34},
|
||||
{0xc028, 34},
|
||||
{0x8002, 40},
|
||||
{0x8009, 40},
|
||||
{0x8017, 40},
|
||||
{0xc028, 40},
|
||||
{0x8002, 41},
|
||||
{0x8009, 41},
|
||||
{0x8017, 41},
|
||||
{0xc028, 41},
|
||||
},
|
||||
/* 76 */
|
||||
{
|
||||
{0x8003, 33},
|
||||
{0x8006, 33},
|
||||
{0x800a, 33},
|
||||
{0x800f, 33},
|
||||
{0x8018, 33},
|
||||
{0x801f, 33},
|
||||
{0x8029, 33},
|
||||
{0xc038, 33},
|
||||
{0x8003, 34},
|
||||
{0x8006, 34},
|
||||
{0x800a, 34},
|
||||
{0x800f, 34},
|
||||
{0x8018, 34},
|
||||
{0x801f, 34},
|
||||
{0x8029, 34},
|
||||
{0xc038, 34},
|
||||
},
|
||||
/* 77 */
|
||||
{
|
||||
{0x8003, 40},
|
||||
{0x8006, 40},
|
||||
{0x800a, 40},
|
||||
{0x800f, 40},
|
||||
{0x8018, 40},
|
||||
{0x801f, 40},
|
||||
{0x8029, 40},
|
||||
{0xc038, 40},
|
||||
{0x8003, 41},
|
||||
{0x8006, 41},
|
||||
{0x800a, 41},
|
||||
{0x800f, 41},
|
||||
{0x8018, 41},
|
||||
{0x801f, 41},
|
||||
{0x8029, 41},
|
||||
{0xc038, 41},
|
||||
},
|
||||
/* 78 */
|
||||
{
|
||||
{0x8002, 63},
|
||||
{0x8009, 63},
|
||||
{0x8017, 63},
|
||||
{0xc028, 63},
|
||||
{0x8001, 39},
|
||||
{0xc016, 39},
|
||||
{0x8001, 43},
|
||||
{0xc016, 43},
|
||||
{0x8001, 124},
|
||||
{0xc016, 124},
|
||||
{0xc000, 35},
|
||||
{0xc000, 62},
|
||||
{0x56, 0},
|
||||
{0x57, 0},
|
||||
{0x59, 0},
|
||||
{0x5a, 0},
|
||||
},
|
||||
/* 79 */
|
||||
{
|
||||
{0x8003, 63},
|
||||
{0x8006, 63},
|
||||
{0x800a, 63},
|
||||
{0x800f, 63},
|
||||
{0x8018, 63},
|
||||
{0x801f, 63},
|
||||
{0x8029, 63},
|
||||
{0xc038, 63},
|
||||
{0x8002, 39},
|
||||
{0x8009, 39},
|
||||
{0x8017, 39},
|
||||
{0xc028, 39},
|
||||
{0x8002, 43},
|
||||
{0x8009, 43},
|
||||
{0x8017, 43},
|
||||
{0xc028, 43},
|
||||
},
|
||||
/* 80 */
|
||||
{
|
||||
{0x8003, 39},
|
||||
{0x8006, 39},
|
||||
{0x800a, 39},
|
||||
{0x800f, 39},
|
||||
{0x8018, 39},
|
||||
{0x801f, 39},
|
||||
{0x8029, 39},
|
||||
{0xc038, 39},
|
||||
{0x8003, 43},
|
||||
{0x8006, 43},
|
||||
{0x800a, 43},
|
||||
{0x800f, 43},
|
||||
{0x8018, 43},
|
||||
{0x801f, 43},
|
||||
{0x8029, 43},
|
||||
{0xc038, 43},
|
||||
},
|
||||
/* 81 */
|
||||
{
|
||||
{0x8002, 124},
|
||||
{0x8009, 124},
|
||||
{0x8017, 124},
|
||||
{0xc028, 124},
|
||||
{0x8001, 35},
|
||||
{0xc016, 35},
|
||||
{0x8001, 62},
|
||||
{0xc016, 62},
|
||||
{0xc000, 0},
|
||||
{0xc000, 36},
|
||||
{0xc000, 64},
|
||||
{0xc000, 91},
|
||||
{0xc000, 93},
|
||||
{0xc000, 126},
|
||||
{0x5b, 0},
|
||||
{0x5c, 0},
|
||||
},
|
||||
/* 82 */
|
||||
{
|
||||
{0x8003, 124},
|
||||
{0x8006, 124},
|
||||
{0x800a, 124},
|
||||
{0x800f, 124},
|
||||
{0x8018, 124},
|
||||
{0x801f, 124},
|
||||
{0x8029, 124},
|
||||
{0xc038, 124},
|
||||
{0x8002, 35},
|
||||
{0x8009, 35},
|
||||
{0x8017, 35},
|
||||
{0xc028, 35},
|
||||
{0x8002, 62},
|
||||
{0x8009, 62},
|
||||
{0x8017, 62},
|
||||
{0xc028, 62},
|
||||
},
|
||||
/* 83 */
|
||||
{
|
||||
{0x8003, 35},
|
||||
{0x8006, 35},
|
||||
{0x800a, 35},
|
||||
{0x800f, 35},
|
||||
{0x8018, 35},
|
||||
{0x801f, 35},
|
||||
{0x8029, 35},
|
||||
{0xc038, 35},
|
||||
{0x8003, 62},
|
||||
{0x8006, 62},
|
||||
{0x800a, 62},
|
||||
{0x800f, 62},
|
||||
{0x8018, 62},
|
||||
{0x801f, 62},
|
||||
{0x8029, 62},
|
||||
{0xc038, 62},
|
||||
},
|
||||
/* 84 */
|
||||
{
|
||||
{0x8001, 0},
|
||||
{0xc016, 0},
|
||||
{0x8001, 36},
|
||||
{0xc016, 36},
|
||||
{0x8001, 64},
|
||||
{0xc016, 64},
|
||||
{0x8001, 91},
|
||||
{0xc016, 91},
|
||||
{0x8001, 93},
|
||||
{0xc016, 93},
|
||||
{0x8001, 126},
|
||||
{0xc016, 126},
|
||||
{0xc000, 94},
|
||||
{0xc000, 125},
|
||||
{0x5d, 0},
|
||||
{0x5e, 0},
|
||||
},
|
||||
/* 85 */
|
||||
{
|
||||
{0x8002, 0},
|
||||
{0x8009, 0},
|
||||
{0x8017, 0},
|
||||
{0xc028, 0},
|
||||
{0x8002, 36},
|
||||
{0x8009, 36},
|
||||
{0x8017, 36},
|
||||
{0xc028, 36},
|
||||
{0x8002, 64},
|
||||
{0x8009, 64},
|
||||
{0x8017, 64},
|
||||
{0xc028, 64},
|
||||
{0x8002, 91},
|
||||
{0x8009, 91},
|
||||
{0x8017, 91},
|
||||
{0xc028, 91},
|
||||
},
|
||||
/* 86 */
|
||||
{
|
||||
{0x8003, 0},
|
||||
{0x8006, 0},
|
||||
{0x800a, 0},
|
||||
{0x800f, 0},
|
||||
{0x8018, 0},
|
||||
{0x801f, 0},
|
||||
{0x8029, 0},
|
||||
{0xc038, 0},
|
||||
{0x8003, 36},
|
||||
{0x8006, 36},
|
||||
{0x800a, 36},
|
||||
{0x800f, 36},
|
||||
{0x8018, 36},
|
||||
{0x801f, 36},
|
||||
{0x8029, 36},
|
||||
{0xc038, 36},
|
||||
},
|
||||
/* 87 */
|
||||
{
|
||||
{0x8003, 64},
|
||||
{0x8006, 64},
|
||||
{0x800a, 64},
|
||||
{0x800f, 64},
|
||||
{0x8018, 64},
|
||||
{0x801f, 64},
|
||||
{0x8029, 64},
|
||||
{0xc038, 64},
|
||||
{0x8003, 91},
|
||||
{0x8006, 91},
|
||||
{0x800a, 91},
|
||||
{0x800f, 91},
|
||||
{0x8018, 91},
|
||||
{0x801f, 91},
|
||||
{0x8029, 91},
|
||||
{0xc038, 91},
|
||||
},
|
||||
/* 88 */
|
||||
{
|
||||
{0x8002, 93},
|
||||
{0x8009, 93},
|
||||
{0x8017, 93},
|
||||
{0xc028, 93},
|
||||
{0x8002, 126},
|
||||
{0x8009, 126},
|
||||
{0x8017, 126},
|
||||
{0xc028, 126},
|
||||
{0x8001, 94},
|
||||
{0xc016, 94},
|
||||
{0x8001, 125},
|
||||
{0xc016, 125},
|
||||
{0xc000, 60},
|
||||
{0xc000, 96},
|
||||
{0xc000, 123},
|
||||
{0x5f, 0},
|
||||
},
|
||||
/* 89 */
|
||||
{
|
||||
{0x8003, 93},
|
||||
{0x8006, 93},
|
||||
{0x800a, 93},
|
||||
{0x800f, 93},
|
||||
{0x8018, 93},
|
||||
{0x801f, 93},
|
||||
{0x8029, 93},
|
||||
{0xc038, 93},
|
||||
{0x8003, 126},
|
||||
{0x8006, 126},
|
||||
{0x800a, 126},
|
||||
{0x800f, 126},
|
||||
{0x8018, 126},
|
||||
{0x801f, 126},
|
||||
{0x8029, 126},
|
||||
{0xc038, 126},
|
||||
},
|
||||
/* 90 */
|
||||
{
|
||||
{0x8002, 94},
|
||||
{0x8009, 94},
|
||||
{0x8017, 94},
|
||||
{0xc028, 94},
|
||||
{0x8002, 125},
|
||||
{0x8009, 125},
|
||||
{0x8017, 125},
|
||||
{0xc028, 125},
|
||||
{0x8001, 60},
|
||||
{0xc016, 60},
|
||||
{0x8001, 96},
|
||||
{0xc016, 96},
|
||||
{0x8001, 123},
|
||||
{0xc016, 123},
|
||||
{0x60, 0},
|
||||
{0x6e, 0},
|
||||
},
|
||||
/* 91 */
|
||||
{
|
||||
{0x8003, 94},
|
||||
{0x8006, 94},
|
||||
{0x800a, 94},
|
||||
{0x800f, 94},
|
||||
{0x8018, 94},
|
||||
{0x801f, 94},
|
||||
{0x8029, 94},
|
||||
{0xc038, 94},
|
||||
{0x8003, 125},
|
||||
{0x8006, 125},
|
||||
{0x800a, 125},
|
||||
{0x800f, 125},
|
||||
{0x8018, 125},
|
||||
{0x801f, 125},
|
||||
{0x8029, 125},
|
||||
{0xc038, 125},
|
||||
},
|
||||
/* 92 */
|
||||
{
|
||||
{0x8002, 60},
|
||||
{0x8009, 60},
|
||||
{0x8017, 60},
|
||||
{0xc028, 60},
|
||||
{0x8002, 96},
|
||||
{0x8009, 96},
|
||||
{0x8017, 96},
|
||||
{0xc028, 96},
|
||||
{0x8002, 123},
|
||||
{0x8009, 123},
|
||||
{0x8017, 123},
|
||||
{0xc028, 123},
|
||||
{0x61, 0},
|
||||
{0x65, 0},
|
||||
{0x6f, 0},
|
||||
{0x85, 0},
|
||||
},
|
||||
/* 93 */
|
||||
{
|
||||
{0x8003, 60},
|
||||
{0x8006, 60},
|
||||
{0x800a, 60},
|
||||
{0x800f, 60},
|
||||
{0x8018, 60},
|
||||
{0x801f, 60},
|
||||
{0x8029, 60},
|
||||
{0xc038, 60},
|
||||
{0x8003, 96},
|
||||
{0x8006, 96},
|
||||
{0x800a, 96},
|
||||
{0x800f, 96},
|
||||
{0x8018, 96},
|
||||
{0x801f, 96},
|
||||
{0x8029, 96},
|
||||
{0xc038, 96},
|
||||
},
|
||||
/* 94 */
|
||||
{
|
||||
{0x8003, 123},
|
||||
{0x8006, 123},
|
||||
{0x800a, 123},
|
||||
{0x800f, 123},
|
||||
{0x8018, 123},
|
||||
{0x801f, 123},
|
||||
{0x8029, 123},
|
||||
{0xc038, 123},
|
||||
{0x62, 0},
|
||||
{0x63, 0},
|
||||
{0x66, 0},
|
||||
{0x69, 0},
|
||||
{0x70, 0},
|
||||
{0x77, 0},
|
||||
{0x86, 0},
|
||||
{0x99, 0},
|
||||
},
|
||||
/* 95 */
|
||||
{
|
||||
{0xc000, 92},
|
||||
{0xc000, 195},
|
||||
{0xc000, 208},
|
||||
{0x64, 0},
|
||||
{0x67, 0},
|
||||
{0x68, 0},
|
||||
{0x6a, 0},
|
||||
{0x6b, 0},
|
||||
{0x71, 0},
|
||||
{0x74, 0},
|
||||
{0x78, 0},
|
||||
{0x7e, 0},
|
||||
{0x87, 0},
|
||||
{0x8e, 0},
|
||||
{0x9a, 0},
|
||||
{0xa9, 0},
|
||||
},
|
||||
/* 96 */
|
||||
{
|
||||
{0x8001, 92},
|
||||
{0xc016, 92},
|
||||
{0x8001, 195},
|
||||
{0xc016, 195},
|
||||
{0x8001, 208},
|
||||
{0xc016, 208},
|
||||
{0xc000, 128},
|
||||
{0xc000, 130},
|
||||
{0xc000, 131},
|
||||
{0xc000, 162},
|
||||
{0xc000, 184},
|
||||
{0xc000, 194},
|
||||
{0xc000, 224},
|
||||
{0xc000, 226},
|
||||
{0x6c, 0},
|
||||
{0x6d, 0},
|
||||
},
|
||||
/* 97 */
|
||||
{
|
||||
{0x8002, 92},
|
||||
{0x8009, 92},
|
||||
{0x8017, 92},
|
||||
{0xc028, 92},
|
||||
{0x8002, 195},
|
||||
{0x8009, 195},
|
||||
{0x8017, 195},
|
||||
{0xc028, 195},
|
||||
{0x8002, 208},
|
||||
{0x8009, 208},
|
||||
{0x8017, 208},
|
||||
{0xc028, 208},
|
||||
{0x8001, 128},
|
||||
{0xc016, 128},
|
||||
{0x8001, 130},
|
||||
{0xc016, 130},
|
||||
},
|
||||
/* 98 */
|
||||
{
|
||||
{0x8003, 92},
|
||||
{0x8006, 92},
|
||||
{0x800a, 92},
|
||||
{0x800f, 92},
|
||||
{0x8018, 92},
|
||||
{0x801f, 92},
|
||||
{0x8029, 92},
|
||||
{0xc038, 92},
|
||||
{0x8003, 195},
|
||||
{0x8006, 195},
|
||||
{0x800a, 195},
|
||||
{0x800f, 195},
|
||||
{0x8018, 195},
|
||||
{0x801f, 195},
|
||||
{0x8029, 195},
|
||||
{0xc038, 195},
|
||||
},
|
||||
/* 99 */
|
||||
{
|
||||
{0x8003, 208},
|
||||
{0x8006, 208},
|
||||
{0x800a, 208},
|
||||
{0x800f, 208},
|
||||
{0x8018, 208},
|
||||
{0x801f, 208},
|
||||
{0x8029, 208},
|
||||
{0xc038, 208},
|
||||
{0x8002, 128},
|
||||
{0x8009, 128},
|
||||
{0x8017, 128},
|
||||
{0xc028, 128},
|
||||
{0x8002, 130},
|
||||
{0x8009, 130},
|
||||
{0x8017, 130},
|
||||
{0xc028, 130},
|
||||
},
|
||||
/* 100 */
|
||||
{
|
||||
{0x8003, 128},
|
||||
{0x8006, 128},
|
||||
{0x800a, 128},
|
||||
{0x800f, 128},
|
||||
{0x8018, 128},
|
||||
{0x801f, 128},
|
||||
{0x8029, 128},
|
||||
{0xc038, 128},
|
||||
{0x8003, 130},
|
||||
{0x8006, 130},
|
||||
{0x800a, 130},
|
||||
{0x800f, 130},
|
||||
{0x8018, 130},
|
||||
{0x801f, 130},
|
||||
{0x8029, 130},
|
||||
{0xc038, 130},
|
||||
},
|
||||
/* 101 */
|
||||
{
|
||||
{0x8001, 131},
|
||||
{0xc016, 131},
|
||||
{0x8001, 162},
|
||||
{0xc016, 162},
|
||||
{0x8001, 184},
|
||||
{0xc016, 184},
|
||||
{0x8001, 194},
|
||||
{0xc016, 194},
|
||||
{0x8001, 224},
|
||||
{0xc016, 224},
|
||||
{0x8001, 226},
|
||||
{0xc016, 226},
|
||||
{0xc000, 153},
|
||||
{0xc000, 161},
|
||||
{0xc000, 167},
|
||||
{0xc000, 172},
|
||||
},
|
||||
/* 102 */
|
||||
{
|
||||
{0x8002, 131},
|
||||
{0x8009, 131},
|
||||
{0x8017, 131},
|
||||
{0xc028, 131},
|
||||
{0x8002, 162},
|
||||
{0x8009, 162},
|
||||
{0x8017, 162},
|
||||
{0xc028, 162},
|
||||
{0x8002, 184},
|
||||
{0x8009, 184},
|
||||
{0x8017, 184},
|
||||
{0xc028, 184},
|
||||
{0x8002, 194},
|
||||
{0x8009, 194},
|
||||
{0x8017, 194},
|
||||
{0xc028, 194},
|
||||
},
|
||||
/* 103 */
|
||||
{
|
||||
{0x8003, 131},
|
||||
{0x8006, 131},
|
||||
{0x800a, 131},
|
||||
{0x800f, 131},
|
||||
{0x8018, 131},
|
||||
{0x801f, 131},
|
||||
{0x8029, 131},
|
||||
{0xc038, 131},
|
||||
{0x8003, 162},
|
||||
{0x8006, 162},
|
||||
{0x800a, 162},
|
||||
{0x800f, 162},
|
||||
{0x8018, 162},
|
||||
{0x801f, 162},
|
||||
{0x8029, 162},
|
||||
{0xc038, 162},
|
||||
},
|
||||
/* 104 */
|
||||
{
|
||||
{0x8003, 184},
|
||||
{0x8006, 184},
|
||||
{0x800a, 184},
|
||||
{0x800f, 184},
|
||||
{0x8018, 184},
|
||||
{0x801f, 184},
|
||||
{0x8029, 184},
|
||||
{0xc038, 184},
|
||||
{0x8003, 194},
|
||||
{0x8006, 194},
|
||||
{0x800a, 194},
|
||||
{0x800f, 194},
|
||||
{0x8018, 194},
|
||||
{0x801f, 194},
|
||||
{0x8029, 194},
|
||||
{0xc038, 194},
|
||||
},
|
||||
/* 105 */
|
||||
{
|
||||
{0x8002, 224},
|
||||
{0x8009, 224},
|
||||
{0x8017, 224},
|
||||
{0xc028, 224},
|
||||
{0x8002, 226},
|
||||
{0x8009, 226},
|
||||
{0x8017, 226},
|
||||
{0xc028, 226},
|
||||
{0x8001, 153},
|
||||
{0xc016, 153},
|
||||
{0x8001, 161},
|
||||
{0xc016, 161},
|
||||
{0x8001, 167},
|
||||
{0xc016, 167},
|
||||
{0x8001, 172},
|
||||
{0xc016, 172},
|
||||
},
|
||||
/* 106 */
|
||||
{
|
||||
{0x8003, 224},
|
||||
{0x8006, 224},
|
||||
{0x800a, 224},
|
||||
{0x800f, 224},
|
||||
{0x8018, 224},
|
||||
{0x801f, 224},
|
||||
{0x8029, 224},
|
||||
{0xc038, 224},
|
||||
{0x8003, 226},
|
||||
{0x8006, 226},
|
||||
{0x800a, 226},
|
||||
{0x800f, 226},
|
||||
{0x8018, 226},
|
||||
{0x801f, 226},
|
||||
{0x8029, 226},
|
||||
{0xc038, 226},
|
||||
},
|
||||
/* 107 */
|
||||
{
|
||||
{0x8002, 153},
|
||||
{0x8009, 153},
|
||||
{0x8017, 153},
|
||||
{0xc028, 153},
|
||||
{0x8002, 161},
|
||||
{0x8009, 161},
|
||||
{0x8017, 161},
|
||||
{0xc028, 161},
|
||||
{0x8002, 167},
|
||||
{0x8009, 167},
|
||||
{0x8017, 167},
|
||||
{0xc028, 167},
|
||||
{0x8002, 172},
|
||||
{0x8009, 172},
|
||||
{0x8017, 172},
|
||||
{0xc028, 172},
|
||||
},
|
||||
/* 108 */
|
||||
{
|
||||
{0x8003, 153},
|
||||
{0x8006, 153},
|
||||
{0x800a, 153},
|
||||
{0x800f, 153},
|
||||
{0x8018, 153},
|
||||
{0x801f, 153},
|
||||
{0x8029, 153},
|
||||
{0xc038, 153},
|
||||
{0x8003, 161},
|
||||
{0x8006, 161},
|
||||
{0x800a, 161},
|
||||
{0x800f, 161},
|
||||
{0x8018, 161},
|
||||
{0x801f, 161},
|
||||
{0x8029, 161},
|
||||
{0xc038, 161},
|
||||
},
|
||||
/* 109 */
|
||||
{
|
||||
{0x8003, 167},
|
||||
{0x8006, 167},
|
||||
{0x800a, 167},
|
||||
{0x800f, 167},
|
||||
{0x8018, 167},
|
||||
{0x801f, 167},
|
||||
{0x8029, 167},
|
||||
{0xc038, 167},
|
||||
{0x8003, 172},
|
||||
{0x8006, 172},
|
||||
{0x800a, 172},
|
||||
{0x800f, 172},
|
||||
{0x8018, 172},
|
||||
{0x801f, 172},
|
||||
{0x8029, 172},
|
||||
{0xc038, 172},
|
||||
},
|
||||
/* 110 */
|
||||
{
|
||||
{0x72, 0},
|
||||
{0x73, 0},
|
||||
{0x75, 0},
|
||||
{0x76, 0},
|
||||
{0x79, 0},
|
||||
{0x7b, 0},
|
||||
{0x7f, 0},
|
||||
{0x82, 0},
|
||||
{0x88, 0},
|
||||
{0x8b, 0},
|
||||
{0x8f, 0},
|
||||
{0x92, 0},
|
||||
{0x9b, 0},
|
||||
{0xa2, 0},
|
||||
{0xaa, 0},
|
||||
{0xb4, 0},
|
||||
},
|
||||
/* 111 */
|
||||
{
|
||||
{0xc000, 176},
|
||||
{0xc000, 177},
|
||||
{0xc000, 179},
|
||||
{0xc000, 209},
|
||||
{0xc000, 216},
|
||||
{0xc000, 217},
|
||||
{0xc000, 227},
|
||||
{0xc000, 229},
|
||||
{0xc000, 230},
|
||||
{0x7a, 0},
|
||||
{0x7c, 0},
|
||||
{0x7d, 0},
|
||||
{0x80, 0},
|
||||
{0x81, 0},
|
||||
{0x83, 0},
|
||||
{0x84, 0},
|
||||
},
|
||||
/* 112 */
|
||||
{
|
||||
{0x8001, 176},
|
||||
{0xc016, 176},
|
||||
{0x8001, 177},
|
||||
{0xc016, 177},
|
||||
{0x8001, 179},
|
||||
{0xc016, 179},
|
||||
{0x8001, 209},
|
||||
{0xc016, 209},
|
||||
{0x8001, 216},
|
||||
{0xc016, 216},
|
||||
{0x8001, 217},
|
||||
{0xc016, 217},
|
||||
{0x8001, 227},
|
||||
{0xc016, 227},
|
||||
{0x8001, 229},
|
||||
{0xc016, 229},
|
||||
},
|
||||
/* 113 */
|
||||
{
|
||||
{0x8002, 176},
|
||||
{0x8009, 176},
|
||||
{0x8017, 176},
|
||||
{0xc028, 176},
|
||||
{0x8002, 177},
|
||||
{0x8009, 177},
|
||||
{0x8017, 177},
|
||||
{0xc028, 177},
|
||||
{0x8002, 179},
|
||||
{0x8009, 179},
|
||||
{0x8017, 179},
|
||||
{0xc028, 179},
|
||||
{0x8002, 209},
|
||||
{0x8009, 209},
|
||||
{0x8017, 209},
|
||||
{0xc028, 209},
|
||||
},
|
||||
/* 114 */
|
||||
{
|
||||
{0x8003, 176},
|
||||
{0x8006, 176},
|
||||
{0x800a, 176},
|
||||
{0x800f, 176},
|
||||
{0x8018, 176},
|
||||
{0x801f, 176},
|
||||
{0x8029, 176},
|
||||
{0xc038, 176},
|
||||
{0x8003, 177},
|
||||
{0x8006, 177},
|
||||
{0x800a, 177},
|
||||
{0x800f, 177},
|
||||
{0x8018, 177},
|
||||
{0x801f, 177},
|
||||
{0x8029, 177},
|
||||
{0xc038, 177},
|
||||
},
|
||||
/* 115 */
|
||||
{
|
||||
{0x8003, 179},
|
||||
{0x8006, 179},
|
||||
{0x800a, 179},
|
||||
{0x800f, 179},
|
||||
{0x8018, 179},
|
||||
{0x801f, 179},
|
||||
{0x8029, 179},
|
||||
{0xc038, 179},
|
||||
{0x8003, 209},
|
||||
{0x8006, 209},
|
||||
{0x800a, 209},
|
||||
{0x800f, 209},
|
||||
{0x8018, 209},
|
||||
{0x801f, 209},
|
||||
{0x8029, 209},
|
||||
{0xc038, 209},
|
||||
},
|
||||
/* 116 */
|
||||
{
|
||||
{0x8002, 216},
|
||||
{0x8009, 216},
|
||||
{0x8017, 216},
|
||||
{0xc028, 216},
|
||||
{0x8002, 217},
|
||||
{0x8009, 217},
|
||||
{0x8017, 217},
|
||||
{0xc028, 217},
|
||||
{0x8002, 227},
|
||||
{0x8009, 227},
|
||||
{0x8017, 227},
|
||||
{0xc028, 227},
|
||||
{0x8002, 229},
|
||||
{0x8009, 229},
|
||||
{0x8017, 229},
|
||||
{0xc028, 229},
|
||||
},
|
||||
/* 117 */
|
||||
{
|
||||
{0x8003, 216},
|
||||
{0x8006, 216},
|
||||
{0x800a, 216},
|
||||
{0x800f, 216},
|
||||
{0x8018, 216},
|
||||
{0x801f, 216},
|
||||
{0x8029, 216},
|
||||
{0xc038, 216},
|
||||
{0x8003, 217},
|
||||
{0x8006, 217},
|
||||
{0x800a, 217},
|
||||
{0x800f, 217},
|
||||
{0x8018, 217},
|
||||
{0x801f, 217},
|
||||
{0x8029, 217},
|
||||
{0xc038, 217},
|
||||
},
|
||||
/* 118 */
|
||||
{
|
||||
{0x8003, 227},
|
||||
{0x8006, 227},
|
||||
{0x800a, 227},
|
||||
{0x800f, 227},
|
||||
{0x8018, 227},
|
||||
{0x801f, 227},
|
||||
{0x8029, 227},
|
||||
{0xc038, 227},
|
||||
{0x8003, 229},
|
||||
{0x8006, 229},
|
||||
{0x800a, 229},
|
||||
{0x800f, 229},
|
||||
{0x8018, 229},
|
||||
{0x801f, 229},
|
||||
{0x8029, 229},
|
||||
{0xc038, 229},
|
||||
},
|
||||
/* 119 */
|
||||
{
|
||||
{0x8001, 230},
|
||||
{0xc016, 230},
|
||||
{0xc000, 129},
|
||||
{0xc000, 132},
|
||||
{0xc000, 133},
|
||||
{0xc000, 134},
|
||||
{0xc000, 136},
|
||||
{0xc000, 146},
|
||||
{0xc000, 154},
|
||||
{0xc000, 156},
|
||||
{0xc000, 160},
|
||||
{0xc000, 163},
|
||||
{0xc000, 164},
|
||||
{0xc000, 169},
|
||||
{0xc000, 170},
|
||||
{0xc000, 173},
|
||||
},
|
||||
/* 120 */
|
||||
{
|
||||
{0x8002, 230},
|
||||
{0x8009, 230},
|
||||
{0x8017, 230},
|
||||
{0xc028, 230},
|
||||
{0x8001, 129},
|
||||
{0xc016, 129},
|
||||
{0x8001, 132},
|
||||
{0xc016, 132},
|
||||
{0x8001, 133},
|
||||
{0xc016, 133},
|
||||
{0x8001, 134},
|
||||
{0xc016, 134},
|
||||
{0x8001, 136},
|
||||
{0xc016, 136},
|
||||
{0x8001, 146},
|
||||
{0xc016, 146},
|
||||
},
|
||||
/* 121 */
|
||||
{
|
||||
{0x8003, 230},
|
||||
{0x8006, 230},
|
||||
{0x800a, 230},
|
||||
{0x800f, 230},
|
||||
{0x8018, 230},
|
||||
{0x801f, 230},
|
||||
{0x8029, 230},
|
||||
{0xc038, 230},
|
||||
{0x8002, 129},
|
||||
{0x8009, 129},
|
||||
{0x8017, 129},
|
||||
{0xc028, 129},
|
||||
{0x8002, 132},
|
||||
{0x8009, 132},
|
||||
{0x8017, 132},
|
||||
{0xc028, 132},
|
||||
},
|
||||
/* 122 */
|
||||
{
|
||||
{0x8003, 129},
|
||||
{0x8006, 129},
|
||||
{0x800a, 129},
|
||||
{0x800f, 129},
|
||||
{0x8018, 129},
|
||||
{0x801f, 129},
|
||||
{0x8029, 129},
|
||||
{0xc038, 129},
|
||||
{0x8003, 132},
|
||||
{0x8006, 132},
|
||||
{0x800a, 132},
|
||||
{0x800f, 132},
|
||||
{0x8018, 132},
|
||||
{0x801f, 132},
|
||||
{0x8029, 132},
|
||||
{0xc038, 132},
|
||||
},
|
||||
/* 123 */
|
||||
{
|
||||
{0x8002, 133},
|
||||
{0x8009, 133},
|
||||
{0x8017, 133},
|
||||
{0xc028, 133},
|
||||
{0x8002, 134},
|
||||
{0x8009, 134},
|
||||
{0x8017, 134},
|
||||
{0xc028, 134},
|
||||
{0x8002, 136},
|
||||
{0x8009, 136},
|
||||
{0x8017, 136},
|
||||
{0xc028, 136},
|
||||
{0x8002, 146},
|
||||
{0x8009, 146},
|
||||
{0x8017, 146},
|
||||
{0xc028, 146},
|
||||
},
|
||||
/* 124 */
|
||||
{
|
||||
{0x8003, 133},
|
||||
{0x8006, 133},
|
||||
{0x800a, 133},
|
||||
{0x800f, 133},
|
||||
{0x8018, 133},
|
||||
{0x801f, 133},
|
||||
{0x8029, 133},
|
||||
{0xc038, 133},
|
||||
{0x8003, 134},
|
||||
{0x8006, 134},
|
||||
{0x800a, 134},
|
||||
{0x800f, 134},
|
||||
{0x8018, 134},
|
||||
{0x801f, 134},
|
||||
{0x8029, 134},
|
||||
{0xc038, 134},
|
||||
},
|
||||
/* 125 */
|
||||
{
|
||||
{0x8003, 136},
|
||||
{0x8006, 136},
|
||||
{0x800a, 136},
|
||||
{0x800f, 136},
|
||||
{0x8018, 136},
|
||||
{0x801f, 136},
|
||||
{0x8029, 136},
|
||||
{0xc038, 136},
|
||||
{0x8003, 146},
|
||||
{0x8006, 146},
|
||||
{0x800a, 146},
|
||||
{0x800f, 146},
|
||||
{0x8018, 146},
|
||||
{0x801f, 146},
|
||||
{0x8029, 146},
|
||||
{0xc038, 146},
|
||||
},
|
||||
/* 126 */
|
||||
{
|
||||
{0x8001, 154},
|
||||
{0xc016, 154},
|
||||
{0x8001, 156},
|
||||
{0xc016, 156},
|
||||
{0x8001, 160},
|
||||
{0xc016, 160},
|
||||
{0x8001, 163},
|
||||
{0xc016, 163},
|
||||
{0x8001, 164},
|
||||
{0xc016, 164},
|
||||
{0x8001, 169},
|
||||
{0xc016, 169},
|
||||
{0x8001, 170},
|
||||
{0xc016, 170},
|
||||
{0x8001, 173},
|
||||
{0xc016, 173},
|
||||
},
|
||||
/* 127 */
|
||||
{
|
||||
{0x8002, 154},
|
||||
{0x8009, 154},
|
||||
{0x8017, 154},
|
||||
{0xc028, 154},
|
||||
{0x8002, 156},
|
||||
{0x8009, 156},
|
||||
{0x8017, 156},
|
||||
{0xc028, 156},
|
||||
{0x8002, 160},
|
||||
{0x8009, 160},
|
||||
{0x8017, 160},
|
||||
{0xc028, 160},
|
||||
{0x8002, 163},
|
||||
{0x8009, 163},
|
||||
{0x8017, 163},
|
||||
{0xc028, 163},
|
||||
},
|
||||
/* 128 */
|
||||
{
|
||||
{0x8003, 154},
|
||||
{0x8006, 154},
|
||||
{0x800a, 154},
|
||||
{0x800f, 154},
|
||||
{0x8018, 154},
|
||||
{0x801f, 154},
|
||||
{0x8029, 154},
|
||||
{0xc038, 154},
|
||||
{0x8003, 156},
|
||||
{0x8006, 156},
|
||||
{0x800a, 156},
|
||||
{0x800f, 156},
|
||||
{0x8018, 156},
|
||||
{0x801f, 156},
|
||||
{0x8029, 156},
|
||||
{0xc038, 156},
|
||||
},
|
||||
/* 129 */
|
||||
{
|
||||
{0x8003, 160},
|
||||
{0x8006, 160},
|
||||
{0x800a, 160},
|
||||
{0x800f, 160},
|
||||
{0x8018, 160},
|
||||
{0x801f, 160},
|
||||
{0x8029, 160},
|
||||
{0xc038, 160},
|
||||
{0x8003, 163},
|
||||
{0x8006, 163},
|
||||
{0x800a, 163},
|
||||
{0x800f, 163},
|
||||
{0x8018, 163},
|
||||
{0x801f, 163},
|
||||
{0x8029, 163},
|
||||
{0xc038, 163},
|
||||
},
|
||||
/* 130 */
|
||||
{
|
||||
{0x8002, 164},
|
||||
{0x8009, 164},
|
||||
{0x8017, 164},
|
||||
{0xc028, 164},
|
||||
{0x8002, 169},
|
||||
{0x8009, 169},
|
||||
{0x8017, 169},
|
||||
{0xc028, 169},
|
||||
{0x8002, 170},
|
||||
{0x8009, 170},
|
||||
{0x8017, 170},
|
||||
{0xc028, 170},
|
||||
{0x8002, 173},
|
||||
{0x8009, 173},
|
||||
{0x8017, 173},
|
||||
{0xc028, 173},
|
||||
},
|
||||
/* 131 */
|
||||
{
|
||||
{0x8003, 164},
|
||||
{0x8006, 164},
|
||||
{0x800a, 164},
|
||||
{0x800f, 164},
|
||||
{0x8018, 164},
|
||||
{0x801f, 164},
|
||||
{0x8029, 164},
|
||||
{0xc038, 164},
|
||||
{0x8003, 169},
|
||||
{0x8006, 169},
|
||||
{0x800a, 169},
|
||||
{0x800f, 169},
|
||||
{0x8018, 169},
|
||||
{0x801f, 169},
|
||||
{0x8029, 169},
|
||||
{0xc038, 169},
|
||||
},
|
||||
/* 132 */
|
||||
{
|
||||
{0x8003, 170},
|
||||
{0x8006, 170},
|
||||
{0x800a, 170},
|
||||
{0x800f, 170},
|
||||
{0x8018, 170},
|
||||
{0x801f, 170},
|
||||
{0x8029, 170},
|
||||
{0xc038, 170},
|
||||
{0x8003, 173},
|
||||
{0x8006, 173},
|
||||
{0x800a, 173},
|
||||
{0x800f, 173},
|
||||
{0x8018, 173},
|
||||
{0x801f, 173},
|
||||
{0x8029, 173},
|
||||
{0xc038, 173},
|
||||
},
|
||||
/* 133 */
|
||||
{
|
||||
{0x89, 0},
|
||||
{0x8a, 0},
|
||||
{0x8c, 0},
|
||||
{0x8d, 0},
|
||||
{0x90, 0},
|
||||
{0x91, 0},
|
||||
{0x93, 0},
|
||||
{0x96, 0},
|
||||
{0x9c, 0},
|
||||
{0x9f, 0},
|
||||
{0xa3, 0},
|
||||
{0xa6, 0},
|
||||
{0xab, 0},
|
||||
{0xae, 0},
|
||||
{0xb5, 0},
|
||||
{0xbe, 0},
|
||||
},
|
||||
/* 134 */
|
||||
{
|
||||
{0xc000, 178},
|
||||
{0xc000, 181},
|
||||
{0xc000, 185},
|
||||
{0xc000, 186},
|
||||
{0xc000, 187},
|
||||
{0xc000, 189},
|
||||
{0xc000, 190},
|
||||
{0xc000, 196},
|
||||
{0xc000, 198},
|
||||
{0xc000, 228},
|
||||
{0xc000, 232},
|
||||
{0xc000, 233},
|
||||
{0x94, 0},
|
||||
{0x95, 0},
|
||||
{0x97, 0},
|
||||
{0x98, 0},
|
||||
},
|
||||
/* 135 */
|
||||
{
|
||||
{0x8001, 178},
|
||||
{0xc016, 178},
|
||||
{0x8001, 181},
|
||||
{0xc016, 181},
|
||||
{0x8001, 185},
|
||||
{0xc016, 185},
|
||||
{0x8001, 186},
|
||||
{0xc016, 186},
|
||||
{0x8001, 187},
|
||||
{0xc016, 187},
|
||||
{0x8001, 189},
|
||||
{0xc016, 189},
|
||||
{0x8001, 190},
|
||||
{0xc016, 190},
|
||||
{0x8001, 196},
|
||||
{0xc016, 196},
|
||||
},
|
||||
/* 136 */
|
||||
{
|
||||
{0x8002, 178},
|
||||
{0x8009, 178},
|
||||
{0x8017, 178},
|
||||
{0xc028, 178},
|
||||
{0x8002, 181},
|
||||
{0x8009, 181},
|
||||
{0x8017, 181},
|
||||
{0xc028, 181},
|
||||
{0x8002, 185},
|
||||
{0x8009, 185},
|
||||
{0x8017, 185},
|
||||
{0xc028, 185},
|
||||
{0x8002, 186},
|
||||
{0x8009, 186},
|
||||
{0x8017, 186},
|
||||
{0xc028, 186},
|
||||
},
|
||||
/* 137 */
|
||||
{
|
||||
{0x8003, 178},
|
||||
{0x8006, 178},
|
||||
{0x800a, 178},
|
||||
{0x800f, 178},
|
||||
{0x8018, 178},
|
||||
{0x801f, 178},
|
||||
{0x8029, 178},
|
||||
{0xc038, 178},
|
||||
{0x8003, 181},
|
||||
{0x8006, 181},
|
||||
{0x800a, 181},
|
||||
{0x800f, 181},
|
||||
{0x8018, 181},
|
||||
{0x801f, 181},
|
||||
{0x8029, 181},
|
||||
{0xc038, 181},
|
||||
},
|
||||
/* 138 */
|
||||
{
|
||||
{0x8003, 185},
|
||||
{0x8006, 185},
|
||||
{0x800a, 185},
|
||||
{0x800f, 185},
|
||||
{0x8018, 185},
|
||||
{0x801f, 185},
|
||||
{0x8029, 185},
|
||||
{0xc038, 185},
|
||||
{0x8003, 186},
|
||||
{0x8006, 186},
|
||||
{0x800a, 186},
|
||||
{0x800f, 186},
|
||||
{0x8018, 186},
|
||||
{0x801f, 186},
|
||||
{0x8029, 186},
|
||||
{0xc038, 186},
|
||||
},
|
||||
/* 139 */
|
||||
{
|
||||
{0x8002, 187},
|
||||
{0x8009, 187},
|
||||
{0x8017, 187},
|
||||
{0xc028, 187},
|
||||
{0x8002, 189},
|
||||
{0x8009, 189},
|
||||
{0x8017, 189},
|
||||
{0xc028, 189},
|
||||
{0x8002, 190},
|
||||
{0x8009, 190},
|
||||
{0x8017, 190},
|
||||
{0xc028, 190},
|
||||
{0x8002, 196},
|
||||
{0x8009, 196},
|
||||
{0x8017, 196},
|
||||
{0xc028, 196},
|
||||
},
|
||||
/* 140 */
|
||||
{
|
||||
{0x8003, 187},
|
||||
{0x8006, 187},
|
||||
{0x800a, 187},
|
||||
{0x800f, 187},
|
||||
{0x8018, 187},
|
||||
{0x801f, 187},
|
||||
{0x8029, 187},
|
||||
{0xc038, 187},
|
||||
{0x8003, 189},
|
||||
{0x8006, 189},
|
||||
{0x800a, 189},
|
||||
{0x800f, 189},
|
||||
{0x8018, 189},
|
||||
{0x801f, 189},
|
||||
{0x8029, 189},
|
||||
{0xc038, 189},
|
||||
},
|
||||
/* 141 */
|
||||
{
|
||||
{0x8003, 190},
|
||||
{0x8006, 190},
|
||||
{0x800a, 190},
|
||||
{0x800f, 190},
|
||||
{0x8018, 190},
|
||||
{0x801f, 190},
|
||||
{0x8029, 190},
|
||||
{0xc038, 190},
|
||||
{0x8003, 196},
|
||||
{0x8006, 196},
|
||||
{0x800a, 196},
|
||||
{0x800f, 196},
|
||||
{0x8018, 196},
|
||||
{0x801f, 196},
|
||||
{0x8029, 196},
|
||||
{0xc038, 196},
|
||||
},
|
||||
/* 142 */
|
||||
{
|
||||
{0x8001, 198},
|
||||
{0xc016, 198},
|
||||
{0x8001, 228},
|
||||
{0xc016, 228},
|
||||
{0x8001, 232},
|
||||
{0xc016, 232},
|
||||
{0x8001, 233},
|
||||
{0xc016, 233},
|
||||
{0xc000, 1},
|
||||
{0xc000, 135},
|
||||
{0xc000, 137},
|
||||
{0xc000, 138},
|
||||
{0xc000, 139},
|
||||
{0xc000, 140},
|
||||
{0xc000, 141},
|
||||
{0xc000, 143},
|
||||
},
|
||||
/* 143 */
|
||||
{
|
||||
{0x8002, 198},
|
||||
{0x8009, 198},
|
||||
{0x8017, 198},
|
||||
{0xc028, 198},
|
||||
{0x8002, 228},
|
||||
{0x8009, 228},
|
||||
{0x8017, 228},
|
||||
{0xc028, 228},
|
||||
{0x8002, 232},
|
||||
{0x8009, 232},
|
||||
{0x8017, 232},
|
||||
{0xc028, 232},
|
||||
{0x8002, 233},
|
||||
{0x8009, 233},
|
||||
{0x8017, 233},
|
||||
{0xc028, 233},
|
||||
},
|
||||
/* 144 */
|
||||
{
|
||||
{0x8003, 198},
|
||||
{0x8006, 198},
|
||||
{0x800a, 198},
|
||||
{0x800f, 198},
|
||||
{0x8018, 198},
|
||||
{0x801f, 198},
|
||||
{0x8029, 198},
|
||||
{0xc038, 198},
|
||||
{0x8003, 228},
|
||||
{0x8006, 228},
|
||||
{0x800a, 228},
|
||||
{0x800f, 228},
|
||||
{0x8018, 228},
|
||||
{0x801f, 228},
|
||||
{0x8029, 228},
|
||||
{0xc038, 228},
|
||||
},
|
||||
/* 145 */
|
||||
{
|
||||
{0x8003, 232},
|
||||
{0x8006, 232},
|
||||
{0x800a, 232},
|
||||
{0x800f, 232},
|
||||
{0x8018, 232},
|
||||
{0x801f, 232},
|
||||
{0x8029, 232},
|
||||
{0xc038, 232},
|
||||
{0x8003, 233},
|
||||
{0x8006, 233},
|
||||
{0x800a, 233},
|
||||
{0x800f, 233},
|
||||
{0x8018, 233},
|
||||
{0x801f, 233},
|
||||
{0x8029, 233},
|
||||
{0xc038, 233},
|
||||
},
|
||||
/* 146 */
|
||||
{
|
||||
{0x8001, 1},
|
||||
{0xc016, 1},
|
||||
{0x8001, 135},
|
||||
{0xc016, 135},
|
||||
{0x8001, 137},
|
||||
{0xc016, 137},
|
||||
{0x8001, 138},
|
||||
{0xc016, 138},
|
||||
{0x8001, 139},
|
||||
{0xc016, 139},
|
||||
{0x8001, 140},
|
||||
{0xc016, 140},
|
||||
{0x8001, 141},
|
||||
{0xc016, 141},
|
||||
{0x8001, 143},
|
||||
{0xc016, 143},
|
||||
},
|
||||
/* 147 */
|
||||
{
|
||||
{0x8002, 1},
|
||||
{0x8009, 1},
|
||||
{0x8017, 1},
|
||||
{0xc028, 1},
|
||||
{0x8002, 135},
|
||||
{0x8009, 135},
|
||||
{0x8017, 135},
|
||||
{0xc028, 135},
|
||||
{0x8002, 137},
|
||||
{0x8009, 137},
|
||||
{0x8017, 137},
|
||||
{0xc028, 137},
|
||||
{0x8002, 138},
|
||||
{0x8009, 138},
|
||||
{0x8017, 138},
|
||||
{0xc028, 138},
|
||||
},
|
||||
/* 148 */
|
||||
{
|
||||
{0x8003, 1},
|
||||
{0x8006, 1},
|
||||
{0x800a, 1},
|
||||
{0x800f, 1},
|
||||
{0x8018, 1},
|
||||
{0x801f, 1},
|
||||
{0x8029, 1},
|
||||
{0xc038, 1},
|
||||
{0x8003, 135},
|
||||
{0x8006, 135},
|
||||
{0x800a, 135},
|
||||
{0x800f, 135},
|
||||
{0x8018, 135},
|
||||
{0x801f, 135},
|
||||
{0x8029, 135},
|
||||
{0xc038, 135},
|
||||
},
|
||||
/* 149 */
|
||||
{
|
||||
{0x8003, 137},
|
||||
{0x8006, 137},
|
||||
{0x800a, 137},
|
||||
{0x800f, 137},
|
||||
{0x8018, 137},
|
||||
{0x801f, 137},
|
||||
{0x8029, 137},
|
||||
{0xc038, 137},
|
||||
{0x8003, 138},
|
||||
{0x8006, 138},
|
||||
{0x800a, 138},
|
||||
{0x800f, 138},
|
||||
{0x8018, 138},
|
||||
{0x801f, 138},
|
||||
{0x8029, 138},
|
||||
{0xc038, 138},
|
||||
},
|
||||
/* 150 */
|
||||
{
|
||||
{0x8002, 139},
|
||||
{0x8009, 139},
|
||||
{0x8017, 139},
|
||||
{0xc028, 139},
|
||||
{0x8002, 140},
|
||||
{0x8009, 140},
|
||||
{0x8017, 140},
|
||||
{0xc028, 140},
|
||||
{0x8002, 141},
|
||||
{0x8009, 141},
|
||||
{0x8017, 141},
|
||||
{0xc028, 141},
|
||||
{0x8002, 143},
|
||||
{0x8009, 143},
|
||||
{0x8017, 143},
|
||||
{0xc028, 143},
|
||||
},
|
||||
/* 151 */
|
||||
{
|
||||
{0x8003, 139},
|
||||
{0x8006, 139},
|
||||
{0x800a, 139},
|
||||
{0x800f, 139},
|
||||
{0x8018, 139},
|
||||
{0x801f, 139},
|
||||
{0x8029, 139},
|
||||
{0xc038, 139},
|
||||
{0x8003, 140},
|
||||
{0x8006, 140},
|
||||
{0x800a, 140},
|
||||
{0x800f, 140},
|
||||
{0x8018, 140},
|
||||
{0x801f, 140},
|
||||
{0x8029, 140},
|
||||
{0xc038, 140},
|
||||
},
|
||||
/* 152 */
|
||||
{
|
||||
{0x8003, 141},
|
||||
{0x8006, 141},
|
||||
{0x800a, 141},
|
||||
{0x800f, 141},
|
||||
{0x8018, 141},
|
||||
{0x801f, 141},
|
||||
{0x8029, 141},
|
||||
{0xc038, 141},
|
||||
{0x8003, 143},
|
||||
{0x8006, 143},
|
||||
{0x800a, 143},
|
||||
{0x800f, 143},
|
||||
{0x8018, 143},
|
||||
{0x801f, 143},
|
||||
{0x8029, 143},
|
||||
{0xc038, 143},
|
||||
},
|
||||
/* 153 */
|
||||
{
|
||||
{0x9d, 0},
|
||||
{0x9e, 0},
|
||||
{0xa0, 0},
|
||||
{0xa1, 0},
|
||||
{0xa4, 0},
|
||||
{0xa5, 0},
|
||||
{0xa7, 0},
|
||||
{0xa8, 0},
|
||||
{0xac, 0},
|
||||
{0xad, 0},
|
||||
{0xaf, 0},
|
||||
{0xb1, 0},
|
||||
{0xb6, 0},
|
||||
{0xb9, 0},
|
||||
{0xbf, 0},
|
||||
{0xcf, 0},
|
||||
},
|
||||
/* 154 */
|
||||
{
|
||||
{0xc000, 147},
|
||||
{0xc000, 149},
|
||||
{0xc000, 150},
|
||||
{0xc000, 151},
|
||||
{0xc000, 152},
|
||||
{0xc000, 155},
|
||||
{0xc000, 157},
|
||||
{0xc000, 158},
|
||||
{0xc000, 165},
|
||||
{0xc000, 166},
|
||||
{0xc000, 168},
|
||||
{0xc000, 174},
|
||||
{0xc000, 175},
|
||||
{0xc000, 180},
|
||||
{0xc000, 182},
|
||||
{0xc000, 183},
|
||||
},
|
||||
/* 155 */
|
||||
{
|
||||
{0x8001, 147},
|
||||
{0xc016, 147},
|
||||
{0x8001, 149},
|
||||
{0xc016, 149},
|
||||
{0x8001, 150},
|
||||
{0xc016, 150},
|
||||
{0x8001, 151},
|
||||
{0xc016, 151},
|
||||
{0x8001, 152},
|
||||
{0xc016, 152},
|
||||
{0x8001, 155},
|
||||
{0xc016, 155},
|
||||
{0x8001, 157},
|
||||
{0xc016, 157},
|
||||
{0x8001, 158},
|
||||
{0xc016, 158},
|
||||
},
|
||||
/* 156 */
|
||||
{
|
||||
{0x8002, 147},
|
||||
{0x8009, 147},
|
||||
{0x8017, 147},
|
||||
{0xc028, 147},
|
||||
{0x8002, 149},
|
||||
{0x8009, 149},
|
||||
{0x8017, 149},
|
||||
{0xc028, 149},
|
||||
{0x8002, 150},
|
||||
{0x8009, 150},
|
||||
{0x8017, 150},
|
||||
{0xc028, 150},
|
||||
{0x8002, 151},
|
||||
{0x8009, 151},
|
||||
{0x8017, 151},
|
||||
{0xc028, 151},
|
||||
},
|
||||
/* 157 */
|
||||
{
|
||||
{0x8003, 147},
|
||||
{0x8006, 147},
|
||||
{0x800a, 147},
|
||||
{0x800f, 147},
|
||||
{0x8018, 147},
|
||||
{0x801f, 147},
|
||||
{0x8029, 147},
|
||||
{0xc038, 147},
|
||||
{0x8003, 149},
|
||||
{0x8006, 149},
|
||||
{0x800a, 149},
|
||||
{0x800f, 149},
|
||||
{0x8018, 149},
|
||||
{0x801f, 149},
|
||||
{0x8029, 149},
|
||||
{0xc038, 149},
|
||||
},
|
||||
/* 158 */
|
||||
{
|
||||
{0x8003, 150},
|
||||
{0x8006, 150},
|
||||
{0x800a, 150},
|
||||
{0x800f, 150},
|
||||
{0x8018, 150},
|
||||
{0x801f, 150},
|
||||
{0x8029, 150},
|
||||
{0xc038, 150},
|
||||
{0x8003, 151},
|
||||
{0x8006, 151},
|
||||
{0x800a, 151},
|
||||
{0x800f, 151},
|
||||
{0x8018, 151},
|
||||
{0x801f, 151},
|
||||
{0x8029, 151},
|
||||
{0xc038, 151},
|
||||
},
|
||||
/* 159 */
|
||||
{
|
||||
{0x8002, 152},
|
||||
{0x8009, 152},
|
||||
{0x8017, 152},
|
||||
{0xc028, 152},
|
||||
{0x8002, 155},
|
||||
{0x8009, 155},
|
||||
{0x8017, 155},
|
||||
{0xc028, 155},
|
||||
{0x8002, 157},
|
||||
{0x8009, 157},
|
||||
{0x8017, 157},
|
||||
{0xc028, 157},
|
||||
{0x8002, 158},
|
||||
{0x8009, 158},
|
||||
{0x8017, 158},
|
||||
{0xc028, 158},
|
||||
},
|
||||
/* 160 */
|
||||
{
|
||||
{0x8003, 152},
|
||||
{0x8006, 152},
|
||||
{0x800a, 152},
|
||||
{0x800f, 152},
|
||||
{0x8018, 152},
|
||||
{0x801f, 152},
|
||||
{0x8029, 152},
|
||||
{0xc038, 152},
|
||||
{0x8003, 155},
|
||||
{0x8006, 155},
|
||||
{0x800a, 155},
|
||||
{0x800f, 155},
|
||||
{0x8018, 155},
|
||||
{0x801f, 155},
|
||||
{0x8029, 155},
|
||||
{0xc038, 155},
|
||||
},
|
||||
/* 161 */
|
||||
{
|
||||
{0x8003, 157},
|
||||
{0x8006, 157},
|
||||
{0x800a, 157},
|
||||
{0x800f, 157},
|
||||
{0x8018, 157},
|
||||
{0x801f, 157},
|
||||
{0x8029, 157},
|
||||
{0xc038, 157},
|
||||
{0x8003, 158},
|
||||
{0x8006, 158},
|
||||
{0x800a, 158},
|
||||
{0x800f, 158},
|
||||
{0x8018, 158},
|
||||
{0x801f, 158},
|
||||
{0x8029, 158},
|
||||
{0xc038, 158},
|
||||
},
|
||||
/* 162 */
|
||||
{
|
||||
{0x8001, 165},
|
||||
{0xc016, 165},
|
||||
{0x8001, 166},
|
||||
{0xc016, 166},
|
||||
{0x8001, 168},
|
||||
{0xc016, 168},
|
||||
{0x8001, 174},
|
||||
{0xc016, 174},
|
||||
{0x8001, 175},
|
||||
{0xc016, 175},
|
||||
{0x8001, 180},
|
||||
{0xc016, 180},
|
||||
{0x8001, 182},
|
||||
{0xc016, 182},
|
||||
{0x8001, 183},
|
||||
{0xc016, 183},
|
||||
},
|
||||
/* 163 */
|
||||
{
|
||||
{0x8002, 165},
|
||||
{0x8009, 165},
|
||||
{0x8017, 165},
|
||||
{0xc028, 165},
|
||||
{0x8002, 166},
|
||||
{0x8009, 166},
|
||||
{0x8017, 166},
|
||||
{0xc028, 166},
|
||||
{0x8002, 168},
|
||||
{0x8009, 168},
|
||||
{0x8017, 168},
|
||||
{0xc028, 168},
|
||||
{0x8002, 174},
|
||||
{0x8009, 174},
|
||||
{0x8017, 174},
|
||||
{0xc028, 174},
|
||||
},
|
||||
/* 164 */
|
||||
{
|
||||
{0x8003, 165},
|
||||
{0x8006, 165},
|
||||
{0x800a, 165},
|
||||
{0x800f, 165},
|
||||
{0x8018, 165},
|
||||
{0x801f, 165},
|
||||
{0x8029, 165},
|
||||
{0xc038, 165},
|
||||
{0x8003, 166},
|
||||
{0x8006, 166},
|
||||
{0x800a, 166},
|
||||
{0x800f, 166},
|
||||
{0x8018, 166},
|
||||
{0x801f, 166},
|
||||
{0x8029, 166},
|
||||
{0xc038, 166},
|
||||
},
|
||||
/* 165 */
|
||||
{
|
||||
{0x8003, 168},
|
||||
{0x8006, 168},
|
||||
{0x800a, 168},
|
||||
{0x800f, 168},
|
||||
{0x8018, 168},
|
||||
{0x801f, 168},
|
||||
{0x8029, 168},
|
||||
{0xc038, 168},
|
||||
{0x8003, 174},
|
||||
{0x8006, 174},
|
||||
{0x800a, 174},
|
||||
{0x800f, 174},
|
||||
{0x8018, 174},
|
||||
{0x801f, 174},
|
||||
{0x8029, 174},
|
||||
{0xc038, 174},
|
||||
},
|
||||
/* 166 */
|
||||
{
|
||||
{0x8002, 175},
|
||||
{0x8009, 175},
|
||||
{0x8017, 175},
|
||||
{0xc028, 175},
|
||||
{0x8002, 180},
|
||||
{0x8009, 180},
|
||||
{0x8017, 180},
|
||||
{0xc028, 180},
|
||||
{0x8002, 182},
|
||||
{0x8009, 182},
|
||||
{0x8017, 182},
|
||||
{0xc028, 182},
|
||||
{0x8002, 183},
|
||||
{0x8009, 183},
|
||||
{0x8017, 183},
|
||||
{0xc028, 183},
|
||||
},
|
||||
/* 167 */
|
||||
{
|
||||
{0x8003, 175},
|
||||
{0x8006, 175},
|
||||
{0x800a, 175},
|
||||
{0x800f, 175},
|
||||
{0x8018, 175},
|
||||
{0x801f, 175},
|
||||
{0x8029, 175},
|
||||
{0xc038, 175},
|
||||
{0x8003, 180},
|
||||
{0x8006, 180},
|
||||
{0x800a, 180},
|
||||
{0x800f, 180},
|
||||
{0x8018, 180},
|
||||
{0x801f, 180},
|
||||
{0x8029, 180},
|
||||
{0xc038, 180},
|
||||
},
|
||||
/* 168 */
|
||||
{
|
||||
{0x8003, 182},
|
||||
{0x8006, 182},
|
||||
{0x800a, 182},
|
||||
{0x800f, 182},
|
||||
{0x8018, 182},
|
||||
{0x801f, 182},
|
||||
{0x8029, 182},
|
||||
{0xc038, 182},
|
||||
{0x8003, 183},
|
||||
{0x8006, 183},
|
||||
{0x800a, 183},
|
||||
{0x800f, 183},
|
||||
{0x8018, 183},
|
||||
{0x801f, 183},
|
||||
{0x8029, 183},
|
||||
{0xc038, 183},
|
||||
},
|
||||
/* 169 */
|
||||
{
|
||||
{0xc000, 188},
|
||||
{0xc000, 191},
|
||||
{0xc000, 197},
|
||||
{0xc000, 231},
|
||||
{0xc000, 239},
|
||||
{0xb0, 0},
|
||||
{0xb2, 0},
|
||||
{0xb3, 0},
|
||||
{0xb7, 0},
|
||||
{0xb8, 0},
|
||||
{0xba, 0},
|
||||
{0xbb, 0},
|
||||
{0xc0, 0},
|
||||
{0xc7, 0},
|
||||
{0xd0, 0},
|
||||
{0xdf, 0},
|
||||
},
|
||||
/* 170 */
|
||||
{
|
||||
{0x8001, 188},
|
||||
{0xc016, 188},
|
||||
{0x8001, 191},
|
||||
{0xc016, 191},
|
||||
{0x8001, 197},
|
||||
{0xc016, 197},
|
||||
{0x8001, 231},
|
||||
{0xc016, 231},
|
||||
{0x8001, 239},
|
||||
{0xc016, 239},
|
||||
{0xc000, 9},
|
||||
{0xc000, 142},
|
||||
{0xc000, 144},
|
||||
{0xc000, 145},
|
||||
{0xc000, 148},
|
||||
{0xc000, 159},
|
||||
},
|
||||
/* 171 */
|
||||
{
|
||||
{0x8002, 188},
|
||||
{0x8009, 188},
|
||||
{0x8017, 188},
|
||||
{0xc028, 188},
|
||||
{0x8002, 191},
|
||||
{0x8009, 191},
|
||||
{0x8017, 191},
|
||||
{0xc028, 191},
|
||||
{0x8002, 197},
|
||||
{0x8009, 197},
|
||||
{0x8017, 197},
|
||||
{0xc028, 197},
|
||||
{0x8002, 231},
|
||||
{0x8009, 231},
|
||||
{0x8017, 231},
|
||||
{0xc028, 231},
|
||||
},
|
||||
/* 172 */
|
||||
{
|
||||
{0x8003, 188},
|
||||
{0x8006, 188},
|
||||
{0x800a, 188},
|
||||
{0x800f, 188},
|
||||
{0x8018, 188},
|
||||
{0x801f, 188},
|
||||
{0x8029, 188},
|
||||
{0xc038, 188},
|
||||
{0x8003, 191},
|
||||
{0x8006, 191},
|
||||
{0x800a, 191},
|
||||
{0x800f, 191},
|
||||
{0x8018, 191},
|
||||
{0x801f, 191},
|
||||
{0x8029, 191},
|
||||
{0xc038, 191},
|
||||
},
|
||||
/* 173 */
|
||||
{
|
||||
{0x8003, 197},
|
||||
{0x8006, 197},
|
||||
{0x800a, 197},
|
||||
{0x800f, 197},
|
||||
{0x8018, 197},
|
||||
{0x801f, 197},
|
||||
{0x8029, 197},
|
||||
{0xc038, 197},
|
||||
{0x8003, 231},
|
||||
{0x8006, 231},
|
||||
{0x800a, 231},
|
||||
{0x800f, 231},
|
||||
{0x8018, 231},
|
||||
{0x801f, 231},
|
||||
{0x8029, 231},
|
||||
{0xc038, 231},
|
||||
},
|
||||
/* 174 */
|
||||
{
|
||||
{0x8002, 239},
|
||||
{0x8009, 239},
|
||||
{0x8017, 239},
|
||||
{0xc028, 239},
|
||||
{0x8001, 9},
|
||||
{0xc016, 9},
|
||||
{0x8001, 142},
|
||||
{0xc016, 142},
|
||||
{0x8001, 144},
|
||||
{0xc016, 144},
|
||||
{0x8001, 145},
|
||||
{0xc016, 145},
|
||||
{0x8001, 148},
|
||||
{0xc016, 148},
|
||||
{0x8001, 159},
|
||||
{0xc016, 159},
|
||||
},
|
||||
/* 175 */
|
||||
{
|
||||
{0x8003, 239},
|
||||
{0x8006, 239},
|
||||
{0x800a, 239},
|
||||
{0x800f, 239},
|
||||
{0x8018, 239},
|
||||
{0x801f, 239},
|
||||
{0x8029, 239},
|
||||
{0xc038, 239},
|
||||
{0x8002, 9},
|
||||
{0x8009, 9},
|
||||
{0x8017, 9},
|
||||
{0xc028, 9},
|
||||
{0x8002, 142},
|
||||
{0x8009, 142},
|
||||
{0x8017, 142},
|
||||
{0xc028, 142},
|
||||
},
|
||||
/* 176 */
|
||||
{
|
||||
{0x8003, 9},
|
||||
{0x8006, 9},
|
||||
{0x800a, 9},
|
||||
{0x800f, 9},
|
||||
{0x8018, 9},
|
||||
{0x801f, 9},
|
||||
{0x8029, 9},
|
||||
{0xc038, 9},
|
||||
{0x8003, 142},
|
||||
{0x8006, 142},
|
||||
{0x800a, 142},
|
||||
{0x800f, 142},
|
||||
{0x8018, 142},
|
||||
{0x801f, 142},
|
||||
{0x8029, 142},
|
||||
{0xc038, 142},
|
||||
},
|
||||
/* 177 */
|
||||
{
|
||||
{0x8002, 144},
|
||||
{0x8009, 144},
|
||||
{0x8017, 144},
|
||||
{0xc028, 144},
|
||||
{0x8002, 145},
|
||||
{0x8009, 145},
|
||||
{0x8017, 145},
|
||||
{0xc028, 145},
|
||||
{0x8002, 148},
|
||||
{0x8009, 148},
|
||||
{0x8017, 148},
|
||||
{0xc028, 148},
|
||||
{0x8002, 159},
|
||||
{0x8009, 159},
|
||||
{0x8017, 159},
|
||||
{0xc028, 159},
|
||||
},
|
||||
/* 178 */
|
||||
{
|
||||
{0x8003, 144},
|
||||
{0x8006, 144},
|
||||
{0x800a, 144},
|
||||
{0x800f, 144},
|
||||
{0x8018, 144},
|
||||
{0x801f, 144},
|
||||
{0x8029, 144},
|
||||
{0xc038, 144},
|
||||
{0x8003, 145},
|
||||
{0x8006, 145},
|
||||
{0x800a, 145},
|
||||
{0x800f, 145},
|
||||
{0x8018, 145},
|
||||
{0x801f, 145},
|
||||
{0x8029, 145},
|
||||
{0xc038, 145},
|
||||
},
|
||||
/* 179 */
|
||||
{
|
||||
{0x8003, 148},
|
||||
{0x8006, 148},
|
||||
{0x800a, 148},
|
||||
{0x800f, 148},
|
||||
{0x8018, 148},
|
||||
{0x801f, 148},
|
||||
{0x8029, 148},
|
||||
{0xc038, 148},
|
||||
{0x8003, 159},
|
||||
{0x8006, 159},
|
||||
{0x800a, 159},
|
||||
{0x800f, 159},
|
||||
{0x8018, 159},
|
||||
{0x801f, 159},
|
||||
{0x8029, 159},
|
||||
{0xc038, 159},
|
||||
},
|
||||
/* 180 */
|
||||
{
|
||||
{0xc000, 171},
|
||||
{0xc000, 206},
|
||||
{0xc000, 215},
|
||||
{0xc000, 225},
|
||||
{0xc000, 236},
|
||||
{0xc000, 237},
|
||||
{0xbc, 0},
|
||||
{0xbd, 0},
|
||||
{0xc1, 0},
|
||||
{0xc4, 0},
|
||||
{0xc8, 0},
|
||||
{0xcb, 0},
|
||||
{0xd1, 0},
|
||||
{0xd8, 0},
|
||||
{0xe0, 0},
|
||||
{0xee, 0},
|
||||
},
|
||||
/* 181 */
|
||||
{
|
||||
{0x8001, 171},
|
||||
{0xc016, 171},
|
||||
{0x8001, 206},
|
||||
{0xc016, 206},
|
||||
{0x8001, 215},
|
||||
{0xc016, 215},
|
||||
{0x8001, 225},
|
||||
{0xc016, 225},
|
||||
{0x8001, 236},
|
||||
{0xc016, 236},
|
||||
{0x8001, 237},
|
||||
{0xc016, 237},
|
||||
{0xc000, 199},
|
||||
{0xc000, 207},
|
||||
{0xc000, 234},
|
||||
{0xc000, 235},
|
||||
},
|
||||
/* 182 */
|
||||
{
|
||||
{0x8002, 171},
|
||||
{0x8009, 171},
|
||||
{0x8017, 171},
|
||||
{0xc028, 171},
|
||||
{0x8002, 206},
|
||||
{0x8009, 206},
|
||||
{0x8017, 206},
|
||||
{0xc028, 206},
|
||||
{0x8002, 215},
|
||||
{0x8009, 215},
|
||||
{0x8017, 215},
|
||||
{0xc028, 215},
|
||||
{0x8002, 225},
|
||||
{0x8009, 225},
|
||||
{0x8017, 225},
|
||||
{0xc028, 225},
|
||||
},
|
||||
/* 183 */
|
||||
{
|
||||
{0x8003, 171},
|
||||
{0x8006, 171},
|
||||
{0x800a, 171},
|
||||
{0x800f, 171},
|
||||
{0x8018, 171},
|
||||
{0x801f, 171},
|
||||
{0x8029, 171},
|
||||
{0xc038, 171},
|
||||
{0x8003, 206},
|
||||
{0x8006, 206},
|
||||
{0x800a, 206},
|
||||
{0x800f, 206},
|
||||
{0x8018, 206},
|
||||
{0x801f, 206},
|
||||
{0x8029, 206},
|
||||
{0xc038, 206},
|
||||
},
|
||||
/* 184 */
|
||||
{
|
||||
{0x8003, 215},
|
||||
{0x8006, 215},
|
||||
{0x800a, 215},
|
||||
{0x800f, 215},
|
||||
{0x8018, 215},
|
||||
{0x801f, 215},
|
||||
{0x8029, 215},
|
||||
{0xc038, 215},
|
||||
{0x8003, 225},
|
||||
{0x8006, 225},
|
||||
{0x800a, 225},
|
||||
{0x800f, 225},
|
||||
{0x8018, 225},
|
||||
{0x801f, 225},
|
||||
{0x8029, 225},
|
||||
{0xc038, 225},
|
||||
},
|
||||
/* 185 */
|
||||
{
|
||||
{0x8002, 236},
|
||||
{0x8009, 236},
|
||||
{0x8017, 236},
|
||||
{0xc028, 236},
|
||||
{0x8002, 237},
|
||||
{0x8009, 237},
|
||||
{0x8017, 237},
|
||||
{0xc028, 237},
|
||||
{0x8001, 199},
|
||||
{0xc016, 199},
|
||||
{0x8001, 207},
|
||||
{0xc016, 207},
|
||||
{0x8001, 234},
|
||||
{0xc016, 234},
|
||||
{0x8001, 235},
|
||||
{0xc016, 235},
|
||||
},
|
||||
/* 186 */
|
||||
{
|
||||
{0x8003, 236},
|
||||
{0x8006, 236},
|
||||
{0x800a, 236},
|
||||
{0x800f, 236},
|
||||
{0x8018, 236},
|
||||
{0x801f, 236},
|
||||
{0x8029, 236},
|
||||
{0xc038, 236},
|
||||
{0x8003, 237},
|
||||
{0x8006, 237},
|
||||
{0x800a, 237},
|
||||
{0x800f, 237},
|
||||
{0x8018, 237},
|
||||
{0x801f, 237},
|
||||
{0x8029, 237},
|
||||
{0xc038, 237},
|
||||
},
|
||||
/* 187 */
|
||||
{
|
||||
{0x8002, 199},
|
||||
{0x8009, 199},
|
||||
{0x8017, 199},
|
||||
{0xc028, 199},
|
||||
{0x8002, 207},
|
||||
{0x8009, 207},
|
||||
{0x8017, 207},
|
||||
{0xc028, 207},
|
||||
{0x8002, 234},
|
||||
{0x8009, 234},
|
||||
{0x8017, 234},
|
||||
{0xc028, 234},
|
||||
{0x8002, 235},
|
||||
{0x8009, 235},
|
||||
{0x8017, 235},
|
||||
{0xc028, 235},
|
||||
},
|
||||
/* 188 */
|
||||
{
|
||||
{0x8003, 199},
|
||||
{0x8006, 199},
|
||||
{0x800a, 199},
|
||||
{0x800f, 199},
|
||||
{0x8018, 199},
|
||||
{0x801f, 199},
|
||||
{0x8029, 199},
|
||||
{0xc038, 199},
|
||||
{0x8003, 207},
|
||||
{0x8006, 207},
|
||||
{0x800a, 207},
|
||||
{0x800f, 207},
|
||||
{0x8018, 207},
|
||||
{0x801f, 207},
|
||||
{0x8029, 207},
|
||||
{0xc038, 207},
|
||||
},
|
||||
/* 189 */
|
||||
{
|
||||
{0x8003, 234},
|
||||
{0x8006, 234},
|
||||
{0x800a, 234},
|
||||
{0x800f, 234},
|
||||
{0x8018, 234},
|
||||
{0x801f, 234},
|
||||
{0x8029, 234},
|
||||
{0xc038, 234},
|
||||
{0x8003, 235},
|
||||
{0x8006, 235},
|
||||
{0x800a, 235},
|
||||
{0x800f, 235},
|
||||
{0x8018, 235},
|
||||
{0x801f, 235},
|
||||
{0x8029, 235},
|
||||
{0xc038, 235},
|
||||
},
|
||||
/* 190 */
|
||||
{
|
||||
{0xc2, 0},
|
||||
{0xc3, 0},
|
||||
{0xc5, 0},
|
||||
{0xc6, 0},
|
||||
{0xc9, 0},
|
||||
{0xca, 0},
|
||||
{0xcc, 0},
|
||||
{0xcd, 0},
|
||||
{0xd2, 0},
|
||||
{0xd5, 0},
|
||||
{0xd9, 0},
|
||||
{0xdc, 0},
|
||||
{0xe1, 0},
|
||||
{0xe7, 0},
|
||||
{0xef, 0},
|
||||
{0xf6, 0},
|
||||
},
|
||||
/* 191 */
|
||||
{
|
||||
{0xc000, 192},
|
||||
{0xc000, 193},
|
||||
{0xc000, 200},
|
||||
{0xc000, 201},
|
||||
{0xc000, 202},
|
||||
{0xc000, 205},
|
||||
{0xc000, 210},
|
||||
{0xc000, 213},
|
||||
{0xc000, 218},
|
||||
{0xc000, 219},
|
||||
{0xc000, 238},
|
||||
{0xc000, 240},
|
||||
{0xc000, 242},
|
||||
{0xc000, 243},
|
||||
{0xc000, 255},
|
||||
{0xce, 0},
|
||||
},
|
||||
/* 192 */
|
||||
{
|
||||
{0x8001, 192},
|
||||
{0xc016, 192},
|
||||
{0x8001, 193},
|
||||
{0xc016, 193},
|
||||
{0x8001, 200},
|
||||
{0xc016, 200},
|
||||
{0x8001, 201},
|
||||
{0xc016, 201},
|
||||
{0x8001, 202},
|
||||
{0xc016, 202},
|
||||
{0x8001, 205},
|
||||
{0xc016, 205},
|
||||
{0x8001, 210},
|
||||
{0xc016, 210},
|
||||
{0x8001, 213},
|
||||
{0xc016, 213},
|
||||
},
|
||||
/* 193 */
|
||||
{
|
||||
{0x8002, 192},
|
||||
{0x8009, 192},
|
||||
{0x8017, 192},
|
||||
{0xc028, 192},
|
||||
{0x8002, 193},
|
||||
{0x8009, 193},
|
||||
{0x8017, 193},
|
||||
{0xc028, 193},
|
||||
{0x8002, 200},
|
||||
{0x8009, 200},
|
||||
{0x8017, 200},
|
||||
{0xc028, 200},
|
||||
{0x8002, 201},
|
||||
{0x8009, 201},
|
||||
{0x8017, 201},
|
||||
{0xc028, 201},
|
||||
},
|
||||
/* 194 */
|
||||
{
|
||||
{0x8003, 192},
|
||||
{0x8006, 192},
|
||||
{0x800a, 192},
|
||||
{0x800f, 192},
|
||||
{0x8018, 192},
|
||||
{0x801f, 192},
|
||||
{0x8029, 192},
|
||||
{0xc038, 192},
|
||||
{0x8003, 193},
|
||||
{0x8006, 193},
|
||||
{0x800a, 193},
|
||||
{0x800f, 193},
|
||||
{0x8018, 193},
|
||||
{0x801f, 193},
|
||||
{0x8029, 193},
|
||||
{0xc038, 193},
|
||||
},
|
||||
/* 195 */
|
||||
{
|
||||
{0x8003, 200},
|
||||
{0x8006, 200},
|
||||
{0x800a, 200},
|
||||
{0x800f, 200},
|
||||
{0x8018, 200},
|
||||
{0x801f, 200},
|
||||
{0x8029, 200},
|
||||
{0xc038, 200},
|
||||
{0x8003, 201},
|
||||
{0x8006, 201},
|
||||
{0x800a, 201},
|
||||
{0x800f, 201},
|
||||
{0x8018, 201},
|
||||
{0x801f, 201},
|
||||
{0x8029, 201},
|
||||
{0xc038, 201},
|
||||
},
|
||||
/* 196 */
|
||||
{
|
||||
{0x8002, 202},
|
||||
{0x8009, 202},
|
||||
{0x8017, 202},
|
||||
{0xc028, 202},
|
||||
{0x8002, 205},
|
||||
{0x8009, 205},
|
||||
{0x8017, 205},
|
||||
{0xc028, 205},
|
||||
{0x8002, 210},
|
||||
{0x8009, 210},
|
||||
{0x8017, 210},
|
||||
{0xc028, 210},
|
||||
{0x8002, 213},
|
||||
{0x8009, 213},
|
||||
{0x8017, 213},
|
||||
{0xc028, 213},
|
||||
},
|
||||
/* 197 */
|
||||
{
|
||||
{0x8003, 202},
|
||||
{0x8006, 202},
|
||||
{0x800a, 202},
|
||||
{0x800f, 202},
|
||||
{0x8018, 202},
|
||||
{0x801f, 202},
|
||||
{0x8029, 202},
|
||||
{0xc038, 202},
|
||||
{0x8003, 205},
|
||||
{0x8006, 205},
|
||||
{0x800a, 205},
|
||||
{0x800f, 205},
|
||||
{0x8018, 205},
|
||||
{0x801f, 205},
|
||||
{0x8029, 205},
|
||||
{0xc038, 205},
|
||||
},
|
||||
/* 198 */
|
||||
{
|
||||
{0x8003, 210},
|
||||
{0x8006, 210},
|
||||
{0x800a, 210},
|
||||
{0x800f, 210},
|
||||
{0x8018, 210},
|
||||
{0x801f, 210},
|
||||
{0x8029, 210},
|
||||
{0xc038, 210},
|
||||
{0x8003, 213},
|
||||
{0x8006, 213},
|
||||
{0x800a, 213},
|
||||
{0x800f, 213},
|
||||
{0x8018, 213},
|
||||
{0x801f, 213},
|
||||
{0x8029, 213},
|
||||
{0xc038, 213},
|
||||
},
|
||||
/* 199 */
|
||||
{
|
||||
{0x8001, 218},
|
||||
{0xc016, 218},
|
||||
{0x8001, 219},
|
||||
{0xc016, 219},
|
||||
{0x8001, 238},
|
||||
{0xc016, 238},
|
||||
{0x8001, 240},
|
||||
{0xc016, 240},
|
||||
{0x8001, 242},
|
||||
{0xc016, 242},
|
||||
{0x8001, 243},
|
||||
{0xc016, 243},
|
||||
{0x8001, 255},
|
||||
{0xc016, 255},
|
||||
{0xc000, 203},
|
||||
{0xc000, 204},
|
||||
},
|
||||
/* 200 */
|
||||
{
|
||||
{0x8002, 218},
|
||||
{0x8009, 218},
|
||||
{0x8017, 218},
|
||||
{0xc028, 218},
|
||||
{0x8002, 219},
|
||||
{0x8009, 219},
|
||||
{0x8017, 219},
|
||||
{0xc028, 219},
|
||||
{0x8002, 238},
|
||||
{0x8009, 238},
|
||||
{0x8017, 238},
|
||||
{0xc028, 238},
|
||||
{0x8002, 240},
|
||||
{0x8009, 240},
|
||||
{0x8017, 240},
|
||||
{0xc028, 240},
|
||||
},
|
||||
/* 201 */
|
||||
{
|
||||
{0x8003, 218},
|
||||
{0x8006, 218},
|
||||
{0x800a, 218},
|
||||
{0x800f, 218},
|
||||
{0x8018, 218},
|
||||
{0x801f, 218},
|
||||
{0x8029, 218},
|
||||
{0xc038, 218},
|
||||
{0x8003, 219},
|
||||
{0x8006, 219},
|
||||
{0x800a, 219},
|
||||
{0x800f, 219},
|
||||
{0x8018, 219},
|
||||
{0x801f, 219},
|
||||
{0x8029, 219},
|
||||
{0xc038, 219},
|
||||
},
|
||||
/* 202 */
|
||||
{
|
||||
{0x8003, 238},
|
||||
{0x8006, 238},
|
||||
{0x800a, 238},
|
||||
{0x800f, 238},
|
||||
{0x8018, 238},
|
||||
{0x801f, 238},
|
||||
{0x8029, 238},
|
||||
{0xc038, 238},
|
||||
{0x8003, 240},
|
||||
{0x8006, 240},
|
||||
{0x800a, 240},
|
||||
{0x800f, 240},
|
||||
{0x8018, 240},
|
||||
{0x801f, 240},
|
||||
{0x8029, 240},
|
||||
{0xc038, 240},
|
||||
},
|
||||
/* 203 */
|
||||
{
|
||||
{0x8002, 242},
|
||||
{0x8009, 242},
|
||||
{0x8017, 242},
|
||||
{0xc028, 242},
|
||||
{0x8002, 243},
|
||||
{0x8009, 243},
|
||||
{0x8017, 243},
|
||||
{0xc028, 243},
|
||||
{0x8002, 255},
|
||||
{0x8009, 255},
|
||||
{0x8017, 255},
|
||||
{0xc028, 255},
|
||||
{0x8001, 203},
|
||||
{0xc016, 203},
|
||||
{0x8001, 204},
|
||||
{0xc016, 204},
|
||||
},
|
||||
/* 204 */
|
||||
{
|
||||
{0x8003, 242},
|
||||
{0x8006, 242},
|
||||
{0x800a, 242},
|
||||
{0x800f, 242},
|
||||
{0x8018, 242},
|
||||
{0x801f, 242},
|
||||
{0x8029, 242},
|
||||
{0xc038, 242},
|
||||
{0x8003, 243},
|
||||
{0x8006, 243},
|
||||
{0x800a, 243},
|
||||
{0x800f, 243},
|
||||
{0x8018, 243},
|
||||
{0x801f, 243},
|
||||
{0x8029, 243},
|
||||
{0xc038, 243},
|
||||
},
|
||||
/* 205 */
|
||||
{
|
||||
{0x8003, 255},
|
||||
{0x8006, 255},
|
||||
{0x800a, 255},
|
||||
{0x800f, 255},
|
||||
{0x8018, 255},
|
||||
{0x801f, 255},
|
||||
{0x8029, 255},
|
||||
{0xc038, 255},
|
||||
{0x8002, 203},
|
||||
{0x8009, 203},
|
||||
{0x8017, 203},
|
||||
{0xc028, 203},
|
||||
{0x8002, 204},
|
||||
{0x8009, 204},
|
||||
{0x8017, 204},
|
||||
{0xc028, 204},
|
||||
},
|
||||
/* 206 */
|
||||
{
|
||||
{0x8003, 203},
|
||||
{0x8006, 203},
|
||||
{0x800a, 203},
|
||||
{0x800f, 203},
|
||||
{0x8018, 203},
|
||||
{0x801f, 203},
|
||||
{0x8029, 203},
|
||||
{0xc038, 203},
|
||||
{0x8003, 204},
|
||||
{0x8006, 204},
|
||||
{0x800a, 204},
|
||||
{0x800f, 204},
|
||||
{0x8018, 204},
|
||||
{0x801f, 204},
|
||||
{0x8029, 204},
|
||||
{0xc038, 204},
|
||||
},
|
||||
/* 207 */
|
||||
{
|
||||
{0xd3, 0},
|
||||
{0xd4, 0},
|
||||
{0xd6, 0},
|
||||
{0xd7, 0},
|
||||
{0xda, 0},
|
||||
{0xdb, 0},
|
||||
{0xdd, 0},
|
||||
{0xde, 0},
|
||||
{0xe2, 0},
|
||||
{0xe4, 0},
|
||||
{0xe8, 0},
|
||||
{0xeb, 0},
|
||||
{0xf0, 0},
|
||||
{0xf3, 0},
|
||||
{0xf7, 0},
|
||||
{0xfa, 0},
|
||||
},
|
||||
/* 208 */
|
||||
{
|
||||
{0xc000, 211},
|
||||
{0xc000, 212},
|
||||
{0xc000, 214},
|
||||
{0xc000, 221},
|
||||
{0xc000, 222},
|
||||
{0xc000, 223},
|
||||
{0xc000, 241},
|
||||
{0xc000, 244},
|
||||
{0xc000, 245},
|
||||
{0xc000, 246},
|
||||
{0xc000, 247},
|
||||
{0xc000, 248},
|
||||
{0xc000, 250},
|
||||
{0xc000, 251},
|
||||
{0xc000, 252},
|
||||
{0xc000, 253},
|
||||
},
|
||||
/* 209 */
|
||||
{
|
||||
{0x8001, 211},
|
||||
{0xc016, 211},
|
||||
{0x8001, 212},
|
||||
{0xc016, 212},
|
||||
{0x8001, 214},
|
||||
{0xc016, 214},
|
||||
{0x8001, 221},
|
||||
{0xc016, 221},
|
||||
{0x8001, 222},
|
||||
{0xc016, 222},
|
||||
{0x8001, 223},
|
||||
{0xc016, 223},
|
||||
{0x8001, 241},
|
||||
{0xc016, 241},
|
||||
{0x8001, 244},
|
||||
{0xc016, 244},
|
||||
},
|
||||
/* 210 */
|
||||
{
|
||||
{0x8002, 211},
|
||||
{0x8009, 211},
|
||||
{0x8017, 211},
|
||||
{0xc028, 211},
|
||||
{0x8002, 212},
|
||||
{0x8009, 212},
|
||||
{0x8017, 212},
|
||||
{0xc028, 212},
|
||||
{0x8002, 214},
|
||||
{0x8009, 214},
|
||||
{0x8017, 214},
|
||||
{0xc028, 214},
|
||||
{0x8002, 221},
|
||||
{0x8009, 221},
|
||||
{0x8017, 221},
|
||||
{0xc028, 221},
|
||||
},
|
||||
/* 211 */
|
||||
{
|
||||
{0x8003, 211},
|
||||
{0x8006, 211},
|
||||
{0x800a, 211},
|
||||
{0x800f, 211},
|
||||
{0x8018, 211},
|
||||
{0x801f, 211},
|
||||
{0x8029, 211},
|
||||
{0xc038, 211},
|
||||
{0x8003, 212},
|
||||
{0x8006, 212},
|
||||
{0x800a, 212},
|
||||
{0x800f, 212},
|
||||
{0x8018, 212},
|
||||
{0x801f, 212},
|
||||
{0x8029, 212},
|
||||
{0xc038, 212},
|
||||
},
|
||||
/* 212 */
|
||||
{
|
||||
{0x8003, 214},
|
||||
{0x8006, 214},
|
||||
{0x800a, 214},
|
||||
{0x800f, 214},
|
||||
{0x8018, 214},
|
||||
{0x801f, 214},
|
||||
{0x8029, 214},
|
||||
{0xc038, 214},
|
||||
{0x8003, 221},
|
||||
{0x8006, 221},
|
||||
{0x800a, 221},
|
||||
{0x800f, 221},
|
||||
{0x8018, 221},
|
||||
{0x801f, 221},
|
||||
{0x8029, 221},
|
||||
{0xc038, 221},
|
||||
},
|
||||
/* 213 */
|
||||
{
|
||||
{0x8002, 222},
|
||||
{0x8009, 222},
|
||||
{0x8017, 222},
|
||||
{0xc028, 222},
|
||||
{0x8002, 223},
|
||||
{0x8009, 223},
|
||||
{0x8017, 223},
|
||||
{0xc028, 223},
|
||||
{0x8002, 241},
|
||||
{0x8009, 241},
|
||||
{0x8017, 241},
|
||||
{0xc028, 241},
|
||||
{0x8002, 244},
|
||||
{0x8009, 244},
|
||||
{0x8017, 244},
|
||||
{0xc028, 244},
|
||||
},
|
||||
/* 214 */
|
||||
{
|
||||
{0x8003, 222},
|
||||
{0x8006, 222},
|
||||
{0x800a, 222},
|
||||
{0x800f, 222},
|
||||
{0x8018, 222},
|
||||
{0x801f, 222},
|
||||
{0x8029, 222},
|
||||
{0xc038, 222},
|
||||
{0x8003, 223},
|
||||
{0x8006, 223},
|
||||
{0x800a, 223},
|
||||
{0x800f, 223},
|
||||
{0x8018, 223},
|
||||
{0x801f, 223},
|
||||
{0x8029, 223},
|
||||
{0xc038, 223},
|
||||
},
|
||||
/* 215 */
|
||||
{
|
||||
{0x8003, 241},
|
||||
{0x8006, 241},
|
||||
{0x800a, 241},
|
||||
{0x800f, 241},
|
||||
{0x8018, 241},
|
||||
{0x801f, 241},
|
||||
{0x8029, 241},
|
||||
{0xc038, 241},
|
||||
{0x8003, 244},
|
||||
{0x8006, 244},
|
||||
{0x800a, 244},
|
||||
{0x800f, 244},
|
||||
{0x8018, 244},
|
||||
{0x801f, 244},
|
||||
{0x8029, 244},
|
||||
{0xc038, 244},
|
||||
},
|
||||
/* 216 */
|
||||
{
|
||||
{0x8001, 245},
|
||||
{0xc016, 245},
|
||||
{0x8001, 246},
|
||||
{0xc016, 246},
|
||||
{0x8001, 247},
|
||||
{0xc016, 247},
|
||||
{0x8001, 248},
|
||||
{0xc016, 248},
|
||||
{0x8001, 250},
|
||||
{0xc016, 250},
|
||||
{0x8001, 251},
|
||||
{0xc016, 251},
|
||||
{0x8001, 252},
|
||||
{0xc016, 252},
|
||||
{0x8001, 253},
|
||||
{0xc016, 253},
|
||||
},
|
||||
/* 217 */
|
||||
{
|
||||
{0x8002, 245},
|
||||
{0x8009, 245},
|
||||
{0x8017, 245},
|
||||
{0xc028, 245},
|
||||
{0x8002, 246},
|
||||
{0x8009, 246},
|
||||
{0x8017, 246},
|
||||
{0xc028, 246},
|
||||
{0x8002, 247},
|
||||
{0x8009, 247},
|
||||
{0x8017, 247},
|
||||
{0xc028, 247},
|
||||
{0x8002, 248},
|
||||
{0x8009, 248},
|
||||
{0x8017, 248},
|
||||
{0xc028, 248},
|
||||
},
|
||||
/* 218 */
|
||||
{
|
||||
{0x8003, 245},
|
||||
{0x8006, 245},
|
||||
{0x800a, 245},
|
||||
{0x800f, 245},
|
||||
{0x8018, 245},
|
||||
{0x801f, 245},
|
||||
{0x8029, 245},
|
||||
{0xc038, 245},
|
||||
{0x8003, 246},
|
||||
{0x8006, 246},
|
||||
{0x800a, 246},
|
||||
{0x800f, 246},
|
||||
{0x8018, 246},
|
||||
{0x801f, 246},
|
||||
{0x8029, 246},
|
||||
{0xc038, 246},
|
||||
},
|
||||
/* 219 */
|
||||
{
|
||||
{0x8003, 247},
|
||||
{0x8006, 247},
|
||||
{0x800a, 247},
|
||||
{0x800f, 247},
|
||||
{0x8018, 247},
|
||||
{0x801f, 247},
|
||||
{0x8029, 247},
|
||||
{0xc038, 247},
|
||||
{0x8003, 248},
|
||||
{0x8006, 248},
|
||||
{0x800a, 248},
|
||||
{0x800f, 248},
|
||||
{0x8018, 248},
|
||||
{0x801f, 248},
|
||||
{0x8029, 248},
|
||||
{0xc038, 248},
|
||||
},
|
||||
/* 220 */
|
||||
{
|
||||
{0x8002, 250},
|
||||
{0x8009, 250},
|
||||
{0x8017, 250},
|
||||
{0xc028, 250},
|
||||
{0x8002, 251},
|
||||
{0x8009, 251},
|
||||
{0x8017, 251},
|
||||
{0xc028, 251},
|
||||
{0x8002, 252},
|
||||
{0x8009, 252},
|
||||
{0x8017, 252},
|
||||
{0xc028, 252},
|
||||
{0x8002, 253},
|
||||
{0x8009, 253},
|
||||
{0x8017, 253},
|
||||
{0xc028, 253},
|
||||
},
|
||||
/* 221 */
|
||||
{
|
||||
{0x8003, 250},
|
||||
{0x8006, 250},
|
||||
{0x800a, 250},
|
||||
{0x800f, 250},
|
||||
{0x8018, 250},
|
||||
{0x801f, 250},
|
||||
{0x8029, 250},
|
||||
{0xc038, 250},
|
||||
{0x8003, 251},
|
||||
{0x8006, 251},
|
||||
{0x800a, 251},
|
||||
{0x800f, 251},
|
||||
{0x8018, 251},
|
||||
{0x801f, 251},
|
||||
{0x8029, 251},
|
||||
{0xc038, 251},
|
||||
},
|
||||
/* 222 */
|
||||
{
|
||||
{0x8003, 252},
|
||||
{0x8006, 252},
|
||||
{0x800a, 252},
|
||||
{0x800f, 252},
|
||||
{0x8018, 252},
|
||||
{0x801f, 252},
|
||||
{0x8029, 252},
|
||||
{0xc038, 252},
|
||||
{0x8003, 253},
|
||||
{0x8006, 253},
|
||||
{0x800a, 253},
|
||||
{0x800f, 253},
|
||||
{0x8018, 253},
|
||||
{0x801f, 253},
|
||||
{0x8029, 253},
|
||||
{0xc038, 253},
|
||||
},
|
||||
/* 223 */
|
||||
{
|
||||
{0xc000, 254},
|
||||
{0xe3, 0},
|
||||
{0xe5, 0},
|
||||
{0xe6, 0},
|
||||
{0xe9, 0},
|
||||
{0xea, 0},
|
||||
{0xec, 0},
|
||||
{0xed, 0},
|
||||
{0xf1, 0},
|
||||
{0xf2, 0},
|
||||
{0xf4, 0},
|
||||
{0xf5, 0},
|
||||
{0xf8, 0},
|
||||
{0xf9, 0},
|
||||
{0xfb, 0},
|
||||
{0xfc, 0},
|
||||
},
|
||||
/* 224 */
|
||||
{
|
||||
{0x8001, 254},
|
||||
{0xc016, 254},
|
||||
{0xc000, 2},
|
||||
{0xc000, 3},
|
||||
{0xc000, 4},
|
||||
{0xc000, 5},
|
||||
{0xc000, 6},
|
||||
{0xc000, 7},
|
||||
{0xc000, 8},
|
||||
{0xc000, 11},
|
||||
{0xc000, 12},
|
||||
{0xc000, 14},
|
||||
{0xc000, 15},
|
||||
{0xc000, 16},
|
||||
{0xc000, 17},
|
||||
{0xc000, 18},
|
||||
},
|
||||
/* 225 */
|
||||
{
|
||||
{0x8002, 254},
|
||||
{0x8009, 254},
|
||||
{0x8017, 254},
|
||||
{0xc028, 254},
|
||||
{0x8001, 2},
|
||||
{0xc016, 2},
|
||||
{0x8001, 3},
|
||||
{0xc016, 3},
|
||||
{0x8001, 4},
|
||||
{0xc016, 4},
|
||||
{0x8001, 5},
|
||||
{0xc016, 5},
|
||||
{0x8001, 6},
|
||||
{0xc016, 6},
|
||||
{0x8001, 7},
|
||||
{0xc016, 7},
|
||||
},
|
||||
/* 226 */
|
||||
{
|
||||
{0x8003, 254},
|
||||
{0x8006, 254},
|
||||
{0x800a, 254},
|
||||
{0x800f, 254},
|
||||
{0x8018, 254},
|
||||
{0x801f, 254},
|
||||
{0x8029, 254},
|
||||
{0xc038, 254},
|
||||
{0x8002, 2},
|
||||
{0x8009, 2},
|
||||
{0x8017, 2},
|
||||
{0xc028, 2},
|
||||
{0x8002, 3},
|
||||
{0x8009, 3},
|
||||
{0x8017, 3},
|
||||
{0xc028, 3},
|
||||
},
|
||||
/* 227 */
|
||||
{
|
||||
{0x8003, 2},
|
||||
{0x8006, 2},
|
||||
{0x800a, 2},
|
||||
{0x800f, 2},
|
||||
{0x8018, 2},
|
||||
{0x801f, 2},
|
||||
{0x8029, 2},
|
||||
{0xc038, 2},
|
||||
{0x8003, 3},
|
||||
{0x8006, 3},
|
||||
{0x800a, 3},
|
||||
{0x800f, 3},
|
||||
{0x8018, 3},
|
||||
{0x801f, 3},
|
||||
{0x8029, 3},
|
||||
{0xc038, 3},
|
||||
},
|
||||
/* 228 */
|
||||
{
|
||||
{0x8002, 4},
|
||||
{0x8009, 4},
|
||||
{0x8017, 4},
|
||||
{0xc028, 4},
|
||||
{0x8002, 5},
|
||||
{0x8009, 5},
|
||||
{0x8017, 5},
|
||||
{0xc028, 5},
|
||||
{0x8002, 6},
|
||||
{0x8009, 6},
|
||||
{0x8017, 6},
|
||||
{0xc028, 6},
|
||||
{0x8002, 7},
|
||||
{0x8009, 7},
|
||||
{0x8017, 7},
|
||||
{0xc028, 7},
|
||||
},
|
||||
/* 229 */
|
||||
{
|
||||
{0x8003, 4},
|
||||
{0x8006, 4},
|
||||
{0x800a, 4},
|
||||
{0x800f, 4},
|
||||
{0x8018, 4},
|
||||
{0x801f, 4},
|
||||
{0x8029, 4},
|
||||
{0xc038, 4},
|
||||
{0x8003, 5},
|
||||
{0x8006, 5},
|
||||
{0x800a, 5},
|
||||
{0x800f, 5},
|
||||
{0x8018, 5},
|
||||
{0x801f, 5},
|
||||
{0x8029, 5},
|
||||
{0xc038, 5},
|
||||
},
|
||||
/* 230 */
|
||||
{
|
||||
{0x8003, 6},
|
||||
{0x8006, 6},
|
||||
{0x800a, 6},
|
||||
{0x800f, 6},
|
||||
{0x8018, 6},
|
||||
{0x801f, 6},
|
||||
{0x8029, 6},
|
||||
{0xc038, 6},
|
||||
{0x8003, 7},
|
||||
{0x8006, 7},
|
||||
{0x800a, 7},
|
||||
{0x800f, 7},
|
||||
{0x8018, 7},
|
||||
{0x801f, 7},
|
||||
{0x8029, 7},
|
||||
{0xc038, 7},
|
||||
},
|
||||
/* 231 */
|
||||
{
|
||||
{0x8001, 8},
|
||||
{0xc016, 8},
|
||||
{0x8001, 11},
|
||||
{0xc016, 11},
|
||||
{0x8001, 12},
|
||||
{0xc016, 12},
|
||||
{0x8001, 14},
|
||||
{0xc016, 14},
|
||||
{0x8001, 15},
|
||||
{0xc016, 15},
|
||||
{0x8001, 16},
|
||||
{0xc016, 16},
|
||||
{0x8001, 17},
|
||||
{0xc016, 17},
|
||||
{0x8001, 18},
|
||||
{0xc016, 18},
|
||||
},
|
||||
/* 232 */
|
||||
{
|
||||
{0x8002, 8},
|
||||
{0x8009, 8},
|
||||
{0x8017, 8},
|
||||
{0xc028, 8},
|
||||
{0x8002, 11},
|
||||
{0x8009, 11},
|
||||
{0x8017, 11},
|
||||
{0xc028, 11},
|
||||
{0x8002, 12},
|
||||
{0x8009, 12},
|
||||
{0x8017, 12},
|
||||
{0xc028, 12},
|
||||
{0x8002, 14},
|
||||
{0x8009, 14},
|
||||
{0x8017, 14},
|
||||
{0xc028, 14},
|
||||
},
|
||||
/* 233 */
|
||||
{
|
||||
{0x8003, 8},
|
||||
{0x8006, 8},
|
||||
{0x800a, 8},
|
||||
{0x800f, 8},
|
||||
{0x8018, 8},
|
||||
{0x801f, 8},
|
||||
{0x8029, 8},
|
||||
{0xc038, 8},
|
||||
{0x8003, 11},
|
||||
{0x8006, 11},
|
||||
{0x800a, 11},
|
||||
{0x800f, 11},
|
||||
{0x8018, 11},
|
||||
{0x801f, 11},
|
||||
{0x8029, 11},
|
||||
{0xc038, 11},
|
||||
},
|
||||
/* 234 */
|
||||
{
|
||||
{0x8003, 12},
|
||||
{0x8006, 12},
|
||||
{0x800a, 12},
|
||||
{0x800f, 12},
|
||||
{0x8018, 12},
|
||||
{0x801f, 12},
|
||||
{0x8029, 12},
|
||||
{0xc038, 12},
|
||||
{0x8003, 14},
|
||||
{0x8006, 14},
|
||||
{0x800a, 14},
|
||||
{0x800f, 14},
|
||||
{0x8018, 14},
|
||||
{0x801f, 14},
|
||||
{0x8029, 14},
|
||||
{0xc038, 14},
|
||||
},
|
||||
/* 235 */
|
||||
{
|
||||
{0x8002, 15},
|
||||
{0x8009, 15},
|
||||
{0x8017, 15},
|
||||
{0xc028, 15},
|
||||
{0x8002, 16},
|
||||
{0x8009, 16},
|
||||
{0x8017, 16},
|
||||
{0xc028, 16},
|
||||
{0x8002, 17},
|
||||
{0x8009, 17},
|
||||
{0x8017, 17},
|
||||
{0xc028, 17},
|
||||
{0x8002, 18},
|
||||
{0x8009, 18},
|
||||
{0x8017, 18},
|
||||
{0xc028, 18},
|
||||
},
|
||||
/* 236 */
|
||||
{
|
||||
{0x8003, 15},
|
||||
{0x8006, 15},
|
||||
{0x800a, 15},
|
||||
{0x800f, 15},
|
||||
{0x8018, 15},
|
||||
{0x801f, 15},
|
||||
{0x8029, 15},
|
||||
{0xc038, 15},
|
||||
{0x8003, 16},
|
||||
{0x8006, 16},
|
||||
{0x800a, 16},
|
||||
{0x800f, 16},
|
||||
{0x8018, 16},
|
||||
{0x801f, 16},
|
||||
{0x8029, 16},
|
||||
{0xc038, 16},
|
||||
},
|
||||
/* 237 */
|
||||
{
|
||||
{0x8003, 17},
|
||||
{0x8006, 17},
|
||||
{0x800a, 17},
|
||||
{0x800f, 17},
|
||||
{0x8018, 17},
|
||||
{0x801f, 17},
|
||||
{0x8029, 17},
|
||||
{0xc038, 17},
|
||||
{0x8003, 18},
|
||||
{0x8006, 18},
|
||||
{0x800a, 18},
|
||||
{0x800f, 18},
|
||||
{0x8018, 18},
|
||||
{0x801f, 18},
|
||||
{0x8029, 18},
|
||||
{0xc038, 18},
|
||||
},
|
||||
/* 238 */
|
||||
{
|
||||
{0xc000, 19},
|
||||
{0xc000, 20},
|
||||
{0xc000, 21},
|
||||
{0xc000, 23},
|
||||
{0xc000, 24},
|
||||
{0xc000, 25},
|
||||
{0xc000, 26},
|
||||
{0xc000, 27},
|
||||
{0xc000, 28},
|
||||
{0xc000, 29},
|
||||
{0xc000, 30},
|
||||
{0xc000, 31},
|
||||
{0xc000, 127},
|
||||
{0xc000, 220},
|
||||
{0xc000, 249},
|
||||
{0xfd, 0},
|
||||
},
|
||||
/* 239 */
|
||||
{
|
||||
{0x8001, 19},
|
||||
{0xc016, 19},
|
||||
{0x8001, 20},
|
||||
{0xc016, 20},
|
||||
{0x8001, 21},
|
||||
{0xc016, 21},
|
||||
{0x8001, 23},
|
||||
{0xc016, 23},
|
||||
{0x8001, 24},
|
||||
{0xc016, 24},
|
||||
{0x8001, 25},
|
||||
{0xc016, 25},
|
||||
{0x8001, 26},
|
||||
{0xc016, 26},
|
||||
{0x8001, 27},
|
||||
{0xc016, 27},
|
||||
},
|
||||
/* 240 */
|
||||
{
|
||||
{0x8002, 19},
|
||||
{0x8009, 19},
|
||||
{0x8017, 19},
|
||||
{0xc028, 19},
|
||||
{0x8002, 20},
|
||||
{0x8009, 20},
|
||||
{0x8017, 20},
|
||||
{0xc028, 20},
|
||||
{0x8002, 21},
|
||||
{0x8009, 21},
|
||||
{0x8017, 21},
|
||||
{0xc028, 21},
|
||||
{0x8002, 23},
|
||||
{0x8009, 23},
|
||||
{0x8017, 23},
|
||||
{0xc028, 23},
|
||||
},
|
||||
/* 241 */
|
||||
{
|
||||
{0x8003, 19},
|
||||
{0x8006, 19},
|
||||
{0x800a, 19},
|
||||
{0x800f, 19},
|
||||
{0x8018, 19},
|
||||
{0x801f, 19},
|
||||
{0x8029, 19},
|
||||
{0xc038, 19},
|
||||
{0x8003, 20},
|
||||
{0x8006, 20},
|
||||
{0x800a, 20},
|
||||
{0x800f, 20},
|
||||
{0x8018, 20},
|
||||
{0x801f, 20},
|
||||
{0x8029, 20},
|
||||
{0xc038, 20},
|
||||
},
|
||||
/* 242 */
|
||||
{
|
||||
{0x8003, 21},
|
||||
{0x8006, 21},
|
||||
{0x800a, 21},
|
||||
{0x800f, 21},
|
||||
{0x8018, 21},
|
||||
{0x801f, 21},
|
||||
{0x8029, 21},
|
||||
{0xc038, 21},
|
||||
{0x8003, 23},
|
||||
{0x8006, 23},
|
||||
{0x800a, 23},
|
||||
{0x800f, 23},
|
||||
{0x8018, 23},
|
||||
{0x801f, 23},
|
||||
{0x8029, 23},
|
||||
{0xc038, 23},
|
||||
},
|
||||
/* 243 */
|
||||
{
|
||||
{0x8002, 24},
|
||||
{0x8009, 24},
|
||||
{0x8017, 24},
|
||||
{0xc028, 24},
|
||||
{0x8002, 25},
|
||||
{0x8009, 25},
|
||||
{0x8017, 25},
|
||||
{0xc028, 25},
|
||||
{0x8002, 26},
|
||||
{0x8009, 26},
|
||||
{0x8017, 26},
|
||||
{0xc028, 26},
|
||||
{0x8002, 27},
|
||||
{0x8009, 27},
|
||||
{0x8017, 27},
|
||||
{0xc028, 27},
|
||||
},
|
||||
/* 244 */
|
||||
{
|
||||
{0x8003, 24},
|
||||
{0x8006, 24},
|
||||
{0x800a, 24},
|
||||
{0x800f, 24},
|
||||
{0x8018, 24},
|
||||
{0x801f, 24},
|
||||
{0x8029, 24},
|
||||
{0xc038, 24},
|
||||
{0x8003, 25},
|
||||
{0x8006, 25},
|
||||
{0x800a, 25},
|
||||
{0x800f, 25},
|
||||
{0x8018, 25},
|
||||
{0x801f, 25},
|
||||
{0x8029, 25},
|
||||
{0xc038, 25},
|
||||
},
|
||||
/* 245 */
|
||||
{
|
||||
{0x8003, 26},
|
||||
{0x8006, 26},
|
||||
{0x800a, 26},
|
||||
{0x800f, 26},
|
||||
{0x8018, 26},
|
||||
{0x801f, 26},
|
||||
{0x8029, 26},
|
||||
{0xc038, 26},
|
||||
{0x8003, 27},
|
||||
{0x8006, 27},
|
||||
{0x800a, 27},
|
||||
{0x800f, 27},
|
||||
{0x8018, 27},
|
||||
{0x801f, 27},
|
||||
{0x8029, 27},
|
||||
{0xc038, 27},
|
||||
},
|
||||
/* 246 */
|
||||
{
|
||||
{0x8001, 28},
|
||||
{0xc016, 28},
|
||||
{0x8001, 29},
|
||||
{0xc016, 29},
|
||||
{0x8001, 30},
|
||||
{0xc016, 30},
|
||||
{0x8001, 31},
|
||||
{0xc016, 31},
|
||||
{0x8001, 127},
|
||||
{0xc016, 127},
|
||||
{0x8001, 220},
|
||||
{0xc016, 220},
|
||||
{0x8001, 249},
|
||||
{0xc016, 249},
|
||||
{0xfe, 0},
|
||||
{0xff, 0},
|
||||
},
|
||||
/* 247 */
|
||||
{
|
||||
{0x8002, 28},
|
||||
{0x8009, 28},
|
||||
{0x8017, 28},
|
||||
{0xc028, 28},
|
||||
{0x8002, 29},
|
||||
{0x8009, 29},
|
||||
{0x8017, 29},
|
||||
{0xc028, 29},
|
||||
{0x8002, 30},
|
||||
{0x8009, 30},
|
||||
{0x8017, 30},
|
||||
{0xc028, 30},
|
||||
{0x8002, 31},
|
||||
{0x8009, 31},
|
||||
{0x8017, 31},
|
||||
{0xc028, 31},
|
||||
},
|
||||
/* 248 */
|
||||
{
|
||||
{0x8003, 28},
|
||||
{0x8006, 28},
|
||||
{0x800a, 28},
|
||||
{0x800f, 28},
|
||||
{0x8018, 28},
|
||||
{0x801f, 28},
|
||||
{0x8029, 28},
|
||||
{0xc038, 28},
|
||||
{0x8003, 29},
|
||||
{0x8006, 29},
|
||||
{0x800a, 29},
|
||||
{0x800f, 29},
|
||||
{0x8018, 29},
|
||||
{0x801f, 29},
|
||||
{0x8029, 29},
|
||||
{0xc038, 29},
|
||||
},
|
||||
/* 249 */
|
||||
{
|
||||
{0x8003, 30},
|
||||
{0x8006, 30},
|
||||
{0x800a, 30},
|
||||
{0x800f, 30},
|
||||
{0x8018, 30},
|
||||
{0x801f, 30},
|
||||
{0x8029, 30},
|
||||
{0xc038, 30},
|
||||
{0x8003, 31},
|
||||
{0x8006, 31},
|
||||
{0x800a, 31},
|
||||
{0x800f, 31},
|
||||
{0x8018, 31},
|
||||
{0x801f, 31},
|
||||
{0x8029, 31},
|
||||
{0xc038, 31},
|
||||
},
|
||||
/* 250 */
|
||||
{
|
||||
{0x8002, 127},
|
||||
{0x8009, 127},
|
||||
{0x8017, 127},
|
||||
{0xc028, 127},
|
||||
{0x8002, 220},
|
||||
{0x8009, 220},
|
||||
{0x8017, 220},
|
||||
{0xc028, 220},
|
||||
{0x8002, 249},
|
||||
{0x8009, 249},
|
||||
{0x8017, 249},
|
||||
{0xc028, 249},
|
||||
{0xc000, 10},
|
||||
{0xc000, 13},
|
||||
{0xc000, 22},
|
||||
{0x100, 0},
|
||||
},
|
||||
/* 251 */
|
||||
{
|
||||
{0x8003, 127},
|
||||
{0x8006, 127},
|
||||
{0x800a, 127},
|
||||
{0x800f, 127},
|
||||
{0x8018, 127},
|
||||
{0x801f, 127},
|
||||
{0x8029, 127},
|
||||
{0xc038, 127},
|
||||
{0x8003, 220},
|
||||
{0x8006, 220},
|
||||
{0x800a, 220},
|
||||
{0x800f, 220},
|
||||
{0x8018, 220},
|
||||
{0x801f, 220},
|
||||
{0x8029, 220},
|
||||
{0xc038, 220},
|
||||
},
|
||||
/* 252 */
|
||||
{
|
||||
{0x8003, 249},
|
||||
{0x8006, 249},
|
||||
{0x800a, 249},
|
||||
{0x800f, 249},
|
||||
{0x8018, 249},
|
||||
{0x801f, 249},
|
||||
{0x8029, 249},
|
||||
{0xc038, 249},
|
||||
{0x8001, 10},
|
||||
{0xc016, 10},
|
||||
{0x8001, 13},
|
||||
{0xc016, 13},
|
||||
{0x8001, 22},
|
||||
{0xc016, 22},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
},
|
||||
/* 253 */
|
||||
{
|
||||
{0x8002, 10},
|
||||
{0x8009, 10},
|
||||
{0x8017, 10},
|
||||
{0xc028, 10},
|
||||
{0x8002, 13},
|
||||
{0x8009, 13},
|
||||
{0x8017, 13},
|
||||
{0xc028, 13},
|
||||
{0x8002, 22},
|
||||
{0x8009, 22},
|
||||
{0x8017, 22},
|
||||
{0xc028, 22},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
},
|
||||
/* 254 */
|
||||
{
|
||||
{0x8003, 10},
|
||||
{0x8006, 10},
|
||||
{0x800a, 10},
|
||||
{0x800f, 10},
|
||||
{0x8018, 10},
|
||||
{0x801f, 10},
|
||||
{0x8029, 10},
|
||||
{0xc038, 10},
|
||||
{0x8003, 13},
|
||||
{0x8006, 13},
|
||||
{0x800a, 13},
|
||||
{0x800f, 13},
|
||||
{0x8018, 13},
|
||||
{0x801f, 13},
|
||||
{0x8029, 13},
|
||||
{0xc038, 13},
|
||||
},
|
||||
/* 255 */
|
||||
{
|
||||
{0x8003, 22},
|
||||
{0x8006, 22},
|
||||
{0x800a, 22},
|
||||
{0x800f, 22},
|
||||
{0x8018, 22},
|
||||
{0x801f, 22},
|
||||
{0x8029, 22},
|
||||
{0xc038, 22},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
},
|
||||
/* 256 */
|
||||
{
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
{0x100, 0},
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,629 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "nghttp2_net.h"
|
||||
|
||||
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) {
|
||||
uint16_t x = htons(n);
|
||||
memcpy(buf, &x, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) {
|
||||
uint32_t x = htonl(n);
|
||||
memcpy(buf, &x, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint16_t nghttp2_get_uint16(const uint8_t *data) {
|
||||
uint16_t n;
|
||||
memcpy(&n, data, sizeof(uint16_t));
|
||||
return ntohs(n);
|
||||
}
|
||||
|
||||
uint32_t nghttp2_get_uint32(const uint8_t *data) {
|
||||
uint32_t n;
|
||||
memcpy(&n, data, sizeof(uint32_t));
|
||||
return ntohl(n);
|
||||
}
|
||||
|
||||
/* Generated by gendowncasetbl.py */
|
||||
static const uint8_t DOWNCASE_TBL[] = {
|
||||
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
|
||||
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
|
||||
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
|
||||
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
|
||||
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
|
||||
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
|
||||
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
|
||||
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
|
||||
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
|
||||
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
|
||||
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
|
||||
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
|
||||
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
|
||||
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
|
||||
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
|
||||
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
|
||||
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
|
||||
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
|
||||
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
|
||||
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
|
||||
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
|
||||
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
|
||||
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
|
||||
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
|
||||
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
|
||||
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
|
||||
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
|
||||
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
|
||||
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
|
||||
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
|
||||
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
|
||||
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
|
||||
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
|
||||
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
|
||||
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
|
||||
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
|
||||
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
|
||||
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
|
||||
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
|
||||
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
|
||||
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
|
||||
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
|
||||
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
|
||||
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
|
||||
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
|
||||
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
|
||||
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
|
||||
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
|
||||
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
|
||||
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
|
||||
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
|
||||
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
|
||||
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
|
||||
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
|
||||
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
|
||||
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
|
||||
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
|
||||
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
|
||||
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
|
||||
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
|
||||
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
|
||||
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
|
||||
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
|
||||
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
|
||||
};
|
||||
|
||||
void nghttp2_downcase(uint8_t *s, size_t len) {
|
||||
size_t i;
|
||||
for (i = 0; i < len; ++i) {
|
||||
s[i] = DOWNCASE_TBL[s[i]];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* local_window_size
|
||||
* ^ *
|
||||
* | * recv_window_size
|
||||
* | * * ^
|
||||
* | * * |
|
||||
* 0+++++++++
|
||||
* | * * \
|
||||
* | * * | This rage is hidden in flow control. But it must be
|
||||
* v * * / kept in order to restore it when window size is enlarged.
|
||||
* recv_reduction
|
||||
* (+ for negative direction)
|
||||
*
|
||||
* recv_window_size could be negative if we decrease
|
||||
* local_window_size more than recv_window_size:
|
||||
*
|
||||
* local_window_size
|
||||
* ^ *
|
||||
* | *
|
||||
* | *
|
||||
* 0++++++++
|
||||
* | * ^ recv_window_size (negative)
|
||||
* | * |
|
||||
* v * *
|
||||
* recv_reduction
|
||||
*/
|
||||
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr) {
|
||||
if (*delta_ptr > 0) {
|
||||
int32_t recv_reduction_delta;
|
||||
int32_t delta;
|
||||
int32_t new_recv_window_size =
|
||||
nghttp2_max(0, *recv_window_size_ptr) - *delta_ptr;
|
||||
|
||||
if (new_recv_window_size >= 0) {
|
||||
*recv_window_size_ptr = new_recv_window_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
delta = -new_recv_window_size;
|
||||
|
||||
/* The delta size is strictly more than received bytes. Increase
|
||||
local_window_size by that difference |delta|. */
|
||||
if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
*local_window_size_ptr += delta;
|
||||
/* If there is recv_reduction due to earlier window_size
|
||||
reduction, we have to adjust it too. */
|
||||
recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta);
|
||||
*recv_reduction_ptr -= recv_reduction_delta;
|
||||
if (*recv_window_size_ptr < 0) {
|
||||
*recv_window_size_ptr += recv_reduction_delta;
|
||||
} else {
|
||||
/* If *recv_window_size_ptr > 0, then those bytes are going to
|
||||
be returned to the remote peer (by WINDOW_UPDATE with the
|
||||
adjusted *delta_ptr), so it is effectively 0 now. We set to
|
||||
*recv_reduction_delta, because caller does not take into
|
||||
account it in *delta_ptr. */
|
||||
*recv_window_size_ptr = recv_reduction_delta;
|
||||
}
|
||||
/* recv_reduction_delta must be paid from *delta_ptr, since it was
|
||||
added in window size reduction (see below). */
|
||||
*delta_ptr -= recv_reduction_delta;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (*local_window_size_ptr + *delta_ptr < 0 ||
|
||||
*recv_window_size_ptr < INT32_MIN - *delta_ptr ||
|
||||
*recv_reduction_ptr > INT32_MAX + *delta_ptr) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
/* Decreasing local window size. Note that we achieve this without
|
||||
noticing to the remote peer. To do this, we cut
|
||||
recv_window_size by -delta. This means that we don't send
|
||||
WINDOW_UPDATE for -delta bytes. */
|
||||
*local_window_size_ptr += *delta_ptr;
|
||||
*recv_window_size_ptr += *delta_ptr;
|
||||
*recv_reduction_ptr -= *delta_ptr;
|
||||
*delta_ptr = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr) {
|
||||
int32_t recv_reduction_delta;
|
||||
int32_t delta;
|
||||
|
||||
delta = *delta_ptr;
|
||||
|
||||
assert(delta >= 0);
|
||||
|
||||
/* The delta size is strictly more than received bytes. Increase
|
||||
local_window_size by that difference |delta|. */
|
||||
if (*local_window_size_ptr > NGHTTP2_MAX_WINDOW_SIZE - delta) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
|
||||
*local_window_size_ptr += delta;
|
||||
/* If there is recv_reduction due to earlier window_size
|
||||
reduction, we have to adjust it too. */
|
||||
recv_reduction_delta = nghttp2_min(*recv_reduction_ptr, delta);
|
||||
*recv_reduction_ptr -= recv_reduction_delta;
|
||||
|
||||
*recv_window_size_ptr += recv_reduction_delta;
|
||||
|
||||
/* recv_reduction_delta must be paid from *delta_ptr, since it was
|
||||
added in window size reduction (see below). */
|
||||
*delta_ptr -= recv_reduction_delta;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_should_send_window_update(int32_t local_window_size,
|
||||
int32_t recv_window_size) {
|
||||
return recv_window_size > 0 && recv_window_size >= local_window_size / 2;
|
||||
}
|
||||
|
||||
const char *nghttp2_strerror(int error_code) {
|
||||
switch (error_code) {
|
||||
case 0:
|
||||
return "Success";
|
||||
case NGHTTP2_ERR_INVALID_ARGUMENT:
|
||||
return "Invalid argument";
|
||||
case NGHTTP2_ERR_BUFFER_ERROR:
|
||||
return "Out of buffer space";
|
||||
case NGHTTP2_ERR_UNSUPPORTED_VERSION:
|
||||
return "Unsupported SPDY version";
|
||||
case NGHTTP2_ERR_WOULDBLOCK:
|
||||
return "Operation would block";
|
||||
case NGHTTP2_ERR_PROTO:
|
||||
return "Protocol error";
|
||||
case NGHTTP2_ERR_INVALID_FRAME:
|
||||
return "Invalid frame octets";
|
||||
case NGHTTP2_ERR_EOF:
|
||||
return "EOF";
|
||||
case NGHTTP2_ERR_DEFERRED:
|
||||
return "Data transfer deferred";
|
||||
case NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE:
|
||||
return "No more Stream ID available";
|
||||
case NGHTTP2_ERR_STREAM_CLOSED:
|
||||
return "Stream was already closed or invalid";
|
||||
case NGHTTP2_ERR_STREAM_CLOSING:
|
||||
return "Stream is closing";
|
||||
case NGHTTP2_ERR_STREAM_SHUT_WR:
|
||||
return "The transmission is not allowed for this stream";
|
||||
case NGHTTP2_ERR_INVALID_STREAM_ID:
|
||||
return "Stream ID is invalid";
|
||||
case NGHTTP2_ERR_INVALID_STREAM_STATE:
|
||||
return "Invalid stream state";
|
||||
case NGHTTP2_ERR_DEFERRED_DATA_EXIST:
|
||||
return "Another DATA frame has already been deferred";
|
||||
case NGHTTP2_ERR_START_STREAM_NOT_ALLOWED:
|
||||
return "request HEADERS is not allowed";
|
||||
case NGHTTP2_ERR_GOAWAY_ALREADY_SENT:
|
||||
return "GOAWAY has already been sent";
|
||||
case NGHTTP2_ERR_INVALID_HEADER_BLOCK:
|
||||
return "Invalid header block";
|
||||
case NGHTTP2_ERR_INVALID_STATE:
|
||||
return "Invalid state";
|
||||
case NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE:
|
||||
return "The user callback function failed due to the temporal error";
|
||||
case NGHTTP2_ERR_FRAME_SIZE_ERROR:
|
||||
return "The length of the frame is invalid";
|
||||
case NGHTTP2_ERR_HEADER_COMP:
|
||||
return "Header compression/decompression error";
|
||||
case NGHTTP2_ERR_FLOW_CONTROL:
|
||||
return "Flow control error";
|
||||
case NGHTTP2_ERR_INSUFF_BUFSIZE:
|
||||
return "Insufficient buffer size given to function";
|
||||
case NGHTTP2_ERR_PAUSE:
|
||||
return "Callback was paused by the application";
|
||||
case NGHTTP2_ERR_TOO_MANY_INFLIGHT_SETTINGS:
|
||||
return "Too many inflight SETTINGS";
|
||||
case NGHTTP2_ERR_PUSH_DISABLED:
|
||||
return "Server push is disabled by peer";
|
||||
case NGHTTP2_ERR_DATA_EXIST:
|
||||
return "DATA or HEADERS frame has already been submitted for the stream";
|
||||
case NGHTTP2_ERR_SESSION_CLOSING:
|
||||
return "The current session is closing";
|
||||
case NGHTTP2_ERR_HTTP_HEADER:
|
||||
return "Invalid HTTP header field was received";
|
||||
case NGHTTP2_ERR_HTTP_MESSAGING:
|
||||
return "Violation in HTTP messaging rule";
|
||||
case NGHTTP2_ERR_REFUSED_STREAM:
|
||||
return "Stream was refused";
|
||||
case NGHTTP2_ERR_INTERNAL:
|
||||
return "Internal error";
|
||||
case NGHTTP2_ERR_CANCEL:
|
||||
return "Cancel";
|
||||
case NGHTTP2_ERR_SETTINGS_EXPECTED:
|
||||
return "When a local endpoint expects to receive SETTINGS frame, it "
|
||||
"receives an other type of frame";
|
||||
case NGHTTP2_ERR_NOMEM:
|
||||
return "Out of memory";
|
||||
case NGHTTP2_ERR_CALLBACK_FAILURE:
|
||||
return "The user callback function failed";
|
||||
case NGHTTP2_ERR_BAD_CLIENT_MAGIC:
|
||||
return "Received bad client magic byte string";
|
||||
case NGHTTP2_ERR_FLOODED:
|
||||
return "Flooding was detected in this HTTP/2 session, and it must be "
|
||||
"closed";
|
||||
default:
|
||||
return "Unknown error code";
|
||||
}
|
||||
}
|
||||
|
||||
/* Generated by gennmchartbl.py */
|
||||
static const int VALID_HD_NAME_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
|
||||
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
|
||||
0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */,
|
||||
0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */,
|
||||
0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */,
|
||||
0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
|
||||
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */,
|
||||
0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */,
|
||||
0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */,
|
||||
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_header_name(const uint8_t *name, size_t len) {
|
||||
const uint8_t *last;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (*name == ':') {
|
||||
if (len == 1) {
|
||||
return 0;
|
||||
}
|
||||
++name;
|
||||
--len;
|
||||
}
|
||||
for (last = name + len; name != last; ++name) {
|
||||
if (!VALID_HD_NAME_CHARS[*name]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generated by genvchartbl.py */
|
||||
static const int VALID_HD_VALUE_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
|
||||
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
|
||||
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
|
||||
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
|
||||
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
|
||||
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
|
||||
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
|
||||
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
|
||||
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
|
||||
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
|
||||
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
|
||||
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
|
||||
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
|
||||
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
|
||||
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
|
||||
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
|
||||
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
|
||||
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
|
||||
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
|
||||
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
|
||||
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
|
||||
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
|
||||
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
|
||||
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
|
||||
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
|
||||
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
|
||||
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
|
||||
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
|
||||
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
|
||||
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
|
||||
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
|
||||
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
|
||||
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
|
||||
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_header_value(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
for (last = value + len; value != last; ++value) {
|
||||
if (!VALID_HD_VALUE_CHARS[*value]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Generated by genauthroitychartbl.py */
|
||||
static char VALID_AUTHORITY_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
0 /* SPC */, 1 /* ! */, 0 /* " */, 0 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||
1 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
0 /* < */, 1 /* = */, 0 /* > */, 0 /* ? */,
|
||||
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||
0 /* \ */, 1 /* ] */, 0 /* ^ */, 1 /* _ */,
|
||||
0 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||
0 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_authority(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
for (last = value + len; value != last; ++value) {
|
||||
if (!VALID_AUTHORITY_CHARS[*value]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) {
|
||||
if (len == 0) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
memcpy(dest, src, len);
|
||||
|
||||
return dest + len;
|
||||
}
|
||||
|
||||
const char *nghttp2_http2_strerror(uint32_t error_code) {
|
||||
switch (error_code) {
|
||||
case NGHTTP2_NO_ERROR:
|
||||
return "NO_ERROR";
|
||||
case NGHTTP2_PROTOCOL_ERROR:
|
||||
return "PROTOCOL_ERROR";
|
||||
case NGHTTP2_INTERNAL_ERROR:
|
||||
return "INTERNAL_ERROR";
|
||||
case NGHTTP2_FLOW_CONTROL_ERROR:
|
||||
return "FLOW_CONTROL_ERROR";
|
||||
case NGHTTP2_SETTINGS_TIMEOUT:
|
||||
return "SETTINGS_TIMEOUT";
|
||||
case NGHTTP2_STREAM_CLOSED:
|
||||
return "STREAM_CLOSED";
|
||||
case NGHTTP2_FRAME_SIZE_ERROR:
|
||||
return "FRAME_SIZE_ERROR";
|
||||
case NGHTTP2_REFUSED_STREAM:
|
||||
return "REFUSED_STREAM";
|
||||
case NGHTTP2_CANCEL:
|
||||
return "CANCEL";
|
||||
case NGHTTP2_COMPRESSION_ERROR:
|
||||
return "COMPRESSION_ERROR";
|
||||
case NGHTTP2_CONNECT_ERROR:
|
||||
return "CONNECT_ERROR";
|
||||
case NGHTTP2_ENHANCE_YOUR_CALM:
|
||||
return "ENHANCE_YOUR_CALM";
|
||||
case NGHTTP2_INADEQUATE_SECURITY:
|
||||
return "INADEQUATE_SECURITY";
|
||||
case NGHTTP2_HTTP_1_1_REQUIRED:
|
||||
return "HTTP_1_1_REQUIRED";
|
||||
default:
|
||||
return "unknown";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HELPER_H
|
||||
#define NGHTTP2_HELPER_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
#define nghttp2_min(A, B) ((A) < (B) ? (A) : (B))
|
||||
#define nghttp2_max(A, B) ((A) > (B) ? (A) : (B))
|
||||
|
||||
#define lstreq(A, B, N) ((sizeof((A)) - 1) == (N) && memcmp((A), (B), (N)) == 0)
|
||||
|
||||
#define nghttp2_struct_of(ptr, type, member) \
|
||||
((type *)(void *)((char *)(ptr)-offsetof(type, member)))
|
||||
|
||||
/*
|
||||
* Copies 2 byte unsigned integer |n| in host byte order to |buf| in
|
||||
* network byte order.
|
||||
*/
|
||||
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n);
|
||||
|
||||
/*
|
||||
* Copies 4 byte unsigned integer |n| in host byte order to |buf| in
|
||||
* network byte order.
|
||||
*/
|
||||
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n);
|
||||
|
||||
/*
|
||||
* Retrieves 2 byte unsigned integer stored in |data| in network byte
|
||||
* order and returns it in host byte order.
|
||||
*/
|
||||
uint16_t nghttp2_get_uint16(const uint8_t *data);
|
||||
|
||||
/*
|
||||
* Retrieves 4 byte unsigned integer stored in |data| in network byte
|
||||
* order and returns it in host byte order.
|
||||
*/
|
||||
uint32_t nghttp2_get_uint32(const uint8_t *data);
|
||||
|
||||
void nghttp2_downcase(uint8_t *s, size_t len);
|
||||
|
||||
/*
|
||||
* Adjusts |*local_window_size_ptr|, |*recv_window_size_ptr|,
|
||||
* |*recv_reduction_ptr| with |*delta_ptr| which is the
|
||||
* WINDOW_UPDATE's window_size_increment sent from local side. If
|
||||
* |delta| is strictly larger than |*recv_window_size_ptr|,
|
||||
* |*local_window_size_ptr| is increased by delta -
|
||||
* *recv_window_size_ptr. If |delta| is negative,
|
||||
* |*local_window_size_ptr| is decreased by delta.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FLOW_CONTROL
|
||||
* local_window_size overflow or gets negative.
|
||||
*/
|
||||
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr);
|
||||
|
||||
/*
|
||||
* This function works like nghttp2_adjust_local_window_size(). The
|
||||
* difference is that this function assumes *delta_ptr >= 0, and
|
||||
* *recv_window_size_ptr is not decreased by *delta_ptr.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_FLOW_CONTROL
|
||||
* local_window_size overflow or gets negative.
|
||||
*/
|
||||
int nghttp2_increase_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr);
|
||||
|
||||
/*
|
||||
* Returns non-zero if the function decided that WINDOW_UPDATE should
|
||||
* be sent.
|
||||
*/
|
||||
int nghttp2_should_send_window_update(int32_t local_window_size,
|
||||
int32_t recv_window_size);
|
||||
|
||||
/*
|
||||
* Copies the buffer |src| of length |len| to the destination pointed
|
||||
* by the |dest|, assuming that the |dest| is at lest |len| bytes long
|
||||
* . Returns dest + len.
|
||||
*/
|
||||
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
|
||||
|
||||
#endif /* NGHTTP2_HELPER_H */
|
||||
@@ -0,0 +1,530 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_http.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
static uint8_t downcase(uint8_t c) {
|
||||
return 'A' <= c && c <= 'Z' ? (uint8_t)(c - 'A' + 'a') : c;
|
||||
}
|
||||
|
||||
static int memieq(const void *a, const void *b, size_t n) {
|
||||
size_t i;
|
||||
const uint8_t *aa = a, *bb = b;
|
||||
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (downcase(aa[i]) != downcase(bb[i])) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define lstrieq(A, B, N) ((sizeof((A)) - 1) == (N) && memieq((A), (B), (N)))
|
||||
|
||||
static int64_t parse_uint(const uint8_t *s, size_t len) {
|
||||
int64_t n = 0;
|
||||
size_t i;
|
||||
if (len == 0) {
|
||||
return -1;
|
||||
}
|
||||
for (i = 0; i < len; ++i) {
|
||||
if ('0' <= s[i] && s[i] <= '9') {
|
||||
if (n > INT64_MAX / 10) {
|
||||
return -1;
|
||||
}
|
||||
n *= 10;
|
||||
if (n > INT64_MAX - (s[i] - '0')) {
|
||||
return -1;
|
||||
}
|
||||
n += s[i] - '0';
|
||||
continue;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static int lws(const uint8_t *s, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
if (s[i] != ' ' && s[i] != '\t') {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int check_pseudo_header(nghttp2_stream *stream, const nghttp2_hd_nv *nv,
|
||||
int flag) {
|
||||
if (stream->http_flags & flag) {
|
||||
return 0;
|
||||
}
|
||||
if (lws(nv->value->base, nv->value->len)) {
|
||||
return 0;
|
||||
}
|
||||
stream->http_flags = (uint16_t)(stream->http_flags | flag);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int expect_response_body(nghttp2_stream *stream) {
|
||||
return (stream->http_flags & NGHTTP2_HTTP_FLAG_METH_HEAD) == 0 &&
|
||||
stream->status_code / 100 != 1 && stream->status_code != 304 &&
|
||||
stream->status_code != 204;
|
||||
}
|
||||
|
||||
/* For "http" or "https" URIs, OPTIONS request may have "*" in :path
|
||||
header field to represent system-wide OPTIONS request. Otherwise,
|
||||
:path header field value must start with "/". This function must
|
||||
be called after ":method" header field was received. This function
|
||||
returns nonzero if path is valid.*/
|
||||
static int check_path(nghttp2_stream *stream) {
|
||||
return (stream->http_flags & NGHTTP2_HTTP_FLAG_SCHEME_HTTP) == 0 ||
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_REGULAR) ||
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_OPTIONS) &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PATH_ASTERISK)));
|
||||
}
|
||||
|
||||
static int http_request_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
||||
int trailer, int connect_protocol) {
|
||||
if (nv->name->base[0] == ':') {
|
||||
if (trailer ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nv->token) {
|
||||
case NGHTTP2_TOKEN__AUTHORITY:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__AUTHORITY)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__METHOD:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__METHOD)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
switch (nv->value->len) {
|
||||
case 4:
|
||||
if (lstreq("HEAD", nv->value->base, nv->value->len)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
switch (nv->value->base[6]) {
|
||||
case 'T':
|
||||
if (lstreq("CONNECT", nv->value->base, nv->value->len)) {
|
||||
if (stream->stream_id % 2 == 0) {
|
||||
/* we won't allow CONNECT for push */
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
if (lstreq("OPTIONS", nv->value->base, nv->value->len)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_OPTIONS;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__PATH:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PATH)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if (nv->value->base[0] == '/') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_REGULAR;
|
||||
} else if (nv->value->len == 1 && nv->value->base[0] == '*') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PATH_ASTERISK;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__SCHEME:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__SCHEME)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if ((nv->value->len == 4 && memieq("http", nv->value->base, 4)) ||
|
||||
(nv->value->len == 5 && memieq("https", nv->value->base, 5))) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_SCHEME_HTTP;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN__PROTOCOL:
|
||||
if (!connect_protocol) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__PROTOCOL)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN_HOST:
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG_HOST)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_TOKEN_CONTENT_LENGTH: {
|
||||
if (stream->content_length != -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->content_length = parse_uint(nv->value->base, nv->value->len);
|
||||
if (stream->content_length == -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* disallowed header fields */
|
||||
case NGHTTP2_TOKEN_CONNECTION:
|
||||
case NGHTTP2_TOKEN_KEEP_ALIVE:
|
||||
case NGHTTP2_TOKEN_PROXY_CONNECTION:
|
||||
case NGHTTP2_TOKEN_TRANSFER_ENCODING:
|
||||
case NGHTTP2_TOKEN_UPGRADE:
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
case NGHTTP2_TOKEN_TE:
|
||||
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
if (nv->name->base[0] != ':') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int http_response_on_header(nghttp2_stream *stream, nghttp2_hd_nv *nv,
|
||||
int trailer) {
|
||||
if (nv->name->base[0] == ':') {
|
||||
if (trailer ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
switch (nv->token) {
|
||||
case NGHTTP2_TOKEN__STATUS: {
|
||||
if (!check_pseudo_header(stream, nv, NGHTTP2_HTTP_FLAG__STATUS)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if (nv->value->len != 3) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->status_code = (int16_t)parse_uint(nv->value->base, nv->value->len);
|
||||
if (stream->status_code == -1 || stream->status_code == 101) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NGHTTP2_TOKEN_CONTENT_LENGTH: {
|
||||
if (stream->status_code == 204) {
|
||||
/* content-length header field in 204 response is prohibited by
|
||||
RFC 7230. But some widely used servers send content-length:
|
||||
0. Until they get fixed, we ignore it. */
|
||||
if (stream->content_length != -1) {
|
||||
/* Found multiple content-length field */
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
if (!lstrieq("0", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->content_length = 0;
|
||||
return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (stream->status_code / 100 == 1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
/* https://tools.ietf.org/html/rfc7230#section-3.3.3 */
|
||||
if (stream->status_code / 100 == 2 &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
|
||||
return NGHTTP2_ERR_REMOVE_HTTP_HEADER;
|
||||
}
|
||||
if (stream->content_length != -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
stream->content_length = parse_uint(nv->value->base, nv->value->len);
|
||||
if (stream->content_length == -1) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* disallowed header fields */
|
||||
case NGHTTP2_TOKEN_CONNECTION:
|
||||
case NGHTTP2_TOKEN_KEEP_ALIVE:
|
||||
case NGHTTP2_TOKEN_PROXY_CONNECTION:
|
||||
case NGHTTP2_TOKEN_TRANSFER_ENCODING:
|
||||
case NGHTTP2_TOKEN_UPGRADE:
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
case NGHTTP2_TOKEN_TE:
|
||||
if (!lstrieq("trailers", nv->value->base, nv->value->len)) {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
|
||||
if (nv->name->base[0] != ':') {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int check_scheme(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(('A' <= *value && *value <= 'Z') || ('a' <= *value && *value <= 'z'))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
last = value + len;
|
||||
++value;
|
||||
|
||||
for (; value != last; ++value) {
|
||||
if (!(('A' <= *value && *value <= 'Z') ||
|
||||
('a' <= *value && *value <= 'z') ||
|
||||
('0' <= *value && *value <= '9') || *value == '+' || *value == '-' ||
|
||||
*value == '.')) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||
nghttp2_frame *frame, nghttp2_hd_nv *nv,
|
||||
int trailer) {
|
||||
int rv;
|
||||
|
||||
/* We are strict for pseudo header field. One bad character should
|
||||
lead to fail. OTOH, we should be a bit forgiving for regular
|
||||
headers, since existing public internet has so much illegal
|
||||
headers floating around and if we kill the stream because of
|
||||
this, we may disrupt many web sites and/or libraries. So we
|
||||
become conservative here, and just ignore those illegal regular
|
||||
headers. */
|
||||
if (!nghttp2_check_header_name(nv->name->base, nv->name->len)) {
|
||||
size_t i;
|
||||
if (nv->name->len > 0 && nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
/* header field name must be lower-cased without exception */
|
||||
for (i = 0; i < nv->name->len; ++i) {
|
||||
uint8_t c = nv->name->base[i];
|
||||
if ('A' <= c && c <= 'Z') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
}
|
||||
/* When ignoring regular headers, we set this flag so that we
|
||||
still enforce header field ordering rule for pseudo header
|
||||
fields. */
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (nv->token == NGHTTP2_TOKEN__AUTHORITY ||
|
||||
nv->token == NGHTTP2_TOKEN_HOST) {
|
||||
rv = nghttp2_check_authority(nv->value->base, nv->value->len);
|
||||
} else if (nv->token == NGHTTP2_TOKEN__SCHEME) {
|
||||
rv = check_scheme(nv->value->base, nv->value->len);
|
||||
} else {
|
||||
rv = nghttp2_check_header_value(nv->value->base, nv->value->len);
|
||||
}
|
||||
|
||||
if (rv == 0) {
|
||||
assert(nv->name->len > 0);
|
||||
if (nv->name->base[0] == ':') {
|
||||
return NGHTTP2_ERR_HTTP_HEADER;
|
||||
}
|
||||
/* When ignoring regular headers, we set this flag so that we
|
||||
still enforce header field ordering rule for pseudo header
|
||||
fields. */
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED;
|
||||
return NGHTTP2_ERR_IGN_HTTP_HEADER;
|
||||
}
|
||||
|
||||
if (session->server || frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||
return http_request_on_header(stream, nv, trailer,
|
||||
session->server &&
|
||||
session->pending_enable_connect_protocol);
|
||||
}
|
||||
|
||||
return http_response_on_header(stream, nv, trailer);
|
||||
}
|
||||
|
||||
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame) {
|
||||
if (!(stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT)) {
|
||||
if ((stream->http_flags &
|
||||
(NGHTTP2_HTTP_FLAG__SCHEME | NGHTTP2_HTTP_FLAG__PATH)) ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0) {
|
||||
return -1;
|
||||
}
|
||||
stream->content_length = -1;
|
||||
} else {
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_REQ_HEADERS) !=
|
||||
NGHTTP2_HTTP_FLAG_REQ_HEADERS ||
|
||||
(stream->http_flags &
|
||||
(NGHTTP2_HTTP_FLAG__AUTHORITY | NGHTTP2_HTTP_FLAG_HOST)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__PROTOCOL) &&
|
||||
((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_CONNECT) == 0 ||
|
||||
(stream->http_flags & NGHTTP2_HTTP_FLAG__AUTHORITY) == 0)) {
|
||||
return -1;
|
||||
}
|
||||
if (!check_path(stream)) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (frame->hd.type == NGHTTP2_PUSH_PROMISE) {
|
||||
/* we are going to reuse data fields for upcoming response. Clear
|
||||
them now, except for method flags. */
|
||||
stream->http_flags &= NGHTTP2_HTTP_FLAG_METH_ALL;
|
||||
stream->content_length = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_response_headers(nghttp2_stream *stream) {
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG__STATUS) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->status_code / 100 == 1) {
|
||||
/* non-final response */
|
||||
stream->http_flags =
|
||||
(uint16_t)((stream->http_flags & NGHTTP2_HTTP_FLAG_METH_ALL) |
|
||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
||||
stream->content_length = -1;
|
||||
stream->status_code = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
stream->http_flags =
|
||||
(uint16_t)(stream->http_flags & ~NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE);
|
||||
|
||||
if (!expect_response_body(stream)) {
|
||||
stream->content_length = 0;
|
||||
} else if (stream->http_flags & (NGHTTP2_HTTP_FLAG_METH_CONNECT |
|
||||
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND)) {
|
||||
stream->content_length = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame) {
|
||||
(void)stream;
|
||||
|
||||
if ((frame->hd.flags & NGHTTP2_FLAG_END_STREAM) == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream) {
|
||||
if (stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (stream->content_length != -1 &&
|
||||
stream->content_length != stream->recv_content_length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n) {
|
||||
stream->recv_content_length += (int64_t)n;
|
||||
|
||||
if ((stream->http_flags & NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE) ||
|
||||
(stream->content_length != -1 &&
|
||||
stream->recv_content_length > stream->content_length)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame) {
|
||||
const nghttp2_nv *nva;
|
||||
size_t nvlen;
|
||||
size_t i;
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
nva = frame->headers.nva;
|
||||
nvlen = frame->headers.nvlen;
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
nva = frame->push_promise.nva;
|
||||
nvlen = frame->push_promise.nvlen;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
/* TODO we should do this strictly. */
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
const nghttp2_nv *nv = &nva[i];
|
||||
if (!(nv->namelen == 7 && nv->name[6] == 'd' &&
|
||||
memcmp(":metho", nv->name, nv->namelen - 1) == 0)) {
|
||||
continue;
|
||||
}
|
||||
if (lstreq("CONNECT", nv->value, nv->valuelen)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_CONNECT;
|
||||
return;
|
||||
}
|
||||
if (lstreq("HEAD", nv->value, nv->valuelen)) {
|
||||
stream->http_flags |= NGHTTP2_HTTP_FLAG_METH_HEAD;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2015 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_HTTP_H
|
||||
#define NGHTTP2_HTTP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_session.h"
|
||||
#include "nghttp2_stream.h"
|
||||
|
||||
/*
|
||||
* This function is called when HTTP header field |nv| in |frame| is
|
||||
* received for |stream|. This function will validate |nv| against
|
||||
* the current state of stream.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_HTTP_HEADER
|
||||
* Invalid HTTP header field was received.
|
||||
* NGHTTP2_ERR_IGN_HTTP_HEADER
|
||||
* Invalid HTTP header field was received but it can be treated as
|
||||
* if it was not received because of compatibility reasons.
|
||||
*/
|
||||
int nghttp2_http_on_header(nghttp2_session *session, nghttp2_stream *stream,
|
||||
nghttp2_frame *frame, nghttp2_hd_nv *nv,
|
||||
int trailer);
|
||||
|
||||
/*
|
||||
* This function is called when request header is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_request_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* This function is called when response header is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_response_headers(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* This function is called trailer header (for both request and
|
||||
* response) is received. This function performs validation and
|
||||
* returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_trailer_headers(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* This function is called when END_STREAM flag is seen in incoming
|
||||
* frame. This function performs validation and returns 0 if it
|
||||
* succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_remote_end_stream(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* This function is called when chunk of data is received. This
|
||||
* function performs validation and returns 0 if it succeeds, or -1.
|
||||
*/
|
||||
int nghttp2_http_on_data_chunk(nghttp2_stream *stream, size_t n);
|
||||
|
||||
/*
|
||||
* This function inspects header field in |frame| and records its
|
||||
* method in stream->http_flags. If frame->hd.type is neither
|
||||
* NGHTTP2_HEADERS nor NGHTTP2_PUSH_PROMISE, this function does
|
||||
* nothing.
|
||||
*/
|
||||
void nghttp2_http_record_request_method(nghttp2_stream *stream,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
#endif /* NGHTTP2_HTTP_H */
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_INT_H
|
||||
#define NGHTTP2_INT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/* Macros, types and constants for internal use */
|
||||
|
||||
/* "less" function, return nonzero if |lhs| is less than |rhs|. */
|
||||
typedef int (*nghttp2_less)(const void *lhs, const void *rhs);
|
||||
|
||||
/* Internal error code. They must be in the range [-499, -100],
|
||||
inclusive. */
|
||||
typedef enum {
|
||||
NGHTTP2_ERR_CREDENTIAL_PENDING = -101,
|
||||
NGHTTP2_ERR_IGN_HEADER_BLOCK = -103,
|
||||
NGHTTP2_ERR_IGN_PAYLOAD = -104,
|
||||
/*
|
||||
* Invalid HTTP header field was received but it can be treated as
|
||||
* if it was not received because of compatibility reasons.
|
||||
*/
|
||||
NGHTTP2_ERR_IGN_HTTP_HEADER = -105,
|
||||
/*
|
||||
* Invalid HTTP header field was received, and it is ignored.
|
||||
* Unlike NGHTTP2_ERR_IGN_HTTP_HEADER, this does not invoke
|
||||
* nghttp2_on_invalid_header_callback.
|
||||
*/
|
||||
NGHTTP2_ERR_REMOVE_HTTP_HEADER = -106
|
||||
} nghttp2_internal_error;
|
||||
|
||||
#endif /* NGHTTP2_INT_H */
|
||||
@@ -0,0 +1,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,123 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_option.h"
|
||||
|
||||
#include "nghttp2_session.h"
|
||||
|
||||
int nghttp2_option_new(nghttp2_option **option_ptr) {
|
||||
*option_ptr = calloc(1, sizeof(nghttp2_option));
|
||||
|
||||
if (*option_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_option_del(nghttp2_option *option) { free(option); }
|
||||
|
||||
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE;
|
||||
option->no_auto_window_update = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
|
||||
uint32_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS;
|
||||
option->peer_max_concurrent_streams = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_recv_client_magic(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC;
|
||||
option->no_recv_client_magic = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_http_messaging(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_HTTP_MESSAGING;
|
||||
option->no_http_messaging = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_reserved_remote_streams(nghttp2_option *option,
|
||||
uint32_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS;
|
||||
option->max_reserved_remote_streams = val;
|
||||
}
|
||||
|
||||
static void set_ext_type(uint8_t *ext_types, uint8_t type) {
|
||||
ext_types[type / 8] = (uint8_t)(ext_types[type / 8] | (1 << (type & 0x7)));
|
||||
}
|
||||
|
||||
void nghttp2_option_set_user_recv_extension_type(nghttp2_option *option,
|
||||
uint8_t type) {
|
||||
if (type < 10) {
|
||||
return;
|
||||
}
|
||||
|
||||
option->opt_set_mask |= NGHTTP2_OPT_USER_RECV_EXT_TYPES;
|
||||
set_ext_type(option->user_recv_ext_types, type);
|
||||
}
|
||||
|
||||
void nghttp2_option_set_builtin_recv_extension_type(nghttp2_option *option,
|
||||
uint8_t type) {
|
||||
switch (type) {
|
||||
case NGHTTP2_ALTSVC:
|
||||
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ALTSVC;
|
||||
return;
|
||||
case NGHTTP2_ORIGIN:
|
||||
option->opt_set_mask |= NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES;
|
||||
option->builtin_recv_ext_types |= NGHTTP2_TYPEMASK_ORIGIN;
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_auto_ping_ack(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_PING_ACK;
|
||||
option->no_auto_ping_ack = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_send_header_block_length(nghttp2_option *option,
|
||||
size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH;
|
||||
option->max_send_header_block_length = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_deflate_dynamic_table_size(nghttp2_option *option,
|
||||
size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE;
|
||||
option->max_deflate_dynamic_table_size = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_no_closed_streams(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_CLOSED_STREAMS;
|
||||
option->no_closed_streams = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_max_outbound_ack(nghttp2_option *option, size_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_MAX_OUTBOUND_ACK;
|
||||
option->max_outbound_ack = val;
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_OPTION_H
|
||||
#define NGHTTP2_OPTION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/**
|
||||
* Configuration options
|
||||
*/
|
||||
typedef enum {
|
||||
/**
|
||||
* This option prevents the library from sending WINDOW_UPDATE for a
|
||||
* connection automatically. If this option is set to nonzero, the
|
||||
* library won't send WINDOW_UPDATE for DATA until application calls
|
||||
* nghttp2_session_consume() to indicate the amount of consumed
|
||||
* DATA. By default, this option is set to zero.
|
||||
*/
|
||||
NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE = 1,
|
||||
/**
|
||||
* This option sets the SETTINGS_MAX_CONCURRENT_STREAMS value of
|
||||
* remote endpoint as if it is received in SETTINGS frame. Without
|
||||
* specifying this option, before the local endpoint receives
|
||||
* SETTINGS_MAX_CONCURRENT_STREAMS in SETTINGS frame from remote
|
||||
* endpoint, SETTINGS_MAX_CONCURRENT_STREAMS is unlimited. This may
|
||||
* cause problem if local endpoint submits lots of requests
|
||||
* initially and sending them at once to the remote peer may lead to
|
||||
* the rejection of some requests. Specifying this option to the
|
||||
* sensible value, say 100, may avoid this kind of issue. This value
|
||||
* will be overwritten if the local endpoint receives
|
||||
* SETTINGS_MAX_CONCURRENT_STREAMS from the remote endpoint.
|
||||
*/
|
||||
NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS = 1 << 1,
|
||||
NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC = 1 << 2,
|
||||
NGHTTP2_OPT_NO_HTTP_MESSAGING = 1 << 3,
|
||||
NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS = 1 << 4,
|
||||
NGHTTP2_OPT_USER_RECV_EXT_TYPES = 1 << 5,
|
||||
NGHTTP2_OPT_NO_AUTO_PING_ACK = 1 << 6,
|
||||
NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES = 1 << 7,
|
||||
NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH = 1 << 8,
|
||||
NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE = 1 << 9,
|
||||
NGHTTP2_OPT_NO_CLOSED_STREAMS = 1 << 10,
|
||||
NGHTTP2_OPT_MAX_OUTBOUND_ACK = 1 << 11,
|
||||
} nghttp2_option_flag;
|
||||
|
||||
/**
|
||||
* Struct to store option values for nghttp2_session.
|
||||
*/
|
||||
struct nghttp2_option {
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_SEND_HEADER_BLOCK_LENGTH
|
||||
*/
|
||||
size_t max_send_header_block_length;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_DEFLATE_DYNAMIC_TABLE_SIZE
|
||||
*/
|
||||
size_t max_deflate_dynamic_table_size;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_OUTBOUND_ACK
|
||||
*/
|
||||
size_t max_outbound_ack;
|
||||
/**
|
||||
* Bitwise OR of nghttp2_option_flag to determine that which fields
|
||||
* are specified.
|
||||
*/
|
||||
uint32_t opt_set_mask;
|
||||
/**
|
||||
* NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS
|
||||
*/
|
||||
uint32_t peer_max_concurrent_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_MAX_RESERVED_REMOTE_STREAMS
|
||||
*/
|
||||
uint32_t max_reserved_remote_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_BUILTIN_RECV_EXT_TYPES
|
||||
*/
|
||||
uint32_t builtin_recv_ext_types;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE
|
||||
*/
|
||||
int no_auto_window_update;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_RECV_CLIENT_MAGIC
|
||||
*/
|
||||
int no_recv_client_magic;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_HTTP_MESSAGING
|
||||
*/
|
||||
int no_http_messaging;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_AUTO_PING_ACK
|
||||
*/
|
||||
int no_auto_ping_ack;
|
||||
/**
|
||||
* NGHTTP2_OPT_NO_CLOSED_STREAMS
|
||||
*/
|
||||
int no_closed_streams;
|
||||
/**
|
||||
* NGHTTP2_OPT_USER_RECV_EXT_TYPES
|
||||
*/
|
||||
uint8_t user_recv_ext_types[32];
|
||||
};
|
||||
|
||||
#endif /* NGHTTP2_OPTION_H */
|
||||
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_outbound_item.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
void nghttp2_outbound_item_init(nghttp2_outbound_item *item) {
|
||||
item->cycle = 0;
|
||||
item->qnext = NULL;
|
||||
item->queued = 0;
|
||||
|
||||
memset(&item->aux_data, 0, sizeof(nghttp2_aux_data));
|
||||
}
|
||||
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem) {
|
||||
nghttp2_frame *frame;
|
||||
|
||||
if (item == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
nghttp2_frame_headers_free(&frame->headers, mem);
|
||||
break;
|
||||
case NGHTTP2_PRIORITY:
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
break;
|
||||
case NGHTTP2_RST_STREAM:
|
||||
nghttp2_frame_rst_stream_free(&frame->rst_stream);
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
nghttp2_frame_settings_free(&frame->settings, mem);
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
nghttp2_frame_push_promise_free(&frame->push_promise, mem);
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
nghttp2_frame_ping_free(&frame->ping);
|
||||
break;
|
||||
case NGHTTP2_GOAWAY:
|
||||
nghttp2_frame_goaway_free(&frame->goaway, mem);
|
||||
break;
|
||||
case NGHTTP2_WINDOW_UPDATE:
|
||||
nghttp2_frame_window_update_free(&frame->window_update);
|
||||
break;
|
||||
default: {
|
||||
nghttp2_ext_aux_data *aux_data;
|
||||
|
||||
aux_data = &item->aux_data.ext;
|
||||
|
||||
if (aux_data->builtin == 0) {
|
||||
nghttp2_frame_extension_free(&frame->ext);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_ALTSVC:
|
||||
nghttp2_frame_altsvc_free(&frame->ext, mem);
|
||||
break;
|
||||
case NGHTTP2_ORIGIN:
|
||||
nghttp2_frame_origin_free(&frame->ext, mem);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q) {
|
||||
q->head = q->tail = NULL;
|
||||
q->n = 0;
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||
nghttp2_outbound_item *item) {
|
||||
if (q->tail) {
|
||||
q->tail = q->tail->qnext = item;
|
||||
} else {
|
||||
q->head = q->tail = item;
|
||||
}
|
||||
++q->n;
|
||||
}
|
||||
|
||||
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q) {
|
||||
nghttp2_outbound_item *item;
|
||||
if (!q->head) {
|
||||
return;
|
||||
}
|
||||
item = q->head;
|
||||
q->head = q->head->qnext;
|
||||
item->qnext = NULL;
|
||||
if (!q->head) {
|
||||
q->tail = NULL;
|
||||
}
|
||||
--q->n;
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_OUTBOUND_ITEM_H
|
||||
#define NGHTTP2_OUTBOUND_ITEM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
/* struct used for HEADERS and PUSH_PROMISE frame */
|
||||
typedef struct {
|
||||
nghttp2_data_provider data_prd;
|
||||
void *stream_user_data;
|
||||
/* error code when request HEADERS is canceled by RST_STREAM while
|
||||
it is in queue. */
|
||||
uint32_t error_code;
|
||||
/* nonzero if request HEADERS is canceled. The error code is stored
|
||||
in |error_code|. */
|
||||
uint8_t canceled;
|
||||
} nghttp2_headers_aux_data;
|
||||
|
||||
/* struct used for DATA frame */
|
||||
typedef struct {
|
||||
/**
|
||||
* The data to be sent for this DATA frame.
|
||||
*/
|
||||
nghttp2_data_provider data_prd;
|
||||
/**
|
||||
* The flags of DATA frame. We use separate flags here and
|
||||
* nghttp2_data frame. The latter contains flags actually sent to
|
||||
* peer. This |flags| may contain NGHTTP2_FLAG_END_STREAM and only
|
||||
* when |eof| becomes nonzero, flags in nghttp2_data has
|
||||
* NGHTTP2_FLAG_END_STREAM set.
|
||||
*/
|
||||
uint8_t flags;
|
||||
/**
|
||||
* The flag to indicate whether EOF was reached or not. Initially
|
||||
* |eof| is 0. It becomes 1 after all data were read.
|
||||
*/
|
||||
uint8_t eof;
|
||||
/**
|
||||
* The flag to indicate that NGHTTP2_DATA_FLAG_NO_COPY is used.
|
||||
*/
|
||||
uint8_t no_copy;
|
||||
} nghttp2_data_aux_data;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_GOAWAY_AUX_NONE = 0x0,
|
||||
/* indicates that session should be terminated after the
|
||||
transmission of this frame. */
|
||||
NGHTTP2_GOAWAY_AUX_TERM_ON_SEND = 0x1,
|
||||
/* indicates that this GOAWAY is just a notification for graceful
|
||||
shutdown. No nghttp2_session.goaway_flags should be updated on
|
||||
the reaction to this frame. */
|
||||
NGHTTP2_GOAWAY_AUX_SHUTDOWN_NOTICE = 0x2
|
||||
} nghttp2_goaway_aux_flag;
|
||||
|
||||
/* struct used for GOAWAY frame */
|
||||
typedef struct {
|
||||
/* bitwise-OR of one or more of nghttp2_goaway_aux_flag. */
|
||||
uint8_t flags;
|
||||
} nghttp2_goaway_aux_data;
|
||||
|
||||
/* struct used for extension frame */
|
||||
typedef struct {
|
||||
/* nonzero if this extension frame is serialized by library
|
||||
function, instead of user-defined callbacks. */
|
||||
uint8_t builtin;
|
||||
} nghttp2_ext_aux_data;
|
||||
|
||||
/* Additional data which cannot be stored in nghttp2_frame struct */
|
||||
typedef union {
|
||||
nghttp2_data_aux_data data;
|
||||
nghttp2_headers_aux_data headers;
|
||||
nghttp2_goaway_aux_data goaway;
|
||||
nghttp2_ext_aux_data ext;
|
||||
} nghttp2_aux_data;
|
||||
|
||||
struct nghttp2_outbound_item;
|
||||
typedef struct nghttp2_outbound_item nghttp2_outbound_item;
|
||||
|
||||
struct nghttp2_outbound_item {
|
||||
nghttp2_frame frame;
|
||||
/* Storage for extension frame payload. frame->ext.payload points
|
||||
to this structure to avoid frequent memory allocation. */
|
||||
nghttp2_ext_frame_payload ext_frame_payload;
|
||||
nghttp2_aux_data aux_data;
|
||||
/* The priority used in priority comparion. Smaller is served
|
||||
earlier. For PING, SETTINGS and non-DATA frames (excluding
|
||||
response HEADERS frame) have dedicated cycle value defined above.
|
||||
For DATA frame, cycle is computed by taking into account of
|
||||
effective weight and frame payload length previously sent, so
|
||||
that the amount of transmission is distributed across streams
|
||||
proportional to effective weight (inside a tree). */
|
||||
uint64_t cycle;
|
||||
nghttp2_outbound_item *qnext;
|
||||
/* nonzero if this object is queued, except for DATA or HEADERS
|
||||
which are attached to stream as item. */
|
||||
uint8_t queued;
|
||||
};
|
||||
|
||||
/*
|
||||
* Initializes |item|. No memory allocation is done in this function.
|
||||
* Don't call nghttp2_outbound_item_free() until frame member is
|
||||
* initialized.
|
||||
*/
|
||||
void nghttp2_outbound_item_init(nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Deallocates resource for |item|. If |item| is NULL, this function
|
||||
* does nothing.
|
||||
*/
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* queue for nghttp2_outbound_item.
|
||||
*/
|
||||
typedef struct {
|
||||
nghttp2_outbound_item *head, *tail;
|
||||
/* number of items in this queue. */
|
||||
size_t n;
|
||||
} nghttp2_outbound_queue;
|
||||
|
||||
void nghttp2_outbound_queue_init(nghttp2_outbound_queue *q);
|
||||
|
||||
/* Pushes |item| into |q| */
|
||||
void nghttp2_outbound_queue_push(nghttp2_outbound_queue *q,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/* Pops |item| at the top from |q|. If |q| is empty, nothing
|
||||
happens. */
|
||||
void nghttp2_outbound_queue_pop(nghttp2_outbound_queue *q);
|
||||
|
||||
/* Returns the top item. */
|
||||
#define nghttp2_outbound_queue_top(Q) ((Q)->head)
|
||||
|
||||
/* Returns the size of the queue */
|
||||
#define nghttp2_outbound_queue_size(Q) ((Q)->n)
|
||||
|
||||
#endif /* NGHTTP2_OUTBOUND_ITEM_H */
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_pq.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem) {
|
||||
pq->mem = mem;
|
||||
pq->capacity = 0;
|
||||
pq->q = NULL;
|
||||
pq->length = 0;
|
||||
pq->less = less;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_pq_free(nghttp2_pq *pq) {
|
||||
nghttp2_mem_free(pq->mem, pq->q);
|
||||
pq->q = NULL;
|
||||
}
|
||||
|
||||
static void swap(nghttp2_pq *pq, size_t i, size_t j) {
|
||||
nghttp2_pq_entry *a = pq->q[i];
|
||||
nghttp2_pq_entry *b = pq->q[j];
|
||||
|
||||
pq->q[i] = b;
|
||||
b->index = i;
|
||||
pq->q[j] = a;
|
||||
a->index = j;
|
||||
}
|
||||
|
||||
static void bubble_up(nghttp2_pq *pq, size_t index) {
|
||||
size_t parent;
|
||||
while (index != 0) {
|
||||
parent = (index - 1) / 2;
|
||||
if (!pq->less(pq->q[index], pq->q[parent])) {
|
||||
return;
|
||||
}
|
||||
swap(pq, parent, index);
|
||||
index = parent;
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item) {
|
||||
if (pq->capacity <= pq->length) {
|
||||
void *nq;
|
||||
size_t ncapacity;
|
||||
|
||||
ncapacity = nghttp2_max(4, (pq->capacity * 2));
|
||||
|
||||
nq = nghttp2_mem_realloc(pq->mem, pq->q,
|
||||
ncapacity * sizeof(nghttp2_pq_entry *));
|
||||
if (nq == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
pq->capacity = ncapacity;
|
||||
pq->q = nq;
|
||||
}
|
||||
pq->q[pq->length] = item;
|
||||
item->index = pq->length;
|
||||
++pq->length;
|
||||
bubble_up(pq, pq->length - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq) {
|
||||
if (pq->length == 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
return pq->q[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void bubble_down(nghttp2_pq *pq, size_t index) {
|
||||
size_t i, j, minindex;
|
||||
for (;;) {
|
||||
j = index * 2 + 1;
|
||||
minindex = index;
|
||||
for (i = 0; i < 2; ++i, ++j) {
|
||||
if (j >= pq->length) {
|
||||
break;
|
||||
}
|
||||
if (pq->less(pq->q[j], pq->q[minindex])) {
|
||||
minindex = j;
|
||||
}
|
||||
}
|
||||
if (minindex == index) {
|
||||
return;
|
||||
}
|
||||
swap(pq, index, minindex);
|
||||
index = minindex;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_pq_pop(nghttp2_pq *pq) {
|
||||
if (pq->length > 0) {
|
||||
pq->q[0] = pq->q[pq->length - 1];
|
||||
pq->q[0]->index = 0;
|
||||
--pq->length;
|
||||
bubble_down(pq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item) {
|
||||
assert(pq->q[item->index] == item);
|
||||
|
||||
if (item->index == 0) {
|
||||
nghttp2_pq_pop(pq);
|
||||
return;
|
||||
}
|
||||
|
||||
if (item->index == pq->length - 1) {
|
||||
--pq->length;
|
||||
return;
|
||||
}
|
||||
|
||||
pq->q[item->index] = pq->q[pq->length - 1];
|
||||
pq->q[item->index]->index = item->index;
|
||||
--pq->length;
|
||||
|
||||
if (pq->less(item, pq->q[item->index])) {
|
||||
bubble_down(pq, item->index);
|
||||
} else {
|
||||
bubble_up(pq, item->index);
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_empty(nghttp2_pq *pq) { return pq->length == 0; }
|
||||
|
||||
size_t nghttp2_pq_size(nghttp2_pq *pq) { return pq->length; }
|
||||
|
||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) {
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
if (pq->length == 0) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < pq->length; ++i) {
|
||||
rv |= (*fun)(pq->q[i], arg);
|
||||
}
|
||||
if (rv) {
|
||||
for (i = pq->length; i > 0; --i) {
|
||||
bubble_down(pq, i - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) {
|
||||
size_t i;
|
||||
|
||||
if (pq->length == 0) {
|
||||
return 0;
|
||||
}
|
||||
for (i = 0; i < pq->length; ++i) {
|
||||
if ((*fun)(pq->q[i], arg)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_PQ_H
|
||||
#define NGHTTP2_PQ_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_int.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
/* Implementation of priority queue */
|
||||
|
||||
typedef struct {
|
||||
size_t index;
|
||||
} nghttp2_pq_entry;
|
||||
|
||||
typedef struct {
|
||||
/* The pointer to the pointer to the item stored */
|
||||
nghttp2_pq_entry **q;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem *mem;
|
||||
/* The number of items stored */
|
||||
size_t length;
|
||||
/* The maximum number of items this pq can store. This is
|
||||
automatically extended when length is reached to this value. */
|
||||
size_t capacity;
|
||||
/* The less function between items */
|
||||
nghttp2_less less;
|
||||
} nghttp2_pq;
|
||||
|
||||
/*
|
||||
* Initializes priority queue |pq| with compare function |cmp|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_less less, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Deallocates any resources allocated for |pq|. The stored items are
|
||||
* not freed by this function.
|
||||
*/
|
||||
void nghttp2_pq_free(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Adds |item| to the priority queue |pq|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_pq_push(nghttp2_pq *pq, nghttp2_pq_entry *item);
|
||||
|
||||
/*
|
||||
* Returns item at the top of the queue |pq|. If the queue is empty,
|
||||
* this function returns NULL.
|
||||
*/
|
||||
nghttp2_pq_entry *nghttp2_pq_top(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Pops item at the top of the queue |pq|. The popped item is not
|
||||
* freed by this function.
|
||||
*/
|
||||
void nghttp2_pq_pop(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the queue |pq| is empty.
|
||||
*/
|
||||
int nghttp2_pq_empty(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Returns the number of items in the queue |pq|.
|
||||
*/
|
||||
size_t nghttp2_pq_size(nghttp2_pq *pq);
|
||||
|
||||
typedef int (*nghttp2_pq_item_cb)(nghttp2_pq_entry *item, void *arg);
|
||||
|
||||
/*
|
||||
* Updates each item in |pq| using function |fun| and re-construct
|
||||
* priority queue. The |fun| must return non-zero if it modifies the
|
||||
* item in a way that it affects ordering in the priority queue. The
|
||||
* |arg| is passed to the 2nd parameter of |fun|.
|
||||
*/
|
||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
||||
|
||||
/*
|
||||
* Applys |fun| to each item in |pq|. The |arg| is passed as arg
|
||||
* parameter to callback function. This function must not change the
|
||||
* ordering key. If the return value from callback is nonzero, this
|
||||
* function returns 1 immediately without iterating remaining items.
|
||||
* Otherwise this function returns 0.
|
||||
*/
|
||||
int nghttp2_pq_each(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg);
|
||||
|
||||
/*
|
||||
* Removes |item| from priority queue.
|
||||
*/
|
||||
void nghttp2_pq_remove(nghttp2_pq *pq, nghttp2_pq_entry *item);
|
||||
|
||||
#endif /* NGHTTP2_PQ_H */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
|
||||
int32_t stream_id, int32_t weight,
|
||||
int exclusive) {
|
||||
pri_spec->stream_id = stream_id;
|
||||
pri_spec->weight = weight;
|
||||
pri_spec->exclusive = exclusive != 0;
|
||||
}
|
||||
|
||||
void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) {
|
||||
pri_spec->stream_id = 0;
|
||||
pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT;
|
||||
pri_spec->exclusive = 0;
|
||||
}
|
||||
|
||||
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) {
|
||||
return pri_spec->stream_id == 0 &&
|
||||
pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT && pri_spec->exclusive == 0;
|
||||
}
|
||||
|
||||
void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec) {
|
||||
if (pri_spec->weight < NGHTTP2_MIN_WEIGHT) {
|
||||
pri_spec->weight = NGHTTP2_MIN_WEIGHT;
|
||||
} else if (pri_spec->weight > NGHTTP2_MAX_WEIGHT) {
|
||||
pri_spec->weight = NGHTTP2_MAX_WEIGHT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2014 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_PRIORITY_SPEC_H
|
||||
#define NGHTTP2_PRIORITY_SPEC_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
/*
|
||||
* This function normalizes pri_spec->weight if it is out of range.
|
||||
* If pri_spec->weight is less than NGHTTP2_MIN_WEIGHT, it is set to
|
||||
* NGHTTP2_MIN_WEIGHT. If pri_spec->weight is larger than
|
||||
* NGHTTP2_MAX_WEIGHT, it is set to NGHTTP2_MAX_WEIGHT.
|
||||
*/
|
||||
void nghttp2_priority_spec_normalize_weight(nghttp2_priority_spec *pri_spec);
|
||||
|
||||
#endif /* NGHTTP2_PRIORITY_SPEC_H */
|
||||
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_queue.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
void nghttp2_queue_init(nghttp2_queue *queue) {
|
||||
queue->front = queue->back = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_queue_free(nghttp2_queue *queue) {
|
||||
if (!queue) {
|
||||
return;
|
||||
} else {
|
||||
nghttp2_queue_cell *p = queue->front;
|
||||
while (p) {
|
||||
nghttp2_queue_cell *next = p->next;
|
||||
free(p);
|
||||
p = next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_queue_push(nghttp2_queue *queue, void *data) {
|
||||
nghttp2_queue_cell *new_cell =
|
||||
(nghttp2_queue_cell *)malloc(sizeof(nghttp2_queue_cell));
|
||||
if (!new_cell) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
new_cell->data = data;
|
||||
new_cell->next = NULL;
|
||||
if (queue->back) {
|
||||
queue->back->next = new_cell;
|
||||
queue->back = new_cell;
|
||||
|
||||
} else {
|
||||
queue->front = queue->back = new_cell;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_queue_pop(nghttp2_queue *queue) {
|
||||
nghttp2_queue_cell *front = queue->front;
|
||||
assert(front);
|
||||
queue->front = front->next;
|
||||
if (front == queue->back) {
|
||||
queue->back = NULL;
|
||||
}
|
||||
free(front);
|
||||
}
|
||||
|
||||
void *nghttp2_queue_front(nghttp2_queue *queue) {
|
||||
assert(queue->front);
|
||||
return queue->front->data;
|
||||
}
|
||||
|
||||
void *nghttp2_queue_back(nghttp2_queue *queue) {
|
||||
assert(queue->back);
|
||||
return queue->back->data;
|
||||
}
|
||||
|
||||
int nghttp2_queue_empty(nghttp2_queue *queue) { return queue->front == NULL; }
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_QUEUE_H
|
||||
#define NGHTTP2_QUEUE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
typedef struct nghttp2_queue_cell {
|
||||
void *data;
|
||||
struct nghttp2_queue_cell *next;
|
||||
} nghttp2_queue_cell;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_queue_cell *front, *back;
|
||||
} nghttp2_queue;
|
||||
|
||||
void nghttp2_queue_init(nghttp2_queue *queue);
|
||||
void nghttp2_queue_free(nghttp2_queue *queue);
|
||||
int nghttp2_queue_push(nghttp2_queue *queue, void *data);
|
||||
void nghttp2_queue_pop(nghttp2_queue *queue);
|
||||
void *nghttp2_queue_front(nghttp2_queue *queue);
|
||||
void *nghttp2_queue_back(nghttp2_queue *queue);
|
||||
int nghttp2_queue_empty(nghttp2_queue *queue);
|
||||
|
||||
#endif /* NGHTTP2_QUEUE_H */
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "nghttp2_rcbuf.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "nghttp2_mem.h"
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size,
|
||||
nghttp2_mem *mem) {
|
||||
uint8_t *p;
|
||||
|
||||
p = nghttp2_mem_malloc(mem, sizeof(nghttp2_rcbuf) + size);
|
||||
if (p == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
*rcbuf_ptr = (void *)p;
|
||||
|
||||
(*rcbuf_ptr)->mem_user_data = mem->mem_user_data;
|
||||
(*rcbuf_ptr)->free = mem->free;
|
||||
(*rcbuf_ptr)->base = p + sizeof(nghttp2_rcbuf);
|
||||
(*rcbuf_ptr)->len = size;
|
||||
(*rcbuf_ptr)->ref = 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src,
|
||||
size_t srclen, nghttp2_mem *mem) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_rcbuf_new(rcbuf_ptr, srclen + 1, mem);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
(*rcbuf_ptr)->len = srclen;
|
||||
*nghttp2_cpymem((*rcbuf_ptr)->base, src, srclen) = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Frees |rcbuf| itself, regardless of its reference cout.
|
||||
*/
|
||||
void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf) {
|
||||
nghttp2_mem_free2(rcbuf->free, rcbuf, rcbuf->mem_user_data);
|
||||
}
|
||||
|
||||
void nghttp2_rcbuf_incref(nghttp2_rcbuf *rcbuf) {
|
||||
if (rcbuf->ref == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
++rcbuf->ref;
|
||||
}
|
||||
|
||||
void nghttp2_rcbuf_decref(nghttp2_rcbuf *rcbuf) {
|
||||
if (rcbuf == NULL || rcbuf->ref == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(rcbuf->ref > 0);
|
||||
|
||||
if (--rcbuf->ref == 0) {
|
||||
nghttp2_rcbuf_del(rcbuf);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_vec nghttp2_rcbuf_get_buf(nghttp2_rcbuf *rcbuf) {
|
||||
nghttp2_vec res = {rcbuf->base, rcbuf->len};
|
||||
return res;
|
||||
}
|
||||
|
||||
int nghttp2_rcbuf_is_static(const nghttp2_rcbuf *rcbuf) {
|
||||
return rcbuf->ref == -1;
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2016 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_RCBUF_H
|
||||
#define NGHTTP2_RCBUF_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
struct nghttp2_rcbuf {
|
||||
/* custom memory allocator belongs to the mem parameter when
|
||||
creating this object. */
|
||||
void *mem_user_data;
|
||||
nghttp2_free free;
|
||||
/* The pointer to the underlying buffer */
|
||||
uint8_t *base;
|
||||
/* Size of buffer pointed by |base|. */
|
||||
size_t len;
|
||||
/* Reference count */
|
||||
int32_t ref;
|
||||
};
|
||||
|
||||
/*
|
||||
* Allocates nghttp2_rcbuf object with |size| as initial buffer size.
|
||||
* When the function succeeds, the reference count becomes 1.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM:
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_rcbuf_new(nghttp2_rcbuf **rcbuf_ptr, size_t size, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Like nghttp2_rcbuf_new(), but initializes the buffer with |src| of
|
||||
* length |srclen|. This function allocates additional byte at the
|
||||
* end and puts '\0' into it, so that the resulting buffer could be
|
||||
* used as NULL-terminated string. Still (*rcbuf_ptr)->len equals to
|
||||
* |srclen|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM:
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_rcbuf_new2(nghttp2_rcbuf **rcbuf_ptr, const uint8_t *src,
|
||||
size_t srclen, nghttp2_mem *mem);
|
||||
|
||||
/*
|
||||
* Frees |rcbuf| itself, regardless of its reference cout.
|
||||
*/
|
||||
void nghttp2_rcbuf_del(nghttp2_rcbuf *rcbuf);
|
||||
|
||||
#endif /* NGHTTP2_RCBUF_H */
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,901 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_SESSION_H
|
||||
#define NGHTTP2_SESSION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_map.h"
|
||||
#include "nghttp2_frame.h"
|
||||
#include "nghttp2_hd.h"
|
||||
#include "nghttp2_stream.h"
|
||||
#include "nghttp2_outbound_item.h"
|
||||
#include "nghttp2_int.h"
|
||||
#include "nghttp2_buf.h"
|
||||
#include "nghttp2_callbacks.h"
|
||||
#include "nghttp2_mem.h"
|
||||
|
||||
/* The global variable for tests where we want to disable strict
|
||||
preface handling. */
|
||||
extern int nghttp2_enable_strict_preface;
|
||||
|
||||
/*
|
||||
* Option flags.
|
||||
*/
|
||||
typedef enum {
|
||||
NGHTTP2_OPTMASK_NO_AUTO_WINDOW_UPDATE = 1 << 0,
|
||||
NGHTTP2_OPTMASK_NO_RECV_CLIENT_MAGIC = 1 << 1,
|
||||
NGHTTP2_OPTMASK_NO_HTTP_MESSAGING = 1 << 2,
|
||||
NGHTTP2_OPTMASK_NO_AUTO_PING_ACK = 1 << 3,
|
||||
NGHTTP2_OPTMASK_NO_CLOSED_STREAMS = 1 << 4
|
||||
} nghttp2_optmask;
|
||||
|
||||
/*
|
||||
* bitmask for built-in type to enable the default handling for that
|
||||
* type of the frame.
|
||||
*/
|
||||
typedef enum {
|
||||
NGHTTP2_TYPEMASK_NONE = 0,
|
||||
NGHTTP2_TYPEMASK_ALTSVC = 1 << 0,
|
||||
NGHTTP2_TYPEMASK_ORIGIN = 1 << 1
|
||||
} nghttp2_typemask;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_OB_POP_ITEM,
|
||||
NGHTTP2_OB_SEND_DATA,
|
||||
NGHTTP2_OB_SEND_NO_COPY,
|
||||
NGHTTP2_OB_SEND_CLIENT_MAGIC
|
||||
} nghttp2_outbound_state;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_bufs framebufs;
|
||||
nghttp2_outbound_state state;
|
||||
} nghttp2_active_outbound_item;
|
||||
|
||||
/* Buffer length for inbound raw byte stream used in
|
||||
nghttp2_session_recv(). */
|
||||
#define NGHTTP2_INBOUND_BUFFER_LENGTH 16384
|
||||
|
||||
/* The default maximum number of incoming reserved streams */
|
||||
#define NGHTTP2_MAX_INCOMING_RESERVED_STREAMS 200
|
||||
|
||||
/* Even if we have less SETTINGS_MAX_CONCURRENT_STREAMS than this
|
||||
number, we keep NGHTTP2_MIN_IDLE_STREAMS streams in idle state */
|
||||
#define NGHTTP2_MIN_IDLE_STREAMS 16
|
||||
|
||||
/* The maximum number of items in outbound queue, which is considered
|
||||
as flooding caused by peer. All frames are not considered here.
|
||||
We only consider PING + ACK and SETTINGS + ACK. This is because
|
||||
they both are response to the frame initiated by peer and peer can
|
||||
send as many of them as they want. If peer does not read network,
|
||||
response frames are stacked up, which leads to memory exhaustion.
|
||||
The value selected here is arbitrary, but safe value and if we have
|
||||
these frames in this number, it is considered suspicious. */
|
||||
#define NGHTTP2_DEFAULT_MAX_OBQ_FLOOD_ITEM 1000
|
||||
|
||||
/* The default value of maximum number of concurrent streams. */
|
||||
#define NGHTTP2_DEFAULT_MAX_CONCURRENT_STREAMS 0xffffffffu
|
||||
|
||||
/* Internal state when receiving incoming frame */
|
||||
typedef enum {
|
||||
/* Receiving frame header */
|
||||
NGHTTP2_IB_READ_CLIENT_MAGIC,
|
||||
NGHTTP2_IB_READ_FIRST_SETTINGS,
|
||||
NGHTTP2_IB_READ_HEAD,
|
||||
NGHTTP2_IB_READ_NBYTE,
|
||||
NGHTTP2_IB_READ_HEADER_BLOCK,
|
||||
NGHTTP2_IB_IGN_HEADER_BLOCK,
|
||||
NGHTTP2_IB_IGN_PAYLOAD,
|
||||
NGHTTP2_IB_FRAME_SIZE_ERROR,
|
||||
NGHTTP2_IB_READ_SETTINGS,
|
||||
NGHTTP2_IB_READ_GOAWAY_DEBUG,
|
||||
NGHTTP2_IB_EXPECT_CONTINUATION,
|
||||
NGHTTP2_IB_IGN_CONTINUATION,
|
||||
NGHTTP2_IB_READ_PAD_DATA,
|
||||
NGHTTP2_IB_READ_DATA,
|
||||
NGHTTP2_IB_IGN_DATA,
|
||||
NGHTTP2_IB_IGN_ALL,
|
||||
NGHTTP2_IB_READ_ALTSVC_PAYLOAD,
|
||||
NGHTTP2_IB_READ_ORIGIN_PAYLOAD,
|
||||
NGHTTP2_IB_READ_EXTENSION_PAYLOAD
|
||||
} nghttp2_inbound_state;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_frame frame;
|
||||
/* Storage for extension frame payload. frame->ext.payload points
|
||||
to this structure to avoid frequent memory allocation. */
|
||||
nghttp2_ext_frame_payload ext_frame_payload;
|
||||
/* The received SETTINGS entry. For the standard settings entries,
|
||||
we only keep the last seen value. For
|
||||
SETTINGS_HEADER_TABLE_SIZE, we also keep minimum value in the
|
||||
last index. */
|
||||
nghttp2_settings_entry *iv;
|
||||
/* buffer pointers to small buffer, raw_sbuf */
|
||||
nghttp2_buf sbuf;
|
||||
/* buffer pointers to large buffer, raw_lbuf */
|
||||
nghttp2_buf lbuf;
|
||||
/* Large buffer, malloced on demand */
|
||||
uint8_t *raw_lbuf;
|
||||
/* The number of entry filled in |iv| */
|
||||
size_t niv;
|
||||
/* The number of entries |iv| can store. */
|
||||
size_t max_niv;
|
||||
/* How many bytes we still need to receive for current frame */
|
||||
size_t payloadleft;
|
||||
/* padding length for the current frame */
|
||||
size_t padlen;
|
||||
nghttp2_inbound_state state;
|
||||
/* Small buffer. Currently the largest contiguous chunk to buffer
|
||||
is frame header. We buffer part of payload, but they are smaller
|
||||
than frame header. */
|
||||
uint8_t raw_sbuf[NGHTTP2_FRAME_HDLEN];
|
||||
} nghttp2_inbound_frame;
|
||||
|
||||
typedef struct {
|
||||
uint32_t header_table_size;
|
||||
uint32_t enable_push;
|
||||
uint32_t max_concurrent_streams;
|
||||
uint32_t initial_window_size;
|
||||
uint32_t max_frame_size;
|
||||
uint32_t max_header_list_size;
|
||||
uint32_t enable_connect_protocol;
|
||||
} nghttp2_settings_storage;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_GOAWAY_NONE = 0,
|
||||
/* Flag means that connection should be terminated after sending GOAWAY. */
|
||||
NGHTTP2_GOAWAY_TERM_ON_SEND = 0x1,
|
||||
/* Flag means GOAWAY to terminate session has been sent */
|
||||
NGHTTP2_GOAWAY_TERM_SENT = 0x2,
|
||||
/* Flag means GOAWAY was sent */
|
||||
NGHTTP2_GOAWAY_SENT = 0x4,
|
||||
/* Flag means GOAWAY was received */
|
||||
NGHTTP2_GOAWAY_RECV = 0x8
|
||||
} nghttp2_goaway_flag;
|
||||
|
||||
/* nghttp2_inflight_settings stores the SETTINGS entries which local
|
||||
endpoint has sent to the remote endpoint, and has not received ACK
|
||||
yet. */
|
||||
struct nghttp2_inflight_settings {
|
||||
struct nghttp2_inflight_settings *next;
|
||||
nghttp2_settings_entry *iv;
|
||||
size_t niv;
|
||||
};
|
||||
|
||||
typedef struct nghttp2_inflight_settings nghttp2_inflight_settings;
|
||||
|
||||
struct nghttp2_session {
|
||||
nghttp2_map /* <nghttp2_stream*> */ streams;
|
||||
/* root of dependency tree*/
|
||||
nghttp2_stream root;
|
||||
/* Queue for outbound urgent frames (PING and SETTINGS) */
|
||||
nghttp2_outbound_queue ob_urgent;
|
||||
/* Queue for non-DATA frames */
|
||||
nghttp2_outbound_queue ob_reg;
|
||||
/* Queue for outbound stream-creating HEADERS (request or push
|
||||
response) frame, which are subject to
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS limit. */
|
||||
nghttp2_outbound_queue ob_syn;
|
||||
nghttp2_active_outbound_item aob;
|
||||
nghttp2_inbound_frame iframe;
|
||||
nghttp2_hd_deflater hd_deflater;
|
||||
nghttp2_hd_inflater hd_inflater;
|
||||
nghttp2_session_callbacks callbacks;
|
||||
/* Memory allocator */
|
||||
nghttp2_mem mem;
|
||||
void *user_data;
|
||||
/* Points to the latest incoming closed stream. NULL if there is no
|
||||
closed stream. Only used when session is initialized as
|
||||
server. */
|
||||
nghttp2_stream *closed_stream_head;
|
||||
/* Points to the oldest incoming closed stream. NULL if there is no
|
||||
closed stream. Only used when session is initialized as
|
||||
server. */
|
||||
nghttp2_stream *closed_stream_tail;
|
||||
/* Points to the latest idle stream. NULL if there is no idle
|
||||
stream. Only used when session is initialized as server .*/
|
||||
nghttp2_stream *idle_stream_head;
|
||||
/* Points to the oldest idle stream. NULL if there is no idle
|
||||
stream. Only used when session is initialized as erver. */
|
||||
nghttp2_stream *idle_stream_tail;
|
||||
/* Queue of In-flight SETTINGS values. SETTINGS bearing ACK is not
|
||||
considered as in-flight. */
|
||||
nghttp2_inflight_settings *inflight_settings_head;
|
||||
/* The number of outgoing streams. This will be capped by
|
||||
remote_settings.max_concurrent_streams. */
|
||||
size_t num_outgoing_streams;
|
||||
/* The number of incoming streams. This will be capped by
|
||||
local_settings.max_concurrent_streams. */
|
||||
size_t num_incoming_streams;
|
||||
/* The number of incoming reserved streams. This is the number of
|
||||
streams in reserved (remote) state. RFC 7540 does not limit this
|
||||
number. nghttp2 offers
|
||||
nghttp2_option_set_max_reserved_remote_streams() to achieve this.
|
||||
If it is used, num_incoming_streams is capped by
|
||||
max_incoming_reserved_streams. Client application should
|
||||
consider to set this because without that server can send
|
||||
arbitrary number of PUSH_PROMISE, and exhaust client's memory. */
|
||||
size_t num_incoming_reserved_streams;
|
||||
/* The maximum number of incoming reserved streams (reserved
|
||||
(remote) state). RST_STREAM will be sent for the pushed stream
|
||||
which exceeds this limit. */
|
||||
size_t max_incoming_reserved_streams;
|
||||
/* The number of closed streams still kept in |streams| hash. The
|
||||
closed streams can be accessed through single linked list
|
||||
|closed_stream_head|. The current implementation only keeps
|
||||
incoming streams and session is initialized as server. */
|
||||
size_t num_closed_streams;
|
||||
/* The number of idle streams kept in |streams| hash. The idle
|
||||
streams can be accessed through doubly linked list
|
||||
|idle_stream_head|. The current implementation only keeps idle
|
||||
streams if session is initialized as server. */
|
||||
size_t num_idle_streams;
|
||||
/* The number of bytes allocated for nvbuf */
|
||||
size_t nvbuflen;
|
||||
/* Counter for detecting flooding in outbound queue. If it exceeds
|
||||
max_outbound_ack, session will be closed. */
|
||||
size_t obq_flood_counter_;
|
||||
/* The maximum number of outgoing SETTINGS ACK and PING ACK in
|
||||
outbound queue. */
|
||||
size_t max_outbound_ack;
|
||||
/* The maximum length of header block to send. Calculated by the
|
||||
same way as nghttp2_hd_deflate_bound() does. */
|
||||
size_t max_send_header_block_length;
|
||||
/* Next Stream ID. Made unsigned int to detect >= (1 << 31). */
|
||||
uint32_t next_stream_id;
|
||||
/* The last stream ID this session initiated. For client session,
|
||||
this is the last stream ID it has sent. For server session, it
|
||||
is the last promised stream ID sent in PUSH_PROMISE. */
|
||||
int32_t last_sent_stream_id;
|
||||
/* The largest stream ID received so far */
|
||||
int32_t last_recv_stream_id;
|
||||
/* The largest stream ID which has been processed in some way. This
|
||||
value will be used as last-stream-id when sending GOAWAY
|
||||
frame. */
|
||||
int32_t last_proc_stream_id;
|
||||
/* Counter of unique ID of PING. Wraps when it exceeds
|
||||
NGHTTP2_MAX_UNIQUE_ID */
|
||||
uint32_t next_unique_id;
|
||||
/* This is the last-stream-ID we have sent in GOAWAY */
|
||||
int32_t local_last_stream_id;
|
||||
/* This is the value in GOAWAY frame received from remote endpoint. */
|
||||
int32_t remote_last_stream_id;
|
||||
/* Current sender window size. This value is computed against the
|
||||
current initial window size of remote endpoint. */
|
||||
int32_t remote_window_size;
|
||||
/* Keep track of the number of bytes received without
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE. */
|
||||
int32_t recv_window_size;
|
||||
/* The number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
/* window size for local flow control. It is initially set to
|
||||
NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE and could be
|
||||
increased/decreased by submitting WINDOW_UPDATE. See
|
||||
nghttp2_submit_window_update(). */
|
||||
int32_t local_window_size;
|
||||
/* This flag is used to indicate that the local endpoint received initial
|
||||
SETTINGS frame from the remote endpoint. */
|
||||
uint8_t remote_settings_received;
|
||||
/* Settings value received from the remote endpoint. */
|
||||
nghttp2_settings_storage remote_settings;
|
||||
/* Settings value of the local endpoint. */
|
||||
nghttp2_settings_storage local_settings;
|
||||
/* Option flags. This is bitwise-OR of 0 or more of nghttp2_optmask. */
|
||||
uint32_t opt_flags;
|
||||
/* Unacked local SETTINGS_MAX_CONCURRENT_STREAMS value. We use this
|
||||
to refuse the incoming stream if it exceeds this value. */
|
||||
uint32_t pending_local_max_concurrent_stream;
|
||||
/* The bitwise OR of zero or more of nghttp2_typemask to indicate
|
||||
that the default handling of extension frame is enabled. */
|
||||
uint32_t builtin_recv_ext_types;
|
||||
/* Unacked local ENABLE_PUSH value. We use this to refuse
|
||||
PUSH_PROMISE before SETTINGS ACK is received. */
|
||||
uint8_t pending_enable_push;
|
||||
/* Unacked local ENABLE_CONNECT_PROTOCOL value. We use this to
|
||||
accept :protocol header field before SETTINGS_ACK is received. */
|
||||
uint8_t pending_enable_connect_protocol;
|
||||
/* Nonzero if the session is server side. */
|
||||
uint8_t server;
|
||||
/* Flags indicating GOAWAY is sent and/or received. The flags are
|
||||
composed by bitwise OR-ing nghttp2_goaway_flag. */
|
||||
uint8_t goaway_flags;
|
||||
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
|
||||
this session. The nonzero does not necessarily mean
|
||||
WINDOW_UPDATE is not queued. */
|
||||
uint8_t window_update_queued;
|
||||
/* Bitfield of extension frame types that application is willing to
|
||||
receive. To designate the bit of given frame type i, use
|
||||
user_recv_ext_types[i / 8] & (1 << (i & 0x7)). First 10 frame
|
||||
types are standard frame types and not used in this bitfield. If
|
||||
bit is set, it indicates that incoming frame with that type is
|
||||
passed to user defined callbacks, otherwise they are ignored. */
|
||||
uint8_t user_recv_ext_types[32];
|
||||
};
|
||||
|
||||
/* Struct used when updating initial window size of each active
|
||||
stream. */
|
||||
typedef struct {
|
||||
nghttp2_session *session;
|
||||
int32_t new_window_size, old_window_size;
|
||||
} nghttp2_update_window_size_arg;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_session *session;
|
||||
/* linked list of streams to close */
|
||||
nghttp2_stream *head;
|
||||
int32_t last_stream_id;
|
||||
/* nonzero if GOAWAY is sent to peer, which means we are going to
|
||||
close incoming streams. zero if GOAWAY is received from peer and
|
||||
we are going to close outgoing streams. */
|
||||
int incoming;
|
||||
} nghttp2_close_stream_on_goaway_arg;
|
||||
|
||||
/* TODO stream timeout etc */
|
||||
|
||||
/*
|
||||
* Returns nonzero value if |stream_id| is initiated by local
|
||||
* endpoint.
|
||||
*/
|
||||
int nghttp2_session_is_my_stream_id(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* Adds |item| to the outbound queue in |session|. When this function
|
||||
* succeeds, it takes ownership of |item|. So caller must not free it
|
||||
* on success.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_STREAM_CLOSED
|
||||
* Stream already closed (DATA and PUSH_PROMISE frame only)
|
||||
*/
|
||||
int nghttp2_session_add_item(nghttp2_session *session,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Adds RST_STREAM frame for the stream |stream_id| with the error
|
||||
* code |error_code|. This is a convenient function built on top of
|
||||
* nghttp2_session_add_frame() to add RST_STREAM easily.
|
||||
*
|
||||
* This function simply returns 0 without adding RST_STREAM frame if
|
||||
* given stream is in NGHTTP2_STREAM_CLOSING state, because multiple
|
||||
* RST_STREAM for a stream is redundant.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
/*
|
||||
* Adds PING frame. This is a convenient functin built on top of
|
||||
* nghttp2_session_add_frame() to add PING easily.
|
||||
*
|
||||
* If the |opaque_data| is not NULL, it must point to 8 bytes memory
|
||||
* region of data. The data pointed by |opaque_data| is copied. It can
|
||||
* be NULL. In this case, 8 bytes NULL is used.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue; this only happens
|
||||
* if NGHTTP2_FLAG_ACK is set in |flags|
|
||||
*/
|
||||
int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
|
||||
const uint8_t *opaque_data);
|
||||
|
||||
/*
|
||||
* Adds GOAWAY frame with the last-stream-ID |last_stream_id| and the
|
||||
* error code |error_code|. This is a convenient function built on top
|
||||
* of nghttp2_session_add_frame() to add GOAWAY easily. The
|
||||
* |aux_flags| are bitwise-OR of one or more of
|
||||
* nghttp2_goaway_aux_flag.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The |opaque_data_len| is too large.
|
||||
*/
|
||||
int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
|
||||
uint32_t error_code, const uint8_t *opaque_data,
|
||||
size_t opaque_data_len, uint8_t aux_flags);
|
||||
|
||||
/*
|
||||
* Adds WINDOW_UPDATE frame with stream ID |stream_id| and
|
||||
* window-size-increment |window_size_increment|. This is a convenient
|
||||
* function built on top of nghttp2_session_add_frame() to add
|
||||
* WINDOW_UPDATE easily.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_session_add_window_update(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t window_size_increment);
|
||||
|
||||
/*
|
||||
* Adds SETTINGS frame.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue; this only happens
|
||||
* if NGHTTP2_FLAG_ACK is set in |flags|
|
||||
*/
|
||||
int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_settings_entry *iv, size_t niv);
|
||||
|
||||
/*
|
||||
* Creates new stream in |session| with stream ID |stream_id|,
|
||||
* priority |pri_spec| and flags |flags|. The |flags| is bitwise OR
|
||||
* of nghttp2_stream_flag. Since this function is called when initial
|
||||
* HEADERS is sent or received, these flags are taken from it. The
|
||||
* state of stream is set to |initial_state|. The |stream_user_data|
|
||||
* is a pointer to the arbitrary user supplied data to be associated
|
||||
* to this stream.
|
||||
*
|
||||
* If |initial_state| is NGHTTP2_STREAM_RESERVED, this function sets
|
||||
* NGHTTP2_STREAM_FLAG_PUSH flag set.
|
||||
*
|
||||
* This function returns a pointer to created new stream object, or
|
||||
* NULL.
|
||||
*
|
||||
* This function adjusts neither the number of closed streams or idle
|
||||
* streams. The caller should manually call
|
||||
* nghttp2_session_adjust_closed_stream() or
|
||||
* nghttp2_session_adjust_idle_stream() respectively.
|
||||
*/
|
||||
nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
||||
int32_t stream_id, uint8_t flags,
|
||||
nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_stream_state initial_state,
|
||||
void *stream_user_data);
|
||||
|
||||
/*
|
||||
* Closes stream whose stream ID is |stream_id|. The reason of closure
|
||||
* is indicated by the |error_code|. When closing the stream,
|
||||
* on_stream_close_callback will be called.
|
||||
*
|
||||
* If the session is initialized as server and |stream| is incoming
|
||||
* stream, stream is just marked closed and this function calls
|
||||
* nghttp2_session_keep_closed_stream() with |stream|. Otherwise,
|
||||
* |stream| will be deleted from memory.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The specified stream does not exist.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_close_stream(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
/*
|
||||
* Deletes |stream| from memory. After this function returns, stream
|
||||
* cannot be accessed.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_destroy_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Tries to keep incoming closed stream |stream|. Due to the
|
||||
* limitation of maximum number of streams in memory, |stream| is not
|
||||
* closed and just deleted from memory (see
|
||||
* nghttp2_session_destroy_stream).
|
||||
*/
|
||||
void nghttp2_session_keep_closed_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Appends |stream| to linked list |session->idle_stream_head|. We
|
||||
* apply fixed limit for list size. To fit into that limit, one or
|
||||
* more oldest streams are removed from list as necessary.
|
||||
*/
|
||||
void nghttp2_session_keep_idle_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Detaches |stream| from idle streams linked list.
|
||||
*/
|
||||
void nghttp2_session_detach_idle_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Deletes closed stream to ensure that number of incoming streams
|
||||
* including active and closed is in the maximum number of allowed
|
||||
* stream.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_adjust_closed_stream(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Deletes idle stream to ensure that number of idle streams is in
|
||||
* certain limit.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_adjust_idle_stream(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* If further receptions and transmissions over the stream |stream_id|
|
||||
* are disallowed, close the stream with error code NGHTTP2_NO_ERROR.
|
||||
*
|
||||
* This function returns 0 if it
|
||||
* succeeds, or one of the following negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The specified stream does not exist.
|
||||
*/
|
||||
int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
int nghttp2_session_on_request_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
int nghttp2_session_on_response_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
int nghttp2_session_on_push_response_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Called when HEADERS is received, assuming |frame| is properly
|
||||
* initialized. This function does first validate received frame and
|
||||
* then open stream and call callback functions.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_IGN_HEADER_BLOCK
|
||||
* Frame was rejected and header block must be decoded but
|
||||
* result must be ignored.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Called when PRIORITY is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_priority_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when RST_STREAM is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when SETTINGS is received, assuming |frame| is properly
|
||||
* initialized. If |noack| is non-zero, SETTINGS with ACK will not be
|
||||
* submitted. If |frame| has NGHTTP2_FLAG_ACK flag set, no SETTINGS
|
||||
* with ACK will not be submitted regardless of |noack|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue, and this is most
|
||||
* likely caused by misbehaviour of peer.
|
||||
*/
|
||||
int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame, int noack);
|
||||
|
||||
/*
|
||||
* Called when PUSH_PROMISE is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_IGN_HEADER_BLOCK
|
||||
* Frame was rejected and header block must be decoded but
|
||||
* result must be ignored.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_push_promise_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when PING is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
* NGHTTP2_ERR_FLOODED
|
||||
* There are too many items in outbound queue, and this is most
|
||||
* likely caused by misbehaviour of peer.
|
||||
*/
|
||||
int nghttp2_session_on_ping_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when GOAWAY is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_goaway_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when WINDOW_UPDATE is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_window_update_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when ALTSVC is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_altsvc_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when ORIGIN is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_origin_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Called when DATA is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The callback function failed.
|
||||
*/
|
||||
int nghttp2_session_on_data_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame);
|
||||
|
||||
/*
|
||||
* Returns nghttp2_stream* object whose stream ID is |stream_id|. It
|
||||
* could be NULL if such stream does not exist. This function returns
|
||||
* NULL if stream is marked as closed.
|
||||
*/
|
||||
nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* This function behaves like nghttp2_session_get_stream(), but it
|
||||
* returns stream object even if it is marked as closed or in
|
||||
* NGHTTP2_STREAM_IDLE state.
|
||||
*/
|
||||
nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
* Packs DATA frame |frame| in wire frame format and stores it in
|
||||
* |bufs|. Payload will be read using |aux_data->data_prd|. The
|
||||
* length of payload is at most |datamax| bytes.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_DEFERRED
|
||||
* The DATA frame is postponed.
|
||||
* NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE
|
||||
* The read_callback failed (stream error).
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed (session error).
|
||||
*/
|
||||
int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||
size_t datamax, nghttp2_frame *frame,
|
||||
nghttp2_data_aux_data *aux_data,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Pops and returns next item to send. If there is no such item,
|
||||
* returns NULL. This function takes into account max concurrent
|
||||
* streams. That means if session->ob_syn has item and max concurrent
|
||||
* streams is reached, the even if other queues contain items, then
|
||||
* this function returns NULL.
|
||||
*/
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_session_pop_next_ob_item(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Returns next item to send. If there is no such item, this function
|
||||
* returns NULL. This function takes into account max concurrent
|
||||
* streams. That means if session->ob_syn has item and max concurrent
|
||||
* streams is reached, the even if other queues contain items, then
|
||||
* this function returns NULL.
|
||||
*/
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_session_get_next_ob_item(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Updates local settings with the |iv|. The number of elements in the
|
||||
* array pointed by the |iv| is given by the |niv|. This function
|
||||
* assumes that the all settings_id member in |iv| are in range 1 to
|
||||
* NGHTTP2_SETTINGS_MAX, inclusive.
|
||||
*
|
||||
* While updating individual stream's local window size, if the window
|
||||
* size becomes strictly larger than NGHTTP2_MAX_WINDOW_SIZE,
|
||||
* RST_STREAM is issued against such a stream.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||
nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
/*
|
||||
* Re-prioritize |stream|. The new priority specification is
|
||||
* |pri_spec|. Caller must ensure that stream->hd.stream_id !=
|
||||
* pri_spec->stream_id.
|
||||
*
|
||||
* This function does not adjust the number of idle streams. The
|
||||
* caller should call nghttp2_session_adjust_idle_stream() later.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_reprioritize_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
/*
|
||||
* Terminates current |session| with the |error_code|. The |reason|
|
||||
* is NULL-terminated debug string.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The |reason| is too long.
|
||||
*/
|
||||
int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
|
||||
uint32_t error_code,
|
||||
const char *reason);
|
||||
|
||||
#endif /* NGHTTP2_SESSION_H */
|
||||
@@ -0,0 +1,1001 @@
|
||||
/*
|
||||
* 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_stream.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "nghttp2_session.h"
|
||||
#include "nghttp2_helper.h"
|
||||
#include "nghttp2_debug.h"
|
||||
#include "nghttp2_frame.h"
|
||||
|
||||
/* Maximum distance between any two stream's cycle in the same
|
||||
prirority queue. Imagine stream A's cycle is A, and stream B's
|
||||
cycle is B, and A < B. The cycle is unsigned 32 bit integer, it
|
||||
may get overflow. Because of how we calculate the next cycle
|
||||
value, if B - A is less than or equals to
|
||||
NGHTTP2_MAX_CYCLE_DISTANCE, A and B are in the same scale, in other
|
||||
words, B is really greater than or equal to A. Otherwise, A is a
|
||||
result of overflow, and it is actually A > B if we consider that
|
||||
fact. */
|
||||
#define NGHTTP2_MAX_CYCLE_DISTANCE \
|
||||
((uint64_t)NGHTTP2_MAX_FRAME_SIZE_MAX * 256 + 255)
|
||||
|
||||
static int stream_less(const void *lhsx, const void *rhsx) {
|
||||
const nghttp2_stream *lhs, *rhs;
|
||||
|
||||
lhs = nghttp2_struct_of(lhsx, nghttp2_stream, pq_entry);
|
||||
rhs = nghttp2_struct_of(rhsx, nghttp2_stream, pq_entry);
|
||||
|
||||
if (lhs->cycle == rhs->cycle) {
|
||||
return lhs->seq < rhs->seq;
|
||||
}
|
||||
|
||||
return rhs->cycle - lhs->cycle <= NGHTTP2_MAX_CYCLE_DISTANCE;
|
||||
}
|
||||
|
||||
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) {
|
||||
nghttp2_map_entry_init(&stream->map_entry, (key_type)stream_id);
|
||||
nghttp2_pq_init(&stream->obq, stream_less, mem);
|
||||
|
||||
stream->stream_id = stream_id;
|
||||
stream->flags = flags;
|
||||
stream->state = initial_state;
|
||||
stream->shut_flags = NGHTTP2_SHUT_NONE;
|
||||
stream->stream_user_data = stream_user_data;
|
||||
stream->item = NULL;
|
||||
stream->remote_window_size = remote_initial_window_size;
|
||||
stream->local_window_size = local_initial_window_size;
|
||||
stream->recv_window_size = 0;
|
||||
stream->consumed_size = 0;
|
||||
stream->recv_reduction = 0;
|
||||
stream->window_update_queued = 0;
|
||||
|
||||
stream->dep_prev = NULL;
|
||||
stream->dep_next = NULL;
|
||||
stream->sib_prev = NULL;
|
||||
stream->sib_next = NULL;
|
||||
|
||||
stream->closed_prev = NULL;
|
||||
stream->closed_next = NULL;
|
||||
|
||||
stream->weight = weight;
|
||||
stream->sum_dep_weight = 0;
|
||||
|
||||
stream->http_flags = NGHTTP2_HTTP_FLAG_NONE;
|
||||
stream->content_length = -1;
|
||||
stream->recv_content_length = 0;
|
||||
stream->status_code = -1;
|
||||
|
||||
stream->queued = 0;
|
||||
stream->descendant_last_cycle = 0;
|
||||
stream->cycle = 0;
|
||||
stream->pending_penalty = 0;
|
||||
stream->descendant_next_seq = 0;
|
||||
stream->seq = 0;
|
||||
stream->last_writelen = 0;
|
||||
}
|
||||
|
||||
void nghttp2_stream_free(nghttp2_stream *stream) {
|
||||
nghttp2_pq_free(&stream->obq);
|
||||
/* We don't free stream->item. If it is assigned to aob, then
|
||||
active_outbound_item_reset() will delete it. Otherwise,
|
||||
nghttp2_stream_close() or session_del() will delete it. */
|
||||
}
|
||||
|
||||
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
|
||||
stream->shut_flags = (uint8_t)(stream->shut_flags | flag);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns nonzero if |stream| is active. This function does not take
|
||||
* into account its descendants.
|
||||
*/
|
||||
static int stream_active(nghttp2_stream *stream) {
|
||||
return stream->item &&
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns nonzero if |stream| or one of its descendants is active
|
||||
*/
|
||||
static int stream_subtree_active(nghttp2_stream *stream) {
|
||||
return stream_active(stream) || !nghttp2_pq_empty(&stream->obq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns next cycle for |stream|.
|
||||
*/
|
||||
static void stream_next_cycle(nghttp2_stream *stream, uint64_t last_cycle) {
|
||||
uint64_t penalty;
|
||||
|
||||
penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT +
|
||||
stream->pending_penalty;
|
||||
|
||||
stream->cycle = last_cycle + penalty / (uint32_t)stream->weight;
|
||||
stream->pending_penalty = (uint32_t)(penalty % (uint32_t)stream->weight);
|
||||
}
|
||||
|
||||
static int stream_obq_push(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
|
||||
int rv;
|
||||
|
||||
for (; dep_stream && !stream->queued;
|
||||
stream = dep_stream, dep_stream = dep_stream->dep_prev) {
|
||||
stream_next_cycle(stream, dep_stream->descendant_last_cycle);
|
||||
stream->seq = dep_stream->descendant_next_seq++;
|
||||
|
||||
DEBUGF("stream: stream=%d obq push cycle=%lu\n", stream->stream_id,
|
||||
stream->cycle);
|
||||
|
||||
DEBUGF("stream: push stream %d to stream %d\n", stream->stream_id,
|
||||
dep_stream->stream_id);
|
||||
|
||||
rv = nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
stream->queued = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes |stream| from parent's obq. If removal of |stream| makes
|
||||
* parent's obq empty, and parent is not active, then parent is also
|
||||
* removed. This process is repeated recursively.
|
||||
*/
|
||||
static void stream_obq_remove(nghttp2_stream *stream) {
|
||||
nghttp2_stream *dep_stream;
|
||||
|
||||
dep_stream = stream->dep_prev;
|
||||
|
||||
if (!stream->queued) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
|
||||
DEBUGF("stream: remove stream %d from stream %d\n", stream->stream_id,
|
||||
dep_stream->stream_id);
|
||||
|
||||
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
|
||||
|
||||
assert(stream->queued);
|
||||
|
||||
stream->queued = 0;
|
||||
stream->cycle = 0;
|
||||
stream->pending_penalty = 0;
|
||||
stream->descendant_last_cycle = 0;
|
||||
stream->last_writelen = 0;
|
||||
|
||||
if (stream_subtree_active(dep_stream)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Moves |stream| from |src|'s obq to |dest|'s obq. Removal from
|
||||
* |src|'s obq is just done calling nghttp2_pq_remove(), so it does
|
||||
* not recursively remove |src| and ancestors, like
|
||||
* stream_obq_remove().
|
||||
*/
|
||||
static int stream_obq_move(nghttp2_stream *dest, nghttp2_stream *src,
|
||||
nghttp2_stream *stream) {
|
||||
if (!stream->queued) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEBUGF("stream: remove stream %d from stream %d (move)\n", stream->stream_id,
|
||||
src->stream_id);
|
||||
|
||||
nghttp2_pq_remove(&src->obq, &stream->pq_entry);
|
||||
stream->queued = 0;
|
||||
|
||||
return stream_obq_push(dest, stream);
|
||||
}
|
||||
|
||||
void nghttp2_stream_reschedule(nghttp2_stream *stream) {
|
||||
nghttp2_stream *dep_stream;
|
||||
|
||||
assert(stream->queued);
|
||||
|
||||
dep_stream = stream->dep_prev;
|
||||
|
||||
for (; dep_stream; stream = dep_stream, dep_stream = dep_stream->dep_prev) {
|
||||
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
|
||||
|
||||
stream_next_cycle(stream, dep_stream->descendant_last_cycle);
|
||||
stream->seq = dep_stream->descendant_next_seq++;
|
||||
|
||||
nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
|
||||
|
||||
DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
|
||||
stream->cycle);
|
||||
|
||||
dep_stream->last_writelen = stream->last_writelen;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight) {
|
||||
nghttp2_stream *dep_stream;
|
||||
uint64_t last_cycle;
|
||||
int32_t old_weight;
|
||||
uint64_t wlen_penalty;
|
||||
|
||||
if (stream->weight == weight) {
|
||||
return;
|
||||
}
|
||||
|
||||
old_weight = stream->weight;
|
||||
stream->weight = weight;
|
||||
|
||||
dep_stream = stream->dep_prev;
|
||||
|
||||
if (!dep_stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
dep_stream->sum_dep_weight += weight - old_weight;
|
||||
|
||||
if (!stream->queued) {
|
||||
return;
|
||||
}
|
||||
|
||||
nghttp2_pq_remove(&dep_stream->obq, &stream->pq_entry);
|
||||
|
||||
wlen_penalty = (uint64_t)stream->last_writelen * NGHTTP2_MAX_WEIGHT;
|
||||
|
||||
/* Compute old stream->pending_penalty we used to calculate
|
||||
stream->cycle */
|
||||
stream->pending_penalty =
|
||||
(uint32_t)((stream->pending_penalty + (uint32_t)old_weight -
|
||||
(wlen_penalty % (uint32_t)old_weight)) %
|
||||
(uint32_t)old_weight);
|
||||
|
||||
last_cycle = stream->cycle -
|
||||
(wlen_penalty + stream->pending_penalty) / (uint32_t)old_weight;
|
||||
|
||||
/* Now we have old stream->pending_penalty and new stream->weight in
|
||||
place */
|
||||
stream_next_cycle(stream, last_cycle);
|
||||
|
||||
if (dep_stream->descendant_last_cycle - stream->cycle <=
|
||||
NGHTTP2_MAX_CYCLE_DISTANCE) {
|
||||
stream->cycle = dep_stream->descendant_last_cycle;
|
||||
}
|
||||
|
||||
/* Continue to use same stream->seq */
|
||||
|
||||
nghttp2_pq_push(&dep_stream->obq, &stream->pq_entry);
|
||||
|
||||
DEBUGF("stream: stream=%d obq resched cycle=%lu\n", stream->stream_id,
|
||||
stream->cycle);
|
||||
}
|
||||
|
||||
static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
|
||||
for (; stream->sib_next; stream = stream->sib_next)
|
||||
;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
|
||||
int32_t weight) {
|
||||
weight = stream->weight * weight / stream->sum_dep_weight;
|
||||
|
||||
return nghttp2_max(1, weight);
|
||||
}
|
||||
|
||||
#ifdef STREAM_DEP_DEBUG
|
||||
|
||||
static void ensure_inactive(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
|
||||
if (stream->queued) {
|
||||
fprintf(stderr, "stream(%p)=%d, stream->queued = 1; want 0\n", stream,
|
||||
stream->stream_id);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (stream_active(stream)) {
|
||||
fprintf(stderr, "stream(%p)=%d, stream_active(stream) = 1; want 0\n",
|
||||
stream, stream->stream_id);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if (!nghttp2_pq_empty(&stream->obq)) {
|
||||
fprintf(stderr, "stream(%p)=%d, nghttp2_pq_size() = %zu; want 0\n", stream,
|
||||
stream->stream_id, nghttp2_pq_size(&stream->obq));
|
||||
assert(0);
|
||||
}
|
||||
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
ensure_inactive(si);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_queued(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
int queued;
|
||||
|
||||
if (stream->queued) {
|
||||
if (!stream_subtree_active(stream)) {
|
||||
fprintf(stderr,
|
||||
"stream(%p)=%d, stream->queued == 1, but "
|
||||
"stream_active() == %d and nghttp2_pq_size(&stream->obq) = %zu\n",
|
||||
stream, stream->stream_id, stream_active(stream),
|
||||
nghttp2_pq_size(&stream->obq));
|
||||
assert(0);
|
||||
}
|
||||
if (!stream_active(stream)) {
|
||||
queued = 0;
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
if (si->queued) {
|
||||
++queued;
|
||||
}
|
||||
}
|
||||
if (queued == 0) {
|
||||
fprintf(stderr,
|
||||
"stream(%p)=%d, stream->queued == 1, and "
|
||||
"!stream_active(), but no descendants is queued\n",
|
||||
stream, stream->stream_id);
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
check_queued(si);
|
||||
}
|
||||
} else {
|
||||
if (stream_active(stream) || !nghttp2_pq_empty(&stream->obq)) {
|
||||
fprintf(stderr,
|
||||
"stream(%p) = %d, stream->queued == 0, but "
|
||||
"stream_active(stream) == %d and "
|
||||
"nghttp2_pq_size(&stream->obq) = %zu\n",
|
||||
stream, stream->stream_id, stream_active(stream),
|
||||
nghttp2_pq_size(&stream->obq));
|
||||
assert(0);
|
||||
}
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
ensure_inactive(si);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void check_sum_dep(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
int32_t n = 0;
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
n += si->weight;
|
||||
}
|
||||
if (n != stream->sum_dep_weight) {
|
||||
fprintf(stderr, "stream(%p)=%d, sum_dep_weight = %d; want %d\n", stream,
|
||||
stream->stream_id, n, stream->sum_dep_weight);
|
||||
assert(0);
|
||||
}
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
check_sum_dep(si);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_dep_prev(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
if (si->dep_prev != stream) {
|
||||
fprintf(stderr, "si->dep_prev = %p; want %p\n", si->dep_prev, stream);
|
||||
assert(0);
|
||||
}
|
||||
check_dep_prev(si);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* STREAM_DEP_DEBUG */
|
||||
|
||||
#ifdef STREAM_DEP_DEBUG
|
||||
static void validate_tree(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
|
||||
if (!stream) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (; stream->dep_prev; stream = stream->dep_prev)
|
||||
;
|
||||
|
||||
assert(stream->stream_id == 0);
|
||||
assert(!stream->queued);
|
||||
|
||||
fprintf(stderr, "checking...\n");
|
||||
if (nghttp2_pq_empty(&stream->obq)) {
|
||||
fprintf(stderr, "root obq empty\n");
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
ensure_inactive(si);
|
||||
}
|
||||
} else {
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
check_queued(si);
|
||||
}
|
||||
}
|
||||
|
||||
check_sum_dep(stream);
|
||||
check_dep_prev(stream);
|
||||
}
|
||||
#else /* !STREAM_DEP_DEBUG */
|
||||
static void validate_tree(nghttp2_stream *stream) { (void)stream; }
|
||||
#endif /* !STREAM_DEP_DEBUG*/
|
||||
|
||||
static int stream_update_dep_on_attach_item(nghttp2_stream *stream) {
|
||||
int rv;
|
||||
|
||||
rv = stream_obq_push(stream->dep_prev, stream);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
validate_tree(stream);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_detach_item(nghttp2_stream *stream) {
|
||||
if (nghttp2_pq_empty(&stream->obq)) {
|
||||
stream_obq_remove(stream);
|
||||
}
|
||||
|
||||
validate_tree(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *item) {
|
||||
int rv;
|
||||
|
||||
assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
|
||||
assert(stream->item == NULL);
|
||||
|
||||
DEBUGF("stream: stream=%d attach item=%p\n", stream->stream_id, item);
|
||||
|
||||
stream->item = item;
|
||||
|
||||
rv = stream_update_dep_on_attach_item(stream);
|
||||
if (rv != 0) {
|
||||
/* This may relave stream->queued == 1, but stream->item == NULL.
|
||||
But only consequence of this error is fatal one, and session
|
||||
destruction. In that execution path, these inconsistency does
|
||||
not matter. */
|
||||
stream->item = NULL;
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_detach_item(nghttp2_stream *stream) {
|
||||
DEBUGF("stream: stream=%d detach item=%p\n", stream->stream_id, stream->item);
|
||||
|
||||
stream->item = NULL;
|
||||
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
||||
|
||||
return stream_update_dep_on_detach_item(stream);
|
||||
}
|
||||
|
||||
int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags) {
|
||||
assert(stream->item);
|
||||
|
||||
DEBUGF("stream: stream=%d defer item=%p cause=%02x\n", stream->stream_id,
|
||||
stream->item, flags);
|
||||
|
||||
stream->flags |= flags;
|
||||
|
||||
return stream_update_dep_on_detach_item(stream);
|
||||
}
|
||||
|
||||
int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags) {
|
||||
assert(stream->item);
|
||||
|
||||
DEBUGF("stream: stream=%d resume item=%p flags=%02x\n", stream->stream_id,
|
||||
stream->item, flags);
|
||||
|
||||
stream->flags = (uint8_t)(stream->flags & ~flags);
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_attach_item(stream);
|
||||
}
|
||||
|
||||
int nghttp2_stream_check_deferred_item(nghttp2_stream *stream) {
|
||||
return stream->item && (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
||||
}
|
||||
|
||||
int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) {
|
||||
return stream->item &&
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
}
|
||||
|
||||
static int update_initial_window_size(int32_t *window_size_ptr,
|
||||
int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size) {
|
||||
int64_t new_window_size = (int64_t)(*window_size_ptr) +
|
||||
new_initial_window_size - old_initial_window_size;
|
||||
if (INT32_MIN > new_window_size ||
|
||||
new_window_size > NGHTTP2_MAX_WINDOW_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
*window_size_ptr = (int32_t)new_window_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_update_remote_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size) {
|
||||
return update_initial_window_size(&stream->remote_window_size,
|
||||
new_initial_window_size,
|
||||
old_initial_window_size);
|
||||
}
|
||||
|
||||
int nghttp2_stream_update_local_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size) {
|
||||
return update_initial_window_size(&stream->local_window_size,
|
||||
new_initial_window_size,
|
||||
old_initial_window_size);
|
||||
}
|
||||
|
||||
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
|
||||
stream->state = NGHTTP2_STREAM_OPENED;
|
||||
stream->flags = (uint8_t)(stream->flags & ~NGHTTP2_STREAM_FLAG_PUSH);
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
|
||||
nghttp2_stream *target) {
|
||||
for (; stream; stream = stream->dep_prev) {
|
||||
if (stream == target) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
int rv;
|
||||
|
||||
DEBUGF("stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
|
||||
dep_stream->stream_id, stream, stream->stream_id);
|
||||
|
||||
stream->sum_dep_weight = dep_stream->sum_dep_weight;
|
||||
dep_stream->sum_dep_weight = stream->weight;
|
||||
|
||||
if (dep_stream->dep_next) {
|
||||
for (si = dep_stream->dep_next; si; si = si->sib_next) {
|
||||
si->dep_prev = stream;
|
||||
if (si->queued) {
|
||||
rv = stream_obq_move(stream, dep_stream, si);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stream_subtree_active(stream)) {
|
||||
rv = stream_obq_push(dep_stream, stream);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
stream->dep_next = dep_stream->dep_next;
|
||||
}
|
||||
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
|
||||
validate_tree(stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void set_dep_prev(nghttp2_stream *stream, nghttp2_stream *dep) {
|
||||
for (; stream; stream = stream->sib_next) {
|
||||
stream->dep_prev = dep;
|
||||
}
|
||||
}
|
||||
|
||||
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
|
||||
dep_stream->dep_next = stream;
|
||||
if (stream) {
|
||||
stream->dep_prev = dep_stream;
|
||||
}
|
||||
}
|
||||
|
||||
static void link_sib(nghttp2_stream *a, nghttp2_stream *b) {
|
||||
a->sib_next = b;
|
||||
if (b) {
|
||||
b->sib_prev = a;
|
||||
}
|
||||
}
|
||||
|
||||
static void insert_link_dep(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream *sib_next;
|
||||
|
||||
assert(stream->sib_prev == NULL);
|
||||
|
||||
sib_next = dep_stream->dep_next;
|
||||
|
||||
link_sib(stream, sib_next);
|
||||
|
||||
link_dep(dep_stream, stream);
|
||||
}
|
||||
|
||||
static void unlink_sib(nghttp2_stream *stream) {
|
||||
nghttp2_stream *prev, *next, *dep_next;
|
||||
|
||||
prev = stream->sib_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
assert(prev);
|
||||
|
||||
if (dep_next) {
|
||||
/*
|
||||
* prev--stream(--sib_next--...)
|
||||
* |
|
||||
* dep_next
|
||||
*/
|
||||
|
||||
link_sib(prev, dep_next);
|
||||
|
||||
set_dep_prev(dep_next, stream->dep_prev);
|
||||
|
||||
if (stream->sib_next) {
|
||||
link_sib(stream_last_sib(dep_next), stream->sib_next);
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* prev--stream(--sib_next--...)
|
||||
*/
|
||||
next = stream->sib_next;
|
||||
|
||||
prev->sib_next = next;
|
||||
|
||||
if (next) {
|
||||
next->sib_prev = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void unlink_dep(nghttp2_stream *stream) {
|
||||
nghttp2_stream *prev, *next, *dep_next;
|
||||
|
||||
prev = stream->dep_prev;
|
||||
dep_next = stream->dep_next;
|
||||
|
||||
assert(prev);
|
||||
|
||||
if (dep_next) {
|
||||
/*
|
||||
* prev
|
||||
* |
|
||||
* stream(--sib_next--...)
|
||||
* |
|
||||
* dep_next
|
||||
*/
|
||||
link_dep(prev, dep_next);
|
||||
|
||||
set_dep_prev(dep_next, stream->dep_prev);
|
||||
|
||||
if (stream->sib_next) {
|
||||
link_sib(stream_last_sib(dep_next), stream->sib_next);
|
||||
}
|
||||
|
||||
} else if (stream->sib_next) {
|
||||
/*
|
||||
* prev
|
||||
* |
|
||||
* stream--sib_next
|
||||
*/
|
||||
next = stream->sib_next;
|
||||
|
||||
next->sib_prev = NULL;
|
||||
|
||||
link_dep(prev, next);
|
||||
} else {
|
||||
prev->dep_next = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream) {
|
||||
DEBUGF("stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n", dep_stream,
|
||||
dep_stream->stream_id, stream, stream->stream_id);
|
||||
|
||||
dep_stream->sum_dep_weight += stream->weight;
|
||||
|
||||
if (dep_stream->dep_next == NULL) {
|
||||
link_dep(dep_stream, stream);
|
||||
} else {
|
||||
insert_link_dep(dep_stream, stream);
|
||||
}
|
||||
|
||||
validate_tree(stream);
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_remove(nghttp2_stream *stream) {
|
||||
nghttp2_stream *dep_prev, *si;
|
||||
int32_t sum_dep_weight_delta;
|
||||
int rv;
|
||||
|
||||
DEBUGF("stream: dep_remove stream(%p)=%d\n", stream, stream->stream_id);
|
||||
|
||||
/* Distribute weight of |stream| to direct descendants */
|
||||
sum_dep_weight_delta = -stream->weight;
|
||||
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
|
||||
|
||||
sum_dep_weight_delta += si->weight;
|
||||
|
||||
if (si->queued) {
|
||||
rv = stream_obq_move(stream->dep_prev, stream, si);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(stream->dep_prev);
|
||||
|
||||
dep_prev = stream->dep_prev;
|
||||
|
||||
dep_prev->sum_dep_weight += sum_dep_weight_delta;
|
||||
|
||||
if (stream->queued) {
|
||||
stream_obq_remove(stream);
|
||||
}
|
||||
|
||||
if (stream->sib_prev) {
|
||||
unlink_sib(stream);
|
||||
} else {
|
||||
unlink_dep(stream);
|
||||
}
|
||||
|
||||
stream->sum_dep_weight = 0;
|
||||
|
||||
stream->dep_prev = NULL;
|
||||
stream->dep_next = NULL;
|
||||
stream->sib_prev = NULL;
|
||||
stream->sib_next = NULL;
|
||||
|
||||
validate_tree(dep_prev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *dep_next;
|
||||
nghttp2_stream *si;
|
||||
int rv;
|
||||
|
||||
DEBUGF("stream: dep_insert_subtree dep_stream(%p)=%d stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id, stream, stream->stream_id);
|
||||
|
||||
stream->sum_dep_weight += dep_stream->sum_dep_weight;
|
||||
dep_stream->sum_dep_weight = stream->weight;
|
||||
|
||||
if (dep_stream->dep_next) {
|
||||
dep_next = dep_stream->dep_next;
|
||||
|
||||
link_dep(dep_stream, stream);
|
||||
|
||||
if (stream->dep_next) {
|
||||
last_sib = stream_last_sib(stream->dep_next);
|
||||
|
||||
link_sib(last_sib, dep_next);
|
||||
} else {
|
||||
link_dep(stream, dep_next);
|
||||
}
|
||||
|
||||
for (si = dep_next; si; si = si->sib_next) {
|
||||
si->dep_prev = stream;
|
||||
if (si->queued) {
|
||||
rv = stream_obq_move(stream, dep_stream, si);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
link_dep(dep_stream, stream);
|
||||
}
|
||||
|
||||
if (stream_subtree_active(stream)) {
|
||||
rv = stream_obq_push(dep_stream, stream);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
validate_tree(dep_stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream) {
|
||||
int rv;
|
||||
|
||||
DEBUGF("stream: dep_add_subtree dep_stream(%p)=%d stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id, stream, stream->stream_id);
|
||||
|
||||
dep_stream->sum_dep_weight += stream->weight;
|
||||
|
||||
if (dep_stream->dep_next) {
|
||||
insert_link_dep(dep_stream, stream);
|
||||
} else {
|
||||
link_dep(dep_stream, stream);
|
||||
}
|
||||
|
||||
if (stream_subtree_active(stream)) {
|
||||
rv = stream_obq_push(dep_stream, stream);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
validate_tree(dep_stream);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
|
||||
nghttp2_stream *next, *dep_prev;
|
||||
|
||||
DEBUGF("stream: dep_remove_subtree stream(%p)=%d\n", stream,
|
||||
stream->stream_id);
|
||||
|
||||
assert(stream->dep_prev);
|
||||
|
||||
dep_prev = stream->dep_prev;
|
||||
|
||||
if (stream->sib_prev) {
|
||||
link_sib(stream->sib_prev, stream->sib_next);
|
||||
} else {
|
||||
next = stream->sib_next;
|
||||
|
||||
link_dep(dep_prev, next);
|
||||
|
||||
if (next) {
|
||||
next->sib_prev = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
dep_prev->sum_dep_weight -= stream->weight;
|
||||
|
||||
if (stream->queued) {
|
||||
stream_obq_remove(stream);
|
||||
}
|
||||
|
||||
validate_tree(dep_prev);
|
||||
|
||||
stream->sib_prev = NULL;
|
||||
stream->sib_next = NULL;
|
||||
stream->dep_prev = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
|
||||
return stream->dep_prev || stream->dep_next || stream->sib_prev ||
|
||||
stream->sib_next;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_stream_next_outbound_item(nghttp2_stream *stream) {
|
||||
nghttp2_pq_entry *ent;
|
||||
nghttp2_stream *si;
|
||||
|
||||
for (;;) {
|
||||
if (stream_active(stream)) {
|
||||
/* Update ascendant's descendant_last_cycle here, so that we can
|
||||
assure that new stream is scheduled based on it. */
|
||||
for (si = stream; si->dep_prev; si = si->dep_prev) {
|
||||
si->dep_prev->descendant_last_cycle = si->cycle;
|
||||
}
|
||||
return stream->item;
|
||||
}
|
||||
ent = nghttp2_pq_top(&stream->obq);
|
||||
if (!ent) {
|
||||
return NULL;
|
||||
}
|
||||
stream = nghttp2_struct_of(ent, nghttp2_stream, pq_entry);
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_stream_proto_state nghttp2_stream_get_state(nghttp2_stream *stream) {
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_CLOSED) {
|
||||
return NGHTTP2_STREAM_STATE_CLOSED;
|
||||
}
|
||||
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_PUSH) {
|
||||
if (stream->shut_flags & NGHTTP2_SHUT_RD) {
|
||||
return NGHTTP2_STREAM_STATE_RESERVED_LOCAL;
|
||||
}
|
||||
|
||||
if (stream->shut_flags & NGHTTP2_SHUT_WR) {
|
||||
return NGHTTP2_STREAM_STATE_RESERVED_REMOTE;
|
||||
}
|
||||
}
|
||||
|
||||
if (stream->shut_flags & NGHTTP2_SHUT_RD) {
|
||||
return NGHTTP2_STREAM_STATE_HALF_CLOSED_REMOTE;
|
||||
}
|
||||
|
||||
if (stream->shut_flags & NGHTTP2_SHUT_WR) {
|
||||
return NGHTTP2_STREAM_STATE_HALF_CLOSED_LOCAL;
|
||||
}
|
||||
|
||||
if (stream->state == NGHTTP2_STREAM_IDLE) {
|
||||
return NGHTTP2_STREAM_STATE_IDLE;
|
||||
}
|
||||
|
||||
return NGHTTP2_STREAM_STATE_OPEN;
|
||||
}
|
||||
|
||||
nghttp2_stream *nghttp2_stream_get_parent(nghttp2_stream *stream) {
|
||||
return stream->dep_prev;
|
||||
}
|
||||
|
||||
nghttp2_stream *nghttp2_stream_get_next_sibling(nghttp2_stream *stream) {
|
||||
return stream->sib_next;
|
||||
}
|
||||
|
||||
nghttp2_stream *nghttp2_stream_get_previous_sibling(nghttp2_stream *stream) {
|
||||
return stream->sib_prev;
|
||||
}
|
||||
|
||||
nghttp2_stream *nghttp2_stream_get_first_child(nghttp2_stream *stream) {
|
||||
return stream->dep_next;
|
||||
}
|
||||
|
||||
int32_t nghttp2_stream_get_weight(nghttp2_stream *stream) {
|
||||
return stream->weight;
|
||||
}
|
||||
|
||||
int32_t nghttp2_stream_get_sum_dependency_weight(nghttp2_stream *stream) {
|
||||
return stream->sum_dep_weight;
|
||||
}
|
||||
|
||||
int32_t nghttp2_stream_get_stream_id(nghttp2_stream *stream) {
|
||||
return stream->stream_id;
|
||||
}
|
||||
@@ -0,0 +1,437 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_STREAM_H
|
||||
#define NGHTTP2_STREAM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
#include "nghttp2_outbound_item.h"
|
||||
#include "nghttp2_map.h"
|
||||
#include "nghttp2_pq.h"
|
||||
#include "nghttp2_int.h"
|
||||
|
||||
/*
|
||||
* If local peer is stream initiator:
|
||||
* NGHTTP2_STREAM_OPENING : upon sending request HEADERS
|
||||
* NGHTTP2_STREAM_OPENED : upon receiving response HEADERS
|
||||
* NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
|
||||
*
|
||||
* If remote peer is stream initiator:
|
||||
* NGHTTP2_STREAM_OPENING : upon receiving request HEADERS
|
||||
* NGHTTP2_STREAM_OPENED : upon sending response HEADERS
|
||||
* NGHTTP2_STREAM_CLOSING : upon queuing RST_STREAM
|
||||
*/
|
||||
typedef enum {
|
||||
/* Initial state */
|
||||
NGHTTP2_STREAM_INITIAL,
|
||||
/* For stream initiator: request HEADERS has been sent, but response
|
||||
HEADERS has not been received yet. For receiver: request HEADERS
|
||||
has been received, but it does not send response HEADERS yet. */
|
||||
NGHTTP2_STREAM_OPENING,
|
||||
/* For stream initiator: response HEADERS is received. For receiver:
|
||||
response HEADERS is sent. */
|
||||
NGHTTP2_STREAM_OPENED,
|
||||
/* RST_STREAM is received, but somehow we need to keep stream in
|
||||
memory. */
|
||||
NGHTTP2_STREAM_CLOSING,
|
||||
/* PUSH_PROMISE is received or sent */
|
||||
NGHTTP2_STREAM_RESERVED,
|
||||
/* Stream is created in this state if it is used as anchor in
|
||||
dependency tree. */
|
||||
NGHTTP2_STREAM_IDLE
|
||||
} nghttp2_stream_state;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_SHUT_NONE = 0,
|
||||
/* Indicates further receptions will be disallowed. */
|
||||
NGHTTP2_SHUT_RD = 0x01,
|
||||
/* Indicates further transmissions will be disallowed. */
|
||||
NGHTTP2_SHUT_WR = 0x02,
|
||||
/* Indicates both further receptions and transmissions will be
|
||||
disallowed. */
|
||||
NGHTTP2_SHUT_RDWR = NGHTTP2_SHUT_RD | NGHTTP2_SHUT_WR
|
||||
} nghttp2_shut_flag;
|
||||
|
||||
typedef enum {
|
||||
NGHTTP2_STREAM_FLAG_NONE = 0,
|
||||
/* Indicates that this stream is pushed stream and not opened
|
||||
yet. */
|
||||
NGHTTP2_STREAM_FLAG_PUSH = 0x01,
|
||||
/* Indicates that this stream was closed */
|
||||
NGHTTP2_STREAM_FLAG_CLOSED = 0x02,
|
||||
/* Indicates the item is deferred due to flow control. */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL = 0x04,
|
||||
/* Indicates the item is deferred by user callback */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
|
||||
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
|
||||
|
||||
} nghttp2_stream_flag;
|
||||
|
||||
/* HTTP related flags to enforce HTTP semantics */
|
||||
typedef enum {
|
||||
NGHTTP2_HTTP_FLAG_NONE = 0,
|
||||
/* header field seen so far */
|
||||
NGHTTP2_HTTP_FLAG__AUTHORITY = 1,
|
||||
NGHTTP2_HTTP_FLAG__PATH = 1 << 1,
|
||||
NGHTTP2_HTTP_FLAG__METHOD = 1 << 2,
|
||||
NGHTTP2_HTTP_FLAG__SCHEME = 1 << 3,
|
||||
/* host is not pseudo header, but we require either host or
|
||||
:authority */
|
||||
NGHTTP2_HTTP_FLAG_HOST = 1 << 4,
|
||||
NGHTTP2_HTTP_FLAG__STATUS = 1 << 5,
|
||||
/* required header fields for HTTP request except for CONNECT
|
||||
method. */
|
||||
NGHTTP2_HTTP_FLAG_REQ_HEADERS = NGHTTP2_HTTP_FLAG__METHOD |
|
||||
NGHTTP2_HTTP_FLAG__PATH |
|
||||
NGHTTP2_HTTP_FLAG__SCHEME,
|
||||
NGHTTP2_HTTP_FLAG_PSEUDO_HEADER_DISALLOWED = 1 << 6,
|
||||
/* HTTP method flags */
|
||||
NGHTTP2_HTTP_FLAG_METH_CONNECT = 1 << 7,
|
||||
NGHTTP2_HTTP_FLAG_METH_HEAD = 1 << 8,
|
||||
NGHTTP2_HTTP_FLAG_METH_OPTIONS = 1 << 9,
|
||||
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND = 1 << 10,
|
||||
NGHTTP2_HTTP_FLAG_METH_ALL = NGHTTP2_HTTP_FLAG_METH_CONNECT |
|
||||
NGHTTP2_HTTP_FLAG_METH_HEAD |
|
||||
NGHTTP2_HTTP_FLAG_METH_OPTIONS |
|
||||
NGHTTP2_HTTP_FLAG_METH_UPGRADE_WORKAROUND,
|
||||
/* :path category */
|
||||
/* path starts with "/" */
|
||||
NGHTTP2_HTTP_FLAG_PATH_REGULAR = 1 << 11,
|
||||
/* path "*" */
|
||||
NGHTTP2_HTTP_FLAG_PATH_ASTERISK = 1 << 12,
|
||||
/* scheme */
|
||||
/* "http" or "https" scheme */
|
||||
NGHTTP2_HTTP_FLAG_SCHEME_HTTP = 1 << 13,
|
||||
/* set if final response is expected */
|
||||
NGHTTP2_HTTP_FLAG_EXPECT_FINAL_RESPONSE = 1 << 14,
|
||||
NGHTTP2_HTTP_FLAG__PROTOCOL = 1 << 15,
|
||||
} nghttp2_http_flag;
|
||||
|
||||
struct nghttp2_stream {
|
||||
/* Intrusive Map */
|
||||
nghttp2_map_entry map_entry;
|
||||
/* Entry for dep_prev->obq */
|
||||
nghttp2_pq_entry pq_entry;
|
||||
/* Priority Queue storing direct descendant (nghttp2_stream). Only
|
||||
streams which itself has some data to send, or has a descendant
|
||||
which has some data to sent. */
|
||||
nghttp2_pq obq;
|
||||
/* Content-Length of request/response body. -1 if unknown. */
|
||||
int64_t content_length;
|
||||
/* Received body so far */
|
||||
int64_t recv_content_length;
|
||||
/* Base last_cycle for direct descendent streams. */
|
||||
uint64_t descendant_last_cycle;
|
||||
/* Next scheduled time to sent item */
|
||||
uint64_t cycle;
|
||||
/* Next seq used for direct descendant streams */
|
||||
uint64_t descendant_next_seq;
|
||||
/* Secondary key for prioritization to break a tie for cycle. This
|
||||
value is monotonically increased for single parent stream. */
|
||||
uint64_t seq;
|
||||
/* pointers to form dependency tree. If multiple streams depend on
|
||||
a stream, only one stream (left most) has non-NULL dep_prev which
|
||||
points to the stream it depends on. The remaining streams are
|
||||
linked using sib_prev and sib_next. The stream which has
|
||||
non-NULL dep_prev always NULL sib_prev. The right most stream
|
||||
has NULL sib_next. If this stream is a root of dependency tree,
|
||||
dep_prev and sib_prev are NULL. */
|
||||
nghttp2_stream *dep_prev, *dep_next;
|
||||
nghttp2_stream *sib_prev, *sib_next;
|
||||
/* When stream is kept after closure, it may be kept in doubly
|
||||
linked list pointed by nghttp2_session closed_stream_head.
|
||||
closed_next points to the next stream object if it is the element
|
||||
of the list. */
|
||||
nghttp2_stream *closed_prev, *closed_next;
|
||||
/* The arbitrary data provided by user for this stream. */
|
||||
void *stream_user_data;
|
||||
/* Item to send */
|
||||
nghttp2_outbound_item *item;
|
||||
/* Last written length of frame payload */
|
||||
size_t last_writelen;
|
||||
/* stream ID */
|
||||
int32_t stream_id;
|
||||
/* Current remote window size. This value is computed against the
|
||||
current initial window size of remote endpoint. */
|
||||
int32_t remote_window_size;
|
||||
/* Keep track of the number of bytes received without
|
||||
WINDOW_UPDATE. This could be negative after submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_window_size;
|
||||
/* The number of bytes consumed by the application and now is
|
||||
subject to WINDOW_UPDATE. This is only used when auto
|
||||
WINDOW_UPDATE is turned off. */
|
||||
int32_t consumed_size;
|
||||
/* The amount of recv_window_size cut using submitting negative
|
||||
value to WINDOW_UPDATE */
|
||||
int32_t recv_reduction;
|
||||
/* window size for local flow control. It is initially set to
|
||||
NGHTTP2_INITIAL_WINDOW_SIZE and could be increased/decreased by
|
||||
submitting WINDOW_UPDATE. See nghttp2_submit_window_update(). */
|
||||
int32_t local_window_size;
|
||||
/* weight of this stream */
|
||||
int32_t weight;
|
||||
/* This is unpaid penalty (offset) when calculating cycle. */
|
||||
uint32_t pending_penalty;
|
||||
/* sum of weight of direct descendants */
|
||||
int32_t sum_dep_weight;
|
||||
nghttp2_stream_state state;
|
||||
/* status code from remote server */
|
||||
int16_t status_code;
|
||||
/* Bitwise OR of zero or more nghttp2_http_flag values */
|
||||
uint16_t http_flags;
|
||||
/* This is bitwise-OR of 0 or more of nghttp2_stream_flag. */
|
||||
uint8_t flags;
|
||||
/* Bitwise OR of zero or more nghttp2_shut_flag values */
|
||||
uint8_t shut_flags;
|
||||
/* Nonzero if this stream has been queued to stream pointed by
|
||||
dep_prev. We maintain the invariant that if a stream is queued,
|
||||
then its ancestors, except for root, are also queued. This
|
||||
invariant may break in fatal error condition. */
|
||||
uint8_t queued;
|
||||
/* This flag is used to reduce excessive queuing of WINDOW_UPDATE to
|
||||
this stream. The nonzero does not necessarily mean WINDOW_UPDATE
|
||||
is not queued. */
|
||||
uint8_t window_update_queued;
|
||||
};
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
uint8_t flags, nghttp2_stream_state initial_state,
|
||||
int32_t weight, int32_t remote_initial_window_size,
|
||||
int32_t local_initial_window_size,
|
||||
void *stream_user_data, nghttp2_mem *mem);
|
||||
|
||||
void nghttp2_stream_free(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Disallow either further receptions or transmissions, or both.
|
||||
* |flag| is bitwise OR of one or more of nghttp2_shut_flag.
|
||||
*/
|
||||
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag);
|
||||
|
||||
/*
|
||||
* Defer |stream->item|. We won't call this function in the situation
|
||||
* where |stream->item| == NULL. The |flags| is bitwise OR of zero or
|
||||
* more of NGHTTP2_STREAM_FLAG_DEFERRED_USER and
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL. The |flags| indicates
|
||||
* the reason of this action.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_defer_item(nghttp2_stream *stream, uint8_t flags);
|
||||
|
||||
/*
|
||||
* Put back deferred data in this stream to active state. The |flags|
|
||||
* are one or more of bitwise OR of the following values:
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_USER and
|
||||
* NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and given masks are
|
||||
* cleared if they are set. So even if this function is called, if
|
||||
* one of flag is still set, data does not become active.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_resume_deferred_item(nghttp2_stream *stream, uint8_t flags);
|
||||
|
||||
/*
|
||||
* Returns nonzero if item is deferred by whatever reason.
|
||||
*/
|
||||
int nghttp2_stream_check_deferred_item(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if item is deferred by flow control.
|
||||
*/
|
||||
int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Updates the remote window size with the new value
|
||||
* |new_initial_window_size|. The |old_initial_window_size| is used to
|
||||
* calculate the current window size.
|
||||
*
|
||||
* This function returns 0 if it succeeds or -1. The failure is due to
|
||||
* overflow.
|
||||
*/
|
||||
int nghttp2_stream_update_remote_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
|
||||
/*
|
||||
* Updates the local window size with the new value
|
||||
* |new_initial_window_size|. The |old_initial_window_size| is used to
|
||||
* calculate the current window size.
|
||||
*
|
||||
* This function returns 0 if it succeeds or -1. The failure is due to
|
||||
* overflow.
|
||||
*/
|
||||
int nghttp2_stream_update_local_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
|
||||
/*
|
||||
* Call this function if promised stream |stream| is replied with
|
||||
* HEADERS. This function makes the state of the |stream| to
|
||||
* NGHTTP2_STREAM_OPENED.
|
||||
*/
|
||||
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |target| is an ancestor of |stream|.
|
||||
*/
|
||||
int nghttp2_stream_dep_find_ancestor(nghttp2_stream *stream,
|
||||
nghttp2_stream *target);
|
||||
|
||||
/*
|
||||
* Computes distributed weight of a stream of the |weight| under the
|
||||
* |stream| if |stream| is removed from a dependency tree.
|
||||
*/
|
||||
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
|
||||
int32_t weight);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* exclusive. All existing direct descendants of |dep_stream| become
|
||||
* the descendants of the |stream|. This function assumes
|
||||
* |stream->item| is NULL.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* not exclusive. This function assumes |stream->item| is NULL.
|
||||
*/
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Removes the |stream| from the current dependency tree. This
|
||||
* function assumes |stream->item| is NULL.
|
||||
*/
|
||||
int nghttp2_stream_dep_remove(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Attaches |item| to |stream|.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_attach_item(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
* Detaches |stream->item|. This function does not free
|
||||
* |stream->item|. The caller must free it.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_detach_item(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* exclusive.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
* not exclusive.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Removes subtree whose root stream is |stream|. The
|
||||
* effective_weight of streams in removed subtree is not updated.
|
||||
*
|
||||
* This function returns 0 if it succeeds, or one of the following
|
||||
* negative error codes:
|
||||
*
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |stream| is in any dependency tree.
|
||||
*/
|
||||
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Schedules transmission of |stream|'s item, assuming stream->item is
|
||||
* attached, and stream->last_writelen was updated.
|
||||
*/
|
||||
void nghttp2_stream_reschedule(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Changes |stream|'s weight to |weight|. If |stream| is queued, it
|
||||
* will be rescheduled based on new weight.
|
||||
*/
|
||||
void nghttp2_stream_change_weight(nghttp2_stream *stream, int32_t weight);
|
||||
|
||||
/*
|
||||
* Returns a stream which has highest priority, updating
|
||||
* descendant_last_cycle of selected stream's ancestors.
|
||||
*/
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_stream_next_outbound_item(nghttp2_stream *stream);
|
||||
|
||||
#endif /* NGHTTP2_STREAM */
|
||||
@@ -0,0 +1,814 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
|
||||
int nghttp2_submit_origin(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_origin_entry *ov, size_t nov) {
|
||||
nghttp2_mem *mem;
|
||||
uint8_t *p;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_ext_origin *origin;
|
||||
nghttp2_origin_entry *ov_copy;
|
||||
size_t len = 0;
|
||||
size_t i;
|
||||
int rv;
|
||||
(void)flags;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
if (nov) {
|
||||
for (i = 0; i < nov; ++i) {
|
||||
len += ov[i].origin_len;
|
||||
}
|
||||
|
||||
if (2 * nov + len > NGHTTP2_MAX_PAYLOADLEN) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
/* The last nov is added for terminal NULL character. */
|
||||
ov_copy =
|
||||
nghttp2_mem_malloc(mem, nov * sizeof(nghttp2_origin_entry) + len + nov);
|
||||
if (ov_copy == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
p = (uint8_t *)ov_copy + nov * sizeof(nghttp2_origin_entry);
|
||||
|
||||
for (i = 0; i < nov; ++i) {
|
||||
ov_copy[i].origin = p;
|
||||
ov_copy[i].origin_len = ov[i].origin_len;
|
||||
p = nghttp2_cpymem(p, ov[i].origin, ov[i].origin_len);
|
||||
*p++ = '\0';
|
||||
}
|
||||
|
||||
assert((size_t)(p - (uint8_t *)ov_copy) ==
|
||||
nov * sizeof(nghttp2_origin_entry) + len + nov);
|
||||
} else {
|
||||
ov_copy = NULL;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail_item_malloc;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
item->aux_data.ext.builtin = 1;
|
||||
|
||||
origin = &item->ext_frame_payload.origin;
|
||||
|
||||
frame = &item->frame;
|
||||
frame->ext.payload = origin;
|
||||
|
||||
nghttp2_frame_origin_init(&frame->ext, ov_copy, nov);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_origin_free(&frame->ext, mem);
|
||||
nghttp2_mem_free(mem, item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_item_malloc:
|
||||
free(ov_copy);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||
if (data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
flags |= NGHTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
|
||||
if (pri_spec) {
|
||||
flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
}
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
int32_t nghttp2_submit_request(nghttp2_session *session,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data) {
|
||||
uint8_t flags;
|
||||
int rv;
|
||||
|
||||
if (session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
rv = detect_self_dependency(session, -1, pri_spec);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
pri_spec = NULL;
|
||||
}
|
||||
|
||||
flags = set_request_flags(pri_spec, data_prd);
|
||||
|
||||
return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen,
|
||||
data_prd, stream_user_data);
|
||||
}
|
||||
|
||||
static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||
if (data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
flags |= NGHTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags;
|
||||
|
||||
if (stream_id <= 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
flags = set_response_flags(data_prd);
|
||||
return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
|
||||
data_prd, NULL);
|
||||
}
|
||||
|
||||
int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_data_aux_data *aux_data;
|
||||
uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
aux_data = &item->aux_data.data;
|
||||
aux_data->data_prd = *data_prd;
|
||||
aux_data->eof = 0;
|
||||
aux_data->flags = nflags;
|
||||
|
||||
/* flags are sent on transmission */
|
||||
nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
|
||||
const nghttp2_settings_entry *iv,
|
||||
size_t niv) {
|
||||
if (!nghttp2_iv_check(iv, niv)) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) {
|
||||
return NGHTTP2_ERR_INSUFF_BUFSIZE;
|
||||
}
|
||||
|
||||
return (ssize_t)nghttp2_frame_pack_settings_payload(buf, iv, niv);
|
||||
}
|
||||
|
||||
int nghttp2_submit_extension(nghttp2_session *session, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id, void *payload) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_mem *mem;
|
||||
|
||||
mem = &session->mem;
|
||||
|
||||
if (type <= NGHTTP2_CONTINUATION) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if (!session->callbacks.pack_extension_callback) {
|
||||
return NGHTTP2_ERR_INVALID_STATE;
|
||||
}
|
||||
|
||||
item = nghttp2_mem_malloc(mem, sizeof(nghttp2_outbound_item));
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
nghttp2_outbound_item_init(item);
|
||||
|
||||
frame = &item->frame;
|
||||
nghttp2_frame_extension_init(&frame->ext, type, flags, stream_id, payload);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_extension_free(&frame->ext);
|
||||
nghttp2_mem_free(mem, item);
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifndef NGHTTP2_SUBMIT_H
|
||||
#define NGHTTP2_SUBMIT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#endif /* NGHTTP2_SUBMIT_H */
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* nghttp2 - HTTP/2 C Library
|
||||
*
|
||||
* Copyright (c) 2012, 2013 Tatsuhiro Tsujikawa
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
static nghttp2_info version = {NGHTTP2_VERSION_AGE, NGHTTP2_VERSION_NUM,
|
||||
NGHTTP2_VERSION, NGHTTP2_PROTO_VERSION_ID};
|
||||
|
||||
nghttp2_info *nghttp2_version(int least_version) {
|
||||
if (least_version > NGHTTP2_VERSION_NUM)
|
||||
return NULL;
|
||||
return &version;
|
||||
}
|
||||
Reference in New Issue
Block a user