From 26ab62b1d8b27c7774f362b6164b06a4f04c819c Mon Sep 17 00:00:00 2001 From: David Koontz Date: Wed, 2 Mar 2016 16:34:19 -0700 Subject: [PATCH 01/15] Test for Index.conflictAdd --- test/tests/index.js | 49 ++++++++++++++++++ test/utils/index_setup.js | 105 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+) create mode 100644 test/utils/index_setup.js diff --git a/test/tests/index.js b/test/tests/index.js index 35e6ecaa4..a1f91b204 100644 --- a/test/tests/index.js +++ b/test/tests/index.js @@ -9,6 +9,7 @@ var writeFile = promisify(function(filename, data, callback) { }); describe("Index", function() { + var IndexUtils = require("../utils/index_setup"); var RepoUtils = require("../utils/repository_setup"); var NodeGit = require("../../"); var Repository = NodeGit.Repository; @@ -307,4 +308,52 @@ describe("Index", function() { return Promise.all(promises); }); }); + + it("can add a conflict to the index", function() { + var repo; + var repoPath = path.join(__dirname, "..", "repos", "index"); + var ourBranchName = "ours"; + var theirBranchName = "theirs"; + var fileName = "testFile.txt"; + var ancestorIndexEntry; + var ourIndexEntry; + var theirIndexEntry; + + return RepoUtils.createRepository(repoPath) + .then(function(_repo) { + repo = _repo; + return IndexUtils.createConflict( + repo, + ourBranchName, + theirBranchName, + fileName + ); + }) + .then(function(indexEntries) { + // Store all indexEntries for conflict + ancestorIndexEntry = indexEntries.ancestor_out; + ourIndexEntry = indexEntries.our_out; + theirIndexEntry = indexEntries.their_out; + + // Stage conflicted file + return RepoUtils.addFileToIndex(repo, fileName); + }) + .then(function() { + return repo.openIndex(); + }) + .then(function(index) { + assert.ok(!index.hasConflicts()); + return index.conflictAdd( + ancestorIndexEntry, + ourIndexEntry, + theirIndexEntry + ); + }) + .then(function() { + return repo.openIndex(); + }) + .then(function(index) { + assert(index.hasConflicts()); + }); + }); }); diff --git a/test/utils/index_setup.js b/test/utils/index_setup.js new file mode 100644 index 000000000..a67da6544 --- /dev/null +++ b/test/utils/index_setup.js @@ -0,0 +1,105 @@ +var assert = require("assert"); +var NodeGit = require("../../"); +var path = require("path"); +var promisify = require("promisify-node"); +var fse = promisify(require("fs-extra")); +var RepoUtils = require("../utils/repository_setup"); + +var IndexSetup = { + createConflict: function createConflict( + repository, + _ourBranchName, + _theirBranchName, + _fileName + ) { + var fileName = _fileName || "everyonesFile.txt"; + + var ourBranchName = _ourBranchName || "ours"; + var theirBranchName = _theirBranchName || "theirs"; + + var baseFileContent = "How do you feel about Toll Roads?\n"; + var ourFileContent = "I like Toll Roads. I have an EZ-Pass!\n"; + var theirFileContent = "I'm skeptical about Toll Roads\n"; + + var ourSignature = NodeGit.Signature.create + ("Ron Paul", "RonPaul@TollRoadsRBest.info", 123456789, 60); + var theirSignature = NodeGit.Signature.create + ("Greg Abbott", "Gregggg@IllTollYourFace.us", 123456789, 60); + + var ourCommit; + var ourBranch; + var theirBranch; + + return fse.writeFile( + path.join(repository.workdir(), fileName), + baseFileContent + ) + .then(function() { + return RepoUtils.addFileToIndex(repository, fileName); + }) + .then(function(oid) { + return repository.createCommit("HEAD", ourSignature, + ourSignature, "initial commit", oid, []); + }) + .then(function(commitOid) { + return repository.getCommit(commitOid).then(function(commit) { + ourCommit = commit; + }).then(function() { + console.log("after creating base commit"); + return repository.createBranch(ourBranchName, commitOid) + .then(function(branch) { + console.log("after creating our branch"); + ourBranch = branch; + return repository.createBranch(theirBranchName, commitOid); + }); + }); + }) + .then(function(branch) { + console.log("after creating their commit"); + + theirBranch = branch; + return fse.writeFile(path.join(repository.workdir(), fileName), + baseFileContent + theirFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, fileName); + }) + .then(function(oid) { + return repository.createCommit(theirBranch.name(), theirSignature, + theirSignature, "they made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + return fse.writeFile(path.join(repository.workdir(), fileName), + baseFileContent + ourFileContent); + }) + .then(function() { + return RepoUtils.addFileToIndex(repository, fileName); + }) + .then(function(oid) { + return repository.createCommit(ourBranch.name(), ourSignature, + ourSignature, "we made a commit", oid, [ourCommit]); + }) + .then(function(commitOid) { + var opts = { + checkoutStrategy: NodeGit.Checkout.STRATEGY.FORCE + }; + + return NodeGit.Checkout.head(repository, opts); + }) + .then(function() { + return repository.mergeBranches(ourBranchName, theirBranchName); + }) + .then(function(commit) { + assert.fail(commit, undefined, + "The index should have been thrown due to merge conflicts"); + }) + .catch(function(index) { + assert.ok(index); + assert.ok(index.hasConflicts()); + + return index.conflictGet(fileName); + }); + } +}; + +module.exports = IndexSetup; From 2e986178c19529b2f5bb4735117913118749f0a4 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Tue, 1 Mar 2016 13:53:08 -0700 Subject: [PATCH 02/15] Add AsyncBatonWithResult and ExecuteAsync just refactoring, eliminating duplicated code --- .../templates/manual/include/async_baton.h | 27 +++++++++++++++++++ .../templates/manual/include/lock_master.h | 2 ++ .../templates/partials/callback_helpers.cc | 17 +----------- .../templates/partials/field_accessors.cc | 17 +----------- generate/templates/templates/class_content.cc | 1 - generate/templates/templates/class_header.h | 4 +-- .../templates/templates/struct_content.cc | 1 - generate/templates/templates/struct_header.h | 4 +-- 8 files changed, 33 insertions(+), 40 deletions(-) diff --git a/generate/templates/manual/include/async_baton.h b/generate/templates/manual/include/async_baton.h index a1ce5c380..43833a2ad 100644 --- a/generate/templates/manual/include/async_baton.h +++ b/generate/templates/manual/include/async_baton.h @@ -4,6 +4,9 @@ #include #include +#include "lock_master.h" +#include "functions/sleep_for_ms.h" + // Base class for Batons used for callbacks (for example, // JS functions passed as callback parameters, // or field properties of configuration objects whose values are callbacks) @@ -13,4 +16,28 @@ struct AsyncBaton { bool done; }; +template +struct AsyncBatonWithResult : public AsyncBaton { + ResultT result; + + ResultT ExecuteAsync(uv_async_cb asyncCallback) { + result = 0; + req.data = this; + done = false; + + uv_async_init(uv_default_loop(), &req, asyncCallback); + { + LockMaster::TemporaryUnlock temporaryUnlock; + + uv_async_send(&req); + + while(!done) { + sleep_for_ms(1); + } + } + + return result; + } +}; + #endif diff --git a/generate/templates/manual/include/lock_master.h b/generate/templates/manual/include/lock_master.h index fd1a09b6f..7fd4ee8dc 100644 --- a/generate/templates/manual/include/lock_master.h +++ b/generate/templates/manual/include/lock_master.h @@ -1,6 +1,8 @@ #ifndef LOCK_MASTER_H #define LOCK_MASTER_H +#include + class LockMasterImpl; class LockMaster { diff --git a/generate/templates/partials/callback_helpers.cc b/generate/templates/partials/callback_helpers.cc index 0acd215ae..0a1d7e782 100644 --- a/generate/templates/partials/callback_helpers.cc +++ b/generate/templates/partials/callback_helpers.cc @@ -12,22 +12,7 @@ baton->{{ arg.name }} = {{ arg.name }}; {% endeach %} - baton->result = 0; - baton->req.data = baton; - baton->done = false; - - uv_async_init(uv_default_loop(), &baton->req, (uv_async_cb) {{ cppFunctionName }}_{{ cbFunction.name }}_async); - { - LockMaster::TemporaryUnlock temporaryUnlock; - - uv_async_send(&baton->req); - - while(!baton->done) { - sleep_for_ms(1); - } - } - - return baton->result; + return baton->ExecuteAsync((uv_async_cb) {{ cppFunctionName }}_{{ cbFunction.name }}_async); } void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbFunction.name }}_async(uv_async_t* req, int status) { diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index 17b338dc3..1f64a9a0b 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -93,22 +93,7 @@ baton->{{ arg.name }} = {{ arg.name }}; {% endeach %} - baton->result = 0; - baton->req.data = baton; - baton->done = false; - - uv_async_init(uv_default_loop(), &baton->req, (uv_async_cb) {{ field.name }}_async); - { - LockMaster::TemporaryUnlock temporaryUnlock; - - uv_async_send(&baton->req); - - while(!baton->done) { - sleep_for_ms(1); - } - } - - return baton->result; + return baton->ExecuteAsync((uv_async_cb) {{ field.name }}_async); } void {{ cppClassName }}::{{ field.name }}_async(uv_async_t* req, int status) { diff --git a/generate/templates/templates/class_content.cc b/generate/templates/templates/class_content.cc index c172e1fa5..8fead5aa8 100644 --- a/generate/templates/templates/class_content.cc +++ b/generate/templates/templates/class_content.cc @@ -11,7 +11,6 @@ extern "C" { #include "../include/lock_master.h" #include "../include/functions/copy.h" #include "../include/{{ filename }}.h" -#include "../include/functions/sleep_for_ms.h" {% each dependencies as dependency %} #include "{{ dependency }}" diff --git a/generate/templates/templates/class_header.h b/generate/templates/templates/class_header.h index 84c9b5c4f..1d493459b 100644 --- a/generate/templates/templates/class_header.h +++ b/generate/templates/templates/class_header.h @@ -64,12 +64,10 @@ class {{ cppClassName }} : public Nan::ObjectWrap { static void {{ function.cppFunctionName }}_{{ arg.name }}_async(uv_async_t* req, int status); static void {{ function.cppFunctionName }}_{{ arg.name }}_promiseCompleted(bool isFulfilled, AsyncBaton *_baton, v8::Local result); - struct {{ function.cppFunctionName }}_{{ arg.name|titleCase }}Baton : AsyncBaton { + struct {{ function.cppFunctionName }}_{{ arg.name|titleCase }}Baton : public AsyncBatonWithResult<{{ arg.return.type }}> { {% each arg.args|argsInfo as cbArg %} {{ cbArg.cType }} {{ cbArg.name }}; {% endeach %} - - {{ arg.return.type }} result; }; {% endif %} {% endeach %} diff --git a/generate/templates/templates/struct_content.cc b/generate/templates/templates/struct_content.cc index cab524a80..561d5c0ef 100644 --- a/generate/templates/templates/struct_content.cc +++ b/generate/templates/templates/struct_content.cc @@ -17,7 +17,6 @@ extern "C" { #include "../include/lock_master.h" #include "../include/functions/copy.h" #include "../include/{{ filename }}.h" -#include "../include/functions/sleep_for_ms.h" {% each dependencies as dependency %} #include "{{ dependency }}" diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index 0320fbbf6..149f97647 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -48,12 +48,10 @@ class {{ cppClassName }} : public Nan::ObjectWrap { static void {{ field.name }}_async(uv_async_t* req, int status); static void {{ field.name }}_promiseCompleted(bool isFulfilled, AsyncBaton *_baton, v8::Local result); - struct {{ field.name|titleCase }}Baton : public AsyncBaton { + struct {{ field.name|titleCase }}Baton : public AsyncBatonWithResult<{{ field.return.type }}> { {% each field.args|argsInfo as arg %} {{ arg.cType }} {{ arg.name}}; {% endeach %} - - {{ field.return.type }} result; }; {% endif %} {% endif %} From 266aa3fa2f7be7c79bf76124919e9f40b9072ed0 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Tue, 1 Mar 2016 14:28:17 -0700 Subject: [PATCH 03/15] Store defaultResult in baton I originally tried doing the throttling in the baton but that ended up being a mistake. This moved the default result to the baton so the baton could use it. I don't think the change is necessary for the final version of this PR, but I still like moving things out of combyne-templated files so I kept it. --- generate/templates/manual/include/async_baton.h | 5 +++++ generate/templates/partials/callback_helpers.cc | 11 ++++++----- generate/templates/partials/field_accessors.cc | 13 +++++++------ generate/templates/templates/class_header.h | 4 ++++ generate/templates/templates/struct_header.h | 4 ++++ 5 files changed, 26 insertions(+), 11 deletions(-) diff --git a/generate/templates/manual/include/async_baton.h b/generate/templates/manual/include/async_baton.h index 43833a2ad..fee87c4c1 100644 --- a/generate/templates/manual/include/async_baton.h +++ b/generate/templates/manual/include/async_baton.h @@ -19,6 +19,11 @@ struct AsyncBaton { template struct AsyncBatonWithResult : public AsyncBaton { ResultT result; + ResultT defaultResult; // result returned if the callback doesn't return anything valid + + AsyncBatonWithResult(const ResultT &defaultResult) + : defaultResult(defaultResult) { + } ResultT ExecuteAsync(uv_async_cb asyncCallback) { result = 0; diff --git a/generate/templates/partials/callback_helpers.cc b/generate/templates/partials/callback_helpers.cc index 0a1d7e782..b776c0097 100644 --- a/generate/templates/partials/callback_helpers.cc +++ b/generate/templates/partials/callback_helpers.cc @@ -6,7 +6,8 @@ {{ arg.cType }} {{ arg.name}}{% if not arg.lastArg %},{% endif %} {% endeach %} ) { - {{ cppFunctionName }}_{{ cbFunction.name|titleCase }}Baton* baton = new {{ cppFunctionName }}_{{ cbFunction.name|titleCase }}Baton(); + {{ cppFunctionName }}_{{ cbFunction.name|titleCase }}Baton* baton = + new {{ cppFunctionName }}_{{ cbFunction.name|titleCase }}Baton({{ cbFunction.return.noResults }}); {% each cbFunction.args|argsInfo as arg %} baton->{{ arg.name }} = {{ arg.name }}; @@ -78,12 +79,12 @@ void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbFunction.name }}_async(uv_as baton->result = (int)result->ToNumber()->Value(); } else { - baton->result = {{ cbFunction.return.noResults }}; + baton->result = baton->defaultResult; } {% endif %} } else { - baton->result = {{ cbFunction.return.noResults }}; + baton->result = baton->defaultResult; } {% endeach %} @@ -112,12 +113,12 @@ void {{ cppClassName }}::{{ cppFunctionName }}_{{ cbFunction.name }}_promiseComp baton->result = (int)result->ToNumber()->Value(); } else { - baton->result = {{ cbFunction.return.noResults }}; + baton->result = baton->defaultResult; } {% endif %} } else { - baton->result = {{ cbFunction.return.noResults }}; + baton->result = baton->defaultResult; } {% endeach %} } diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index 1f64a9a0b..6081f15fd 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -87,7 +87,8 @@ {{ arg.cType }} {{ arg.name}}{% if not arg.lastArg %},{% endif %} {% endeach %} ) { - {{ field.name|titleCase }}Baton* baton = new {{ field.name|titleCase }}Baton(); + {{ field.name|titleCase }}Baton* baton = + new {{ field.name|titleCase }}Baton({{ field.return.noResults }}); {% each field.args|argsInfo as arg %} baton->{{ arg.name }} = {{ arg.name }}; @@ -106,7 +107,7 @@ if (instance->{{ field.name }}->IsEmpty()) { {% if field.return.type == "int" %} - baton->result = {{ field.return.noResults }}; // no results acquired + baton->result = baton->defaultResult; // no results acquired {% endif %} baton->done = true; @@ -172,12 +173,12 @@ baton->result = (int)result->ToNumber()->Value(); } else { - baton->result = {{ field.return.noResults }}; + baton->result = baton->defaultResult; } {% endif %} } else { - baton->result = {{ field.return.noResults }}; + baton->result = baton->defaultResult; } {% endeach %} baton->done = true; @@ -205,12 +206,12 @@ baton->result = (int)result->ToNumber()->Value(); } else{ - baton->result = {{ field.return.noResults }}; + baton->result = baton->defaultResult; } {% endif %} } else { - baton->result = {{ field.return.noResults }}; + baton->result = baton->defaultResult; } {% endeach %} } diff --git a/generate/templates/templates/class_header.h b/generate/templates/templates/class_header.h index 1d493459b..b18defd0e 100644 --- a/generate/templates/templates/class_header.h +++ b/generate/templates/templates/class_header.h @@ -68,6 +68,10 @@ class {{ cppClassName }} : public Nan::ObjectWrap { {% each arg.args|argsInfo as cbArg %} {{ cbArg.cType }} {{ cbArg.name }}; {% endeach %} + + {{ function.cppFunctionName }}_{{ arg.name|titleCase }}Baton(const {{ arg.return.type }} &defaultResult) + : AsyncBatonWithResult<{{ arg.return.type }}>(defaultResult) { + } }; {% endif %} {% endeach %} diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index 149f97647..703023556 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -52,6 +52,10 @@ class {{ cppClassName }} : public Nan::ObjectWrap { {% each field.args|argsInfo as arg %} {{ arg.cType }} {{ arg.name}}; {% endeach %} + + {{ field.name|titleCase }}Baton(const {{ field.return.type }} &defaultResult) + : AsyncBatonWithResult<{{ field.return.type }}>(defaultResult) { + } }; {% endif %} {% endif %} From 89faca2026a707024ef606a5eefac6f74ff0c27a Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Wed, 2 Mar 2016 15:28:43 -0700 Subject: [PATCH 04/15] Refactor structs to use CallbackWrapper for callbacks just refactoring, leverages the previously unused CallbackWrapper to set us up for bundling throttling state with the javascript callback. --- .../manual/include/callback_wrapper.h | 26 +++++++++++++++++-- .../templates/partials/field_accessors.cc | 14 ++++------ .../templates/templates/struct_content.cc | 4 --- generate/templates/templates/struct_header.h | 3 ++- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/generate/templates/manual/include/callback_wrapper.h b/generate/templates/manual/include/callback_wrapper.h index 41552de3e..9b848bbd6 100644 --- a/generate/templates/manual/include/callback_wrapper.h +++ b/generate/templates/manual/include/callback_wrapper.h @@ -9,9 +9,31 @@ using namespace v8; using namespace node; -struct CallbackWrapper { +class CallbackWrapper { Nan::Callback* jsCallback; - void * payload; + +public: + CallbackWrapper() { + jsCallback = NULL; + } + ~CallbackWrapper() { + SetCallback(NULL); + } + + bool HasCallback() { + return jsCallback != NULL; + } + + Nan::Callback* GetCallback() { + return jsCallback; + } + + void SetCallback(Nan::Callback* callback) { + if(jsCallback) { + delete jsCallback; + } + jsCallback = callback; + } }; #endif diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index 6081f15fd..66a9c44fc 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -11,8 +11,8 @@ info.GetReturnValue().Set(Nan::New(wrapper->{{ field.name }})); {% elsif field.isCallbackFunction %} - if (wrapper->{{field.name}} != NULL) { - info.GetReturnValue().Set(wrapper->{{ field.name }}->GetFunction()); + if (wrapper->{{field.name}}.HasCallback()) { + info.GetReturnValue().Set(wrapper->{{ field.name }}.GetCallback()->GetFunction()); } else { info.GetReturnValue().SetUndefined(); } @@ -47,16 +47,12 @@ wrapper->raw->{{ field.name }} = {% if not field.cType | isPointer %}*{% endif %}{% if field.cppClassName == 'GitStrarray' %}StrArrayConverter::Convert({{ field.name }}->ToObject()){% else %}Nan::ObjectWrap::Unwrap<{{ field.cppClassName }}>({{ field.name }}->ToObject())->GetValue(){% endif %}; {% elsif field.isCallbackFunction %} - if (wrapper->{{ field.name }} != NULL) { - delete wrapper->{{ field.name }}; - } - if (value->IsFunction()) { if (!wrapper->raw->{{ field.name }}) { wrapper->raw->{{ field.name }} = ({{ field.cType }}){{ field.name }}_cppCallback; } - wrapper->{{ field.name }} = new Nan::Callback(value.As()); + wrapper->{{ field.name }}.SetCallback(new Nan::Callback(value.As())); } {% elsif field.payloadFor %} @@ -105,7 +101,7 @@ {% if arg.payload == true %}{{arg.name}}{% elsif arg.lastArg %}{{arg.name}}{% endif %} {% endeach %}); - if (instance->{{ field.name }}->IsEmpty()) { + if (instance->{{ field.name }}.GetCallback()->IsEmpty()) { {% if field.return.type == "int" %} baton->result = baton->defaultResult; // no results acquired {% endif %} @@ -149,7 +145,7 @@ }; Nan::TryCatch tryCatch; - Local result = instance->{{ field.name }}->Call({{ field.args|jsArgsCount }}, argv); + Local result = instance->{{ field.name }}.GetCallback()->Call({{ field.args|jsArgsCount }}, argv); uv_close((uv_handle_t*) &baton->req, NULL); diff --git a/generate/templates/templates/struct_content.cc b/generate/templates/templates/struct_content.cc index 561d5c0ef..b54af5510 100644 --- a/generate/templates/templates/struct_content.cc +++ b/generate/templates/templates/struct_content.cc @@ -52,10 +52,7 @@ using namespace std; {% if not field.ignore %} {% if not field.isEnum %} {% if field.isCallbackFunction %} - if (this->{{ field.name }} != NULL) { - delete this->{{ field.name }}; this->raw->{{ fields|payloadFor field.name }} = NULL; - } {% endif %} {% endif %} {% endif %} @@ -83,7 +80,6 @@ void {{ cppClassName }}::ConstructFields() { // the current instance this->raw->{{ field.name }} = NULL; this->raw->{{ fields|payloadFor field.name }} = (void *)this; - this->{{ field.name }} = NULL; {% elsif field.payloadFor %} Local {{ field.name }} = Nan::Undefined(); diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index 703023556..d0a797227 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -6,6 +6,7 @@ #include #include "async_baton.h" +#include "callback_wrapper.h" extern "C" { #include @@ -75,7 +76,7 @@ class {{ cppClassName }} : public Nan::ObjectWrap { {% if field.isLibgitType %} Nan::Persistent {{ field.name }}; {% elsif field.isCallbackFunction %} - Nan::Callback* {{ field.name }}; + CallbackWrapper {{ field.name }}; {% elsif field.payloadFor %} Nan::Persistent {{ field.name }}; {% endif %} From e8f8de5c9e18b1f623262689545a0157e2885d25 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Wed, 2 Mar 2016 17:52:01 -0700 Subject: [PATCH 05/15] Add callback throttle functionality --- .../manual/include/callback_wrapper.h | 31 +++++++++++--- .../templates/partials/field_accessors.cc | 42 +++++++++++++++++-- generate/templates/templates/struct_header.h | 2 + 3 files changed, 66 insertions(+), 9 deletions(-) diff --git a/generate/templates/manual/include/callback_wrapper.h b/generate/templates/manual/include/callback_wrapper.h index 9b848bbd6..b23a7bb36 100644 --- a/generate/templates/manual/include/callback_wrapper.h +++ b/generate/templates/manual/include/callback_wrapper.h @@ -1,10 +1,8 @@ #ifndef CALLBACK_WRAPPER_H #define CALLBACK_WRAPPER_H -#include -#include - -#include "nan.h" +#include +#include using namespace v8; using namespace node; @@ -12,10 +10,17 @@ using namespace node; class CallbackWrapper { Nan::Callback* jsCallback; + // throttling data, used for callbacks that need to be throttled + int throttle; // in milliseconds - if > 0, calls to the JS callback will be throttled + uint64_t lastCallTime; + public: CallbackWrapper() { jsCallback = NULL; + lastCallTime = 0; + throttle = 0; } + ~CallbackWrapper() { SetCallback(NULL); } @@ -28,11 +33,27 @@ class CallbackWrapper { return jsCallback; } - void SetCallback(Nan::Callback* callback) { + void SetCallback(Nan::Callback* callback, int throttle = 0) { if(jsCallback) { delete jsCallback; } jsCallback = callback; + this->throttle = throttle; + } + + bool WillBeThrottled() { + if(!throttle) { + return false; + } + // throttle if needed + uint64_t now = uv_hrtime(); + if(lastCallTime > 0 && now < lastCallTime + throttle * 1000000) { + // throttled + return true; + } else { + lastCallTime = now; + return false; + } } }; diff --git a/generate/templates/partials/field_accessors.cc b/generate/templates/partials/field_accessors.cc index 66a9c44fc..6a3123095 100644 --- a/generate/templates/partials/field_accessors.cc +++ b/generate/templates/partials/field_accessors.cc @@ -31,6 +31,7 @@ } NAN_SETTER({{ cppClassName }}::Set{{ field.cppFunctionName }}) { + Nan::HandleScope scope; {{ cppClassName }} *wrapper = Nan::ObjectWrap::Unwrap<{{ cppClassName }}>(info.This()); @@ -47,12 +48,35 @@ wrapper->raw->{{ field.name }} = {% if not field.cType | isPointer %}*{% endif %}{% if field.cppClassName == 'GitStrarray' %}StrArrayConverter::Convert({{ field.name }}->ToObject()){% else %}Nan::ObjectWrap::Unwrap<{{ field.cppClassName }}>({{ field.name }}->ToObject())->GetValue(){% endif %}; {% elsif field.isCallbackFunction %} + Nan::Callback *callback = NULL; + int throttle = {%if field.return.throttle %}{{ field.return.throttle }}{%else%}0{%endif%}; + if (value->IsFunction()) { + callback = new Nan::Callback(value.As()); + } else if (value->IsObject()) { + Local object = value.As(); + Local callbackKey; + Nan::MaybeLocal maybeObjectCallback = Nan::Get(object, Nan::New("callback").ToLocalChecked()); + if (!maybeObjectCallback.IsEmpty()) { + Local objectCallback = maybeObjectCallback.ToLocalChecked(); + if (objectCallback->IsFunction()) { + callback = new Nan::Callback(objectCallback.As()); + Nan::MaybeLocal maybeObjectThrottle = Nan::Get(object, Nan::New("throttle").ToLocalChecked()); + if(!maybeObjectThrottle.IsEmpty()) { + Local objectThrottle = maybeObjectThrottle.ToLocalChecked(); + if (objectThrottle->IsNumber()) { + throttle = (int)objectThrottle.As()->Value(); + } + } + } + } + } + if (callback) { if (!wrapper->raw->{{ field.name }}) { wrapper->raw->{{ field.name }} = ({{ field.cType }}){{ field.name }}_cppCallback; } - wrapper->{{ field.name }}.SetCallback(new Nan::Callback(value.As())); + wrapper->{{ field.name }}.SetCallback(callback, throttle); } {% elsif field.payloadFor %} @@ -78,6 +102,12 @@ } {% if field.isCallbackFunction %} + {{ cppClassName }}* {{ cppClassName }}::{{ field.name }}_getInstanceFromBaton({{ field.name|titleCase }}Baton* baton) { + return static_cast<{{ cppClassName }}*>(baton->{% each field.args|argsInfo as arg %} + {% if arg.payload == true %}{{arg.name}}{% elsif arg.lastArg %}{{arg.name}}{% endif %} + {% endeach %}); + } + {{ field.return.type }} {{ cppClassName }}::{{ field.name }}_cppCallback ( {% each field.args|argsInfo as arg %} {{ arg.cType }} {{ arg.name}}{% if not arg.lastArg %},{% endif %} @@ -90,6 +120,12 @@ baton->{{ arg.name }} = {{ arg.name }}; {% endeach %} + {{ cppClassName }}* instance = {{ field.name }}_getInstanceFromBaton(baton); + + if (instance->{{ field.name }}.WillBeThrottled()) { + return baton->defaultResult; + } + return baton->ExecuteAsync((uv_async_cb) {{ field.name }}_async); } @@ -97,9 +133,7 @@ Nan::HandleScope scope; {{ field.name|titleCase }}Baton* baton = static_cast<{{ field.name|titleCase }}Baton*>(req->data); - {{ cppClassName }}* instance = static_cast<{{ cppClassName }}*>(baton->{% each field.args|argsInfo as arg %} - {% if arg.payload == true %}{{arg.name}}{% elsif arg.lastArg %}{{arg.name}}{% endif %} - {% endeach %}); + {{ cppClassName }}* instance = {{ field.name }}_getInstanceFromBaton(baton); if (instance->{{ field.name }}.GetCallback()->IsEmpty()) { {% if field.return.type == "int" %} diff --git a/generate/templates/templates/struct_header.h b/generate/templates/templates/struct_header.h index d0a797227..87720aa4a 100644 --- a/generate/templates/templates/struct_header.h +++ b/generate/templates/templates/struct_header.h @@ -58,6 +58,8 @@ class {{ cppClassName }} : public Nan::ObjectWrap { : AsyncBatonWithResult<{{ field.return.type }}>(defaultResult) { } }; + static {{ cppClassName }} * {{ field.name }}_getInstanceFromBaton ( + {{ field.name|titleCase }}Baton *baton); {% endif %} {% endif %} {% endeach %} From f5286a89be443402f3652f1ec450da25fc2d594c Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Wed, 2 Mar 2016 17:53:23 -0700 Subject: [PATCH 06/15] Specify throttle in progress callback descriptors default settings for progress callbacks. --- generate/input/callbacks.json | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/generate/input/callbacks.json b/generate/input/callbacks.json index d18919768..eb6b128a3 100644 --- a/generate/input/callbacks.json +++ b/generate/input/callbacks.json @@ -96,7 +96,8 @@ "type": "int", "noResults": 1, "success": 0, - "error": -1 + "error": -1, + "throttle": 100 } }, "git_checkout_perfdata_cb": { @@ -207,7 +208,8 @@ "type": "int", "noResults": 1, "success": 0, - "error": -1 + "error": -1, + "throttle": 100 } }, "git_diff_hunk_cb": { @@ -560,7 +562,8 @@ "type": "int", "noResults":0, "success": 0, - "error": -1 + "error": -1, + "throttle": 100 } }, "git_stash_cb": { @@ -670,7 +673,8 @@ "type": "int", "noResults": 0, "success": 0, - "error": -1 + "error": -1, + "throttle": 100 } }, "git_transport_cb": { From b6215ac57abec90a3ca6bfb5995916af9448c3d5 Mon Sep 17 00:00:00 2001 From: Stjepan Rajko Date: Wed, 2 Mar 2016 17:53:46 -0700 Subject: [PATCH 07/15] Add throttling tests --- test/tests/clone.js | 109 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/test/tests/clone.js b/test/tests/clone.js index 46830a889..3e2a86446 100644 --- a/test/tests/clone.js +++ b/test/tests/clone.js @@ -3,6 +3,7 @@ var assert = require("assert"); var promisify = require("promisify-node"); var fse = promisify(require("fs-extra")); var local = path.join.bind(path, __dirname); +var _ = require("lodash"); describe("Clone", function() { var NodeGit = require("../../"); @@ -37,6 +38,114 @@ describe("Clone", function() { }); }); + it("can clone twice with http using same config object", function() { + var test = this; + var url = "http://git.tbranyen.com/smart/site-content"; + var progressCount = 0; + var opts = { + fetchOpts: { + callbacks: { + transferProgress: function(progress) { + progressCount++; + } + } + } + }; + + return Clone(url, clonePath, opts) + .then(function(repo) { + assert.ok(repo instanceof Repository); + assert.notEqual(progressCount, 0); + return fse.remove(clonePath); + }) + .then(function() { + progressCount = 0; + return Clone(url, clonePath, opts); + }) + .then(function(repo) { + assert.ok(repo instanceof Repository); + assert.notEqual(progressCount, 0); + test.repository = repo; + }); + }); + + function updateProgressIntervals(progressIntervals, lastInvocation) { + var now = new Date(); + if (lastInvocation) { + progressIntervals.push(now - lastInvocation); + } + return now; + } + + it("can clone with http and default throttled progress", function() { + var test = this; + var url = "http://git.tbranyen.com/smart/site-content"; + var progressCount = 0; + var lastInvocation; + var progressIntervals = []; + var opts = { + fetchOpts: { + callbacks: { + transferProgress: function(progress) { + lastInvocation = updateProgressIntervals(progressIntervals); + progressCount++; + } + } + } + }; + + return Clone(url, clonePath, opts).then(function(repo) { + assert.ok(repo instanceof Repository); + assert.notEqual(progressCount, 0); + var averageProgressInterval = _.sum(progressIntervals) / + progressIntervals.length; + // even though we are specifying a throttle period of 100, + // the throttle is applied on the scheduling side, + // and actual execution is at the mercy of the main js thread + // so the actual throttle intervals could be less than the specified + // throttle period + if (averageProgressInterval < 75) { + assert.fail(averageProgressInterval, 75, + "unexpected average time between callbacks", "<"); + } + test.repository = repo; + }); + }); + + it("can clone with http and explicitly throttled progress", function() { + var test = this; + var url = "http://git.tbranyen.com/smart/site-content"; + var progressCount = 0; + var lastInvocation; + var progressIntervals = []; + var opts = { + fetchOpts: { + callbacks: { + transferProgress: { + throttle: 50, + callback: function(progress) { + lastInvocation = updateProgressIntervals(progressIntervals, + lastInvocation); + progressCount++; + } + } + } + } + }; + + return Clone(url, clonePath, opts).then(function(repo) { + assert.ok(repo instanceof Repository); + assert.notEqual(progressCount, 0); + var averageProgressInterval = _.sum(progressIntervals) / + progressIntervals.length; + if (averageProgressInterval < 35) { + assert.fail(averageProgressInterval, 35, + "unexpected average time between callbacks", "<"); + } + test.repository = repo; + }); + }); + it("can clone with https", function() { var test = this; var url = "https://github.com/nodegit/test.git"; From fda0fc4c2ffb310c3bc58385ddde8b7284e41d57 Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Thu, 3 Mar 2016 14:36:41 -0700 Subject: [PATCH 08/15] Removed accidental console logs in index tests --- test/utils/index_setup.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/utils/index_setup.js b/test/utils/index_setup.js index a67da6544..a55e95924 100644 --- a/test/utils/index_setup.js +++ b/test/utils/index_setup.js @@ -45,18 +45,14 @@ var IndexSetup = { return repository.getCommit(commitOid).then(function(commit) { ourCommit = commit; }).then(function() { - console.log("after creating base commit"); return repository.createBranch(ourBranchName, commitOid) .then(function(branch) { - console.log("after creating our branch"); ourBranch = branch; return repository.createBranch(theirBranchName, commitOid); }); }); }) .then(function(branch) { - console.log("after creating their commit"); - theirBranch = branch; return fse.writeFile(path.join(repository.workdir(), fileName), baseFileContent + theirFileContent); From 90d80ab7502831826ba0a490893a4faa31069f1e Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Thu, 3 Mar 2016 17:20:05 -0700 Subject: [PATCH 09/15] Docs: improved Merge.merge param docs --- lib/merge.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/merge.js b/lib/merge.js index 79f9a2b44..818f95c02 100644 --- a/lib/merge.js +++ b/lib/merge.js @@ -29,7 +29,7 @@ Merge.commits = function(repo, ourCommit, theirCommit, options) { * Merge a commit into HEAD and writes the results to the working directory. * * @param {Repository} repo Repository that contains the given commits - * @param {Commit} theirHead The annotated to merge into HEAD + * @param {AnnotatedCommit} theirHead The annotated commit to merge into HEAD * @param {MergeOptions} [mergeOpts] The merge tree options (null for default) * @param {CheckoutOptions} [checkoutOpts] The checkout options * (null for default) From 9096eb631fd5a8c1ca26d1ea5069fc6f22c72bb7 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 4 Mar 2016 11:40:59 -0500 Subject: [PATCH 10/15] Failing test. --- test/tests/diff.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/test/tests/diff.js b/test/tests/diff.js index 42c0e624c..24b218ee4 100644 --- a/test/tests/diff.js +++ b/test/tests/diff.js @@ -8,6 +8,7 @@ describe("Diff", function() { var NodeGit = require("../../"); var Repository = NodeGit.Repository; var Diff = NodeGit.Diff; + var Blob = NodeGit.Blob; var reposPath = local("../repos/workdir"); var oid = "fce88902e66c72b5b93e75bdb5ae717038b221f6"; @@ -220,6 +221,33 @@ describe("Diff", function() { }); }); + it("can diff the contents of a file to a string with unicode characters", + function(done) { + var evilString = "Unicode’s fun!\nAnd it’s good for you!\n"; + var buffer = new Buffer(evilString); + var oid = Blob.createFromBuffer(this.repository, buffer, buffer.length); + Blob.lookup(this.repository, oid) + .then(function(blob) { + blob.repo = this.repository; + return Diff.blobToBuffer( + blob, + null, + evilString, + null, + null, + null, + null, + function(delta, hunk, payload) { + assert.fail( + "There aren't any changes so this shouldn't be called."); + done(); + }); + }) + .then(function() { + done(); + }); + }); + it("can diff with a null tree", function() { var repo = this.repository; var tree = this.masterCommitTree; From 5c04ba7b6d94c4cc67de3f0df9444cd161125234 Mon Sep 17 00:00:00 2001 From: joshaber Date: Fri, 4 Mar 2016 11:43:40 -0500 Subject: [PATCH 11/15] Get the byte count of the string. --- lib/diff.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/diff.js b/lib/diff.js index bf3eccb82..34c279047 100644 --- a/lib/diff.js +++ b/lib/diff.js @@ -68,7 +68,15 @@ Diff.blobToBuffer= function( binary_cb, hunk_cb, line_cb) { - var bufferLength = !buffer ? 0 : buffer.length; + var bufferText; + var bufferLength; + if (buffer instanceof Buffer) { + bufferText = buffer.toString("utf8"); + bufferLength = buffer.length; + } else { + bufferText = buffer; + bufferLength = !buffer ? 0 : Buffer.byteLength(buffer, "utf8"); + } opts = normalizeOptions(opts, NodeGit.DiffOptions); From 6608751ad4f2f79126ac93e029660fde6df4b5c8 Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Thu, 3 Mar 2016 17:28:09 -0700 Subject: [PATCH 12/15] Tests: generalized createConflict in index utils Leave the repository in a conflicted state and return the index rather than the IndexEntries of the ancestor, ours, and theirs --- test/tests/index.js | 6 +++++- test/utils/index_setup.js | 22 +++++++--------------- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/test/tests/index.js b/test/tests/index.js index a1f91b204..ff0fb6d35 100644 --- a/test/tests/index.js +++ b/test/tests/index.js @@ -311,7 +311,7 @@ describe("Index", function() { it("can add a conflict to the index", function() { var repo; - var repoPath = path.join(__dirname, "..", "repos", "index"); + var repoPath = local("../repos/index"); var ourBranchName = "ours"; var theirBranchName = "theirs"; var fileName = "testFile.txt"; @@ -329,6 +329,10 @@ describe("Index", function() { fileName ); }) + .then(function(index) { + assert.ok(index.hasConflicts()); + return index.conflictGet(fileName); + }) .then(function(indexEntries) { // Store all indexEntries for conflict ancestorIndexEntry = indexEntries.ancestor_out; diff --git a/test/utils/index_setup.js b/test/utils/index_setup.js index a55e95924..eafcd5b52 100644 --- a/test/utils/index_setup.js +++ b/test/utils/index_setup.js @@ -1,4 +1,3 @@ -var assert = require("assert"); var NodeGit = require("../../"); var path = require("path"); var promisify = require("promisify-node"); @@ -75,25 +74,18 @@ var IndexSetup = { return repository.createCommit(ourBranch.name(), ourSignature, ourSignature, "we made a commit", oid, [ourCommit]); }) - .then(function(commitOid) { - var opts = { - checkoutStrategy: NodeGit.Checkout.STRATEGY.FORCE - }; - - return NodeGit.Checkout.head(repository, opts); + .then(function() { + return repository.checkoutBranch( + ourBranch, + new NodeGit.CheckoutOptions() + ); }) .then(function() { return repository.mergeBranches(ourBranchName, theirBranchName); }) - .then(function(commit) { - assert.fail(commit, undefined, - "The index should have been thrown due to merge conflicts"); - }) .catch(function(index) { - assert.ok(index); - assert.ok(index.hasConflicts()); - - return index.conflictGet(fileName); + return NodeGit.Checkout.index(repository, index) + .then(function() { return index; }); }); } }; From b60cc8e546ca992e5527bf76fd0f9f5e3b4c5c80 Mon Sep 17 00:00:00 2001 From: Kyle Smith Date: Thu, 3 Mar 2016 17:58:23 -0700 Subject: [PATCH 13/15] Exposed function `mergeheadForeach` --- generate/input/descriptor.json | 5 +++- lib/repository.js | 10 ++++++++ test/tests/repository.js | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+), 1 deletion(-) diff --git a/generate/input/descriptor.json b/generate/input/descriptor.json index f7aef8c27..f51d219ba 100644 --- a/generate/input/descriptor.json +++ b/generate/input/descriptor.json @@ -1759,7 +1759,10 @@ "ignore": true }, "git_repository_mergehead_foreach": { - "ignore": true + "isAsync": true, + "return": { + "isErrorCode": true + } }, "git_repository_message": { "ignore": true diff --git a/lib/repository.js b/lib/repository.js index c6c851b70..8004d944d 100644 --- a/lib/repository.js +++ b/lib/repository.js @@ -1200,6 +1200,16 @@ Repository.prototype.fetchheadForeach = function(callback) { return fetchheadForeach.call(this, callback, null); }; +var mergeheadForeach = Repository.prototype.mergeheadForeach; +/** + * @async + * @param {MergeheadForeachCb} callback The callback function to be called on + * each entry + */ +Repository.prototype.mergeheadForeach = function(callback) { + return mergeheadForeach.call(this, callback, null); +}; + /** * Stages or unstages line selection of a specified file * diff --git a/test/tests/repository.js b/test/tests/repository.js index 6f710ef10..5f7555ac4 100644 --- a/test/tests/repository.js +++ b/test/tests/repository.js @@ -3,6 +3,8 @@ var path = require("path"); var promisify = require("promisify-node"); var fse = promisify(require("fs-extra")); var local = path.join.bind(path, __dirname); +var IndexUtils = require("../utils/index_setup"); +var RepoUtils = require("../utils/repository_setup"); describe("Repository", function() { var NodeGit = require("../../"); @@ -260,4 +262,48 @@ describe("Repository", function() { }); }); }); + + it("can get all merge heads in a repo with mergeheadForeach", function() { + var repo; + var repoPath = local("../repos/merge-head"); + var ourBranchName = "ours"; + var theirBranchName = "theirs"; + var theirBranch; + var fileName = "testFile.txt"; + var numMergeHeads = 0; + var assertBranchTargetIs = function (theirBranch, mergeHead) { + assert.equal(theirBranch.target(), mergeHead.toString()); + numMergeHeads++; + }; + + return RepoUtils.createRepository(repoPath) + .then(function(_repo) { + repo = _repo; + return IndexUtils.createConflict( + repo, + ourBranchName, + theirBranchName, + fileName + ); + }) + .then(function() { + return repo.getBranch(theirBranchName); + }) + .then(function(_theirBranch) { + // Write the MERGE_HEAD file manually since createConflict does not + theirBranch = _theirBranch; + return fse.writeFile( + path.join(repoPath, ".git", "MERGE_HEAD"), + theirBranch.target().toString() + "\n" + ); + }) + .then(function() { + return repo.mergeheadForeach( + assertBranchTargetIs.bind(this, theirBranch) + ); + }) + .then(function() { + assert.equal(numMergeHeads, 1); + }); + }); }); From 59dc8b988cc49770c0db7bc32ef4af65e4cef544 Mon Sep 17 00:00:00 2001 From: John Haley Date: Tue, 1 Mar 2016 09:02:49 -0700 Subject: [PATCH 14/15] Revert "Merge pull request #931 from nodegit/bump-http-parser" Bumping `http-parser` to 2.6.1 broke fetching/pulling from bitbucket in earlier versions of node somehow. This undoes that change and we'll have to look into fixing node v5.6.x later. --- .travis.yml | 2 +- appveyor.yml | 2 +- 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 +----------------------- 10 files changed, 108 insertions(+), 514 deletions(-) diff --git a/.travis.yml b/.travis.yml index f871a28e5..d10faa0fc 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.6" + - export NODE_VERSION="5.0" matrix: fast_finish: true diff --git a/appveyor.yml b/appveyor.yml index 4bfa5af66..41d4f90ff 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.6" + - nodejs_version: "5.0" matrix: fast_finish: true diff --git a/vendor/http_parser/.gitignore b/vendor/http_parser/.gitignore index c122e76fb..32cb51b2d 100644 --- a/vendor/http_parser/.gitignore +++ b/vendor/http_parser/.gitignore @@ -12,8 +12,6 @@ parsertrace_g *.mk *.Makefile *.so.* -*.exe.* -*.exe *.a diff --git a/vendor/http_parser/AUTHORS b/vendor/http_parser/AUTHORS index 5323b685c..8e2df1d06 100644 --- a/vendor/http_parser/AUTHORS +++ b/vendor/http_parser/AUTHORS @@ -65,4 +65,3 @@ Romain Giraud Jay Satiro Arne Steen Kjell Schubert -Olivier Mengué diff --git a/vendor/http_parser/Makefile b/vendor/http_parser/Makefile index b3e0ff4ae..373709c66 100644 --- a/vendor/http_parser/Makefile +++ b/vendor/http_parser/Makefile @@ -19,19 +19,7 @@ # IN THE SOFTWARE. PLATFORM ?= $(shell sh -c 'uname -s | tr "[A-Z]" "[a-z]"') -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 +SONAME ?= libhttp_parser.so.2.5.0 CC?=gcc AR?=ar @@ -65,8 +53,8 @@ LDFLAGS_LIB += -Wl,-soname=$(SONAME) endif test: test_g test_fast - $(HELPER) ./test_g$(BINEXT) - $(HELPER) ./test_fast$(BINEXT) + ./test_g + ./test_fast test_g: http_parser_g.o test_g.o $(CC) $(CFLAGS_DEBUG) $(LDFLAGS) http_parser_g.o test_g.o -o $@ @@ -93,7 +81,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 $(HELPER) ./test_fast$(BINEXT) > /dev/null; done + while(true) do time ./test_fast > /dev/null; done test-valgrind: test_g valgrind ./test_g @@ -114,10 +102,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$(BINEXT) + $(CC) $(CPPFLAGS_FAST) $(CFLAGS_FAST) $^ -o parsertrace parsertrace_g: http_parser_g.o contrib/parsertrace.c - $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g$(BINEXT) + $(CC) $(CPPFLAGS_DEBUG) $(CFLAGS_DEBUG) $^ -o parsertrace_g tags: http_parser.c http_parser.h test.c ctags $^ @@ -125,12 +113,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.$(SOEXT) + ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.so 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.$(SOEXT) + ln -s $(LIBDIR)/$(SONAME) $(LIBDIR)/libhttp_parser.so uninstall: rm $(INCLUDEDIR)/http_parser.h @@ -140,8 +128,7 @@ 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 \ - *.exe *.exe.so + url_parser url_parser_g parsertrace parsertrace_g 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 eedd7f8c9..7c54dd42d 100644 --- a/vendor/http_parser/README.md +++ b/vendor/http_parser/README.md @@ -1,7 +1,7 @@ HTTP Parser =========== -[![Build Status](https://api.travis-ci.org/nodejs/http-parser.svg?branch=master)](https://travis-ci.org/nodejs/http-parser) +[![Build Status](https://travis-ci.org/joyent/http-parser.png?branch=master)](https://travis-ci.org/joyent/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 WebSocket protocol which sends +increasingly common example of this is the Web Socket protocol which sends a request like GET /demo HTTP/1.1 @@ -106,8 +106,8 @@ a request like followed by non-HTTP data. -(See [RFC6455](https://tools.ietf.org/html/rfc6455) for more information the -WebSocket protocol.) +(See http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-75 for more +information the Web Socket 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,69 +137,6 @@ 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 f235bed9e..6650b414a 100644 --- a/vendor/http_parser/contrib/url_parser.c +++ b/vendor/http_parser/contrib/url_parser.c @@ -35,7 +35,6 @@ 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); @@ -44,4 +43,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 d0c77ea73..0fa1c3627 100644 --- a/vendor/http_parser/http_parser.c +++ b/vendor/http_parser/http_parser.c @@ -400,8 +400,6 @@ 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 }; @@ -435,12 +433,6 @@ 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) @@ -645,7 +637,6 @@ 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) { @@ -966,23 +957,21 @@ 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; /* or LINK */ break; + case 'L': parser->method = HTTP_LOCK; 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; /* or REBIND */ break; + case 'R': parser->method = HTTP_REPORT; 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, UNBIND, UNLINK */ break; + case 'U': parser->method = HTTP_UNLOCK; /* or UNSUBSCRIBE */ break; default: SET_ERRNO(HPE_INVALID_METHOD); goto error; @@ -1007,40 +996,69 @@ size_t http_parser_execute (http_parser *parser, UPDATE_STATE(s_req_spaces_before_url); } else if (ch == matcher[parser->index]) { ; /* nada */ - } 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: + } 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 { SET_ERRNO(HPE_INVALID_METHOD); goto error; + } + } else { + SET_ERRNO(HPE_INVALID_METHOD); + goto error; } - } else if (ch == '-' && - parser->index == 1 && - parser->method == HTTP_MKCOL) { - parser->method = HTTP_MSEARCH; + } else if (parser->index == 4 && parser->method == HTTP_PROPFIND && ch == 'P') { + parser->method = HTTP_PROPPATCH; } else { SET_ERRNO(HPE_INVALID_METHOD); goto error; @@ -1366,12 +1384,7 @@ 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; @@ -1523,11 +1536,6 @@ 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) { @@ -1695,10 +1703,7 @@ size_t http_parser_execute (http_parser *parser, case s_header_almost_done: { - if (UNLIKELY(ch != LF)) { - SET_ERRNO(HPE_LF_EXPECTED); - goto error; - } + STRICT_CHECK(ch != LF); UPDATE_STATE(s_header_value_lws); break; @@ -1782,14 +1787,6 @@ 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 */ @@ -1831,12 +1828,11 @@ size_t http_parser_execute (http_parser *parser, case s_headers_done: { - int hasBody; STRICT_CHECK(ch != LF); parser->nread = 0; - hasBody = parser->flags & F_CHUNKED || + int 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)) { @@ -1861,7 +1857,8 @@ size_t http_parser_execute (http_parser *parser, /* Content-Length header given and non-zero */ UPDATE_STATE(s_body_identity); } else { - if (!http_message_needs_eof(parser)) { + if (parser->type == HTTP_REQUEST || + !http_message_needs_eof(parser)) { /* Assume content-length 0 - read the next */ UPDATE_STATE(NEW_MESSAGE()); CALLBACK_NOTIFY(message_complete); @@ -2156,13 +2153,15 @@ http_parser_settings_init(http_parser_settings *settings) const char * http_errno_name(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); + assert(((size_t) err) < + (sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); return http_strerror_tab[err].name; } const char * http_errno_description(enum http_errno err) { - assert(((size_t) err) < ARRAY_SIZE(http_strerror_tab)); + assert(((size_t) err) < + (sizeof(http_strerror_tab) / sizeof(http_strerror_tab[0]))); return http_strerror_tab[err].description; } @@ -2215,23 +2214,6 @@ 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: @@ -2250,7 +2232,6 @@ 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; @@ -2282,11 +2263,6 @@ 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; @@ -2316,8 +2292,6 @@ 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: @@ -2329,11 +2303,6 @@ 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) @@ -2407,12 +2376,7 @@ 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)) && - (u->field_set & (1 << UF_HOST)) == 0) { - return 1; - } - - if (u->field_set & (1 << UF_HOST)) { + if ((u->field_set & ((1 << UF_SCHEMA) | (1 << UF_HOST))) != 0) { 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 e33c0620a..eb71bf992 100644 --- a/vendor/http_parser/http_parser.h +++ b/vendor/http_parser/http_parser.h @@ -26,12 +26,11 @@ extern "C" { /* Also update SONAME in the Makefile whenever you change these. */ #define HTTP_PARSER_VERSION_MAJOR 2 -#define HTTP_PARSER_VERSION_MINOR 6 -#define HTTP_PARSER_VERSION_PATCH 1 +#define HTTP_PARSER_VERSION_MINOR 5 +#define HTTP_PARSER_VERSION_PATCH 0 #include -#if defined(_WIN32) && !defined(__MINGW32__) && \ - (!defined(_MSC_VER) || _MSC_VER<1600) && !defined(__WINE__) +#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) #include #include typedef __int8 int8_t; @@ -96,7 +95,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) \ @@ -105,28 +104,21 @@ 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(20, REPORT, REPORT) \ - XX(21, MKACTIVITY, MKACTIVITY) \ - XX(22, CHECKOUT, CHECKOUT) \ - XX(23, MERGE, MERGE) \ + XX(16, REPORT, REPORT) \ + XX(17, MKACTIVITY, MKACTIVITY) \ + XX(18, CHECKOUT, CHECKOUT) \ + XX(19, MERGE, MERGE) \ /* upnp */ \ - XX(24, MSEARCH, M-SEARCH) \ - XX(25, NOTIFY, NOTIFY) \ - XX(26, SUBSCRIBE, SUBSCRIBE) \ - XX(27, UNSUBSCRIBE, UNSUBSCRIBE) \ + XX(20, MSEARCH, M-SEARCH) \ + XX(21, NOTIFY, NOTIFY) \ + XX(22, SUBSCRIBE, SUBSCRIBE) \ + XX(23, UNSUBSCRIBE, UNSUBSCRIBE) \ /* RFC-5789 */ \ - XX(28, PATCH, PATCH) \ - XX(29, PURGE, PURGE) \ + XX(24, PATCH, PATCH) \ + XX(25, PURGE, PURGE) \ /* CalDAV */ \ - XX(30, MKCALENDAR, MKCALENDAR) \ - /* RFC-2068, section 19.6.1.2 */ \ - XX(31, LINK, LINK) \ - XX(32, UNLINK, UNLINK) \ + XX(26, MKCALENDAR, MKCALENDAR) \ enum http_method { @@ -148,12 +140,11 @@ 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) \ @@ -191,8 +182,6 @@ 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") \ @@ -217,11 +206,10 @@ enum http_errno { struct http_parser { /** PRIVATE **/ unsigned int type : 2; /* enum http_parser_type */ - unsigned int flags : 8; /* F_* values from 'flags' enum; semi-public */ + unsigned int flags : 7; /* F_* values from 'flags' enum; semi-public */ unsigned int state : 7; /* enum state from http_parser.c */ - 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; + unsigned int header_state : 8; /* enum header_state from http_parser.c */ + unsigned int index : 8; /* index into current matcher */ uint32_t nread; /* # bytes read in various scenarios */ uint64_t content_length; /* # bytes in body (0 if no Content-Length header) */ @@ -337,9 +325,6 @@ 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 4fcebaf79..4c00571eb 100644 --- a/vendor/http_parser/test.c +++ b/vendor/http_parser/test.c @@ -1101,58 +1101,6 @@ 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 */ }; @@ -2444,7 +2392,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++) { @@ -2970,59 +2918,6 @@ 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: Mon, 7 Mar 2016 11:22:07 -0700 Subject: [PATCH 15/15] Bump to 0.11.7 --- CHANGELOG.md | 9 +++++++++ README.md | 2 +- package.json | 2 +- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07809db6a..92a6dee8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # Change Log +## [0.11.7](https://github.com/nodegit/nodegit/releases/tag/v0.11.7) (2016-03-07) + +[Full Changelog](https://github.com/nodegit/nodegit/compare/v0.11.6...v0.11.7) + +- Added `Repository#mergeheadForeach` [PR #937](https://github.com/nodegit/nodegit/pull/937) +- Fixed `Merge.merge` docs to show it takes in an `AnnotatedCommit` and not a `Commit` [PR #935](https://github.com/nodegit/nodegit/pull/935) +- Fixed unicode in `Diff.blobToBuffer` getting corrupted [PR #935](https://github.com/nodegit/nodegit/pull/935) +- Fixed fetching/pulling to bitbucket in versions > v5.6 of node [PR #942](https://github.com/nodegit/nodegit/pull/942) + ## [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) diff --git a/README.md b/README.md index 5a982d009..7d84e166e 100644 --- a/README.md +++ b/README.md @@ -31,7 +31,7 @@ NodeGit -**Stable: 0.11.6** +**Stable: 0.11.7** ## Have a problem? Come chat with us! ## diff --git a/package.json b/package.json index f5912c818..f00d77862 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegit", "description": "Node.js libgit2 asynchronous native bindings", - "version": "0.11.6", + "version": "0.11.7", "homepage": "http://nodegit.org", "keywords": [ "libgit2",