Update doc
This commit is contained in:
parent
cd3337aed2
commit
3432a0bed9
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
@ -89,6 +89,7 @@ div.sphinxsidebar #searchbox input[type="submit"] {
|
|||
|
||||
img {
|
||||
border: 0;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
/* -- search page ----------------------------------------------------------- */
|
||||
|
@ -401,10 +402,6 @@ dl.glossary dt {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
.refcount {
|
||||
color: #060;
|
||||
}
|
||||
|
||||
.optional {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
@ -32,7 +32,7 @@ if (!window.console || !console.firebug) {
|
|||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
return decodeURIComponent(x).replace(/\+/g, ' ');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* small helper function to urlencode strings
|
||||
|
@ -61,18 +61,6 @@ jQuery.getQueryParameters = function(s) {
|
|||
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
|
||||
* span elements with the given class name.
|
||||
|
@ -180,6 +168,9 @@ var Documentation = {
|
|||
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
|
||||
if (terms.length) {
|
||||
var body = $('div.body');
|
||||
if (!body.length) {
|
||||
body = $('body');
|
||||
}
|
||||
window.setTimeout(function() {
|
||||
$.each(terms, function() {
|
||||
body.highlightText(this.toLowerCase(), 'highlighted');
|
||||
|
|
|
@ -4,38 +4,11 @@
|
|||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
@ -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
|
||||
*/
|
||||
|
@ -239,8 +244,13 @@ var Search = {
|
|||
},
|
||||
|
||||
loadIndex : function(url) {
|
||||
$.ajax({type: "GET", url: url, data: null, success: null,
|
||||
dataType: "script", cache: true});
|
||||
$.ajax({type: "GET", url: url, data: null,
|
||||
dataType: "script", cache: true,
|
||||
complete: function(jqxhr, textstatus) {
|
||||
if (textstatus != "success") {
|
||||
document.getElementById("searchindexloader").src = url;
|
||||
}
|
||||
}});
|
||||
},
|
||||
|
||||
setIndex : function(index) {
|
||||
|
@ -268,19 +278,20 @@ var Search = {
|
|||
if (this._pulse_status >= 0)
|
||||
return;
|
||||
function pulse() {
|
||||
var i;
|
||||
Search._pulse_status = (Search._pulse_status + 1) % 4;
|
||||
var dotString = '';
|
||||
for (var i = 0; i < Search._pulse_status; i++)
|
||||
for (i = 0; i < Search._pulse_status; i++)
|
||||
dotString += '.';
|
||||
Search.dots.text(dotString);
|
||||
if (Search._pulse_status > -1)
|
||||
window.setTimeout(pulse, 500);
|
||||
};
|
||||
}
|
||||
pulse();
|
||||
},
|
||||
|
||||
/**
|
||||
* perform a search for something
|
||||
* perform a search for something (or wait until index is loaded)
|
||||
*/
|
||||
performSearch : function(query) {
|
||||
// create the required interface elements
|
||||
|
@ -300,41 +311,46 @@ var Search = {
|
|||
this.deferQuery(query);
|
||||
},
|
||||
|
||||
/**
|
||||
* execute search (requires search index to be loaded)
|
||||
*/
|
||||
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"];
|
||||
|
||||
// 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 searchterms = [];
|
||||
var excluded = [];
|
||||
var hlterms = [];
|
||||
var tmp = query.split(/\s+/);
|
||||
var objectterms = [];
|
||||
for (var i = 0; i < tmp.length; i++) {
|
||||
if (tmp[i] != "") {
|
||||
for (i = 0; i < tmp.length; i++) {
|
||||
if (tmp[i] !== "") {
|
||||
objectterms.push(tmp[i].toLowerCase());
|
||||
}
|
||||
|
||||
if ($u.indexOf(stopwords, tmp[i]) != -1 || tmp[i].match(/^\d+$/) ||
|
||||
tmp[i] == "") {
|
||||
if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i].match(/^\d+$/) ||
|
||||
tmp[i] === "") {
|
||||
// skip this "word"
|
||||
continue;
|
||||
}
|
||||
// stem the word
|
||||
var word = stemmer.stemWord(tmp[i]).toLowerCase();
|
||||
var word = stemmer.stemWord(tmp[i].toLowerCase());
|
||||
var toAppend;
|
||||
// select the correct list
|
||||
if (word[0] == '-') {
|
||||
var toAppend = excluded;
|
||||
toAppend = excluded;
|
||||
word = word.substr(1);
|
||||
}
|
||||
else {
|
||||
var toAppend = searchterms;
|
||||
toAppend = searchterms;
|
||||
hlterms.push(tmp[i].toLowerCase());
|
||||
}
|
||||
// only add if not already in the list
|
||||
if (!$.contains(toAppend, word))
|
||||
if (!$u.contains(toAppend, word))
|
||||
toAppend.push(word);
|
||||
};
|
||||
}
|
||||
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
|
||||
|
||||
// console.debug('SEARCH: searching for:');
|
||||
|
@ -342,89 +358,51 @@ var Search = {
|
|||
// console.info('excluded: ', excluded);
|
||||
|
||||
// prepare search
|
||||
var filenames = this._index.filenames;
|
||||
var titles = this._index.titles;
|
||||
var terms = this._index.terms;
|
||||
var fileMap = {};
|
||||
var files = null;
|
||||
// different result priorities
|
||||
var importantResults = [];
|
||||
var objectResults = [];
|
||||
var regularResults = [];
|
||||
var unimportantResults = [];
|
||||
var titleterms = this._index.titleterms;
|
||||
|
||||
// array of [filename, title, anchor, descr, score]
|
||||
var results = [];
|
||||
$('#search-progress').empty();
|
||||
|
||||
// lookup as object
|
||||
for (var i = 0; i < objectterms.length; i++) {
|
||||
var others = [].concat(objectterms.slice(0,i),
|
||||
objectterms.slice(i+1, objectterms.length))
|
||||
var results = 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);
|
||||
for (i = 0; i < objectterms.length; i++) {
|
||||
var others = [].concat(objectterms.slice(0, i),
|
||||
objectterms.slice(i+1, objectterms.length));
|
||||
results = results.concat(this.performObjectSearch(objectterms[i], others));
|
||||
}
|
||||
|
||||
// perform the search on the required terms
|
||||
for (var i = 0; i < searchterms.length; i++) {
|
||||
var word = searchterms[i];
|
||||
// no match but word was a required one
|
||||
if ((files = terms[word]) == null)
|
||||
break;
|
||||
if (files.length == undefined) {
|
||||
files = [files];
|
||||
}
|
||||
// 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];
|
||||
}
|
||||
// lookup as search terms in fulltext
|
||||
results = results.concat(this.performTermsSearch(searchterms, excluded, terms, Scorer.term))
|
||||
.concat(this.performTermsSearch(searchterms, excluded, titleterms, Scorer.title));
|
||||
|
||||
// let the scorer override scores with a custom scoring function
|
||||
if (Scorer.score) {
|
||||
for (i = 0; i < results.length; i++)
|
||||
results[i][4] = Scorer.score(results[i]);
|
||||
}
|
||||
|
||||
// now check if the files don't contain excluded terms
|
||||
for (var 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 (var i = 0; i < excluded.length; i++) {
|
||||
if (terms[excluded[i]] == file ||
|
||||
$.contains(terms[excluded[i]] || [], file)) {
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
// now sort the results by score (in opposite order of appearance, since the
|
||||
// display function below uses pop() to retrieve items) and then
|
||||
// alphabetically
|
||||
results.sort(function(a, b) {
|
||||
var left = a[4];
|
||||
var right = b[4];
|
||||
if (left > right) {
|
||||
return 1;
|
||||
} else if (left < right) {
|
||||
return -1;
|
||||
} else {
|
||||
// same score: sort alphabetically
|
||||
left = a[1].toLowerCase();
|
||||
right = b[1].toLowerCase();
|
||||
return (left > right) ? -1 : ((left < right) ? 1 : 0);
|
||||
}
|
||||
|
||||
// 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);
|
||||
});
|
||||
|
||||
// combine all results
|
||||
var results = unimportantResults.concat(regularResults)
|
||||
.concat(objectResults).concat(importantResults);
|
||||
// for debugging
|
||||
//Search.lastresults = results.slice(); // a copy
|
||||
//console.info('search results:', Search.lastresults);
|
||||
|
||||
// print the results
|
||||
var resultCount = results.length;
|
||||
|
@ -433,7 +411,7 @@ var Search = {
|
|||
if (results.length) {
|
||||
var item = results.pop();
|
||||
var listItem = $('<li style="display:none"></li>');
|
||||
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX == '') {
|
||||
if (DOCUMENTATION_OPTIONS.FILE_SUFFIX === '') {
|
||||
// dirhtml builder
|
||||
var dirname = item[0] + '/';
|
||||
if (dirname.match(/\/index\/$/)) {
|
||||
|
@ -457,16 +435,18 @@ var Search = {
|
|||
displayNextItem();
|
||||
});
|
||||
} else if (DOCUMENTATION_OPTIONS.HAS_SOURCE) {
|
||||
$.get(DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' +
|
||||
item[0] + '.txt', function(data) {
|
||||
if (data != '') {
|
||||
listItem.append($.makeSearchSummary(data, searchterms, hlterms));
|
||||
Search.output.append(listItem);
|
||||
}
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}, "text");
|
||||
$.ajax({url: DOCUMENTATION_OPTIONS.URL_ROOT + '_sources/' + item[0] + '.txt',
|
||||
dataType: "text",
|
||||
complete: function(jqxhr, textstatus) {
|
||||
var data = jqxhr.responseText;
|
||||
if (data !== '') {
|
||||
listItem.append(Search.makeSearchSummary(data, searchterms, hlterms));
|
||||
}
|
||||
Search.output.append(listItem);
|
||||
listItem.slideDown(5, function() {
|
||||
displayNextItem();
|
||||
});
|
||||
}});
|
||||
} else {
|
||||
// no source available, just display title
|
||||
Search.output.append(listItem);
|
||||
|
@ -489,20 +469,32 @@ var Search = {
|
|||
displayNextItem();
|
||||
},
|
||||
|
||||
/**
|
||||
* search for object names
|
||||
*/
|
||||
performObjectSearch : function(object, otherterms) {
|
||||
var filenames = this._index.filenames;
|
||||
var objects = this._index.objects;
|
||||
var objnames = this._index.objnames;
|
||||
var titles = this._index.titles;
|
||||
|
||||
var importantResults = [];
|
||||
var objectResults = [];
|
||||
var unimportantResults = [];
|
||||
var i;
|
||||
var results = [];
|
||||
|
||||
for (var prefix in objects) {
|
||||
for (var name in objects[prefix]) {
|
||||
var fullname = (prefix ? prefix + '.' : '') + name;
|
||||
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 objname = objnames[match[1]][2];
|
||||
var title = titles[match[0]];
|
||||
|
@ -512,7 +504,7 @@ var Search = {
|
|||
var haystack = (prefix + ' ' + name + ' ' +
|
||||
objname + ' ' + title).toLowerCase();
|
||||
var allfound = true;
|
||||
for (var i = 0; i < otherterms.length; i++) {
|
||||
for (i = 0; i < otherterms.length; i++) {
|
||||
if (haystack.indexOf(otherterms[i]) == -1) {
|
||||
allfound = false;
|
||||
break;
|
||||
|
@ -523,37 +515,107 @@ var Search = {
|
|||
}
|
||||
}
|
||||
var descr = objname + _(', in ') + title;
|
||||
anchor = match[3];
|
||||
if (anchor == '')
|
||||
|
||||
var anchor = match[3];
|
||||
if (anchor === '')
|
||||
anchor = fullname;
|
||||
else if (anchor == '-')
|
||||
anchor = objnames[match[1]][1] + '-' + fullname;
|
||||
result = [filenames[match[0]], fullname, '#'+anchor, descr];
|
||||
switch (match[2]) {
|
||||
case 1: objectResults.push(result); break;
|
||||
case 0: importantResults.push(result); break;
|
||||
case 2: unimportantResults.push(result); break;
|
||||
// add custom score for some objects according to scorer
|
||||
if (Scorer.objPrio.hasOwnProperty(match[2])) {
|
||||
score += Scorer.objPrio[match[2]];
|
||||
} else {
|
||||
score += Scorer.objPrioDefault;
|
||||
}
|
||||
results.push([filenames[match[0]], fullname, '#'+anchor, descr, score]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort results descending
|
||||
objectResults.sort(function(a, b) {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
return results;
|
||||
},
|
||||
|
||||
importantResults.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;
|
||||
|
||||
unimportantResults.sort(function(a, b) {
|
||||
return (a[1] > b[1]) ? -1 : ((a[1] < b[1]) ? 1 : 0);
|
||||
});
|
||||
var i, j, file, files;
|
||||
var fileMap = {};
|
||||
var results = [];
|
||||
|
||||
return [importantResults, objectResults, unimportantResults]
|
||||
// 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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
Search.init();
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
|
1499
apiref.html
1499
apiref.html
File diff suppressed because it is too large
Load Diff
488
genindex.html
488
genindex.html
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,5 @@
|
|||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
|
@ -22,7 +21,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'',
|
||||
URL_ROOT:'./',
|
||||
VERSION:'0.4.0-DEV',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
|
@ -22,7 +21,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'',
|
||||
URL_ROOT:'./',
|
||||
VERSION:'0.4.0-DEV',
|
||||
COLLAPSE_INDEX:false,
|
||||
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"> * also lower-cases all names in |nva|.</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"> * 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>
|
||||
|
@ -2310,7 +2316,8 @@
|
|||
<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">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"> * @function</span>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
|
@ -22,7 +21,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'',
|
||||
URL_ROOT:'./',
|
||||
VERSION:'0.4.0-DEV',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
|
|
BIN
objects.inv
BIN
objects.inv
Binary file not shown.
|
@ -1,6 +1,5 @@
|
|||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
|
@ -22,7 +21,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'',
|
||||
URL_ROOT:'./',
|
||||
VERSION:'0.4.0-DEV',
|
||||
COLLAPSE_INDEX:false,
|
||||
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>
|
||||
<p>Building from git is easy, but please be sure that at least autoconf 2.68 is
|
||||
used:</p>
|
||||
<div class="highlight-c"><pre>$ autoreconf -i
|
||||
<div class="highlight-c"><div class="highlight"><pre>$ autoreconf -i
|
||||
$ automake
|
||||
$ autoconf
|
||||
$ ./configure
|
||||
$ make</pre>
|
||||
$ make
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" id="building-documentation">
|
||||
|
@ -285,7 +285,8 @@ $ make</pre>
|
|||
<p class="last">Documentation is still incomplete.</p>
|
||||
</div>
|
||||
<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>
|
||||
<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>
|
||||
|
@ -301,7 +302,7 @@ $ make</pre>
|
|||
with prior knowledge, HTTP Upgrade and NPN/ALPN TLS extension.</p>
|
||||
<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>
|
||||
<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:
|
||||
* h2-10
|
||||
* 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-type: text/html
|
||||
[ 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: "b1-4e5535a027780-gzip"
|
||||
[ 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) vary: Accept-Encoding
|
||||
|
@ -354,10 +355,11 @@ The negotiated protocol: h2-10
|
|||
[ 0.008] recv DATA frame <length=0, flags=0x01, stream_id=1>
|
||||
; END_STREAM
|
||||
[ 0.008] send GOAWAY frame <length=8, flags=0x00, stream_id=0>
|
||||
(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>
|
||||
<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
|
||||
GET / HTTP/1.1
|
||||
Host: localhost:8080
|
||||
|
@ -389,7 +391,7 @@ Upgrade: h2-10
|
|||
[ 0.001] (stream_id=1) content-length: 177
|
||||
[ 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) etag: "b1-4e5535a027780"
|
||||
[ 0.001] (stream_id=1) etag: "b1-4e5535a027780"
|
||||
[ 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) vary: Accept-Encoding
|
||||
|
@ -408,7 +410,8 @@ Upgrade: h2-10
|
|||
(last_stream_id=0, error_code=NO_ERROR(0), opaque_data(0)=[])
|
||||
[ 0.002] recv SETTINGS frame <length=0, flags=0x01, stream_id=0>
|
||||
; ACK
|
||||
(niv=0)</pre>
|
||||
(niv=0)
|
||||
</pre></div>
|
||||
</div>
|
||||
</div>
|
||||
<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>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>
|
||||
<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
|
||||
IPv6: listen on port 8080
|
||||
[id=1] [ 1.027] send SETTINGS frame <length=10, flags=0x00, stream_id=0>
|
||||
|
@ -465,7 +468,8 @@ IPv6: listen on port 8080
|
|||
(niv=0)
|
||||
[id=1] [ 1.028] recv GOAWAY frame <length=8, flags=0x00, stream_id=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 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
|
||||
certificate for secure proxy.</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>
|
||||
<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>
|
||||
|
@ -1002,16 +1007,14 @@ corresponding header set was processed. The format is the same as
|
|||
<div class="section" id="python-bindings">
|
||||
<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
|
||||
bindings currently only provide HPACK compressor and decompressor
|
||||
classes.</p>
|
||||
bindings currently provide HPACK compressor and decompressor
|
||||
classes and HTTP/2 server.</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
|
||||
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>
|
||||
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>
|
||||
<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
|
||||
and decompressor in Python:</p>
|
||||
<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>
|
||||
</pre></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’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">'/css/bootstrap.css'</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">'content-length'</span><span class="p">,</span> <span class="n">b</span><span class="s">'3'</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">'foo'</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">'/js/bootstrap.js'</span><span class="p">,</span>
|
||||
<span class="n">method</span><span class="o">=</span><span class="s">'GET'</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">'content-length'</span><span class="p">,</span> <span class="n">b</span><span class="s">'10'</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">'foobarbuzz'</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">'content-type'</span><span class="p">,</span> <span class="n">b</span><span class="s">'text/plain'</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">'nghttp2-python FTW'</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">'h2-10'</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">'server.crt'</span><span class="p">,</span> <span class="s">'server.key'</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">'127.0.0.1'</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>
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'',
|
||||
URL_ROOT:'./',
|
||||
VERSION:'0.4.0-DEV',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,6 +1,5 @@
|
|||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
|
@ -22,7 +21,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'',
|
||||
URL_ROOT:'./',
|
||||
VERSION:'0.4.0-DEV',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
|
@ -154,7 +153,8 @@ the end of this page. It also resides in examples directory in the
|
|||
archive or repository.</p>
|
||||
<p>This simple client takes 1 argument, HTTPS URI, and retrieves the
|
||||
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>
|
||||
<p>We use libevent in this tutorial to handle networking I/O. Please
|
||||
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.
|
||||
The NPN callback is used for the client to select the next application
|
||||
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>
|
||||
<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>
|
||||
|
@ -310,15 +310,15 @@ finished successfully. We first initialize nghttp2 session object in
|
|||
<span class="p">}</span>
|
||||
</pre></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
|
||||
nghttp2 session. We’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
|
||||
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,
|
||||
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
|
||||
<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>
|
||||
|
@ -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
|
||||
really not needed for this tiny example progoram, but we are
|
||||
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
|
||||
<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
|
||||
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#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
|
||||
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>
|
||||
<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>
|
||||
|
@ -373,9 +373,9 @@ request in <tt class="docutils literal"><span class="pre">submit_request()</span
|
|||
</pre></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
|
||||
<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,
|
||||
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
|
||||
callbacks which we’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
|
||||
|
@ -402,8 +402,8 @@ data is available to read in the bufferevent input buffer:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<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
|
||||
<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
|
||||
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#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
|
||||
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>
|
||||
|
@ -420,10 +420,10 @@ frames. The <tt class="docutils literal"><span class="pre">session_send()</span>
|
|||
<span class="p">}</span>
|
||||
</pre></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
|
||||
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
|
||||
<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#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
|
||||
<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
|
||||
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>
|
||||
|
@ -438,13 +438,13 @@ defined as follows:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<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
|
||||
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
|
||||
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
|
||||
regulate the amount data to be buffered by ourselves to avoid possible
|
||||
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
|
||||
conditions as well. Using these information, 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> 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
|
||||
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#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
|
||||
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
|
||||
|
@ -501,7 +501,7 @@ about to be sent:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<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
|
||||
increased, the stream ID is not assigned just before transmission.
|
||||
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).
|
||||
The assigned stream ID is <tt class="docutils literal"><span class="pre">frame->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
|
||||
<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#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_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_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
|
||||
that <tt class="docutils literal"><span class="pre">session_data->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
|
||||
unnecessary to compare them, but real applications surely deal with
|
||||
multiple streams, and <em>stream_user_data</em> is very handy to identify
|
||||
|
@ -563,7 +563,7 @@ how to use it here.</p>
|
|||
</div>
|
||||
<p>In this tutorial, we are just interested in the HTTP response
|
||||
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>
|
||||
<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>
|
||||
|
@ -609,7 +609,7 @@ is about to close:</p>
|
|||
<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
|
||||
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
|
||||
some data associated for the stream to be closed, you may delete it
|
||||
here.</p>
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
|
||||
|
||||
<!DOCTYPE html>
|
||||
<!--[if IE 8]><html class="no-js lt-ie9" lang="en" > <![endif]-->
|
||||
<!--[if gt IE 8]><!--> <html class="no-js" lang="en" > <!--<![endif]-->
|
||||
|
@ -22,7 +21,7 @@
|
|||
|
||||
<script type="text/javascript">
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT:'',
|
||||
URL_ROOT:'./',
|
||||
VERSION:'0.4.0-DEV',
|
||||
COLLAPSE_INDEX:false,
|
||||
FILE_SUFFIX:'.html',
|
||||
|
@ -157,7 +156,8 @@ repository.</p>
|
|||
<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
|
||||
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>
|
||||
<p>We use libevent in this tutorial to handle networking I/O. Please
|
||||
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
|
||||
identifier. In this tutorial, we advertise the HTTP/2.0 protocol the
|
||||
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
|
||||
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
|
||||
|
@ -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
|
||||
<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
|
||||
(<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’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
|
||||
<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>
|
||||
</div>
|
||||
<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
|
||||
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
|
||||
|
@ -387,7 +387,7 @@ these 2 functions later.</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<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’ll talk about these callbacks later.</p>
|
||||
<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>
|
||||
|
@ -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
|
||||
SETTINGS_MAX_CONCURRENT_STREAMS to 100 in 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 <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
|
||||
<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>
|
||||
<p>Since bufferevent may buffer more than first 24 bytes from the client,
|
||||
we have to process them here since libevent won’t invoke callback
|
||||
|
@ -440,8 +440,8 @@ functions for these pending data. To process received data, we call
|
|||
</pre></div>
|
||||
</div>
|
||||
<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
|
||||
<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
|
||||
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#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
|
||||
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>
|
||||
|
@ -457,10 +457,10 @@ those frames. The <tt class="docutils literal"><span class="pre">session_send()<
|
|||
<span class="p">}</span>
|
||||
</pre></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
|
||||
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
|
||||
<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#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
|
||||
<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
|
||||
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>
|
||||
|
@ -480,19 +480,19 @@ defined as follows:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<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
|
||||
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
|
||||
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
|
||||
regulate the amount data to be buffered by ourselves to avoid possible
|
||||
huge memory consumption. To achieve this, we check the size of output
|
||||
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
|
||||
<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>
|
||||
<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>
|
||||
|
@ -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
|
||||
frame and other error conditions as well. Using these information,
|
||||
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>
|
||||
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
|
||||
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#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
|
||||
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
|
||||
|
@ -641,7 +641,7 @@ fully received:</p>
|
|||
</div>
|
||||
<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
|
||||
<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
|
||||
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
|
||||
|
@ -664,7 +664,7 @@ requested file and send its content. We send 1 header field
|
|||
<span class="p">}</span>
|
||||
</pre></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
|
||||
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
|
||||
|
@ -689,11 +689,11 @@ function to read content of the file:</p>
|
|||
</pre></div>
|
||||
</div>
|
||||
<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
|
||||
<tt class="docutils literal"><span class="pre">*eof</span></tt> to tell the nghttp2 library that we have finished reading
|
||||
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>
|
||||
<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>
|
||||
|
|
Loading…
Reference in New Issue