From 9120067c96b2c004122890e9b128d791a2d3438d Mon Sep 17 00:00:00 2001 From: Gautier TANGUY Date: Wed, 3 Feb 2016 19:40:29 +0100 Subject: [PATCH 01/17] make checkoutBranch works with branches that lives outside of refs/heads --- lib/repository.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index 50a165bf5..bdb7f2b09 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1146,9 +1146,6 @@ Repository.prototype.checkoutBranch = function(branch, opts) { NodeGit.Checkout.STRATEGY.RECREATE_MISSING); return repo.getReference(branch) .then(function(ref) { - if (!ref.isBranch()) { - return false; - } reference = ref; return repo.getBranchCommit(ref.name()); }) From 816a3af0cd7feea4a3c2516d1d2dbf4f2b44ed0d Mon Sep 17 00:00:00 2001 From: Gautier TANGUY Date: Fri, 5 Feb 2016 18:56:31 +0100 Subject: [PATCH 02/17] extract a checkoutRef method from checkoutBranch for references outside of refs/heads --- lib/repository.js | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index bdb7f2b09..20ec96f58 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1128,27 +1128,22 @@ Repository.prototype.getSubmoduleNames = function(callback) { }; /** - * This will set the HEAD to point to the local branch and then attempt + * This will set the HEAD to point to the reference and then attempt * to update the index and working tree to match the content of the - * latest commit on that branch + * latest commit on that reference * * @async - * @param {String|Reference} branch the branch to checkout + * @param {Reference} reference the reference to checkout * @param {Object|CheckoutOptions} opts the options to use for the checkout */ -Repository.prototype.checkoutBranch = function(branch, opts) { +Repository.prototype.checkoutRef = function(reference, opts) { var repo = this; - var reference; opts = opts || {}; opts.checkoutStrategy = opts.checkoutStrategy || (NodeGit.Checkout.STRATEGY.SAFE | NodeGit.Checkout.STRATEGY.RECREATE_MISSING); - return repo.getReference(branch) - .then(function(ref) { - reference = ref; - return repo.getBranchCommit(ref.name()); - }) + return repo.getReferenceCommit(reference.name()); .then(function(commit) { return commit.getTree(); }) @@ -1161,6 +1156,27 @@ Repository.prototype.checkoutBranch = function(branch, opts) { }); }; +/** + * This will set the HEAD to point to the local branch and then attempt + * to update the index and working tree to match the content of the + * latest commit on that branch + * + * @async + * @param {String|Reference} branch the branch to checkout + * @param {Object|CheckoutOptions} opts the options to use for the checkout + */ +Repository.prototype.checkoutBranch = function(branch, opts) { + var repo = this; + + return repo.getReference(branch) + .then(function(ref) { + if (!ref.isBranch()) { + return false; + } + return repo.checkoutRef(ref, opts); + }); +}; + var fetchheadForeach = Repository.prototype.fetchheadForeach; /** * @async From 81dc218f16aebec7e9f7e7a122d7b64641254630 Mon Sep 17 00:00:00 2001 From: Gautier TANGUY Date: Fri, 5 Feb 2016 21:49:28 +0100 Subject: [PATCH 03/17] fix checkoutRef --- lib/repository.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/repository.js b/lib/repository.js index 20ec96f58..aea3440f1 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1143,7 +1143,7 @@ Repository.prototype.checkoutRef = function(reference, opts) { opts.checkoutStrategy = opts.checkoutStrategy || (NodeGit.Checkout.STRATEGY.SAFE | NodeGit.Checkout.STRATEGY.RECREATE_MISSING); - return repo.getReferenceCommit(reference.name()); + return repo.getReferenceCommit(reference.name()) .then(function(commit) { return commit.getTree(); }) From 41525fbaefb22e91bb633887e27dcfc7450ddad0 Mon Sep 17 00:00:00 2001 From: maxkorp Date: Thu, 25 Feb 2016 14:02:14 -0700 Subject: [PATCH 04/17] tidy up comment generation --- generate/scripts/generateNativeCode.js | 16 ++++++++++------ generate/scripts/utils.js | 11 ++++++++++- generate/templates/templates/binding.gyp | 2 -- generate/templates/templates/class_content.cc | 1 - generate/templates/templates/class_header.h | 1 - generate/templates/templates/nodegit.cc | 1 - generate/templates/templates/struct_content.cc | 1 - generate/templates/templates/struct_header.h | 1 - 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/generate/scripts/generateNativeCode.js b/generate/scripts/generateNativeCode.js index fe58d8896..93867b49c 100644 --- a/generate/scripts/generateNativeCode.js +++ b/generate/scripts/generateNativeCode.js @@ -107,22 +107,26 @@ module.exports = function generateNativeCode() { return fse.copy(path.resolve(__dirname, "../templates/manual/src"), path.resolve(__dirname, "../../src")); }).then(function() { // Write out single purpose templates. - utils.writeFile("../binding.gyp", beautify(templates.binding.render(enabled))); - utils.writeFile("../src/nodegit.cc", templates.nodegitCC.render(enabled)); - utils.writeFile("../lib/nodegit.js", beautify(templates.nodegitJS.render(enabled))); + utils.writeFile("../binding.gyp", beautify(templates.binding.render(enabled)), "binding.gyp"); + utils.writeFile("../src/nodegit.cc", templates.nodegitCC.render(enabled), "nodegit.cc"); + utils.writeFile("../lib/nodegit.js", beautify(templates.nodegitJS.render(enabled)), "nodegit.js"); // Write out all the classes. enabled.forEach(function(idef) { if (idef.type && idef.type != "enum") { utils.writeFile( - "../src/" + idef.filename + ".cc", templates[idef.type + "_content"].render(idef) + "../src/" + idef.filename + ".cc", + templates[idef.type + "_content"].render(idef), + idef.type + "_content.cc" ); utils.writeFile( - "../include/" + idef.filename + ".h", templates[idef.type + "_header"].render(idef) + "../include/" + idef.filename + ".h", + templates[idef.type + "_header"].render(idef), + idef.type + "_header.h" ); } }); - utils.writeFile("../lib/enums.js", beautify(templates.enums.render(enabled))); + utils.writeFile("../lib/enums.js", beautify(templates.enums.render(enabled)), "enums.js"); }).then(function() { return exec("command -v astyle").then(function(astyle) { if (astyle) { diff --git a/generate/scripts/utils.js b/generate/scripts/utils.js index 3395fe272..b09d9a15f 100644 --- a/generate/scripts/utils.js +++ b/generate/scripts/utils.js @@ -20,13 +20,22 @@ var util = { } }, - writeFile: function(file, content) { + writeFile: function(file, content, header) { try { var file = local(file); if (typeof content == "object") { content = JSON.stringify(content, null, 2) } + if (header) { + var commentPrefix = ~header.indexOf('.gyp') ? '#' : '//' + content = commentPrefix + + " This is a generated file, modify: generate/templates/" + + header + + "\n\n" + + content; + } + fse.ensureFileSync(file); fse.writeFileSync(file, content); return true; diff --git a/generate/templates/templates/binding.gyp b/generate/templates/templates/binding.gyp index 9c5649abb..9a2813579 100644 --- a/generate/templates/templates/binding.gyp +++ b/generate/templates/templates/binding.gyp @@ -1,5 +1,3 @@ -# // This is a generated file, modify: generate/templates/binding.gyp. - { "targets": [ { diff --git a/generate/templates/templates/class_content.cc b/generate/templates/templates/class_content.cc index bda244812..c172e1fa5 100644 --- a/generate/templates/templates/class_content.cc +++ b/generate/templates/templates/class_content.cc @@ -1,4 +1,3 @@ -// This is a generated file, modify: generate/templates/class_content.cc. #include #include diff --git a/generate/templates/templates/class_header.h b/generate/templates/templates/class_header.h index 11316c51f..84c9b5c4f 100644 --- a/generate/templates/templates/class_header.h +++ b/generate/templates/templates/class_header.h @@ -1,6 +1,5 @@ #ifndef {{ cppClassName|upper }}_H #define {{ cppClassName|upper }}_H -// generated from class_header.h #include #include #include diff --git a/generate/templates/templates/nodegit.cc b/generate/templates/templates/nodegit.cc index a1bf7bf30..f165307b3 100644 --- a/generate/templates/templates/nodegit.cc +++ b/generate/templates/templates/nodegit.cc @@ -1,4 +1,3 @@ -// This is a generated file, modify: generate/templates/nodegit.cc. #include #include diff --git a/generate/templates/templates/struct_content.cc b/generate/templates/templates/struct_content.cc index b6ab0f16b..cab524a80 100644 --- a/generate/templates/templates/struct_content.cc +++ b/generate/templates/templates/struct_content.cc @@ -1,4 +1,3 @@ -// This is a generated file, modify: generate/templates/struct_content.cc. #include #include #ifdef WIN32 diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index d15bf677c..0320fbbf6 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -1,6 +1,5 @@ #ifndef {{ cppClassName|upper }}_H #define {{ cppClassName|upper }}_H -// generated from struct_header.h #include #include #include From a7174688b2dd17d6c12580570aa30b1a663b1a52 Mon Sep 17 00:00:00 2001 From: Josh Shaw Date: Mon, 29 Feb 2016 14:10:39 +1300 Subject: [PATCH 05/17] fixes #852 should not be an array with null in it --- lib/repository.js | 5 ++++- test/tests/repository.js | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/lib/repository.js b/lib/repository.js index 61d221729..30692c6bb 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -535,13 +535,16 @@ Repository.prototype.createCommitOnHead = function( .then(function(treeOid) { return repo.getHeadCommit() .then(function(parent) { + if (parent !== null) { // To handle a fresh repo with no commits + parent = [parent]; + } return repo.createCommit( "HEAD", author, committer, message, treeOid, - [parent] + parent ); }); }, callback); diff --git a/test/tests/repository.js b/test/tests/repository.js index adaec151e..6f710ef10 100644 --- a/test/tests/repository.js +++ b/test/tests/repository.js @@ -231,4 +231,33 @@ describe("Repository", function() { assert(!commit); }); }); + + it("can commit on head on a empty repo with createCommitOnHead", function() { + var fileName = "my-new-file-that-shouldnt-exist.file"; + var fileContent = "new file from repository test"; + var repo = this.emptyRepo; + var filePath = path.join(repo.workdir(), fileName); + var authSig = repo.defaultSignature(); + var commitSig = repo.defaultSignature(); + var commitMsg = "Doug this has been commited"; + + return fse.writeFile(filePath, fileContent) + .then(function() { + return repo.createCommitOnHead( + [filePath], + authSig, + commitSig, + commitMsg + ); + }) + .then(function(oidResult) { + return repo.getHeadCommit() + .then(function(commit) { + assert.equal( + commit.toString(), + oidResult.toString() + ); + }); + }); + }); }); From 731feeeaed68f84e07d03a6688341cc3f5818dda Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 29 Feb 2016 15:30:10 -0500 Subject: [PATCH 06/17] Let's use a const. --- generate/templates/manual/src/convenient_patch.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/generate/templates/manual/src/convenient_patch.cc b/generate/templates/manual/src/convenient_patch.cc index adc324988..a65649cbd 100644 --- a/generate/templates/manual/src/convenient_patch.cc +++ b/generate/templates/manual/src/convenient_patch.cc @@ -68,7 +68,7 @@ PatchData *createFromRaw(git_patch *raw) { hunkData->lines = new std::vector; hunkData->lines->reserve(hunkData->numLines); - + static const int noNewlineStringLength = 29; bool EOFFlag = false; for (unsigned int j = 0; j < hunkData->numLines; ++j) { git_diff_line *storeLine = (git_diff_line *)malloc(sizeof(git_diff_line)); @@ -79,9 +79,9 @@ PatchData *createFromRaw(git_patch *raw) { // calculate strlen only once for the first line of the first hunk. int calculatedContentLength = strlen(line->content); if ( - calculatedContentLength > 29 && + calculatedContentLength > noNewlineStringLength && !strcmp( - &line->content[calculatedContentLength - 29], + &line->content[calculatedContentLength - noNewlineStringLength], "\n\\ No newline at end of file\n" )) { EOFFlag = true; @@ -96,10 +96,10 @@ PatchData *createFromRaw(git_patch *raw) { storeLine->content_offset = line->content_offset; char * transferContent; if (EOFFlag) { - transferContent = (char *)malloc(storeLine->content_len + 30); + transferContent = (char *)malloc(storeLine->content_len + noNewlineStringLength + 1); memcpy(transferContent, line->content, storeLine->content_len); - memcpy(transferContent + storeLine->content_len, "\n\\ No newline at end of file\n", 29); - transferContent[storeLine->content_len + 29] = '\0'; + memcpy(transferContent + storeLine->content_len, "\n\\ No newline at end of file\n", noNewlineStringLength); + transferContent[storeLine->content_len + noNewlineStringLength] = '\0'; } else { transferContent = (char *)malloc(storeLine->content_len + 1); memcpy(transferContent, line->content, storeLine->content_len); From 7d41651ade67b3d85e5374d2ab2a2d7eacccad7c Mon Sep 17 00:00:00 2001 From: joshaber Date: Mon, 29 Feb 2016 15:30:25 -0500 Subject: [PATCH 07/17] We'll need to free this patch. --- generate/templates/manual/patches/convenient_patches.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/generate/templates/manual/patches/convenient_patches.cc b/generate/templates/manual/patches/convenient_patches.cc index 38ccc44a6..79823e37a 100644 --- a/generate/templates/manual/patches/convenient_patches.cc +++ b/generate/templates/manual/patches/convenient_patches.cc @@ -62,6 +62,7 @@ void GitPatch::ConvenientFromDiffWorker::Execute() { if (nextPatch != NULL) { baton->out->push_back(createFromRaw(nextPatch)); + patchesToBeFreed.push_back(nextPatch); } } From 1973dfb9eb7e13816007e1729d8a534d44464c67 Mon Sep 17 00:00:00 2001 From: Josh Shaw Date: Tue, 1 Mar 2016 09:47:18 +1300 Subject: [PATCH 08/17] fixes #852 fixed tab issue PR #927 --- lib/repository.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/repository.js b/lib/repository.js index 30692c6bb..47e2220e9 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -535,9 +535,9 @@ Repository.prototype.createCommitOnHead = function( .then(function(treeOid) { return repo.getHeadCommit() .then(function(parent) { - if (parent !== null) { // To handle a fresh repo with no commits - parent = [parent]; - } + if (parent !== null) { // To handle a fresh repo with no commits + parent = [parent]; + } return repo.createCommit( "HEAD", author, From 3d6025281ebac4022a9237da1a5ecda51fc1e693 Mon Sep 17 00:00:00 2001 From: joseg Date: Mon, 29 Feb 2016 12:15:52 -0700 Subject: [PATCH 09/17] fix tree.walk() and add test --- lib/tree.js | 5 ++- test/tests/tree.js | 77 ++++++++++++++++++++++++++++++++++ test/utils/repository_setup.js | 16 +++++-- 3 files changed, 93 insertions(+), 5 deletions(-) create mode 100644 test/tests/tree.js diff --git a/lib/tree.js b/lib/tree.js index 138099c2e..a9f00fe40 100644 --- a/lib/tree.js +++ b/lib/tree.js @@ -127,6 +127,7 @@ Tree.prototype.walk = function(blobsOnly) { var event = new events.EventEmitter(); var total = 1; + var entries = []; // This looks like a DFS, but it is a BFS because of implicit queueing in // the recursive call to `entry.getTree(bfs)` @@ -136,8 +137,8 @@ Tree.prototype.walk = function(blobsOnly) { if (error) { return event.emit("error", error); } - var entries = tree.entries(); - entries.forEach(function (entry, entryIndex) { + + tree.entries().forEach(function (entry, entryIndex) { if (!blobsOnly || entry.isFile()) { event.emit("entry", entry); entries.push(entry); diff --git a/test/tests/tree.js b/test/tests/tree.js new file mode 100644 index 000000000..9808b516e --- /dev/null +++ b/test/tests/tree.js @@ -0,0 +1,77 @@ +var assert = require("assert"); +var path = require("path"); +var local = path.join.bind(path, __dirname); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); + +describe("Tree", function() { + var RepoUtils = require("../utils/repository_setup"); + + var repoPath = local("../repos/tree"); + + beforeEach(function() { + var test = this; + return RepoUtils.createRepository(repoPath) + .then(function(repo) { + test.repository = repo; + }); + }); + + after(function() { + return fse.remove(repoPath); + }); + + it("walks its entries and returns the same entries on both progress and end", + function() { + var repo = this.repository; + var progressEntries = []; + var endEntries; + + return RepoUtils.commitFileToRepo(repo, "test.txt", "") + .then(function(commit) { + return RepoUtils.commitFileToRepo(repo, "foo/bar.txt", "", commit); + }) + .then(function(commit) { + return commit.getTree(); + }) + .then(function(tree) { + assert(tree); + + return new Promise(function (resolve, reject) { + var walker = tree.walk(); + + walker.on("entry", function(entry) { + progressEntries.push(entry); + }); + walker.on("end", function(entries) { + endEntries = entries; + resolve(); + }); + walker.on("error", reject); + + walker.start(); + }); + }) + .then(function() { + assert(progressEntries.length); + assert(endEntries && endEntries.length); + + assert.equal( + progressEntries.length, endEntries.length, + "Different number of progress entries and end entries" + ); + + function getEntryPath(entry) { + return entry.path(); + } + + var progressFilePaths = progressEntries.map(getEntryPath).sort(); + var endFilePaths = endEntries.map(getEntryPath); + + assert.deepEqual( + progressFilePaths.sort(), endFilePaths.sort(), + "progress entries do not match end entries" + ); + }); + }); +}); diff --git a/test/utils/repository_setup.js b/test/utils/repository_setup.js index 26384bd91..d48c04650 100644 --- a/test/utils/repository_setup.js +++ b/test/utils/repository_setup.js @@ -18,18 +18,28 @@ var RepositorySetup = { }, commitFileToRepo: - function commitFileToRepo(repository, fileName, fileContent) { + function commitFileToRepo(repository, fileName, fileContent, parentCommit) { var repoWorkDir = repository.workdir(); var signature = NodeGit.Signature.create("Foo bar", "foo@bar.com", 123456789, 60); - return fse.writeFile(path.join(repoWorkDir, fileName), fileContent) + var filePath = path.join(repoWorkDir, fileName); + var parents = []; + if (parentCommit) { + parents.push(parentCommit); + } + + // fse.ensure allows us to write files inside new folders + return fse.ensureFile(filePath) + .then(function() { + return fse.writeFile(filePath, fileContent); + }) .then(function() { return RepositorySetup.addFileToIndex(repository, fileName); }) .then(function(oid) { return repository.createCommit("HEAD", signature, signature, - "initial commit", oid, []); + "initial commit", oid, parents); }) .then(function(commitOid) { return repository.getCommit(commitOid); From 123e2db21e2a7c6247c09966fd4b936692a930bd Mon Sep 17 00:00:00 2001 From: joseg Date: Mon, 29 Feb 2016 12:50:47 -0700 Subject: [PATCH 10/17] make sure both `entry` event and `end` event entries are what we expect --- test/tests/tree.js | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/test/tests/tree.js b/test/tests/tree.js index 9808b516e..164a54447 100644 --- a/test/tests/tree.js +++ b/test/tests/tree.js @@ -24,12 +24,15 @@ describe("Tree", function() { it("walks its entries and returns the same entries on both progress and end", function() { var repo = this.repository; + var file1 = "test.txt"; + var file2 = "foo/bar.txt"; + var expectedPaths = [file1, file2]; var progressEntries = []; var endEntries; - return RepoUtils.commitFileToRepo(repo, "test.txt", "") + return RepoUtils.commitFileToRepo(repo, file1, "") .then(function(commit) { - return RepoUtils.commitFileToRepo(repo, "foo/bar.txt", "", commit); + return RepoUtils.commitFileToRepo(repo, file2, "", commit); }) .then(function(commit) { return commit.getTree(); @@ -56,21 +59,21 @@ describe("Tree", function() { assert(progressEntries.length); assert(endEntries && endEntries.length); - assert.equal( - progressEntries.length, endEntries.length, - "Different number of progress entries and end entries" - ); - function getEntryPath(entry) { return entry.path(); } - var progressFilePaths = progressEntries.map(getEntryPath).sort(); + var progressFilePaths = progressEntries.map(getEntryPath); var endFilePaths = endEntries.map(getEntryPath); assert.deepEqual( - progressFilePaths.sort(), endFilePaths.sort(), - "progress entries do not match end entries" + expectedPaths, progressFilePaths, + "progress entry paths do not match expected paths" + ); + + assert.deepEqual( + expectedPaths, endFilePaths, + "end entry paths do not match expected paths" ); }); }); From 952b6b21098676fe4e8d43ba662e6ab24c24d7f0 Mon Sep 17 00:00:00 2001 From: joseg Date: Mon, 29 Feb 2016 13:09:48 -0700 Subject: [PATCH 11/17] make sure test file name is correct on all OSs --- test/tests/tree.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/tests/tree.js b/test/tests/tree.js index 164a54447..630ba9cca 100644 --- a/test/tests/tree.js +++ b/test/tests/tree.js @@ -26,7 +26,8 @@ describe("Tree", function() { var repo = this.repository; var file1 = "test.txt"; var file2 = "foo/bar.txt"; - var expectedPaths = [file1, file2]; + // index.addByPath doesn't like \s so normalize only for the expected paths + var expectedPaths = [file1, path.normalize(file2)]; var progressEntries = []; var endEntries; From 5b868abb7b27a12b5efd3b0ed7f63d6e182ba7d0 Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 1 Mar 2016 07:56:45 -0700 Subject: [PATCH 12/17] Bump `http-parser` to 2.6.1 --- vendor/http_parser/.gitignore | 2 + vendor/http_parser/AUTHORS | 1 + vendor/http_parser/Makefile | 31 ++- vendor/http_parser/README.md | 71 +++++- vendor/http_parser/contrib/url_parser.c | 3 +- vendor/http_parser/http_parser.c | 180 +++++++++------ vendor/http_parser/http_parser.h | 53 +++-- vendor/http_parser/test.c | 277 +++++++++++++++++++++++- 8 files changed, 512 insertions(+), 106 deletions(-) diff --git a/vendor/http_parser/.gitignore b/vendor/http_parser/.gitignore index 32cb51b2d..c122e76fb 100644 --- a/vendor/http_parser/.gitignore +++ b/vendor/http_parser/.gitignore @@ -12,6 +12,8 @@ parsertrace_g *.mk *.Makefile *.so.* +*.exe.* +*.exe *.a diff --git a/vendor/http_parser/AUTHORS b/vendor/http_parser/AUTHORS index 8e2df1d06..5323b685c 100644 --- a/vendor/http_parser/AUTHORS +++ b/vendor/http_parser/AUTHORS @@ -65,3 +65,4 @@ Romain Giraud Jay Satiro Arne Steen Kjell Schubert +Olivier Mengué diff --git a/vendor/http_parser/Makefile b/vendor/http_parser/Makefile index 373709c66..b3e0ff4ae 100644 --- a/vendor/http_parser/Makefile +++ b/vendor/http_parser/Makefile @@ -19,7 +19,19 @@ # IN THE SOFTWARE. PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') -SONAME ?= libhttp_parser.so.2.5.0 +HELPER ?= +BINEXT ?= +ifeq (darwin,$(PLATFORM)) +SONAME ?= libhttp_parser.2.6.1.dylib +SOEXT ?= dylib +else ifeq (wine,$(PLATFORM)) +CC = winegcc +BINEXT = .exe.so +HELPER = wine +else +SONAME ?= libhttp_parser.so.2.6.1 +SOEXT ?= so +endif CC?=gcc AR?=ar @@ -53,8 +65,8 @@ LDFLAGS_LIB += -Wl,-soname=$(SONAME) endif test: test_g test_fast - ./test_g - ./test_fast + $(HELPER) ./test_g$(BINEXT) + $(HELPER) ./test_fast$(BINEXT) test_g: http_parser_g.o test_g.o $(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o test_g.o -o $@ @@ -81,7 +93,7 @@ http_parser.o: http_parser.c http_parser.h Makefile $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) -c http_parser.c test-run-timed: test_fast - while(true) do time ./test_fast > /dev/null; done + while(true) do time $(HELPER) ./test_fast$(BINEXT) > /dev/null; done test-valgrind: test_g valgrind ./test_g @@ -102,10 +114,10 @@ url_parser_g: http_parser_g.o contrib/url_parser.c $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o $@ parsertrace: http_parser.o contrib/parsertrace.c - $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace + $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace$(BINEXT) parsertrace_g: http_parser_g.o contrib/parsertrace.c - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g + $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g$(BINEXT) tags: http_parser.c http_parser.h test.c ctags $^ @@ -113,12 +125,12 @@ tags: http_parser.c http_parser.h test.c install: library $(INSTALL) -D http_parser.h $(INCLUDEDIR)/http_parser.h $(INSTALL) -D $(SONAME) $(LIBDIR)/$(SONAME) - ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.so + ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.$(SOEXT) install-strip: library $(INSTALL) -D http_parser.h $(INCLUDEDIR)/http_parser.h $(INSTALL) -D -s $(SONAME) $(LIBDIR)/$(SONAME) - ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.so + ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.$(SOEXT) uninstall: rm $(INCLUDEDIR)/http_parser.h @@ -128,7 +140,8 @@ uninstall: clean: rm -f *.o *.a tags test test_fast test_g \ http_parser.tar libhttp_parser.so.* \ - url_parser url_parser_g parsertrace parsertrace_g + url_parser url_parser_g parsertrace parsertrace_g \ + *.exe *.exe.so contrib/url_parser.c: http_parser.h contrib/parsertrace.c: http_parser.h diff --git a/vendor/http_parser/README.md b/vendor/http_parser/README.md index 7c54dd42d..eedd7f8c9 100644 --- a/vendor/http_parser/README.md +++ b/vendor/http_parser/README.md @@ -1,7 +1,7 @@ HTTP Parser =========== -[![Build Status](https://travis-ci.org/joyent/http-parser.png?branch=master)](https://travis-ci.org/joyent/http-parser) +[![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser) This is a parser for HTTP messages written in C. It parses both requests and responses. The parser is designed to be used in performance HTTP @@ -94,7 +94,7 @@ The Special Problem of Upgrade ------------------------------ HTTP supports upgrading the connection to a different protocol. An -increasingly common example of this is the Web Socket protocol which sends +increasingly common example of this is the WebSocket protocol which sends a request like GET /demo HTTP/1.1 @@ -106,8 +106,8 @@ a request like followed by non-HTTP data. -(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more -information the Web Socket protocol.) +(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the +WebSocket protocol.) To support this, the parser will treat this as a normal HTTP message without a body, issuing both on_headers_complete and on_message_complete callbacks. However @@ -137,6 +137,69 @@ There are two types of callbacks: Callbacks must return 0 on success. Returning a non-zero value indicates error to the parser, making it exit immediately. +For cases where it is necessary to pass local information to/from a callback, +the `http_parser` object's `data` field can be used. +An example of such a case is when using threads to handle a socket connection, +parse a request, and then give a response over that socket. By instantiation +of a thread-local struct containing relevant data (e.g. accepted socket, +allocated memory for callbacks to write into, etc), a parser's callbacks are +able to communicate data between the scope of the thread and the scope of the +callback in a threadsafe manner. This allows http-parser to be used in +multi-threaded contexts. + +Example: +``` + typedef struct { + socket_t sock; + void* buffer; + int buf_len; + } custom_data_t; + + +int my_url_callback(http_parser* parser, const char *at, size_t length) { + /* access to thread local custom_data_t struct. + Use this access save parsed data for later use into thread local + buffer, or communicate over socket + */ + parser->data; + ... + return 0; +} + +... + +void http_parser_thread(socket_t sock) { + int nparsed = 0; + /* allocate memory for user data */ + custom_data_t *my_data = malloc(sizeof(custom_data_t)); + + /* some information for use by callbacks. + * achieves thread -> callback information flow */ + my_data->sock = sock; + + /* instantiate a thread-local parser */ + http_parser *parser = malloc(sizeof(http_parser)); + http_parser_init(parser, HTTP_REQUEST); /* initialise parser */ + /* this custom data reference is accessible through the reference to the + parser supplied to callback functions */ + parser->data = my_data; + + http_parser_settings settings; / * set up callbacks */ + settings.on_url = my_url_callback; + + /* execute parser */ + nparsed = http_parser_execute(parser, &settings, buf, recved); + + ... + /* parsed information copied from callback. + can now perform action on data copied into thread-local memory from callbacks. + achieves callback -> thread information flow */ + my_data->buffer; + ... +} + +``` + In case you parse HTTP message in chunks (i.e. `read()` request line from socket, parse, read half headers, parse, etc) your data callbacks may be called more than once. Http-parser guarantees that data pointer is only diff --git a/vendor/http_parser/contrib/url_parser.c b/vendor/http_parser/contrib/url_parser.c index 6650b414a..f235bed9e 100644 --- a/vendor/http_parser/contrib/url_parser.c +++ b/vendor/http_parser/contrib/url_parser.c @@ -35,6 +35,7 @@ int main(int argc, char ** argv) { connect = strcmp("connect", argv[1]) == 0 ? 1 : 0; printf("Parsing %s, connect %d\n", argv[2], connect); + http_parser_url_init(&u); result = http_parser_parse_url(argv[2], len, connect, &u); if (result != 0) { printf("Parse error : %d\n", result); @@ -43,4 +44,4 @@ int main(int argc, char ** argv) { printf("Parse ok, result : \n"); dump_url(argv[2], &u); return 0; -} \ No newline at end of file +} diff --git a/vendor/http_parser/http_parser.c b/vendor/http_parser/http_parser.c index 0fa1c3627..d0c77ea73 100644 --- a/vendor/http_parser/http_parser.c +++ b/vendor/http_parser/http_parser.c @@ -400,6 +400,8 @@ enum http_host_state , s_http_host , s_http_host_v6 , s_http_host_v6_end + , s_http_host_v6_zone_start + , s_http_host_v6_zone , s_http_host_port_start , s_http_host_port }; @@ -433,6 +435,12 @@ enum http_host_state (IS_ALPHANUM(c) || (c) == '.' || (c) == '-' || (c) == '_') #endif +/** + * Verify that a char is a valid visible (printable) US-ASCII + * character or %x80-FF + **/ +#define IS_HEADER_CHAR(ch) \ + (ch == CR || ch == LF || ch == 9 || (ch > 31 && ch != 127)) #define start_state (parser->type == HTTP_REQUEST ? s_start_req : s_start_res) @@ -637,6 +645,7 @@ size_t http_parser_execute (http_parser *parser, const char *body_mark = 0; const char *status_mark = 0; enum state p_state = (enum state) parser->state; + const unsigned int lenient = parser->lenient_http_headers; /* We're in an error state. Don't bother doing anything. */ if (HTTP_PARSER_ERRNO(parser) != HPE_OK) { @@ -957,21 +966,23 @@ size_t http_parser_execute (http_parser *parser, parser->method = (enum http_method) 0; parser->index = 1; switch (ch) { + case 'A': parser->method = HTTP_ACL; break; + case 'B': parser->method = HTTP_BIND; break; case 'C': parser->method = HTTP_CONNECT; /* or COPY, CHECKOUT */ break; case 'D': parser->method = HTTP_DELETE; break; case 'G': parser->method = HTTP_GET; break; case 'H': parser->method = HTTP_HEAD; break; - case 'L': parser->method = HTTP_LOCK; break; + case 'L': parser->method = HTTP_LOCK; /* or LINK */ break; case 'M': parser->method = HTTP_MKCOL; /* or MOVE, MKACTIVITY, MERGE, M-SEARCH, MKCALENDAR */ break; case 'N': parser->method = HTTP_NOTIFY; break; case 'O': parser->method = HTTP_OPTIONS; break; case 'P': parser->method = HTTP_POST; /* or PROPFIND|PROPPATCH|PUT|PATCH|PURGE */ break; - case 'R': parser->method = HTTP_REPORT; break; + case 'R': parser->method = HTTP_REPORT; /* or REBIND */ break; case 'S': parser->method = HTTP_SUBSCRIBE; /* or SEARCH */ break; case 'T': parser->method = HTTP_TRACE; break; - case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE, UNBIND, UNLINK */ break; default: SET_ERRNO(HPE_INVALID_METHOD); goto error; @@ -996,69 +1007,40 @@ size_t http_parser_execute (http_parser *parser, UPDATE_STATE(s_req_spaces_before_url); } else if (ch == matcher[parser->index]) { ; /* nada */ - } else if (parser->method == HTTP_CONNECT) { - if (parser->index == 1 && ch == 'H') { - parser->method = HTTP_CHECKOUT; - } else if (parser->index == 2 && ch == 'P') { - parser->method = HTTP_COPY; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_MKCOL) { - if (parser->index == 1 && ch == 'O') { - parser->method = HTTP_MOVE; - } else if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_MERGE; - } else if (parser->index == 1 && ch == '-') { - parser->method = HTTP_MSEARCH; - } else if (parser->index == 2 && ch == 'A') { - parser->method = HTTP_MKACTIVITY; - } else if (parser->index == 3 && ch == 'A') { - parser->method = HTTP_MKCALENDAR; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_SUBSCRIBE) { - if (parser->index == 1 && ch == 'E') { - parser->method = HTTP_SEARCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 1 && parser->method == HTTP_POST) { - if (ch == 'R') { - parser->method = HTTP_PROPFIND; /* or HTTP_PROPPATCH */ - } else if (ch == 'U') { - parser->method = HTTP_PUT; /* or HTTP_PURGE */ - } else if (ch == 'A') { - parser->method = HTTP_PATCH; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->index == 2) { - if (parser->method == HTTP_PUT) { - if (ch == 'R') { - parser->method = HTTP_PURGE; - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; - } - } else if (parser->method == HTTP_UNLOCK) { - if (ch == 'S') { - parser->method = HTTP_UNSUBSCRIBE; - } else { + } else if (IS_ALPHA(ch)) { + + switch (parser->method << 16 | parser->index << 8 | ch) { +#define XX(meth, pos, ch, new_meth) \ + case (HTTP_##meth << 16 | pos << 8 | ch): \ + parser->method = HTTP_##new_meth; break; + + XX(POST, 1, 'U', PUT) + XX(POST, 1, 'A', PATCH) + XX(CONNECT, 1, 'H', CHECKOUT) + XX(CONNECT, 2, 'P', COPY) + XX(MKCOL, 1, 'O', MOVE) + XX(MKCOL, 1, 'E', MERGE) + XX(MKCOL, 2, 'A', MKACTIVITY) + XX(MKCOL, 3, 'A', MKCALENDAR) + XX(SUBSCRIBE, 1, 'E', SEARCH) + XX(REPORT, 2, 'B', REBIND) + XX(POST, 1, 'R', PROPFIND) + XX(PROPFIND, 4, 'P', PROPPATCH) + XX(PUT, 2, 'R', PURGE) + XX(LOCK, 1, 'I', LINK) + XX(UNLOCK, 2, 'S', UNSUBSCRIBE) + XX(UNLOCK, 2, 'B', UNBIND) + XX(UNLOCK, 3, 'I', UNLINK) +#undef XX + + default: SET_ERRNO(HPE_INVALID_METHOD); goto error; - } - } else { - SET_ERRNO(HPE_INVALID_METHOD); - goto error; } - } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { - parser->method = HTTP_PROPPATCH; + } else if (ch == '-' && + parser->index == 1 && + parser->method == HTTP_MKCOL) { + parser->method = HTTP_MSEARCH; } else { SET_ERRNO(HPE_INVALID_METHOD); goto error; @@ -1384,7 +1366,12 @@ size_t http_parser_execute (http_parser *parser, || c != CONTENT_LENGTH[parser->index]) { parser->header_state = h_general; } else if (parser->index == sizeof(CONTENT_LENGTH)-2) { + if (parser->flags & F_CONTENTLENGTH) { + SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); + goto error; + } parser->header_state = h_content_length; + parser->flags |= F_CONTENTLENGTH; } break; @@ -1536,6 +1523,11 @@ size_t http_parser_execute (http_parser *parser, REEXECUTE(); } + if (!lenient && !IS_HEADER_CHAR(ch)) { + SET_ERRNO(HPE_INVALID_HEADER_TOKEN); + goto error; + } + c = LOWER(ch); switch (h_state) { @@ -1703,7 +1695,10 @@ size_t http_parser_execute (http_parser *parser, case s_header_almost_done: { - STRICT_CHECK(ch != LF); + if (UNLIKELY(ch != LF)) { + SET_ERRNO(HPE_LF_EXPECTED); + goto error; + } UPDATE_STATE(s_header_value_lws); break; @@ -1787,6 +1782,14 @@ size_t http_parser_execute (http_parser *parser, REEXECUTE(); } + /* Cannot use chunked encoding and a content-length header together + per the HTTP specification. */ + if ((parser->flags & F_CHUNKED) && + (parser->flags & F_CONTENTLENGTH)) { + SET_ERRNO(HPE_UNEXPECTED_CONTENT_LENGTH); + goto error; + } + UPDATE_STATE(s_headers_done); /* Set this here so that on_headers_complete() callbacks can see it */ @@ -1828,11 +1831,12 @@ size_t http_parser_execute (http_parser *parser, case s_headers_done: { + int hasBody; STRICT_CHECK(ch != LF); parser->nread = 0; - int hasBody = parser->flags & F_CHUNKED || + hasBody = parser->flags & F_CHUNKED || (parser->content_length > 0 && parser->content_length != ULLONG_MAX); if (parser->upgrade && (parser->method == HTTP_CONNECT || (parser->flags & F_SKIPBODY) || !hasBody)) { @@ -1857,8 +1861,7 @@ size_t http_parser_execute (http_parser *parser, /* Content-Length header given and non-zero */ UPDATE_STATE(s_body_identity); } else { - if (parser->type == HTTP_REQUEST || - !http_message_needs_eof(parser)) { + if (!http_message_needs_eof(parser)) { /* Assume content-length 0 - read the next */ UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); @@ -2153,15 +2156,13 @@ http_parser_settings_init(http_parser_settings *settings) const char * http_errno_name(enum http_errno err) { - assert(((size_t) err) < - (sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); + assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); return http_strerror_tab[err].name; } const char * http_errno_description(enum http_errno err) { - assert(((size_t) err) < - (sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); + assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); return http_strerror_tab[err].description; } @@ -2214,6 +2215,23 @@ http_parse_host_char(enum http_host_state s, const char ch) { return s_http_host_v6; } + if (s == s_http_host_v6 && ch == '%') { + return s_http_host_v6_zone_start; + } + break; + + case s_http_host_v6_zone: + if (ch == ']') { + return s_http_host_v6_end; + } + + /* FALLTHROUGH */ + case s_http_host_v6_zone_start: + /* RFC 6874 Zone ID consists of 1*( unreserved / pct-encoded) */ + if (IS_ALPHANUM(ch) || ch == '%' || ch == '.' || ch == '-' || ch == '_' || + ch == '~') { + return s_http_host_v6_zone; + } break; case s_http_host_port: @@ -2232,6 +2250,7 @@ http_parse_host_char(enum http_host_state s, const char ch) { static int http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { + assert(u->field_set & (1 << UF_HOST)); enum http_host_state s; const char *p; @@ -2263,6 +2282,11 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { u->field_data[UF_HOST].len++; break; + case s_http_host_v6_zone_start: + case s_http_host_v6_zone: + u->field_data[UF_HOST].len++; + break; + case s_http_host_port: if (s != s_http_host_port) { u->field_data[UF_PORT].off = p - buf; @@ -2292,6 +2316,8 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { case s_http_host_start: case s_http_host_v6_start: case s_http_host_v6: + case s_http_host_v6_zone_start: + case s_http_host_v6_zone: case s_http_host_port_start: case s_http_userinfo: case s_http_userinfo_start: @@ -2303,6 +2329,11 @@ http_parse_host(const char * buf, struct http_parser_url *u, int found_at) { return 0; } +void +http_parser_url_init(struct http_parser_url *u) { + memset(u, 0, sizeof(*u)); +} + int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, struct http_parser_url *u) @@ -2376,7 +2407,12 @@ http_parser_parse_url(const char *buf, size_t buflen, int is_connect, /* host must be present if there is a schema */ /* parsing http:///toto will fail */ - if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { + if ((u->field_set & (1 << UF_SCHEMA)) && + (u->field_set & (1 << UF_HOST)) == 0) { + return 1; + } + + if (u->field_set & (1 << UF_HOST)) { if (http_parse_host(buf, u, found_at) != 0) { return 1; } diff --git a/vendor/http_parser/http_parser.h b/vendor/http_parser/http_parser.h index eb71bf992..e33c0620a 100644 --- a/vendor/http_parser/http_parser.h +++ b/vendor/http_parser/http_parser.h @@ -26,11 +26,12 @@ extern "C" { /* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 5 -#define HTTP_PARSER_VERSION_PATCH 0 +#define HTTP_PARSER_VERSION_MINOR 6 +#define HTTP_PARSER_VERSION_PATCH 1 #include -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) +#if defined(_WIN32) && !defined(__MINGW32__) && \ + (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) #include #include typedef __int8 int8_t; @@ -95,7 +96,7 @@ typedef int (*http_cb) (http_parser*); XX(5, CONNECT, CONNECT) \ XX(6, OPTIONS, OPTIONS) \ XX(7, TRACE, TRACE) \ - /* webdav */ \ + /* WebDAV */ \ XX(8, COPY, COPY) \ XX(9, LOCK, LOCK) \ XX(10, MKCOL, MKCOL) \ @@ -104,21 +105,28 @@ typedef int (*http_cb) (http_parser*); XX(13, PROPPATCH, PROPPATCH) \ XX(14, SEARCH, SEARCH) \ XX(15, UNLOCK, UNLOCK) \ + XX(16, BIND, BIND) \ + XX(17, REBIND, REBIND) \ + XX(18, UNBIND, UNBIND) \ + XX(19, ACL, ACL) \ /* subversion */ \ - XX(16, REPORT, REPORT) \ - XX(17, MKACTIVITY, MKACTIVITY) \ - XX(18, CHECKOUT, CHECKOUT) \ - XX(19, MERGE, MERGE) \ + XX(20, REPORT, REPORT) \ + XX(21, MKACTIVITY, MKACTIVITY) \ + XX(22, CHECKOUT, CHECKOUT) \ + XX(23, MERGE, MERGE) \ /* upnp */ \ - XX(20, MSEARCH, M-SEARCH) \ - XX(21, NOTIFY, NOTIFY) \ - XX(22, SUBSCRIBE, SUBSCRIBE) \ - XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(24, MSEARCH, M-SEARCH) \ + XX(25, NOTIFY, NOTIFY) \ + XX(26, SUBSCRIBE, SUBSCRIBE) \ + XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ /* RFC-5789 */ \ - XX(24, PATCH, PATCH) \ - XX(25, PURGE, PURGE) \ + XX(28, PATCH, PATCH) \ + XX(29, PURGE, PURGE) \ /* CalDAV */ \ - XX(26, MKCALENDAR, MKCALENDAR) \ + XX(30, MKCALENDAR, MKCALENDAR) \ + /* RFC-2068, section 19.6.1.2 */ \ + XX(31, LINK, LINK) \ + XX(32, UNLINK, UNLINK) \ enum http_method { @@ -140,11 +148,12 @@ enum flags , F_TRAILING = 1 << 4 , F_UPGRADE = 1 << 5 , F_SKIPBODY = 1 << 6 + , F_CONTENTLENGTH = 1 << 7 }; /* Map for errno-related constants - * + * * The provided argument should be a macro that takes 2 arguments. */ #define HTTP_ERRNO_MAP(XX) \ @@ -182,6 +191,8 @@ enum flags XX(INVALID_HEADER_TOKEN, "invalid character in header") \ XX(INVALID_CONTENT_LENGTH, \ "invalid character in content-length header") \ + XX(UNEXPECTED_CONTENT_LENGTH, \ + "unexpected content-length header") \ XX(INVALID_CHUNK_SIZE, \ "invalid character in chunk size header") \ XX(INVALID_CONSTANT, "invalid constant string") \ @@ -206,10 +217,11 @@ enum http_errno { struct http_parser { /** PRIVATE **/ unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 7; /* F_* values from 'flags' enum; semi-public */ + unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ unsigned int state : 7; /* enum state from http_parser.c */ - unsigned int header_state : 8; /* enum header_state from http_parser.c */ - unsigned int index : 8; /* index into current matcher */ + unsigned int header_state : 7; /* enum header_state from http_parser.c */ + unsigned int index : 7; /* index into current matcher */ + unsigned int lenient_http_headers : 1; uint32_t nread; /* # bytes read in various scenarios */ uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ @@ -325,6 +337,9 @@ const char *http_errno_name(enum http_errno err); /* Return a string description of the given error */ const char *http_errno_description(enum http_errno err); +/* Initialize all http_parser_url members to 0 */ +void http_parser_url_init(struct http_parser_url *u); + /* Parse a URL; return nonzero on failure */ int http_parser_parse_url(const char *buf, size_t buflen, int is_connect, diff --git a/vendor/http_parser/test.c b/vendor/http_parser/test.c index 4c00571eb..4fcebaf79 100644 --- a/vendor/http_parser/test.c +++ b/vendor/http_parser/test.c @@ -1101,6 +1101,58 @@ const struct message requests[] = ,.body= "" } +/* Examples from the Internet draft for LINK/UNLINK methods: + * https://tools.ietf.org/id/draft-snell-link-method-01.html#rfc.section.5 + */ + +#define LINK_REQUEST 40 +, {.name = "link request" + ,.type= HTTP_REQUEST + ,.raw= "LINK /images/my_dog.jpg HTTP/1.1\r\n" + "Host: example.com\r\n" + "Link: ; rel=\"tag\"\r\n" + "Link: ; rel=\"tag\"\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_LINK + ,.request_path= "/images/my_dog.jpg" + ,.request_url= "/images/my_dog.jpg" + ,.query_string= "" + ,.fragment= "" + ,.num_headers= 3 + ,.headers= { { "Host", "example.com" } + , { "Link", "; rel=\"tag\"" } + , { "Link", "; rel=\"tag\"" } + } + ,.body= "" + } + +#define UNLINK_REQUEST 41 +, {.name = "link request" + ,.type= HTTP_REQUEST + ,.raw= "UNLINK /images/my_dog.jpg HTTP/1.1\r\n" + "Host: example.com\r\n" + "Link: ; rel=\"tag\"\r\n" + "\r\n" + ,.should_keep_alive= TRUE + ,.message_complete_on_eof= FALSE + ,.http_major= 1 + ,.http_minor= 1 + ,.method= HTTP_UNLINK + ,.request_path= "/images/my_dog.jpg" + ,.request_url= "/images/my_dog.jpg" + ,.query_string= "" + ,.fragment= "" + ,.num_headers= 2 + ,.headers= { { "Host", "example.com" } + , { "Link", "; rel=\"tag\"" } + } + ,.body= "" + } + , {.name= NULL } /* sentinel */ }; @@ -2392,7 +2444,7 @@ upgrade_message_fix(char *body, const size_t nread, const size_t nmsgs, ...) { va_list ap; size_t i; size_t off = 0; - + va_start(ap, nmsgs); for (i = 0; i < nmsgs; i++) { @@ -2918,6 +2970,59 @@ const struct url_test url_tests[] = ,.rv=1 /* s_dead */ } +, {.name="ipv6 address with Zone ID" + ,.url="http://[fe80::a%25eth0]/" + ,.is_connect=0 + ,.u= + {.field_set= (1< Date: Tue, 1 Mar 2016 07:57:07 -0700 Subject: [PATCH 13/17] Update CI to use Node v5.6.x instead of v5.0.x --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d10faa0fc..f871a28e5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,7 +15,7 @@ env: matrix: - export NODE_VERSION="0.12" - export NODE_VERSION="4.1" - - export NODE_VERSION="5.0" + - export NODE_VERSION="5.6" matrix: fast_finish: true diff --git a/appveyor.yml b/appveyor.yml index 41d4f90ff..4bfa5af66 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,7 +31,7 @@ environment: - nodejs_version: "0.12" # Node.js - nodejs_version: "4.1" - - nodejs_version: "5.0" + - nodejs_version: "5.6" matrix: fast_finish: true From 99149c8ce2eefacdd521253f39edc1735ad1c406 Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 1 Mar 2016 09:57:43 -0700 Subject: [PATCH 14/17] Use `Set` in `Tree#walk` for storing entries --- lib/tree.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/tree.js b/lib/tree.js index a9f00fe40..845bd0400 100644 --- a/lib/tree.js +++ b/lib/tree.js @@ -127,7 +127,7 @@ Tree.prototype.walk = function(blobsOnly) { var event = new events.EventEmitter(); var total = 1; - var entries = []; + var entries = new Set(); // This looks like a DFS, but it is a BFS because of implicit queueing in // the recursive call to `entry.getTree(bfs)` @@ -139,9 +139,9 @@ Tree.prototype.walk = function(blobsOnly) { } tree.entries().forEach(function (entry, entryIndex) { - if (!blobsOnly || entry.isFile()) { + if (!blobsOnly || entry.isFile() && !entries.has(entry)) { event.emit("entry", entry); - entries.push(entry); + entries.add(entry); } if (entry.isTree()) { @@ -151,7 +151,7 @@ Tree.prototype.walk = function(blobsOnly) { }); if (total === 0) { - event.emit("end", entries); + event.emit("end", Array.from(entries)); } } From 14b2c601e390fbd587dfd4aa69fafec610fae4bf Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 1 Mar 2016 10:05:11 -0700 Subject: [PATCH 15/17] Fix linter --- .jshintrc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.jshintrc b/.jshintrc index 17b577845..9f0a2639b 100644 --- a/.jshintrc +++ b/.jshintrc @@ -18,7 +18,8 @@ "maxlen": 80, "node": true, "predef": [ - "Promise" + "Promise", + "Set" ], "proto": true, "quotmark": "double", From 0e64add66055f7510a0b0e428abbe4fb4f8919d4 Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 1 Mar 2016 10:36:23 -0700 Subject: [PATCH 16/17] Fix tests Neither `[v for (v of set)]` nor `Array.from` work in Node 0.12 so we have to maintain our own list of entries instead of re-iterating through them to create the final array result. --- lib/tree.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/tree.js b/lib/tree.js index 845bd0400..c85a925bc 100644 --- a/lib/tree.js +++ b/lib/tree.js @@ -128,6 +128,7 @@ Tree.prototype.walk = function(blobsOnly) { var total = 1; var entries = new Set(); + var finalEntires = []; // This looks like a DFS, but it is a BFS because of implicit queueing in // the recursive call to `entry.getTree(bfs)` @@ -142,6 +143,10 @@ Tree.prototype.walk = function(blobsOnly) { if (!blobsOnly || entry.isFile() && !entries.has(entry)) { event.emit("entry", entry); entries.add(entry); + + // Node 0.12 doesn't support either [v for (v of entries)] nor + // Array.from so we'll just maintain our own list. + finalEntires.push(entry); } if (entry.isTree()) { @@ -151,7 +156,7 @@ Tree.prototype.walk = function(blobsOnly) { }); if (total === 0) { - event.emit("end", Array.from(entries)); + event.emit("end", finalEntires); } } From 53d38e9846fea641d4cd03a1bc236cb45a87f9f7 Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 1 Mar 2016 11:40:13 -0700 Subject: [PATCH 17/17] Bump to 0.11.6 --- CHANGELOG.md | 13 ++++++++++++- README.md | 2 +- package.json | 2 +- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa8665ce7..07809db6a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,22 @@ # Change Log +## [0.11.6](https://github.com/nodegit/nodegit/releases/tag/v0.11.6) (2016-03-01) + +[Full Changelog](https://github.com/nodegit/nodegit/compare/v0.11.5...v0.11.6) + +- Added `Repository#checkoutRef` [PR #891](https://github.com/nodegit/nodegit/pull/891) +- `Repository#createCommitOnHead` no longer dies if the repo is empty [PR #927](https://github.com/nodegit/nodegit/pull/927) +- Fixed memory leak in `Patch#convenientFromDiff` [PR #930](https://github.com/nodegit/nodegit/pull/930) +- Generated files now have a header comment indicating that they are generated [PR #924](https://github.com/nodegit/nodegit/pull/924) +- Fixed http parsing errors in Node 5.6 [PR #931](https://github.com/nodegit/nodegit/pull/931) +- Fixed `Tree#walk` not returning the correct entries on `end` [PR #929](https://github.com/nodegit/nodegit/pull/929) + ## [0.11.5](https://github.com/nodegit/nodegit/releases/tag/v0.11.5) (2016-02-25) [Full Changelog](https://github.com/nodegit/nodegit/compare/v0.11.4...v0.11.5) - Fixed crash when calculating a diff [PR #922](https://github.com/nodegit/nodegit/pull/922) -- Fixed an issue with return values getting randomly corrupted [PR #923](https://github.com/nodegit/nodegit/pull/923) +- Fixed an issue with return values getting randomly corrupted [PR #923](https://github.com/nodegit/nodegit/pull/923)) ## [0.11.4](https://github.com/nodegit/nodegit/releases/tag/v0.11.4) (2016-02-24) diff --git a/README.md b/README.md index b7caa80ec..5a982d009 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ NodeGit -**Stable: 0.11.5** +**Stable: 0.11.6** ## Have a problem? Come chat with us! ## diff --git a/package.json b/package.json index ab30d68af..f5912c818 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegit", "description": "Node.js libgit2 asynchronous native bindings", - "version": "0.11.5", + "version": "0.11.6", "homepage": "http://nodegit.org", "keywords": [ "libgit2",