Update doc

This commit is contained in:
Tatsuhiro Tsujikawa 2014-02-25 01:49:22 +09:00
parent cd3337aed2
commit 3432a0bed9
15 changed files with 1369 additions and 1240 deletions

View File

@ -4,7 +4,7 @@
* *
* Sphinx stylesheet -- basic theme. * Sphinx stylesheet -- basic theme.
* *
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details. * :license: BSD, see LICENSE for details.
* *
*/ */
@ -89,6 +89,7 @@ div.sphinxsidebar #searchbox input[type="submit"] {
img { img {
border: 0; border: 0;
max-width: 100%;
} }
/* -- search page ----------------------------------------------------------- */ /* -- search page ----------------------------------------------------------- */
@ -401,10 +402,6 @@ dl.glossary dt {
margin: 0; margin: 0;
} }
.refcount {
color: #060;
}
.optional { .optional {
font-size: 1.3em; font-size: 1.3em;
} }

View File

@ -4,7 +4,7 @@
* *
* Sphinx JavaScript utilities for all documentation. * Sphinx JavaScript utilities for all documentation.
* *
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details. * :license: BSD, see LICENSE for details.
* *
*/ */
@ -32,7 +32,7 @@ if (!window.console || !console.firebug) {
*/ */
jQuery.urldecode = function(x) { jQuery.urldecode = function(x) {
return decodeURIComponent(x).replace(/\+/g, ' '); return decodeURIComponent(x).replace(/\+/g, ' ');
} };
/** /**
* small helper function to urlencode strings * small helper function to urlencode strings
@ -61,18 +61,6 @@ jQuery.getQueryParameters = function(s) {
return result; return result;
}; };
/**
* small function to check if an array contains
* a given item.
*/
jQuery.contains = function(arr, item) {
for (var i = 0; i < arr.length; i++) {
if (arr[i] == item)
return true;
}
return false;
};
/** /**
* highlight a given string on a jquery object by wrapping it in * highlight a given string on a jquery object by wrapping it in
* span elements with the given class name. * span elements with the given class name.
@ -180,6 +168,9 @@ var Documentation = {
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) { if (terms.length) {
var body = $('div.body'); var body = $('div.body');
if (!body.length) {
body = $('body');
}
window.setTimeout(function() { window.setTimeout(function() {
$.each(terms, function() { $.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted'); body.highlightText(this.toLowerCase(), 'highlighted');

View File

@ -4,38 +4,11 @@
* *
* Sphinx JavaScript utilties for the full-text search. * Sphinx JavaScript utilties for the full-text search.
* *
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details. * :license: BSD, see LICENSE for details.
* *
*/ */
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurance, the
* latter for highlighting it.
*/
jQuery.makeSearchSummary = function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
/** /**
* Porter Stemmer * Porter Stemmer
@ -220,6 +193,38 @@ var Stemmer = function() {
} }
/**
* Simple result scoring code.
*/
var Scorer = {
// Implement the following function to further tweak the score for each result
// The function takes a result array [filename, title, anchor, descr, score]
// and returns the new score.
/*
score: function(result) {
return result[4];
},
*/
// query matches the full name of an object
objNameMatch: 11,
// or matches in the last dotted part of the object name
objPartialMatch: 6,
// Additive scores depending on the priority of the object
objPrio: {0: 15, // used to be importantResults
1: 5, // used to be objectResults
2: -5}, // used to be unimportantResults
// Used when the priority is not in the mapping.
objPrioDefault: 0,
// query found in title
title: 15,
// query found in terms
term: 5
};
/** /**
* Search Module * Search Module
*/ */
@ -239,8 +244,13 @@ var Search = {
}, },
loadIndex : function(url) { loadIndex : function(url) {
$.ajax({type: "GET", url: url, data: null, success: null, $.ajax({type: "GET", url: url, data: null,
dataType: "script", cache: true}); dataType: "script", cache: true,
complete: function(jqxhr, textstatus) {
if (textstatus != "success") {
document.getElementById("searchindexloader").src = url;
}
}});
}, },
setIndex : function(index) { setIndex : function(index) {
@ -268,19 +278,20 @@ var Search = {
if (this._pulse_status >= 0) if (this._pulse_status >= 0)
return; return;
function pulse() { function pulse() {
var i;
Search._pulse_status = (Search._pulse_status + 1) % 4; Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = ''; var dotString = '';
for (var i = 0; i < Search._pulse_status; i++) for (i = 0; i < Search._pulse_status; i++)
dotString += '.'; dotString += '.';
Search.dots.text(dotString); Search.dots.text(dotString);
if (Search._pulse_status > -1) if (Search._pulse_status > -1)
window.setTimeout(pulse, 500); window.setTimeout(pulse, 500);
}; }
pulse(); pulse();
}, },
/** /**
* perform a search for something * perform a search for something (or wait until index is loaded)
*/ */
performSearch : function(query) { performSearch : function(query) {
// create the required interface elements // create the required interface elements
@ -300,41 +311,46 @@ var Search = {
this.deferQuery(query); this.deferQuery(query);
}, },
/**
* execute search (requires search index to be loaded)
*/
query : function(query) { query : function(query) {
var i;
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"]; var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
// Stem the searchterms and add them to the correct list // stem the searchterms and add them to the correct list
var stemmer = new Stemmer(); var stemmer = new Stemmer();
var searchterms = []; var searchterms = [];
var excluded = []; var excluded = [];
var hlterms = []; var hlterms = [];
var tmp = query.split(/\s+/); var tmp = query.split(/\s+/);
var objectterms = []; var objectterms = [];
for (var i = 0; i < tmp.length; i++) { for (i = 0; i < tmp.length; i++) {
if (tmp[i] != "") { if (tmp[i] !== "") {
objectterms.push(tmp[i].toLowerCase()); objectterms.push(tmp[i].toLowerCase());
} }
if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) || if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
tmp[i] == "") { tmp[i] === "") {
// skip this "word" // skip this "word"
continue; continue;
} }
// stem the word // stem the word
var word = stemmer.stemWord(tmp[i]).toLowerCase(); var word = stemmer.stemWord(tmp[i].toLowerCase());
var toAppend;
// select the correct list // select the correct list
if (word[0] == '-') { if (word[0] == '-') {
var toAppend = excluded; toAppend = excluded;
word = word.substr(1); word = word.substr(1);
} }
else { else {
var toAppend = searchterms; toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase()); hlterms.push(tmp[i].toLowerCase());
} }
// only add if not already in the list // only add if not already in the list
if (!$.contains(toAppend, word)) if (!$u.contains(toAppend, word))
toAppend.push(word); toAppend.push(word);
}; }
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" ")); var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:'); // console.debug('SEARCH: searching for:');
@ -342,89 +358,51 @@ var Search = {
// console.info('excluded: ', excluded); // console.info('excluded: ', excluded);
// prepare search // prepare search
var filenames = this._index.filenames;
var titles = this._index.titles;
var terms = this._index.terms; var terms = this._index.terms;
var fileMap = {}; var titleterms = this._index.titleterms;
var files = null;
// different result priorities // array of [filename, title, anchor, descr, score]
var importantResults = []; var results = [];
var objectResults = [];
var regularResults = [];
var unimportantResults = [];
$('#search-progress').empty(); $('#search-progress').empty();
// lookup as object // lookup as object
for (var i = 0; i < objectterms.length; i++) { for (i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0, i), var others = [].concat(objectterms.slice(0, i),
objectterms.slice(i+1, objectterms.length)) objectterms.slice(i+1, objectterms.length));
var results = this.performObjectSearch(objectterms[i], others); results = results.concat(this.performObjectSearch(objectterms[i], others));
// Assume first word is most likely to be the object,
// other words more likely to be in description.
// Therefore put matches for earlier words first.
// (Results are eventually used in reverse order).
objectResults = results[0].concat(objectResults);
importantResults = results[1].concat(importantResults);
unimportantResults = results[2].concat(unimportantResults);
} }
// perform the search on the required terms // lookup as search terms in fulltext
for (var i = 0; i < searchterms.length; i++) { results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
var word = searchterms[i]; .concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
// no match but word was a required one
if ((files = terms[word]) == null) // let the scorer override scores with a custom scoring function
break; if (Scorer.score) {
if (files.length == undefined) { for (i = 0; i < results.length; i++)
files = [files]; results[i][4] = Scorer.score(results[i]);
}
// create the mapping
for (var j = 0; j < files.length; j++) {
var file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
} }
// now check if the files don't contain excluded terms // now sort the results by score (in opposite order of appearance, since the
for (var file in fileMap) { // display function below uses pop() to retrieve items) and then
var valid = true; // alphabetically
results.sort(function(a, b) {
// check if all requirements are matched var left = a[4];
if (fileMap[file].length != searchterms.length) var right = b[4];
continue; if (left > right) {
return 1;
// ensure that none of the excluded terms is in the } else if (left < right) {
// search result. return -1;
for (var i = 0; i < excluded.length; i++) { } else {
if (terms[excluded[i]] == file || // same score: sort alphabetically
$.contains(terms[excluded[i]] || [], file)) { left = a[1].toLowerCase();
valid = false; right = b[1].toLowerCase();
break;
}
}
// if we have still a valid result we can add it
// to the result list
if (valid)
regularResults.push([filenames[file], titles[file], '', null]);
}
// delete unused variables in order to not waste
// memory until list is retrieved completely
delete filenames, titles, terms;
// now sort the regular results descending by title
regularResults.sort(function(a, b) {
var left = a[1].toLowerCase();
var right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0); return (left > right) ? -1 : ((left < right) ? 1 : 0);
}
}); });
// combine all results // for debugging
var results = unimportantResults.concat(regularResults) //Search.lastresults = results.slice(); // a copy
.concat(objectResults).concat(importantResults); //console.info('search results:', Search.lastresults);
// print the results // print the results
var resultCount = results.length; var resultCount = results.length;
@ -433,7 +411,7 @@ var Search = {
if (results.length) { if (results.length) {
var item = results.pop(); var item = results.pop();
var listItem = $('<li style="display:none"></li>'); var listItem = $('<li style="display:none"></li>');
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') { if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
// dirhtml builder // dirhtml builder
var dirname = item[0] + '/'; var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) { if (dirname.match(/\/index\/$/)) {
@ -457,16 +435,18 @@ var Search = {
displayNextItem(); displayNextItem();
}); });
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) { } else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
$.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + $.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
item[0] + '.txt', function(data) { dataType: "text",
if (data != '') { complete: function(jqxhr, textstatus) {
listItem.append($.makeSearchSummary(data, searchterms, hlterms)); var data = jqxhr.responseText;
Search.output.append(listItem); if (data !== '') {
listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
} }
Search.output.append(listItem);
listItem.slideDown(5, function() { listItem.slideDown(5, function() {
displayNextItem(); displayNextItem();
}); });
}, "text"); }});
} else { } else {
// no source available, just display title // no source available, just display title
Search.output.append(listItem); Search.output.append(listItem);
@ -489,20 +469,32 @@ var Search = {
displayNextItem(); displayNextItem();
}, },
/**
* search for object names
*/
performObjectSearch : function(object, otherterms) { performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames; var filenames = this._index.filenames;
var objects = this._index.objects; var objects = this._index.objects;
var objnames = this._index.objnames; var objnames = this._index.objnames;
var titles = this._index.titles; var titles = this._index.titles;
var importantResults = []; var i;
var objectResults = []; var results = [];
var unimportantResults = [];
for (var prefix in objects) { for (var prefix in objects) {
for (var name in objects[prefix]) { for (var name in objects[prefix]) {
var fullname = (prefix ? prefix + '.' : '') + name; var fullname = (prefix ? prefix + '.' : '') + name;
if (fullname.toLowerCase().indexOf(object) > -1) { if (fullname.toLowerCase().indexOf(object) > -1) {
var score = 0;
var parts = fullname.split('.');
// check for different match types: exact matches of full name or
// "last name" (i.e. last dotted part)
if (fullname == object || parts[parts.length - 1] == object) {
score += Scorer.objNameMatch;
// matches in last name
} else if (parts[parts.length - 1].indexOf(object) > -1) {
score += Scorer.objPartialMatch;
}
var match = objects[prefix][name]; var match = objects[prefix][name];
var objname = objnames[match[1]][2]; var objname = objnames[match[1]][2];
var title = titles[match[0]]; var title = titles[match[0]];
@ -512,7 +504,7 @@ var Search = {
var haystack = (prefix + ' ' + name + ' ' + var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase(); objname + ' ' + title).toLowerCase();
var allfound = true; var allfound = true;
for (var i = 0; i < otherterms.length; i++) { for (i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) { if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false; allfound = false;
break; break;
@ -523,37 +515,107 @@ var Search = {
} }
} }
var descr = objname + _(', in ') + title; var descr = objname + _(', in ') + title;
anchor = match[3];
if (anchor == '') var anchor = match[3];
if (anchor === '')
anchor = fullname; anchor = fullname;
else if (anchor == '-') else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname; anchor = objnames[match[1]][1] + '-' + fullname;
result = [filenames[match[0]], fullname, '#'+anchor, descr]; // add custom score for some objects according to scorer
switch (match[2]) { if (Scorer.objPrio.hasOwnProperty(match[2])) {
case 1: objectResults.push(result); break; score += Scorer.objPrio[match[2]];
case 0: importantResults.push(result); break; } else {
case 2: unimportantResults.push(result); break; score += Scorer.objPrioDefault;
} }
results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
} }
} }
} }
// sort results descending return results;
objectResults.sort(function(a, b) { },
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
/**
* search for full-text terms in the index
*/
performTermsSearch : function(searchterms, excluded, terms, score) {
var filenames = this._index.filenames;
var titles = this._index.titles;
var i, j, file, files;
var fileMap = {};
var results = [];
// perform the search on the required terms
for (i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
// no match but word was a required one
if ((files = terms[word]) === undefined)
break;
if (files.length === undefined) {
files = [files];
}
// create the mapping
for (j = 0; j < files.length; j++) {
file = files[j];
if (file in fileMap)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (file in fileMap) {
var valid = true;
// check if all requirements are matched
if (fileMap[file].length != searchterms.length)
continue;
// ensure that none of the excluded terms is in the search result
for (i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
$u.contains(terms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it to the result list
if (valid) {
results.push([filenames[file], titles[file], '', null, score]);
}
}
return results;
},
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurance, the
* latter for highlighting it.
*/
makeSearchSummary : function(text, keywords, hlwords) {
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
}); });
start = Math.max(start - 120, 0);
importantResults.sort(function(a, b) { var excerpt = ((start > 0) ? '...' : '') +
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0); $.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<div class="context"></div>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
}); });
return rv;
unimportantResults.sort(function(a, b) {
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
});
return [importantResults, objectResults, unimportantResults]
}
} }
};
$(document).ready(function() { $(document).ready(function() {
Search.init(); Search.init();

View File

@ -4,7 +4,7 @@
* *
* sphinx.websupport utilties for all documentation. * sphinx.websupport utilties for all documentation.
* *
* :copyright: Copyright 2007-2011 by the Sphinx team, see AUTHORS. * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details. * :license: BSD, see LICENSE for details.
* *
*/ */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
@ -22,7 +21,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'', URL_ROOT:'./',
VERSION:'0.4.0-DEV', VERSION:'0.4.0-DEV',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
@ -22,7 +21,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'', URL_ROOT:'./',
VERSION:'0.4.0-DEV', VERSION:'0.4.0-DEV',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
@ -2290,6 +2289,13 @@
<span class="cm"> * This function creates copies of all name/value pairs in |nva|. It</span> <span class="cm"> * This function creates copies of all name/value pairs in |nva|. It</span>
<span class="cm"> * also lower-cases all names in |nva|.</span> <span class="cm"> * also lower-cases all names in |nva|.</span>
<span class="cm"> *</span> <span class="cm"> *</span>
<span class="cm"> * The |promised_stream_user_data| is a pointer to an arbitrary data</span>
<span class="cm"> * which is associated to the promised stream this frame will open and</span>
<span class="cm"> * make it in reserved state. It is available using</span>
<span class="cm"> * `nghttp2_session_get_stream_user_data()`. The application can</span>
<span class="cm"> * access it in :type:`nghttp2_before_frame_send_callback` and</span>
<span class="cm"> * :type:`nghttp2_on_frame_send_callback` of this frame.</span>
<span class="cm"> *</span>
<span class="cm"> * Since the library reorders the frames and tries to send the highest</span> <span class="cm"> * Since the library reorders the frames and tries to send the highest</span>
<span class="cm"> * prioritized one first and the HTTP/2.0 specification requires the</span> <span class="cm"> * prioritized one first and the HTTP/2.0 specification requires the</span>
<span class="cm"> * stream ID must be strictly increasing, the promised stream ID</span> <span class="cm"> * stream ID must be strictly increasing, the promised stream ID</span>
@ -2310,7 +2316,8 @@
<span class="cm"> */</span> <span class="cm"> */</span>
<span class="kt">int</span> <span class="nf">nghttp2_submit_push_promise</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">flags</span><span class="p">,</span> <span class="kt">int</span> <span class="nf">nghttp2_submit_push_promise</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <span class="kt">uint8_t</span> <span class="n">flags</span><span class="p">,</span>
<span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">,</span> <span class="kt">int32_t</span> <span class="n">stream_id</span><span class="p">,</span>
<span class="k">const</span> <span class="n">nghttp2_nv</span> <span class="o">*</span><span class="n">nva</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">nvlen</span><span class="p">);</span> <span class="k">const</span> <span class="n">nghttp2_nv</span> <span class="o">*</span><span class="n">nva</span><span class="p">,</span> <span class="kt">size_t</span> <span class="n">nvlen</span><span class="p">,</span>
<span class="kt">void</span> <span class="o">*</span><span class="n">promised_stream_user_data</span><span class="p">);</span>
<span class="cm">/**</span> <span class="cm">/**</span>
<span class="cm"> * @function</span> <span class="cm"> * @function</span>

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
@ -22,7 +21,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'', URL_ROOT:'./',
VERSION:'0.4.0-DEV', VERSION:'0.4.0-DEV',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',

Binary file not shown.

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
@ -22,7 +21,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'', URL_ROOT:'./',
VERSION:'0.4.0-DEV', VERSION:'0.4.0-DEV',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
@ -271,11 +270,12 @@ installed:</p>
<h2>Build from git<a class="headerlink" href="#build-from-git" title="Permalink to this headline"></a></h2> <h2>Build from git<a class="headerlink" href="#build-from-git" title="Permalink to this headline"></a></h2>
<p>Building from git is easy, but please be sure that at least autoconf 2.68 is <p>Building from git is easy, but please be sure that at least autoconf 2.68 is
used:</p> used:</p>
<div class="highlight-c"><pre>$ autoreconf -i <div class="highlight-c"><div class="highlight"><pre>$ autoreconf -i
$ automake $ automake
$ autoconf $ autoconf
$ ./configure $ ./configure
$ make</pre> $ make
</pre></div>
</div> </div>
</div> </div>
<div class="section" id="building-documentation"> <div class="section" id="building-documentation">
@ -285,7 +285,8 @@ $ make</pre>
<p class="last">Documentation is still incomplete.</p> <p class="last">Documentation is still incomplete.</p>
</div> </div>
<p>To build documentation, run:</p> <p>To build documentation, run:</p>
<div class="highlight-c"><pre>$ make html</pre> <div class="highlight-c"><div class="highlight"><pre>$ make html
</pre></div>
</div> </div>
<p>The documents will be generated under <tt class="docutils literal"><span class="pre">doc/manual/html/</span></tt>.</p> <p>The documents will be generated under <tt class="docutils literal"><span class="pre">doc/manual/html/</span></tt>.</p>
<p>The generated documents will not be installed with <tt class="docutils literal"><span class="pre">make</span> <span class="pre">install</span></tt>.</p> <p>The generated documents will not be installed with <tt class="docutils literal"><span class="pre">make</span> <span class="pre">install</span></tt>.</p>
@ -301,7 +302,7 @@ $ make</pre>
with prior knowledge, HTTP Upgrade and NPN/ALPN TLS extension.</p> with prior knowledge, HTTP Upgrade and NPN/ALPN TLS extension.</p>
<p>It has verbose output mode for framing information. Here is sample <p>It has verbose output mode for framing information. Here is sample
output from <tt class="docutils literal"><span class="pre">nghttp</span></tt> client:</p> output from <tt class="docutils literal"><span class="pre">nghttp</span></tt> client:</p>
<div class="highlight-c"><pre>$ src/nghttp -nv https://localhost:8443 <div class="highlight-c"><div class="highlight"><pre>$ src/nghttp -nv https://localhost:8443
[ 0.004][NPN] server offers: [ 0.004][NPN] server offers:
* h2-10 * h2-10
* spdy/3.1 * spdy/3.1
@ -341,7 +342,7 @@ The negotiated protocol: h2-10
[ 0.008] (stream_id=1) content-length: 146 [ 0.008] (stream_id=1) content-length: 146
[ 0.008] (stream_id=1) content-type: text/html [ 0.008] (stream_id=1) content-type: text/html
[ 0.008] (stream_id=1) date: Sat, 15 Feb 2014 08:14:12 GMT [ 0.008] (stream_id=1) date: Sat, 15 Feb 2014 08:14:12 GMT
[ 0.008] (stream_id=1) etag: "b1-4e5535a027780-gzip" [ 0.008] (stream_id=1) etag: &quot;b1-4e5535a027780-gzip&quot;
[ 0.008] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT [ 0.008] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT
[ 0.008] (stream_id=1) server: Apache/2.4.6 (Debian) [ 0.008] (stream_id=1) server: Apache/2.4.6 (Debian)
[ 0.008] (stream_id=1) vary: Accept-Encoding [ 0.008] (stream_id=1) vary: Accept-Encoding
@ -354,10 +355,11 @@ The negotiated protocol: h2-10
[ 0.008] recv DATA frame &lt;length=0, flags=0x01, stream_id=1&gt; [ 0.008] recv DATA frame &lt;length=0, flags=0x01, stream_id=1&gt;
; END_STREAM ; END_STREAM
[ 0.008] send GOAWAY frame &lt;length=8, flags=0x00, stream_id=0&gt; [ 0.008] send GOAWAY frame &lt;length=8, flags=0x00, stream_id=0&gt;
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])</pre> (last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
</pre></div>
</div> </div>
<p>The HTTP Upgrade is performed like this:</p> <p>The HTTP Upgrade is performed like this:</p>
<div class="highlight-c"><pre>$ src/nghttp -nvu http://localhost:8080 <div class="highlight-c"><div class="highlight"><pre>$ src/nghttp -nvu http://localhost:8080
[ 0.000] HTTP Upgrade request [ 0.000] HTTP Upgrade request
GET / HTTP/1.1 GET / HTTP/1.1
Host: localhost:8080 Host: localhost:8080
@ -389,7 +391,7 @@ Upgrade: h2-10
[ 0.001] (stream_id=1) content-length: 177 [ 0.001] (stream_id=1) content-length: 177
[ 0.001] (stream_id=1) content-type: text/html [ 0.001] (stream_id=1) content-type: text/html
[ 0.001] (stream_id=1) date: Sat, 15 Feb 2014 08:16:23 GMT [ 0.001] (stream_id=1) date: Sat, 15 Feb 2014 08:16:23 GMT
[ 0.001] (stream_id=1) etag: "b1-4e5535a027780" [ 0.001] (stream_id=1) etag: &quot;b1-4e5535a027780&quot;
[ 0.001] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT [ 0.001] (stream_id=1) last-modified: Sun, 01 Sep 2013 14:34:22 GMT
[ 0.001] (stream_id=1) server: Apache/2.4.6 (Debian) [ 0.001] (stream_id=1) server: Apache/2.4.6 (Debian)
[ 0.001] (stream_id=1) vary: Accept-Encoding [ 0.001] (stream_id=1) vary: Accept-Encoding
@ -408,7 +410,8 @@ Upgrade: h2-10
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[]) (last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
[ 0.002] recv SETTINGS frame &lt;length=0, flags=0x01, stream_id=0&gt; [ 0.002] recv SETTINGS frame &lt;length=0, flags=0x01, stream_id=0&gt;
; ACK ; ACK
(niv=0)</pre> (niv=0)
</pre></div>
</div> </div>
</div> </div>
<div class="section" id="nghttpd-server"> <div class="section" id="nghttpd-server">
@ -422,7 +425,7 @@ HTTP/2.0 connection. No HTTP Upgrade is supported.</p>
<p><tt class="docutils literal"><span class="pre">-p</span></tt> option allows users to configure server push.</p> <p><tt class="docutils literal"><span class="pre">-p</span></tt> option allows users to configure server push.</p>
<p>Just like <tt class="docutils literal"><span class="pre">nghttp</span></tt>, it has verbose output mode for framing <p>Just like <tt class="docutils literal"><span class="pre">nghttp</span></tt>, it has verbose output mode for framing
information. Here is sample output from <tt class="docutils literal"><span class="pre">nghttpd</span></tt> server:</p> information. Here is sample output from <tt class="docutils literal"><span class="pre">nghttpd</span></tt> server:</p>
<div class="highlight-c"><pre>$ src/nghttpd --no-tls -v 8080 <div class="highlight-c"><div class="highlight"><pre>$ src/nghttpd --no-tls -v 8080
IPv4: listen on port 8080 IPv4: listen on port 8080
IPv6: listen on port 8080 IPv6: listen on port 8080
[id=1] [ 1.027] send SETTINGS frame &lt;length=10, flags=0x00, stream_id=0&gt; [id=1] [ 1.027] send SETTINGS frame &lt;length=10, flags=0x00, stream_id=0&gt;
@ -465,7 +468,8 @@ IPv6: listen on port 8080
(niv=0) (niv=0)
[id=1] [ 1.028] recv GOAWAY frame &lt;length=8, flags=0x00, stream_id=0&gt; [id=1] [ 1.028] recv GOAWAY frame &lt;length=8, flags=0x00, stream_id=0&gt;
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[]) (last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
[id=1] [ 1.028] closed</pre> [id=1] [ 1.028] closed
</pre></div>
</div> </div>
</div> </div>
<div class="section" id="nghttpx-proxy"> <div class="section" id="nghttpx-proxy">
@ -555,7 +559,8 @@ create proxy.pac script like this:</p>
machine nghttpx is running. Please note that Chrome requires valid machine nghttpx is running. Please note that Chrome requires valid
certificate for secure proxy.</p> certificate for secure proxy.</p>
<p>Then run chrome with the following arguments:</p> <p>Then run chrome with the following arguments:</p>
<div class="highlight-c"><pre>$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn</pre> <div class="highlight-c"><div class="highlight"><pre>$ google-chrome --proxy-pac-url=file:///path/to/proxy.pac --use-npn
</pre></div>
</div> </div>
<p>With <tt class="docutils literal"><span class="pre">--http2-bridge</span></tt>, it accepts HTTP/2.0, SPDY and HTTP/1.1 <p>With <tt class="docutils literal"><span class="pre">--http2-bridge</span></tt>, it accepts HTTP/2.0, SPDY and HTTP/1.1
connections and communicates with backend in HTTP/2.0:</p> connections and communicates with backend in HTTP/2.0:</p>
@ -1002,16 +1007,14 @@ corresponding header set was processed. The format is the same as
<div class="section" id="python-bindings"> <div class="section" id="python-bindings">
<h2>Python bindings<a class="headerlink" href="#python-bindings" title="Permalink to this headline"></a></h2> <h2>Python bindings<a class="headerlink" href="#python-bindings" title="Permalink to this headline"></a></h2>
<p>This <tt class="docutils literal"><span class="pre">python</span></tt> directory contains nghttp2 Python bindings. The <p>This <tt class="docutils literal"><span class="pre">python</span></tt> directory contains nghttp2 Python bindings. The
bindings currently only provide HPACK compressor and decompressor bindings currently provide HPACK compressor and decompressor
classes.</p> classes and HTTP/2 server.</p>
<p>The extension module is called <tt class="docutils literal"><span class="pre">nghttp2</span></tt>.</p> <p>The extension module is called <tt class="docutils literal"><span class="pre">nghttp2</span></tt>.</p>
<p><tt class="docutils literal"><span class="pre">make</span></tt> will build the bindings and target Python version is <p><tt class="docutils literal"><span class="pre">make</span></tt> will build the bindings and target Python version is
determined by configure script. If the detected Python version is not determined by configure script. If the detected Python version is not
what you expect, specify a path to Python executable in <tt class="docutils literal"><span class="pre">PYTHON</span></tt> what you expect, specify a path to Python executable in <tt class="docutils literal"><span class="pre">PYTHON</span></tt>
variable as an argument to configure script (e.g., <tt class="docutils literal"><span class="pre">./configure</span> variable as an argument to configure script (e.g., <tt class="docutils literal"><span class="pre">./configure</span>
<span class="pre">PYTHON=/usr/bin/python3.3</span></tt>).</p> <span class="pre">PYTHON=/usr/bin/python3.3</span></tt>).</p>
<div class="section" id="example">
<h3>Example<a class="headerlink" href="#example" title="Permalink to this headline"></a></h3>
<p>The following example code illustrates basic usage of HPACK compressor <p>The following example code illustrates basic usage of HPACK compressor
and decompressor in Python:</p> and decompressor in Python:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">binascii</span> <div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">binascii</span>
@ -1028,6 +1031,74 @@ and decompressor in Python:</p>
<span class="k">print</span><span class="p">(</span><span class="n">hdrs</span><span class="p">)</span> <span class="k">print</span><span class="p">(</span><span class="n">hdrs</span><span class="p">)</span>
</pre></div> </pre></div>
</div> </div>
<p>The <tt class="docutils literal"><span class="pre">nghttp2.HTTP2Server</span></tt> class builds on top of the asyncio event
loop. On construction, <em>RequestHandlerClass</em> must be given, which must
be a subclass of <tt class="docutils literal"><span class="pre">nghttp2.BaseRequestHandler</span></tt> class.</p>
<p>The <tt class="docutils literal"><span class="pre">BaseRequestHandler</span></tt> class is used to handle the HTTP/2
stream. By default, it does not nothing. It must be subclassed to
handle each event callback method.</p>
<p>The first callback method invoked is <tt class="docutils literal"><span class="pre">on_headers()</span></tt>. It is called
when HEADERS frame, which includes request header fields, is arrived.</p>
<p>If request has request body, <tt class="docutils literal"><span class="pre">on_data(data)</span></tt> is invoked for each
chunk of received data.</p>
<p>When whole request is received, <tt class="docutils literal"><span class="pre">on_request_done()</span></tt> is invoked.</p>
<p>When stream is closed, <tt class="docutils literal"><span class="pre">on_close(error_code)</span></tt> is called.</p>
<p>The application can send response using <tt class="docutils literal"><span class="pre">send_response()</span></tt> method. It
can be used in <tt class="docutils literal"><span class="pre">on_headers()</span></tt>, <tt class="docutils literal"><span class="pre">on_data()</span></tt> or
<tt class="docutils literal"><span class="pre">on_request_done()</span></tt>.</p>
<p>The application can push resource using <tt class="docutils literal"><span class="pre">push()</span></tt> method. It must be
used before <tt class="docutils literal"><span class="pre">send_response()</span></tt> call.</p>
<p>The following instance variables are available:</p>
<dl class="docutils">
<dt>client_address</dt>
<dd>Contains a tuple of the form (host, port) referring to the
client&#8217;s address.</dd>
<dt>stream_id</dt>
<dd>Stream ID of this stream</dd>
<dt>scheme</dt>
<dd>Scheme of the request URI. This is a value of :scheme header field.</dd>
<dt>method</dt>
<dd>Method of this stream. This is a value of :method header field.</dd>
<dt>host</dt>
<dd>This is a value of :authority or host header field.</dd>
<dt>path</dt>
<dd>This is a value of :path header field.</dd>
</dl>
<p>The following example illustrates the HTTP2Server and
BaseRequestHandler usage:</p>
<div class="highlight-python"><div class="highlight"><pre><span class="c">#!/usr/bin/env python</span>
<span class="kn">import</span> <span class="nn">io</span><span class="o">,</span> <span class="nn">ssl</span>
<span class="kn">from</span> <span class="nn">pprint</span> <span class="kn">import</span> <span class="n">pprint</span>
<span class="kn">import</span> <span class="nn">nghttp2</span>
<span class="k">class</span> <span class="nc">Handler</span><span class="p">(</span><span class="n">nghttp2</span><span class="o">.</span><span class="n">BaseRequestHandler</span><span class="p">):</span>
<span class="k">def</span> <span class="nf">on_headers</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
<span class="bp">self</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="n">path</span><span class="o">=</span><span class="s">&#39;/css/bootstrap.css&#39;</span><span class="p">,</span>
<span class="n">request_headers</span> <span class="o">=</span> <span class="p">[(</span><span class="n">b</span><span class="s">&#39;content-length&#39;</span><span class="p">,</span> <span class="n">b</span><span class="s">&#39;3&#39;</span><span class="p">)],</span>
<span class="n">status</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="n">body</span><span class="o">=</span><span class="s">&#39;foo&#39;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="n">path</span><span class="o">=</span><span class="s">&#39;/js/bootstrap.js&#39;</span><span class="p">,</span>
<span class="n">method</span><span class="o">=</span><span class="s">&#39;GET&#39;</span><span class="p">,</span>
<span class="n">request_headers</span> <span class="o">=</span> <span class="p">[(</span><span class="n">b</span><span class="s">&#39;content-length&#39;</span><span class="p">,</span> <span class="n">b</span><span class="s">&#39;10&#39;</span><span class="p">)],</span>
<span class="n">status</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="n">body</span><span class="o">=</span><span class="s">&#39;foobarbuzz&#39;</span><span class="p">)</span>
<span class="bp">self</span><span class="o">.</span><span class="n">send_response</span><span class="p">(</span><span class="n">status</span><span class="o">=</span><span class="mi">200</span><span class="p">,</span>
<span class="n">headers</span> <span class="o">=</span> <span class="p">[(</span><span class="n">b</span><span class="s">&#39;content-type&#39;</span><span class="p">,</span> <span class="n">b</span><span class="s">&#39;text/plain&#39;</span><span class="p">)],</span>
<span class="n">body</span><span class="o">=</span><span class="n">io</span><span class="o">.</span><span class="n">BytesIO</span><span class="p">(</span><span class="n">b</span><span class="s">&#39;nghttp2-python FTW&#39;</span><span class="p">))</span>
<span class="n">ctx</span> <span class="o">=</span> <span class="n">ssl</span><span class="o">.</span><span class="n">SSLContext</span><span class="p">(</span><span class="n">ssl</span><span class="o">.</span><span class="n">PROTOCOL_SSLv23</span><span class="p">)</span>
<span class="n">ctx</span><span class="o">.</span><span class="n">options</span> <span class="o">=</span> <span class="n">ssl</span><span class="o">.</span><span class="n">OP_ALL</span> <span class="o">|</span> <span class="n">ssl</span><span class="o">.</span><span class="n">OP_NO_SSLv2</span>
<span class="n">ctx</span><span class="o">.</span><span class="n">set_npn_protocols</span><span class="p">([</span><span class="s">&#39;h2-10&#39;</span><span class="p">])</span>
<span class="n">ctx</span><span class="o">.</span><span class="n">load_cert_chain</span><span class="p">(</span><span class="s">&#39;server.crt&#39;</span><span class="p">,</span> <span class="s">&#39;server.key&#39;</span><span class="p">)</span>
<span class="c"># give None to ssl to make the server non-SSL/TLS</span>
<span class="n">server</span> <span class="o">=</span> <span class="n">nghttp2</span><span class="o">.</span><span class="n">HTTP2Server</span><span class="p">((</span><span class="s">&#39;127.0.0.1&#39;</span><span class="p">,</span> <span class="mi">8443</span><span class="p">),</span> <span class="n">Handler</span><span class="p">,</span> <span class="n">ssl</span><span class="o">=</span><span class="n">ctx</span><span class="p">)</span>
<span class="n">server</span><span class="o">.</span><span class="n">serve_forever</span><span class="p">()</span>
</pre></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -21,7 +21,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'', URL_ROOT:'./',
VERSION:'0.4.0-DEV', VERSION:'0.4.0-DEV',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
@ -22,7 +21,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'', URL_ROOT:'./',
VERSION:'0.4.0-DEV', VERSION:'0.4.0-DEV',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
@ -154,7 +153,8 @@ the end of this page. It also resides in examples directory in the
archive or repository.</p> archive or repository.</p>
<p>This simple client takes 1 argument, HTTPS URI, and retrieves the <p>This simple client takes 1 argument, HTTPS URI, and retrieves the
resource denoted by the URI. Its synopsis is like this:</p> resource denoted by the URI. Its synopsis is like this:</p>
<div class="highlight-c"><pre>$ libevent-client HTTPS_URI</pre> <div class="highlight-c"><div class="highlight"><pre>$ libevent-client HTTPS_URI
</pre></div>
</div> </div>
<p>We use libevent in this tutorial to handle networking I/O. Please <p>We use libevent in this tutorial to handle networking I/O. Please
note that nghttp2 itself does not depend on libevent.</p> note that nghttp2 itself does not depend on libevent.</p>
@ -163,7 +163,7 @@ function <tt class="docutils literal"><span class="pre">main()</span></tt> and <
library use. The one thing you should look at is setup NPN callback. library use. The one thing you should look at is setup NPN callback.
The NPN callback is used for the client to select the next application The NPN callback is used for the client to select the next application
protocol over the SSL/TLS transport. In this tutorial, we use protocol over the SSL/TLS transport. In this tutorial, we use
<a class="reference internal" href="apiref.html#nghttp2_select_next_protocol" title="nghttp2_select_next_protocol"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_select_next_protocol()</span></tt></a> function to select the HTTP/2.0 <a class="reference internal" href="apiref.html#c.nghttp2_select_next_protocol" title="nghttp2_select_next_protocol"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_select_next_protocol()</span></tt></a> function to select the HTTP/2.0
protocol the library supports:</p> protocol the library supports:</p>
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">int</span> <span class="nf">select_next_proto_cb</span><span class="p">(</span><span class="n">SSL</span><span class="o">*</span> <span class="n">ssl</span><span class="p">,</span> <div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">int</span> <span class="nf">select_next_proto_cb</span><span class="p">(</span><span class="n">SSL</span><span class="o">*</span> <span class="n">ssl</span><span class="p">,</span>
<span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="n">out</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">outlen</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">**</span><span class="n">out</span><span class="p">,</span> <span class="kt">unsigned</span> <span class="kt">char</span> <span class="o">*</span><span class="n">outlen</span><span class="p">,</span>
@ -310,15 +310,15 @@ finished successfully. We first initialize nghttp2 session object in
<span class="p">}</span> <span class="p">}</span>
</pre></div> </pre></div>
</div> </div>
<p>Since we are creating client, we use <a class="reference internal" href="apiref.html#nghttp2_session_client_new" title="nghttp2_session_client_new"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_client_new()</span></tt></a> to <p>Since we are creating client, we use <a class="reference internal" href="apiref.html#c.nghttp2_session_client_new" title="nghttp2_session_client_new"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_client_new()</span></tt></a> to
initialize nghttp2 session object. We setup 7 callbacks for the initialize nghttp2 session object. We setup 7 callbacks for the
nghttp2 session. We&#8217;ll explain these callbacks later.</p> nghttp2 session. We&#8217;ll explain these callbacks later.</p>
<p>The <tt class="xref c c-func docutils literal"><span class="pre">delete_http2_session_data()</span></tt> destroys <tt class="docutils literal"><span class="pre">session_data</span></tt> and frees <p>The <tt class="xref c c-func docutils literal"><span class="pre">delete_http2_session_data()</span></tt> destroys <tt class="docutils literal"><span class="pre">session_data</span></tt> and frees
its bufferevent, so it closes underlying connection as well. It also its bufferevent, so it closes underlying connection as well. It also
calls <a class="reference internal" href="apiref.html#nghttp2_session_del" title="nghttp2_session_del"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_del()</span></tt></a> to delete nghttp2 session object.</p> calls <a class="reference internal" href="apiref.html#c.nghttp2_session_del" title="nghttp2_session_del"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_del()</span></tt></a> to delete nghttp2 session object.</p>
<p>We begin HTTP/2.0 communication by sending client connection header, <p>We begin HTTP/2.0 communication by sending client connection header,
which is 24 bytes magic byte sequence which is 24 bytes magic byte sequence
(<a class="reference internal" href="apiref.html#NGHTTP2_CLIENT_CONNECTION_HEADER" title="NGHTTP2_CLIENT_CONNECTION_HEADER"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_CLIENT_CONNECTION_HEADER</span></tt></a>) followed by SETTINGS (<a class="reference internal" href="apiref.html#c.NGHTTP2_CLIENT_CONNECTION_HEADER" title="NGHTTP2_CLIENT_CONNECTION_HEADER"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_CLIENT_CONNECTION_HEADER</span></tt></a>) followed by SETTINGS
frame. The transmission of client connection header is done in frame. The transmission of client connection header is done in
<tt class="docutils literal"><span class="pre">send_client_connection_header()</span></tt>:</p> <tt class="docutils literal"><span class="pre">send_client_connection_header()</span></tt>:</p>
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">void</span> <span class="nf">send_client_connection_header</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span> <div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">void</span> <span class="nf">send_client_connection_header</span><span class="p">(</span><span class="n">http2_session_data</span> <span class="o">*</span><span class="n">session_data</span><span class="p">)</span>
@ -342,10 +342,10 @@ frame. The transmission of client connection header is done in
<p>Here we specify SETTINGS_MAX_CONCURRENT_STREAMS to 100, which is <p>Here we specify SETTINGS_MAX_CONCURRENT_STREAMS to 100, which is
really not needed for this tiny example progoram, but we are really not needed for this tiny example progoram, but we are
demonstrating the use of SETTINGS frame. To queue the SETTINGS frame demonstrating the use of SETTINGS frame. To queue the SETTINGS frame
for the transmission, we use <a class="reference internal" href="apiref.html#nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a>. Note that for the transmission, we use <a class="reference internal" href="apiref.html#c.nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a>. Note that
<a class="reference internal" href="apiref.html#nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a> function only queues the frame and not <a class="reference internal" href="apiref.html#c.nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a> function only queues the frame and not
actually send it. All <tt class="docutils literal"><span class="pre">nghttp2_submit_*()</span></tt> family functions have actually send it. All <tt class="docutils literal"><span class="pre">nghttp2_submit_*()</span></tt> family functions have
this property. To actually send the frame, <a class="reference internal" href="apiref.html#nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> is this property. To actually send the frame, <a class="reference internal" href="apiref.html#c.nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> is
used, which is described about later.</p> used, which is described about later.</p>
<p>After the transmission of client connection header, we enqueue HTTP <p>After the transmission of client connection header, we enqueue HTTP
request in <tt class="docutils literal"><span class="pre">submit_request()</span></tt> function:</p> request in <tt class="docutils literal"><span class="pre">submit_request()</span></tt> function:</p>
@ -373,9 +373,9 @@ request in <tt class="docutils literal"><span class="pre">submit_request()</span
</pre></div> </pre></div>
</div> </div>
<p>We build HTTP request header fields in <tt class="docutils literal"><span class="pre">hdrs</span></tt> which is an array of <p>We build HTTP request header fields in <tt class="docutils literal"><span class="pre">hdrs</span></tt> which is an array of
<a class="reference internal" href="apiref.html#nghttp2_nv" title="nghttp2_nv"><tt class="xref c c-type docutils literal"><span class="pre">nghttp2_nv</span></tt></a>. There are 4 header fields to be sent: <tt class="docutils literal"><span class="pre">:method</span></tt>, <a class="reference internal" href="apiref.html#c.nghttp2_nv" title="nghttp2_nv"><tt class="xref c c-type docutils literal"><span class="pre">nghttp2_nv</span></tt></a>. There are 4 header fields to be sent: <tt class="docutils literal"><span class="pre">:method</span></tt>,
<tt class="docutils literal"><span class="pre">:scheme</span></tt>, <tt class="docutils literal"><span class="pre">:authority</span></tt> and <tt class="docutils literal"><span class="pre">:path</span></tt>. To queue this HTTP request, <tt class="docutils literal"><span class="pre">:scheme</span></tt>, <tt class="docutils literal"><span class="pre">:authority</span></tt> and <tt class="docutils literal"><span class="pre">:path</span></tt>. To queue this HTTP request,
we use <a class="reference internal" href="apiref.html#nghttp2_submit_request" title="nghttp2_submit_request"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_request()</span></tt></a> function. The <tt class="xref c c-func docutils literal"><span class="pre">stream_data()</span></tt> is we use <a class="reference internal" href="apiref.html#c.nghttp2_submit_request" title="nghttp2_submit_request"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_request()</span></tt></a> function. The <tt class="xref c c-func docutils literal"><span class="pre">stream_data()</span></tt> is
passed in <em>stream_user_data</em> parameter. It is used in nghttp2 passed in <em>stream_user_data</em> parameter. It is used in nghttp2
callbacks which we&#8217;ll describe about later.</p> callbacks which we&#8217;ll describe about later.</p>
<p>The next bufferevent callback is <tt class="docutils literal"><span class="pre">readcb()</span></tt>, which is invoked when <p>The next bufferevent callback is <tt class="docutils literal"><span class="pre">readcb()</span></tt>, which is invoked when
@ -402,8 +402,8 @@ data is available to read in the bufferevent input buffer:</p>
</pre></div> </pre></div>
</div> </div>
<p>In this function, we feed all unprocessed, received data to nghttp2 <p>In this function, we feed all unprocessed, received data to nghttp2
session object using <a class="reference internal" href="apiref.html#nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> function. The session object using <a class="reference internal" href="apiref.html#c.nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> function. The
<a class="reference internal" href="apiref.html#nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> processes the received data and may <a class="reference internal" href="apiref.html#c.nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> processes the received data and may
invoke nghttp2 callbacks and also queue frames. Since there may be invoke nghttp2 callbacks and also queue frames. Since there may be
pending frames, we call <tt class="docutils literal"><span class="pre">session_send()</span></tt> function to send those pending frames, we call <tt class="docutils literal"><span class="pre">session_send()</span></tt> function to send those
frames. The <tt class="docutils literal"><span class="pre">session_send()</span></tt> function is defined as follows:</p> frames. The <tt class="docutils literal"><span class="pre">session_send()</span></tt> function is defined as follows:</p>
@ -420,10 +420,10 @@ frames. The <tt class="docutils literal"><span class="pre">session_send()</span>
<span class="p">}</span> <span class="p">}</span>
</pre></div> </pre></div>
</div> </div>
<p>The <a class="reference internal" href="apiref.html#nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> function serializes the frame into wire <p>The <a class="reference internal" href="apiref.html#c.nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> function serializes the frame into wire
format and call <a class="reference internal" href="apiref.html#nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> with format and call <a class="reference internal" href="apiref.html#c.nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> with
it. We set <tt class="docutils literal"><span class="pre">send_callback()</span></tt> function to it. We set <tt class="docutils literal"><span class="pre">send_callback()</span></tt> function to
<a class="reference internal" href="apiref.html#nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> in <a class="reference internal" href="apiref.html#c.nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> in
<tt class="docutils literal"><span class="pre">initialize_nghttp2_session()</span></tt> function described earlier. It is <tt class="docutils literal"><span class="pre">initialize_nghttp2_session()</span></tt> function described earlier. It is
defined as follows:</p> defined as follows:</p>
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">send_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">send_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
@ -438,13 +438,13 @@ defined as follows:</p>
</pre></div> </pre></div>
</div> </div>
<p>Since we use bufferevent to abstract network I/O, we just write the <p>Since we use bufferevent to abstract network I/O, we just write the
data to the bufferevent object. Note that <a class="reference internal" href="apiref.html#nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> data to the bufferevent object. Note that <a class="reference internal" href="apiref.html#c.nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a>
continues to write all frames queued so far. If we were writing the continues to write all frames queued so far. If we were writing the
data to the non-blocking socket directly using <tt class="docutils literal"><span class="pre">write()</span></tt> system call data to the non-blocking socket directly using <tt class="docutils literal"><span class="pre">write()</span></tt> system call
in the <a class="reference internal" href="apiref.html#nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a>, we will in the <a class="reference internal" href="apiref.html#c.nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a>, we will
surely get <tt class="docutils literal"><span class="pre">EAGAIN</span></tt> or <tt class="docutils literal"><span class="pre">EWOULDBLOCK</span></tt> since the socket has limited surely get <tt class="docutils literal"><span class="pre">EAGAIN</span></tt> or <tt class="docutils literal"><span class="pre">EWOULDBLOCK</span></tt> since the socket has limited
send buffer. If that happens, we can return send buffer. If that happens, we can return
<a class="reference internal" href="apiref.html#NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></tt></a> to signal the nghttp2 library to stop <a class="reference internal" href="apiref.html#c.NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></tt></a> to signal the nghttp2 library to stop
sending further data. But writing to the bufferevent, we have to sending further data. But writing to the bufferevent, we have to
regulate the amount data to be buffered by ourselves to avoid possible regulate the amount data to be buffered by ourselves to avoid possible
huge memory consumption. In this example client, we do not limit huge memory consumption. In this example client, we do not limit
@ -469,8 +469,8 @@ we have to drop connection or not. The nghttp2 session object keeps
track of reception and transmission of GOAWAY frame and other error track of reception and transmission of GOAWAY frame and other error
conditions as well. Using these information, nghttp2 session object conditions as well. Using these information, nghttp2 session object
will tell whether the connection should be dropped or not. More will tell whether the connection should be dropped or not. More
specifically, both <a class="reference internal" href="apiref.html#nghttp2_session_want_read" title="nghttp2_session_want_read"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_read()</span></tt></a> and specifically, both <a class="reference internal" href="apiref.html#c.nghttp2_session_want_read" title="nghttp2_session_want_read"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_read()</span></tt></a> and
<a class="reference internal" href="apiref.html#nghttp2_session_want_write" title="nghttp2_session_want_write"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_write()</span></tt></a> return 0, we have no business in the <a class="reference internal" href="apiref.html#c.nghttp2_session_want_write" title="nghttp2_session_want_write"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_write()</span></tt></a> return 0, we have no business in the
connection. But since we are using bufferevent and its deferred connection. But since we are using bufferevent and its deferred
callback option, the bufferevent output buffer may contain the pending callback option, the bufferevent output buffer may contain the pending
data when the <tt class="docutils literal"><span class="pre">writecb()</span></tt> is called. To handle this situation, we data when the <tt class="docutils literal"><span class="pre">writecb()</span></tt> is called. To handle this situation, we
@ -501,7 +501,7 @@ about to be sent:</p>
</pre></div> </pre></div>
</div> </div>
<p>Remember that we have not get stream ID when we submit HTTP request <p>Remember that we have not get stream ID when we submit HTTP request
using <a class="reference internal" href="apiref.html#nghttp2_submit_request" title="nghttp2_submit_request"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_request()</span></tt></a>. Since nghttp2 library reorders the using <a class="reference internal" href="apiref.html#c.nghttp2_submit_request" title="nghttp2_submit_request"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_request()</span></tt></a>. Since nghttp2 library reorders the
request based on priority and stream ID must be monotonically request based on priority and stream ID must be monotonically
increased, the stream ID is not assigned just before transmission. increased, the stream ID is not assigned just before transmission.
The one of the purpose of this callback is get the stream ID assigned The one of the purpose of this callback is get the stream ID assigned
@ -510,11 +510,11 @@ HEADERS has several meanings in HTTP/2.0, we check that it is request
HEADERS (which means that the first HEADERS frame to create a stream). HEADERS (which means that the first HEADERS frame to create a stream).
The assigned stream ID is <tt class="docutils literal"><span class="pre">frame-&gt;hd.stream_id</span></tt>. Recall that we The assigned stream ID is <tt class="docutils literal"><span class="pre">frame-&gt;hd.stream_id</span></tt>. Recall that we
passed <tt class="docutils literal"><span class="pre">stream_data</span></tt> in the <em>stream_user_data</em> parameter of passed <tt class="docutils literal"><span class="pre">stream_data</span></tt> in the <em>stream_user_data</em> parameter of
<a class="reference internal" href="apiref.html#nghttp2_submit_request" title="nghttp2_submit_request"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_request()</span></tt></a> function. We can get it using <a class="reference internal" href="apiref.html#c.nghttp2_submit_request" title="nghttp2_submit_request"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_request()</span></tt></a> function. We can get it using
<a class="reference internal" href="apiref.html#nghttp2_session_get_stream_user_data" title="nghttp2_session_get_stream_user_data"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_get_stream_user_data()</span></tt></a> function. To really sure that <a class="reference internal" href="apiref.html#c.nghttp2_session_get_stream_user_data" title="nghttp2_session_get_stream_user_data"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_get_stream_user_data()</span></tt></a> function. To really sure that
this HEADERS frame is the request HEADERS we have queued, we check this HEADERS frame is the request HEADERS we have queued, we check
that <tt class="docutils literal"><span class="pre">session_data-&gt;stream_data</span></tt> and <tt class="docutils literal"><span class="pre">stream_data</span></tt> returned from that <tt class="docutils literal"><span class="pre">session_data-&gt;stream_data</span></tt> and <tt class="docutils literal"><span class="pre">stream_data</span></tt> returned from
<a class="reference internal" href="apiref.html#nghttp2_session_get_stream_user_data" title="nghttp2_session_get_stream_user_data"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_get_stream_user_data()</span></tt></a> are pointing the same <a class="reference internal" href="apiref.html#c.nghttp2_session_get_stream_user_data" title="nghttp2_session_get_stream_user_data"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_get_stream_user_data()</span></tt></a> are pointing the same
location. In this example program, we just only uses 1 stream, it is location. In this example program, we just only uses 1 stream, it is
unnecessary to compare them, but real applications surely deal with unnecessary to compare them, but real applications surely deal with
multiple streams, and <em>stream_user_data</em> is very handy to identify multiple streams, and <em>stream_user_data</em> is very handy to identify
@ -563,7 +563,7 @@ how to use it here.</p>
</div> </div>
<p>In this tutorial, we are just interested in the HTTP response <p>In this tutorial, we are just interested in the HTTP response
HEADERS. We check te frame type and its category (it should be HEADERS. We check te frame type and its category (it should be
<a class="reference internal" href="apiref.html#NGHTTP2_HCAT_RESPONSE" title="NGHTTP2_HCAT_RESPONSE"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_HCAT_RESPONSE</span></tt></a> for HTTP response HEADERS). Also check <a class="reference internal" href="apiref.html#c.NGHTTP2_HCAT_RESPONSE" title="NGHTTP2_HCAT_RESPONSE"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_HCAT_RESPONSE</span></tt></a> for HTTP response HEADERS). Also check
its stream ID.</p> its stream ID.</p>
<p>The <tt class="docutils literal"><span class="pre">on_data_chunk_recv_callback()</span></tt> function is invoked when a chunk <p>The <tt class="docutils literal"><span class="pre">on_data_chunk_recv_callback()</span></tt> function is invoked when a chunk
of data is received from the remote peer:</p> of data is received from the remote peer:</p>
@ -609,7 +609,7 @@ is about to close:</p>
<p>If the stream ID matches the one we initiated, it means that its <p>If the stream ID matches the one we initiated, it means that its
stream is going to be closed. Since we have finished to get the stream is going to be closed. Since we have finished to get the
resource we want (or the stream was reset by RST_STREAM from the resource we want (or the stream was reset by RST_STREAM from the
remote peer), we call <a class="reference internal" href="apiref.html#nghttp2_session_terminate_session" title="nghttp2_session_terminate_session"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_terminate_session()</span></tt></a> to remote peer), we call <a class="reference internal" href="apiref.html#c.nghttp2_session_terminate_session" title="nghttp2_session_terminate_session"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_terminate_session()</span></tt></a> to
commencing the closure of the HTTP/2.0 session gracefully. If you have commencing the closure of the HTTP/2.0 session gracefully. If you have
some data associated for the stream to be closed, you may delete it some data associated for the stream to be closed, you may delete it
here.</p> here.</p>

View File

@ -1,6 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]--> <!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]--> <!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
@ -22,7 +21,7 @@
<script type="text/javascript"> <script type="text/javascript">
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT:'', URL_ROOT:'./',
VERSION:'0.4.0-DEV', VERSION:'0.4.0-DEV',
COLLAPSE_INDEX:false, COLLAPSE_INDEX:false,
FILE_SUFFIX:'.html', FILE_SUFFIX:'.html',
@ -157,7 +156,8 @@ repository.</p>
<p>This simple server takes 3 arguments, a port number to listen to, a <p>This simple server takes 3 arguments, a port number to listen to, a
path to SSL/TLS private key file and certificate file. Its synopsis path to SSL/TLS private key file and certificate file. Its synopsis
is like this:</p> is like this:</p>
<div class="highlight-c"><pre>$ libevent-server PORT /path/to/server.key /path/to/server.crt</pre> <div class="highlight-c"><div class="highlight"><pre>$ libevent-server PORT /path/to/server.key /path/to/server.crt
</pre></div>
</div> </div>
<p>We use libevent in this tutorial to handle networking I/O. Please <p>We use libevent in this tutorial to handle networking I/O. Please
note that nghttp2 itself does not depend on libevent.</p> note that nghttp2 itself does not depend on libevent.</p>
@ -203,7 +203,7 @@ life time:</p>
exactly one byte is used to specify the length of each protocol exactly one byte is used to specify the length of each protocol
identifier. In this tutorial, we advertise the HTTP/2.0 protocol the identifier. In this tutorial, we advertise the HTTP/2.0 protocol the
nghttp2 library supports. The nghttp2 library exports its identifier nghttp2 library supports. The nghttp2 library exports its identifier
in <a class="reference internal" href="apiref.html#NGHTTP2_PROTO_VERSION_ID" title="NGHTTP2_PROTO_VERSION_ID"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_PROTO_VERSION_ID</span></tt></a>. The <tt class="docutils literal"><span class="pre">next_proto_cb()</span></tt> function in <a class="reference internal" href="apiref.html#c.NGHTTP2_PROTO_VERSION_ID" title="NGHTTP2_PROTO_VERSION_ID"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_PROTO_VERSION_ID</span></tt></a>. The <tt class="docutils literal"><span class="pre">next_proto_cb()</span></tt> function
is the server-side NPN callback. In OpenSSL implementation, we just is the server-side NPN callback. In OpenSSL implementation, we just
assign the pointer to the NPN buffers we filled earlier. The NPN assign the pointer to the NPN buffers we filled earlier. The NPN
callback function is set to <tt class="docutils literal"><span class="pre">SSL_CTX</span></tt> object using callback function is set to <tt class="docutils literal"><span class="pre">SSL_CTX</span></tt> object using
@ -244,7 +244,7 @@ object in O(1). The first element of this list is pointed by the
is <tt class="docutils literal"><span class="pre">NULL</span></tt>. The <tt class="docutils literal"><span class="pre">handshake_leftlen</span></tt> member of is <tt class="docutils literal"><span class="pre">NULL</span></tt>. The <tt class="docutils literal"><span class="pre">handshake_leftlen</span></tt> member of
<tt class="docutils literal"><span class="pre">http2_session_data</span></tt> is used to track the number of bytes remaining <tt class="docutils literal"><span class="pre">http2_session_data</span></tt> is used to track the number of bytes remaining
when receiving first 24 bytes magic value when receiving first 24 bytes magic value
(<a class="reference internal" href="apiref.html#NGHTTP2_CLIENT_CONNECTION_HEADER" title="NGHTTP2_CLIENT_CONNECTION_HEADER"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_CLIENT_CONNECTION_HEADER</span></tt></a>) from the client. We use (<a class="reference internal" href="apiref.html#c.NGHTTP2_CLIENT_CONNECTION_HEADER" title="NGHTTP2_CLIENT_CONNECTION_HEADER"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_CLIENT_CONNECTION_HEADER</span></tt></a>) from the client. We use
libevent&#8217;s bufferevent structure to perform network I/O. Notice that libevent&#8217;s bufferevent structure to perform network I/O. Notice that
bufferevent object is in <tt class="docutils literal"><span class="pre">http2_session_data</span></tt> and not in bufferevent object is in <tt class="docutils literal"><span class="pre">http2_session_data</span></tt> and not in
<tt class="docutils literal"><span class="pre">http2_stream_data</span></tt>. This is because <tt class="docutils literal"><span class="pre">http2_stream_data</span></tt> is just a <tt class="docutils literal"><span class="pre">http2_stream_data</span></tt>. This is because <tt class="docutils literal"><span class="pre">http2_stream_data</span></tt> is just a
@ -365,7 +365,7 @@ it:</p>
</pre></div> </pre></div>
</div> </div>
<p>We check that the received byte string matches <p>We check that the received byte string matches
<a class="reference internal" href="apiref.html#NGHTTP2_CLIENT_CONNECTION_HEADER" title="NGHTTP2_CLIENT_CONNECTION_HEADER"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_CLIENT_CONNECTION_HEADER</span></tt></a>. When they match, the <a class="reference internal" href="apiref.html#c.NGHTTP2_CLIENT_CONNECTION_HEADER" title="NGHTTP2_CLIENT_CONNECTION_HEADER"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_CLIENT_CONNECTION_HEADER</span></tt></a>. When they match, the
connection state is ready for starting HTTP/2.0 communication. First connection state is ready for starting HTTP/2.0 communication. First
we change the callback functions for the bufferevent object. We use we change the callback functions for the bufferevent object. We use
same <tt class="docutils literal"><span class="pre">eventcb</span></tt> as before. But we specify new <tt class="docutils literal"><span class="pre">readcb</span></tt> and same <tt class="docutils literal"><span class="pre">eventcb</span></tt> as before. But we specify new <tt class="docutils literal"><span class="pre">readcb</span></tt> and
@ -387,7 +387,7 @@ these 2 functions later.</p>
</pre></div> </pre></div>
</div> </div>
<p>Since we are creating server, nghttp2 session object is created using <p>Since we are creating server, nghttp2 session object is created using
<a class="reference internal" href="apiref.html#nghttp2_session_server_new" title="nghttp2_session_server_new"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_server_new()</span></tt></a> function. We registers 5 callbacks to <a class="reference internal" href="apiref.html#c.nghttp2_session_server_new" title="nghttp2_session_server_new"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_server_new()</span></tt></a> function. We registers 5 callbacks to
nghttp2 session object. We&#8217;ll talk about these callbacks later.</p> nghttp2 session object. We&#8217;ll talk about these callbacks later.</p>
<p>After initialization of nghttp2 session object, we are going to send <p>After initialization of nghttp2 session object, we are going to send
server connection header in <tt class="docutils literal"><span class="pre">send_server_connection_header()</span></tt>:</p> server connection header in <tt class="docutils literal"><span class="pre">send_server_connection_header()</span></tt>:</p>
@ -411,10 +411,10 @@ server connection header in <tt class="docutils literal"><span class="pre">send_
<p>The server connection header is SETTINGS frame. We specify <p>The server connection header is SETTINGS frame. We specify
SETTINGS_MAX_CONCURRENT_STREAMS to 100 in SETTINGS frame. To queue SETTINGS_MAX_CONCURRENT_STREAMS to 100 in SETTINGS frame. To queue
the SETTINGS frame for the transmission, we use the SETTINGS frame for the transmission, we use
<a class="reference internal" href="apiref.html#nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a>. Note that <a class="reference internal" href="apiref.html#nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a> <a class="reference internal" href="apiref.html#c.nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a>. Note that <a class="reference internal" href="apiref.html#c.nghttp2_submit_settings" title="nghttp2_submit_settings"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_settings()</span></tt></a>
function only queues the frame and not actually send it. All function only queues the frame and not actually send it. All
<tt class="docutils literal"><span class="pre">nghttp2_submit_*()</span></tt> family functions have this property. To <tt class="docutils literal"><span class="pre">nghttp2_submit_*()</span></tt> family functions have this property. To
actually send the frame, <a class="reference internal" href="apiref.html#nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> is used, which is actually send the frame, <a class="reference internal" href="apiref.html#c.nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> is used, which is
described about later.</p> described about later.</p>
<p>Since bufferevent may buffer more than first 24 bytes from the client, <p>Since bufferevent may buffer more than first 24 bytes from the client,
we have to process them here since libevent won&#8217;t invoke callback we have to process them here since libevent won&#8217;t invoke callback
@ -440,8 +440,8 @@ functions for these pending data. To process received data, we call
</pre></div> </pre></div>
</div> </div>
<p>In this function, we feed all unprocessed, received data to nghttp2 <p>In this function, we feed all unprocessed, received data to nghttp2
session object using <a class="reference internal" href="apiref.html#nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> function. The session object using <a class="reference internal" href="apiref.html#c.nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> function. The
<a class="reference internal" href="apiref.html#nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> processes the received data and may <a class="reference internal" href="apiref.html#c.nghttp2_session_mem_recv" title="nghttp2_session_mem_recv"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_mem_recv()</span></tt></a> processes the received data and may
invoke nghttp2 callbacks and also queue outgoing frames. Since there invoke nghttp2 callbacks and also queue outgoing frames. Since there
may be pending frames, we call <tt class="docutils literal"><span class="pre">session_send()</span></tt> function to send may be pending frames, we call <tt class="docutils literal"><span class="pre">session_send()</span></tt> function to send
those frames. The <tt class="docutils literal"><span class="pre">session_send()</span></tt> function is defined as follows:</p> those frames. The <tt class="docutils literal"><span class="pre">session_send()</span></tt> function is defined as follows:</p>
@ -457,10 +457,10 @@ those frames. The <tt class="docutils literal"><span class="pre">session_send()<
<span class="p">}</span> <span class="p">}</span>
</pre></div> </pre></div>
</div> </div>
<p>The <a class="reference internal" href="apiref.html#nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> function serializes the frame into wire <p>The <a class="reference internal" href="apiref.html#c.nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> function serializes the frame into wire
format and call <a class="reference internal" href="apiref.html#nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> with format and call <a class="reference internal" href="apiref.html#c.nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> with
it. We set <tt class="docutils literal"><span class="pre">send_callback()</span></tt> function to it. We set <tt class="docutils literal"><span class="pre">send_callback()</span></tt> function to
<a class="reference internal" href="apiref.html#nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> in <a class="reference internal" href="apiref.html#c.nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a> in
<tt class="docutils literal"><span class="pre">initialize_nghttp2_session()</span></tt> function described earlier. It is <tt class="docutils literal"><span class="pre">initialize_nghttp2_session()</span></tt> function described earlier. It is
defined as follows:</p> defined as follows:</p>
<div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">send_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span> <div class="highlight-c"><div class="highlight"><pre><span class="k">static</span> <span class="kt">ssize_t</span> <span class="nf">send_callback</span><span class="p">(</span><span class="n">nghttp2_session</span> <span class="o">*</span><span class="n">session</span><span class="p">,</span>
@ -480,19 +480,19 @@ defined as follows:</p>
</pre></div> </pre></div>
</div> </div>
<p>Since we use bufferevent to abstract network I/O, we just write the <p>Since we use bufferevent to abstract network I/O, we just write the
data to the bufferevent object. Note that <a class="reference internal" href="apiref.html#nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a> data to the bufferevent object. Note that <a class="reference internal" href="apiref.html#c.nghttp2_session_send" title="nghttp2_session_send"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_send()</span></tt></a>
continues to write all frames queued so far. If we were writing the continues to write all frames queued so far. If we were writing the
data to the non-blocking socket directly using <tt class="docutils literal"><span class="pre">write()</span></tt> system call data to the non-blocking socket directly using <tt class="docutils literal"><span class="pre">write()</span></tt> system call
in the <a class="reference internal" href="apiref.html#nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a>, we will in the <a class="reference internal" href="apiref.html#c.nghttp2_session_callbacks.send_callback" title="nghttp2_session_callbacks.send_callback"><tt class="xref c c-member docutils literal"><span class="pre">nghttp2_session_callbacks.send_callback</span></tt></a>, we will
surely get <tt class="docutils literal"><span class="pre">EAGAIN</span></tt> or <tt class="docutils literal"><span class="pre">EWOULDBLOCK</span></tt> since the socket has limited surely get <tt class="docutils literal"><span class="pre">EAGAIN</span></tt> or <tt class="docutils literal"><span class="pre">EWOULDBLOCK</span></tt> since the socket has limited
send buffer. If that happens, we can return send buffer. If that happens, we can return
<a class="reference internal" href="apiref.html#NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></tt></a> to signal the nghttp2 library to stop <a class="reference internal" href="apiref.html#c.NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></tt></a> to signal the nghttp2 library to stop
sending further data. But writing to the bufferevent, we have to sending further data. But writing to the bufferevent, we have to
regulate the amount data to be buffered by ourselves to avoid possible regulate the amount data to be buffered by ourselves to avoid possible
huge memory consumption. To achieve this, we check the size of output huge memory consumption. To achieve this, we check the size of output
buffer and if it is more than or equal to buffer and if it is more than or equal to
<tt class="docutils literal"><span class="pre">OUTPUT_WOULDBLOCK_THRESHOLD</span></tt> bytes, we stop writing data and return <tt class="docutils literal"><span class="pre">OUTPUT_WOULDBLOCK_THRESHOLD</span></tt> bytes, we stop writing data and return
<a class="reference internal" href="apiref.html#NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></tt></a> to tell the library to stop calling <a class="reference internal" href="apiref.html#c.NGHTTP2_ERR_WOULDBLOCK" title="NGHTTP2_ERR_WOULDBLOCK"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_WOULDBLOCK</span></tt></a> to tell the library to stop calling
send_callback.</p> send_callback.</p>
<p>The next bufferevent callback is <tt class="docutils literal"><span class="pre">readcb()</span></tt>, which is invoked when <p>The next bufferevent callback is <tt class="docutils literal"><span class="pre">readcb()</span></tt>, which is invoked when
data is available to read in the bufferevent input buffer:</p> data is available to read in the bufferevent input buffer:</p>
@ -532,8 +532,8 @@ all data written in the bufferevent output buffer have been sent:</p>
session object keeps track of reception and transmission of GOAWAY session object keeps track of reception and transmission of GOAWAY
frame and other error conditions as well. Using these information, frame and other error conditions as well. Using these information,
nghttp2 session object will tell whether the connection should be nghttp2 session object will tell whether the connection should be
dropped or not. More specifically, both <a class="reference internal" href="apiref.html#nghttp2_session_want_read" title="nghttp2_session_want_read"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_read()</span></tt></a> dropped or not. More specifically, both <a class="reference internal" href="apiref.html#c.nghttp2_session_want_read" title="nghttp2_session_want_read"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_read()</span></tt></a>
and <a class="reference internal" href="apiref.html#nghttp2_session_want_write" title="nghttp2_session_want_write"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_write()</span></tt></a> return 0, we have no business in and <a class="reference internal" href="apiref.html#c.nghttp2_session_want_write" title="nghttp2_session_want_write"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_want_write()</span></tt></a> return 0, we have no business in
the connection. But since we are using bufferevent and its deferred the connection. But since we are using bufferevent and its deferred
callback option, the bufferevent output buffer may contain the pending callback option, the bufferevent output buffer may contain the pending
data when the <tt class="docutils literal"><span class="pre">writecb()</span></tt> is called. To handle this situation, we data when the <tt class="docutils literal"><span class="pre">writecb()</span></tt> is called. To handle this situation, we
@ -641,7 +641,7 @@ fully received:</p>
</div> </div>
<p>First we retrieve <tt class="docutils literal"><span class="pre">http2_stream_data</span></tt> object associated to the <p>First we retrieve <tt class="docutils literal"><span class="pre">http2_stream_data</span></tt> object associated to the
stream in <tt class="docutils literal"><span class="pre">on_begin_headers_callback()</span></tt>. It is done using stream in <tt class="docutils literal"><span class="pre">on_begin_headers_callback()</span></tt>. It is done using
<a class="reference internal" href="apiref.html#nghttp2_session_get_stream_user_data" title="nghttp2_session_get_stream_user_data"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_get_stream_user_data()</span></tt></a>. If the requested path cannot <a class="reference internal" href="apiref.html#c.nghttp2_session_get_stream_user_data" title="nghttp2_session_get_stream_user_data"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_session_get_stream_user_data()</span></tt></a>. If the requested path cannot
be served for some reasons (e.g., file is not found), we send 404 be served for some reasons (e.g., file is not found), we send 404
response, which is done in <tt class="docutils literal"><span class="pre">error_reply()</span></tt>. Otherwise, we open response, which is done in <tt class="docutils literal"><span class="pre">error_reply()</span></tt>. Otherwise, we open
requested file and send its content. We send 1 header field requested file and send its content. We send 1 header field
@ -664,7 +664,7 @@ requested file and send its content. We send 1 header field
<span class="p">}</span> <span class="p">}</span>
</pre></div> </pre></div>
</div> </div>
<p>The nghttp2 library uses <a class="reference internal" href="apiref.html#nghttp2_data_provider" title="nghttp2_data_provider"><tt class="xref c c-type docutils literal"><span class="pre">nghttp2_data_provider</span></tt></a> structure to <p>The nghttp2 library uses <a class="reference internal" href="apiref.html#c.nghttp2_data_provider" title="nghttp2_data_provider"><tt class="xref c c-type docutils literal"><span class="pre">nghttp2_data_provider</span></tt></a> structure to
send entity body to the remote peer. The <tt class="docutils literal"><span class="pre">source</span></tt> member of this send entity body to the remote peer. The <tt class="docutils literal"><span class="pre">source</span></tt> member of this
structure is a union and it can be either void pointer or int which is structure is a union and it can be either void pointer or int which is
intended to be used as file descriptor. In this example server, we use intended to be used as file descriptor. In this example server, we use
@ -689,11 +689,11 @@ function to read content of the file:</p>
</pre></div> </pre></div>
</div> </div>
<p>If error happens while reading file, we return <p>If error happens while reading file, we return
<a class="reference internal" href="apiref.html#NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE" title="NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE</span></tt></a>. This tells the library <a class="reference internal" href="apiref.html#c.NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE" title="NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE"><tt class="xref c c-macro docutils literal"><span class="pre">NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE</span></tt></a>. This tells the library
to send RST_STREAM to the stream. When all data is read, set 1 to to send RST_STREAM to the stream. When all data is read, set 1 to
<tt class="docutils literal"><span class="pre">*eof</span></tt> to tell the nghttp2 library that we have finished reading <tt class="docutils literal"><span class="pre">*eof</span></tt> to tell the nghttp2 library that we have finished reading
file.</p> file.</p>
<p>The <a class="reference internal" href="apiref.html#nghttp2_submit_response" title="nghttp2_submit_response"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_response()</span></tt></a> is used to send response to the remote <p>The <a class="reference internal" href="apiref.html#c.nghttp2_submit_response" title="nghttp2_submit_response"><tt class="xref c c-func docutils literal"><span class="pre">nghttp2_submit_response()</span></tt></a> is used to send response to the remote
peer.</p> peer.</p>
<p>The <tt class="docutils literal"><span class="pre">on_stream_close_callback()</span></tt> function is invoked when the stream <p>The <tt class="docutils literal"><span class="pre">on_stream_close_callback()</span></tt> function is invoked when the stream
is about to close:</p> is about to close:</p>